526

I have this multi-line string (quotes included):

abc'asdf"
$(dont-execute-this)
foo"bar"''

How would I assign it to a variable using a heredoc in Bash?

I need to preserve newlines.

I don't want to escape the characters in the string, that would be annoying...

Smi
  • 13,850
  • 9
  • 56
  • 64
Neil
  • 24,551
  • 15
  • 60
  • 81
  • @JohnM - I have just tried a heredoc assignment with single-quoted `'EOF'`, with escaped linebreaks with `\` in the content: if the second line has `cd` command, I get back: "_.sh: line X: cd: command not found_"; but if I double-quote `"EOF"`; then bash variables `${A}` do not get preserved as strings (they get expanded); but then, line-breaks _are_ preserved - and, I don't have a problem running a command with `cd` in second line (_and both 'EOF' and "EOF" seem to play well also with `eval`, for running a set of commands stored in a string variable_). Cheers! – sdaau May 24 '12 at 08:08
  • 1
    ... and to add to my previous comment: bash comments "#" in double-qouted `"EOF"` variable, if called via `eval $VAR`, will cause all of the rest of the script to be commented, as here $VAR will be seen as a single line; to be able to use bash `#` comments in multiline script, double-quote also variable in the `eval call: `eval "$VAR"`. – sdaau May 24 '12 at 08:18
  • @sdaau: I had problems with `eval` ith this methods, but did not track it down since it was part of some package which `eval`s some variables defined in it's config file. Error message was: `/usr/lib/network/network: eval: line 153: syntax error: unexpected end of file`. I just switched to another solution. – Golar Ramblar Apr 10 '18 at 06:36
  • There _are_ situations when you really genuinely want a here document, but if you are simply looking for how to put a newline in a static string, probably read https://stackoverflow.com/questions/3005963/how-can-i-have-a-newline-in-a-string-in-sh instead. – tripleee Mar 28 '22 at 05:03

13 Answers13

700

You can avoid a useless use of cat and handle mismatched quotes better with this:

$ read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF

If you don't quote the variable when you echo it, newlines are lost. Quoting it preserves them:

$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

If you want to use indentation for readability in the source code, use a dash after the less-thans. The indentation must be done using only tabs (no spaces).

$ read -r -d '' VAR <<-'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
    EOF
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

If, instead, you want to preserve the tabs in the contents of the resulting variable, you need to remove tab from IFS. The terminal marker for the here doc (EOF) must not be indented.

$ IFS='' read -r -d '' VAR <<'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
EOF
$ echo "$VAR"
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''

Tabs can be inserted at the command line by pressing Ctrl-V Tab. If you are using an editor, depending on which one, that may also work or you may have to turn off the feature that automatically converts tabs to spaces.

Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • 1
    This is useful to embed multi-line perl programs in bash variables when combined with the `-r` option to preserve backslashes as well. – TrinitronX Apr 19 '11 at 03:54
  • @TrinitronX: True, `read` should almost always have `-r`. I forgot to include it (fixed). – Dennis Williamson Apr 19 '11 at 13:13
  • 194
    I think it's worth mentioning that if you have `set -o errexit` (a.k.a `set -e`) in your script and you use this then it will terminate your script because `read` returns a non-zero return code when it reaches EOF. – Mark Byers Jun 28 '11 at 08:04
  • 20
    @MarkByers: That's one of the reasons I never use `set -e` and always recommend against its use. It's better to use proper error handling instead. `trap` is your friend. Other friends: `else` and `||` among others. – Dennis Williamson Jun 29 '11 at 03:37
  • @Dennis How do I do this while including the tab character for indention? I know I can just use space, but is this possible? – Tyilo Aug 04 '11 at 17:29
  • 1
    @DennisWilliamson is there an alternative to using the `-d` parameter on `read`? I'm stuck using an environment that doesn't have the `-d` option, but I can't figure out any other way to get `read` to load multiple lines without it. – Haravikk Oct 22 '13 at 17:53
  • 25
    Is the avoidance of `cat` really worth it in such a case? Assigning a heredoc to a variable with `cat` is a well known idiom. Somehow using `read` obfuscates things for little benefits imho. – Gregory Pakosz Jan 07 '14 at 21:18
  • 1
    Meh. A warning from someone who's been trying to be too smart (me): **`read -rd'' VAR << EOF` won't work**, because `VAR` will be parsed as the delimiter (and the heredoc will end up in `$REPLY`). – ulidtko Mar 24 '14 at 13:04
  • 10
    @ulidtko That's because you don't have a space between `d` and the empty string; `bash` collapses `-rd''` to simply `-rd` before `read` ever sees its arguments, so `VAR` is treated as the argument to `-d`. – chepner Apr 01 '14 at 19:16
  • 8
    In this format, `read` will return with a non-zero exit code. This makes this method less than ideal in a script with error checking enabled (eg `set -e`). – Swiss Apr 28 '15 at 22:08
  • 3
    @Swiss: [`set -e` should never be used](http://mywiki.wooledge.org/BashFAQ/105) - do proper error checking instead – Dennis Williamson Apr 28 '15 at 22:33
  • @DennisWilliamson `set -e` was just an example. My point is that the read command reports failure when this is run. – Swiss Apr 28 '15 at 23:09
  • 2
    Is it possible to use this and get variable substitution? I would like to use $variables in my multiline string. – Landon Kuhn Apr 11 '16 at 20:07
  • 1
    @LandonKuhn: Remove the quotes from around the name of the heredoc. This will also allow command substitutions to be evaluated and will affect white space in the manner i indicated in my answer. – Dennis Williamson Apr 12 '16 at 02:31
  • It is too slow because shell calls `read`(2) for each 1 byte in the here document. – fumiyas May 17 '16 at 12:51
  • 1
    Why does is `$?` == 1 after executing `IFS='' read -r -d '' VAR <<'EOF'` even when it consumes an "EOF" at the beginning of the line? Any way to work around this? – Tom Hale Feb 21 '17 at 07:58
  • 1
    Answering my own question, see [this answer](http://unix.stackexchange.com/a/265151/143394) (thanks @ffledgling). – Tom Hale Feb 21 '17 at 08:10
  • 1
    While I love `trap`ing errors too, when you are working on a shared code base, it's not polite to change an agreed upon standard (like `#!/bin/bash -eu`). So, I added a note to the end of this otherwise excellent answer. – Bruno Bronosky Jan 22 '18 at 04:41
  • @BrunoBronosky: `set -e` [should never be used](https://mywiki.wooledge.org/BashFAQ/105). – Dennis Williamson Jan 22 '18 at 16:25
  • 1
    what do these arguments mean `-r -d ` ? I couldn't find in `man read`. Example 3 worked well in my case. – lacostenycoder Jul 27 '18 at 19:10
  • 4
    @lacostenycoder: `man read` is about the operating system function call so it doesn't directly apply. In this context, `read` is a Bash builtin and you can get information about it using `help read` or `man bash`. The option `-r` is to accept backslashes literally instead of using them to escape any characters. The `-d` option sets the first character of the following argument as the delimiter between records (lines) instead of the default which is newline. In the example, I'm setting the delimiter to a null string. – Dennis Williamson Jul 27 '18 at 20:22
  • 1
    A tiny note to this otherwise wonderful answer: Leading/trailing blank lines are chomped by `read` unless `IFS=`. – mogsie Jan 03 '19 at 14:39
  • You could use [`sed` to keep your indentation, for example...](https://unix.stackexchange.com/a/535019/104957). – c0xc Aug 11 '19 at 14:56
  • 1
    Thanks to @dennis-williamson and @mark-byers I am still astonished why no one suggested: `set -o errexit` `eof=$'\4'` `read -r -d "$eof" VAR < – 166_MMX Sep 03 '19 at 17:19
  • 1
    @166_MMX: I repeat: [don't use `errexit`](https://mywiki.wooledge.org/BashFAQ/105). – Dennis Williamson Sep 03 '19 at 17:30
  • Its not useless use of cat. With `read`, you will always get exit code 1. With cat you don't. Do you use bash unofficial strict mode? In this case, I consider `cat` the winner. – Benjamin Marwell Oct 18 '19 at 07:55
  • ?ote that: **zsh** allows this syntax to work: `var=$(< – Léa Gris Aug 30 '20 at 17:03
  • 3
    @Pauseduntilfurthernotice. At the bottom of the document that you keep linking, there is a conclusions section. Two of the three conclusions suggest not using errexit, but one suggests using it while being aware of the consequences. In short, it's debatable. – calico_ Nov 12 '20 at 21:12
  • 3
    Regarding getting non-zero exit code one could use a `|| true` right after the start of heredoc, i.e `read -r -d '' VAR <<'EOF' || true` for the first example. – Cigarette Smoking Man Dec 04 '21 at 10:39
  • 2
    Absolutely do use `-e` / `-o errexit`. The bash FAQ was written decades ago and is outdated. You cannot predict all possible failure scenarios. Not using `-e` is equivalent to `ON ERROR RESUME NEXT` in Visual Basic. Do not do this. As for this particular instance, the error is due to `-d ''`, which tells `read` to stop on a NUL character (i.e. a zero byte). Because there is none in the input, the command correctly reports an error, so masking it (e.g. with `|| true) is the correct fix. (You also clearly can't use this for data containing NUL bytes, but you can't put those in variables anyway.) – Vladimir Panteleev Jan 15 '22 at 17:03
  • 1
    `IFS=''` is needed to preserve trailing whitespace. – Vladimir Panteleev Jan 15 '22 at 18:11
  • Amendment to my previous comment: `-e` / `-o errexit` and/or an `ERR` trap. – Vladimir Panteleev Apr 26 '22 at 13:58
  • **Pro:** `read` is a bash builtin, and so will invoke quicker than `cat`. **Con:** `-d` is not apart of POSIX, and may not be portable to other shells. – tmillr Apr 03 '23 at 09:17
  • @MarkByers maybe this is an argument to use `cat` instead of `read`. – Chris Jul 24 '23 at 16:04
393

Use $() to assign the output of cat to your variable like this:

VAR=$(
cat <<'END_HEREDOC'
abc'asdf"
$(dont-execute-this)
foo"bar"''
END_HEREDOC
)

# this will echo variable with new lines intact
echo "$VAR"
# this will echo variable without new lines (changed to space character)
echo $VAR

Making sure to delimit starting END_HEREDOC with single-quotes. This will prevent the content of the heredoc from being expanded, so dont-execute-this will not be executed.

Note that ending heredoc delimiter END_HEREDOC must be alone on the line (hence the ending parenthesis ) is on the next line).

Thanks to @ephemient for the answer.

joeytwiddle
  • 29,306
  • 13
  • 121
  • 110
Neil
  • 24,551
  • 15
  • 60
  • 81
  • 1
    Actually, this one lets through quotes in some circumstances. I managed to do this in Perl easily... – Neil Jul 23 '09 at 15:24
  • 60
    +1. This is the most readable solution, at least for my eyes. It leaves the name of the variable at the far left of the page, instead of embedding it in the read command. – Clayton Stanley Apr 26 '13 at 22:57
  • 1
    When using this construct, I see Newlines are being converted to $ (dollar character) ?? – WestCoastProjects Jun 05 '13 at 19:13
  • There's a nitch: you musn't leave blank beside the '=' sign. – Scott Chu Apr 25 '14 at 05:40
  • 23
    PSA: remember that the variable *must* be quoted to preserve newlines. `echo "$VAR"` instead of `echo $VAR`. – sevko Nov 06 '14 at 03:43
  • 8
    This is nice with `ash` and OpenWRT where `read` doesn't support `-d`. – David Ehrmann Jan 19 '15 at 04:22
  • 4
    For reasons I cannot fathom, this fails with an "unexpected EOF" error if you have an **unpaired** backtick in the heredoc. – Resigned June 2023 Nov 01 '16 at 00:31
  • Drop the heredoc, and just use `$(cat)` and press Ctrl-D to send an EOF. This has the advantage of allowing "END_HEREDOC" to possibly occur in the text. – Tom Hale Feb 21 '17 at 08:04
  • 3
    What is the advantage of quoting `'END_HEREDOC'`? – Hubert Grzeskowiak Nov 17 '17 at 03:12
  • 5
    @HubertGrzeskowiak it prevents variable expansion. – miken32 Nov 17 '17 at 18:52
  • 1
    This is the shell-agnostic solution (if you care about portability) as `read` is a Bash built-in and not necessarily compatible with [Zsh](http://zsh.sourceforge.net/Doc/Release/Shell-Builtin-Commands.html). – anishpatel Feb 19 '18 at 20:30
  • `$(cat <<-'}'` -- terminate with *indented* `}`, followed by `)` on the following line. – Brent Bradburn Aug 30 '18 at 02:45
  • Here is the best solution for all – 1234 Jan 04 '20 at 01:37
  • 2
    @RadonRosborough Getting "unexpected EOF" if there are **UN-paired backticks** happens in Bash v3.x. The newer versions 4.x and 5.0 don't have this issue. Unfortunately this matters because many Apple users are stuck with Bash 3.2.x now and in the future. (Apple just announce their new OS versions will *NOT* get Bash 4.x; instead `zsh` will be the default shell in 10.15+) – DouglasDD Jul 12 '20 at 19:44
  • The [other answer](https://stackoverflow.com/a/1655389/23023) seems to provide a _mostly compatible_ bash3 / macOS portable solution for this. – conny Sep 13 '21 at 04:20
  • Warning: the command substitution used in this solution strips trailing whitespace/newlines from the heredoc. Using `read` on the other hand does not. – wheeler Feb 10 '23 at 02:49
103

this is variation of Dennis method, looks more elegant in the scripts.

function definition:

define(){ IFS='\n' read -r -d '' ${1} || true; }

usage:

define VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF

echo "$VAR"

enjoy

p.s. made a 'read loop' version for shells that do not support read -d. should work with set -eu and unpaired backticks, but not tested very well:

define(){ o=; while IFS="\n" read -r a; do o="$o$a"'
'; done; eval "$1=\$o"; }
ttt
  • 1,177
  • 1
  • 7
  • 4
  • 1
    This seems to work only superficially. The define function will return a status of 1, and I'm not quite sure what needs to be corrected. – fny May 29 '12 at 19:01
  • 1
    This is also superior to the accepted answer, because it can be modified to support POSIX sh in addition to bash (a `read` loop in the function, to avoid the `-d ''` bashism necessary to preserve newlines). – ELLIOTTCABLE Dec 22 '14 at 00:32
  • Unlike the cat-in-a-subshell option, this works with **unpaired** backticks in the heredoc. Thank you! – Resigned June 2023 Nov 01 '16 at 15:51
  • 2
    This solution works with `set -e` set, whereas the selected answer does not. It seems to be because of `http://unix.stackexchange.com/a/265151/20650` – ffledgling Nov 08 '16 at 11:30
  • @ELLIOTTCABLE how would the `read` loop actually look like to avoid the `-d ''`? Since the beautiful answer of the OP certainly does not work on AIX. – ikaerom May 10 '17 at 08:53
  • @Moreaki added 'read loop' version, but have no access to AIX for testing, so ymmv. – ttt Oct 04 '17 at 15:44
  • 4
    @fny p.s. return status has long been fixed – ttt Oct 04 '17 at 15:54
  • 3
    ShellCheck SC2141 says it should be `define(){ IFS=$'\n' ...` (added `$`) – luckman212 Sep 27 '20 at 05:36
  • 1
    `IFS='\n'` doesn't what you want (it sets the IFS to a literal `n` after removing the backslash). You can fix that with a literal newline between the quotes, or in Bash with `IFS=$'\n'` as suggested in previous comments. – tripleee Mar 28 '22 at 04:57
  • In addition to `$'\n'`, the eval is a bit shady. especially since it's missing quotes. `eval "$1=\"\$o\""` perhaps better to use `printf -v` instead of eval... as it is, this would be a security hole, and could `$(insert executed code)`. – Ajax Aug 31 '23 at 19:56
53
VAR=<<END
abc
END

doesn't work because you are redirecting stdin to something that doesn't care about it, namely the assignment

export A=`cat <<END
sdfsdf
sdfsdf
sdfsfds
END
` ; echo $A

works, but there's a back-tic in there that may stop you from using this. Also, you should really avoid using backticks, it's better to use the command substitution notation $(..).

export A=$(cat <<END
sdfsdf
sdfsdf
sdfsfds
END
) ; echo $A
slm
  • 15,396
  • 12
  • 109
  • 124
l0st3d
  • 2,860
  • 1
  • 27
  • 29
  • I've updated my question to include $(executable). Also, how do you preserve newlines? – Neil Jul 22 '09 at 20:05
  • 3
    @l0st3d: So close... Use `$(cat <<'END'` instead. @Neil: The very last newline will not be part of the variable, but the rest will be preserved. – ephemient Jul 22 '09 at 20:16
  • 1
    It doesn't seem like any newlines are preserved. Running the above example I see: "sdfsdf sdfsdf sdfsfds"... ah! But writing `echo "$A"` (i.e. putting $A in double quotes) and you do see the newlines! – Darren Cook May 15 '13 at 11:58
  • 2
    @Darren: aha! I had noticed the newlines issue, and using the quotes around the output variable does fix the issue. thx! – WestCoastProjects Jun 05 '13 at 19:14
  • 1
    @l0st3d I would just leave out mention of backticks. – Brad Koch May 21 '14 at 16:03
  • You don't need to use cat inside the $(...) since << already sends the here document to stdout. So `export A=$(< – Spoike Sep 08 '16 at 11:24
  • 3
    Interestingly, due to the quirk of the first example, in a pinch you can use it for makeshift comment blocks like this: `REM=<< 'REM' ... comment block goes here ... REM`. Or more compactly, `: << 'REM' ...`. Where "REM" could be something like "NOTES" or "SCRATCHPAD", etc. – Beejor Dec 09 '17 at 03:35
49

There is still no solution that preserves newlines.

This is not true - you're probably just being misled by the behaviour of echo:

echo $VAR # strips newlines

echo "$VAR" # preserves newlines

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
patspam
  • 2,069
  • 18
  • 6
  • 9
    Really this is the behavior of how quoting a variable works. Without quotes, it will insert them as different parameters, space deliminated, while with quotes the entire variable contents will be treated as one argument – Czipperz Nov 09 '15 at 01:02
24

Branching off Neil's answer, you often don't need a var at all, you can use a function in much the same way as a variable and it's much easier to read than the inline or read-based solutions.

$ complex_message() {
  cat <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
}

$ echo "This is a $(complex_message)"
This is a abc'asdf"
$(dont-execute-this)
foo"bar"''
Community
  • 1
  • 1
dimo414
  • 47,227
  • 18
  • 148
  • 244
16

An array is a variable, so in that case mapfile will work

mapfile y <<'z'
abc'asdf"
$(dont-execute-this)
foo"bar"''
z

Then you can print like this

printf %s "${y[@]}"
Zombo
  • 1
  • 62
  • 391
  • 407
7

I can't believe I'm the first to post this.

@Erman and @Zombo are close, but mapfile doesn't just read arrays...

Consider this:

#!/bin/bash
mapfile -d '' EXAMPLE << 'EOF'
Hello
こんにちは
今晩は
小夜なら
EOF
echo -n "$EXAMPLE"

Yielding:

Hello
こんにちは
今晩は
小夜なら

$'' is the delimiter given to mapfile, it will never occur, it means "not delimited".

So there's no need for a useless use of cat and no need to incur the penalty of recombining arrays.

Furthermore, you get this benefit:

$ echo $EXAMPLE
Hello こんにちは 今晩は 小夜なら

Which you do not receive with @Zombo's method:

mapfile y <<'z'
abc'asdf"
$(dont-execute-this)
foo"bar"''
z
echo $y
abc'asdf"

Bonus

If you run it through head -c -1 you can also get rid of that last newline in a way that won't be non-performant:

unset EXAMPLE
mapfile -d '' EXAMPLE < <(head -c -1 << EOF
Hello
こんにちは
今晩は
小夜なら
EOF
)
printf "%q" "$EXAMPLE"
$'Hello\nこんにちは\n今晩は\n小夜なら'
Fredrick Brennan
  • 7,079
  • 2
  • 30
  • 61
3

assign a heredoc value to a variable

VAR="$(cat <<'VAREOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
VAREOF
)"

used as an argument of a command

echo "$(cat <<'SQLEOF'
xxx''xxx'xxx'xx  123123    123123
abc'asdf"
$(dont-execute-this)
foo"bar"''
SQLEOF
)"
bronze man
  • 1,470
  • 2
  • 15
  • 28
  • When I tried the first method, there seems to be no line terminators between the lines. Must be some kind of configuration on my linux machine? – Kemin Zhou Nov 24 '15 at 18:46
  • 1
    This probably means when you were echoing your variable, you didn't put quotes around it... Try it like so: `echo "$VAR"` – Brad Parks Feb 22 '16 at 15:15
2

Thanks to dimo414's answer, this shows how his great solution works, and shows that you can have quotes and variables in the text easily as well:

example output

$ ./test.sh

The text from the example function is:
  Welcome dev: Would you "like" to know how many 'files' there are in /tmp?

  There are "      38" files in /tmp, according to the "wc" command

test.sh

#!/bin/bash

function text1()
{
  COUNT=$(\ls /tmp | wc -l)
cat <<EOF

  $1 Would you "like" to know how many 'files' there are in /tmp?

  There are "$COUNT" files in /tmp, according to the "wc" command

EOF
}

function main()
{
  OUT=$(text1 "Welcome dev:")
  echo "The text from the example function is: $OUT"
}

main
Community
  • 1
  • 1
Brad Parks
  • 66,836
  • 64
  • 257
  • 336
  • It would be interesting to see an unmatched quote in the text to see how it handles that. Maybe ` Don't freak out, there are "$COUNT" files` so the apostrophe/single quote can make things interesting. – dragon788 May 02 '18 at 17:52
1

I found myself having to read a string with NULL in it, so here is a solution that will read anything you throw at it. Although if you actually are dealing with NULL, you will need to deal with that at the hex level.

$ cat > read.dd.sh

read.dd() {
     buf= 
     while read; do
        buf+=$REPLY
     done < <( dd bs=1 2>/dev/null | xxd -p )

     printf -v REPLY '%b' $( sed 's/../ \\\x&/g' <<< $buf )
}

Proof:

$ . read.dd.sh
$ read.dd < read.dd.sh
$ echo -n "$REPLY" > read.dd.sh.copy
$ diff read.dd.sh read.dd.sh.copy || echo "File are different"
$ 

HEREDOC example (with ^J, ^M, ^I):

$ read.dd <<'HEREDOC'
>       (TAB)
>       (SPACES)
(^J)^M(^M)
> DONE
>
> HEREDOC

$ declare -p REPLY
declare -- REPLY="  (TAB)
      (SPACES)
(^M)
DONE

"

$ declare -p REPLY | xxd
0000000: 6465 636c 6172 6520 2d2d 2052 4550 4c59  declare -- REPLY
0000010: 3d22 0928 5441 4229 0a20 2020 2020 2028  =".(TAB).      (
0000020: 5350 4143 4553 290a 285e 4a29 0d28 5e4d  SPACES).(^J).(^M
0000030: 290a 444f 4e45 0a0a 220a                 ).DONE
Orwellophile
  • 13,235
  • 3
  • 69
  • 45
-1

Here's a way to do it that is (imho) quite elegant and avoids a UUOC:

  VAR=$(sed -e 's/[ ]*\| //g' -e '1d;$d' <<'--------------------'
      | 
      | <!DOCTYPE html>
      | <html>
      |   <head>
      |     <script src='script.js'></script>
      |   </head>
      |   <body>
      |     <span id='hello-world'></span>
      |   </body>
      | </html>
      | 
--------------------
    )

The '|' characters define the margin, and only the whitespace to the right of the margin is respected in the printed string. The '1d;$d' strips the first and last line, which are just added as a top and bottom margin around the content. Everything can be indented to whatever level you like, except the HEREDOC delimiter, which in this case is just a bunch of hyphens.

echo "$VAR"

# prints

<!DOCTYPE html>
<html>
  <head>
    <script src='script.js'></script>
  </head>
  <body>
    <span id='hello-world'></span>
  </body>
</html>
awwsmm
  • 1,353
  • 1
  • 18
  • 28
  • Um, dude, good attempt but clearly compiling a regular expression and running a global replace is _far more_ resource-hungry of an operation than a UUOC. The `mapfile` approach is best per appearance and performance, this one is way out there (why the margin??) – Fredrick Brennan Aug 16 '22 at 08:31
-11
$TEST="ok"
read MYTEXT <<EOT
this bash trick
should preserve
newlines $TEST
long live perl
EOT
echo -e $MYTEXT