MyTetra Share
Делитесь знаниями!
How to assign a heredoc value to a variable in Bash?
Время создания: 22.08.2013 14:58
Раздел: root - Linux - Console - bash
Запись: Yurons/mytetra/master/base/137717268569mrtokyw8/text.html на raw.github.com

http://stackoverflow.com/questions/1167746/how-to-assign-a-heredoc-value-to-a-variable-in-bash

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.share|improve this answer edited Jun 12 '12 at 4:00

answered Oct 31 '09 at 19:41

Dennis Williamson

79.3k1388162

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 3:54

@TrinitronX: True, read should almost always have -r. I forgot to include it (fixed). – Dennis Williamson Apr 19 '11 at 13:13

1

I've never seen an answer from Dennis that wasn't useful. +1 as always. That 33.3K is well deserved. – iconoclast May 16 '11 at 21:05

2

@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 3:37

2

@DennisWilliamson: Shouldn't it be IFS=$'\n' instead of IFS='\n' ? Or even better, to preserve leading/trailing newline characters: IFS='' – Håkon A. Hjortland Jun 12 '12 at 0:14

show 5 more comments

up vote

20

down vote

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

)

echo "$VAR"

Making sure to delimit END_HEREDOC with single-quotes.

Thanks to @ephemient for the answer.share|improve this answer edited Jul 13 at 20:10

user456584

3,43151238 answered Jul 22 '09 at 20:37

Neil

3,94131833

Actually, this one lets through quotes in some circumstances. I managed to do this in Perl easily... – Neil Jul 23 '09 at 15:24

+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 at 22:57

When using this construct, I see Newlines are being converted to $ (dollar character) ?? – javadba Jun 5 at 19:13

up vote

16

down vote

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"

enjoyshare|improve this answer edited Nov 19 '12 at 15:24

answered Nov 11 '11 at 0:12

ttt

16114

4

+1 for caring about readability in a bash script. – quodlibetor Mar 29 '12 at 1:18

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. – faraz May 29 '12 at 19:01

2

read returns 1 on EOF, but that was never a problem for me. if you want you can work around this by using: define(){ IFS='\n' read -r -d '' ${1}; return 0; } – ttt Sep 28 '12 at 14:24

I like this, but it doesn't work if -e is set. I guess read has an error on EOF, so the script exits. Any ideas? – cdunn2001 Oct 31 '12 at 19:01

i have edited the script to ignore return status of 'read' by '||true', this should now work with 'set -e' and similar situations. – ttt Nov 19 '12 at 15:14

up vote

3

down vote 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.share|improve this answer answered Jul 22 '09 at 19:57

l0st3d

901821

I've updated my question to include $(executable). Also, how do you preserve newlines? – Neil Jul 22 '09 at 20:05

1

@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

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 at 11:58

@Darren: aha! I had noticed the newlines issue, and using the quotes around the output variable does fix the issue. thx! – javadba Jun 5 at 19:14

up vote

2

down vote

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 ).DONEshare|improve this answer answered Jun 4 '12 at 4:41

Orwellophile

1,4201110

This one works as expected, but it depends on gvim. – Techlive Zheng Oct 10 '12 at 16:00

up vote

0

down vote 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

)"share|improve this answer edited Jul 28 at 4:11

answered Jul 23 at 5:20

bronze man

593

up vote

0

down vote

Adding comment here as an answer since I don't have enough rep points to comment on your question text.

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 newlinesshare|improve this ans

 
MyTetra Share v.0.65
Яндекс индекс цитирования