Getting a Bourne shell "here document" into a shell variable

May 20, 2022

Suppose, for reasons to be discussed in a later entry, you would like to write a shell script that turns an embedded here document into a shell variable (ie, an unexported environment variable). As a preview, one reason to want to do this is that here documents allow almost arbitrary contents, while other forms of getting things into environment variables or command line arguments may block using certain characters or require awkward quoting.

It turns out that in a modern Bourne shell, this is straightforward with command substitution (normally using a quoted here document delimiter, because otherwise various things will get expanded on you):

yourvar="$(cat <<'EOF'
All of your content goes here.
Any characters and sequences are
fair game, like $, ", ', and
no expansion of eg $HOME or
stuff like $(hostname).
EOF
)"

This is more straightforward than I was expecting, and as far as I can tell there are no surprises and traps here. The resulting variable has the contents you expect and can be used normally as you need it.

(I haven't tried this with the old style command substitution using `...` instead of $(...), but I'd expect it to fail in various ways because the backtick style command substitution historically had lots of problems with escaping things. Also, there's not much reason to use the backtick style today.)

In Bash (or any Bourne shell that supports process substitution (Wikipedia)), you can also provide a program a command line argument that's a file that comes from a here document embedded into the shell script:

awk -f <(cat <<'EOF'
BEGIN { .... }
[...]
EOF
)

If you're going this far, extra arguments to the program go after the process substitution:

awk -f <(cat <<'EOF'
[...]
EOF
) /tmp/file1 /tmp/file2

I suggest trying hard to not need to do this in order to keep your sanity; this is situation like the rules for combining things with here documents where keeping it simple is much better (cf the sensible way to use here documents in pipelines). Because this is limited and somewhat tangled, I would only use it in a situation where I absolutely had to provide a program with a file (with the desired contents) instead of being able to provide things as a command line argument.

(The resulting script would be a Bash script instead of a general Bourne shell script, but sometimes this is fine.)

Written on 20 May 2022.
« Moving a libvirt-based virtualization setup from one machine to another
Some things that make languages easy (or not) to embed in Unix shell scripts »

Page tools: View Source.
Search:
Login: Password:

Last modified: Fri May 20 21:46:11 2022
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.