There are multiple ways to do this. The simplest is probably this:
cat <<EOF | sh
touch somefile
echo foo > somefile
EOF
Another, which is nicer syntax in my opinion:
(
cat <<EOF
touch somefile
echo foo > somefile
EOF
) | sh
This works as well, but without the subshell:
{
cat <<EOF
touch somefile
echo foo > somefile
EOF
} | sh
More variations:
cat <<EOF |
touch somefile
echo foo > somefile
EOF
sh
Or:
{ cat | sh; } << EOF
touch somefile
echo foo > somefile
EOF
By the way, I expect the use of cat
in your question is a placeholder for something else. If not, take it out, like this:
sh <<EOF
touch somefile
echo foo > somefile
EOF
Which could be simplified to this:
sh -c 'touch somefile; echo foo > somefile'
or:
sh -c 'touch somefile
echo foo > somefile'
Redirecting output instead of piping
sh >out <<EOF
touch somefile
echo foo > somefile
EOF
Using cat
to get the equivalent of echo test > out
:
cat >out <<EOF
test
EOF
Multiple Here Documents
( cat; echo ---; cat <&3 ) <<EOF 3<<EOF2
hi
EOF
there
EOF2
This produces the output:
hi
---
there
Here's what's going on:
- The shell sees the
( ... )
and runs the enclosed commands in a subshell.
- The cat and echo are simple enough. The
cat <&3
says to run cat with file descriptor (fd) 0 (stdin) redirected from fd 3; in other words, cat out the input from fd 3.
- Before the
(...)
is started, the shell sees the two here document redirects and substitutes fd 0 (<<EOF
) and fd 3 (3<<EOF2
) with the read-side of pipes
- Once the initial command is started, the shell reads its stdin until EOF is reached and sends that to the write-side of the first pipe
- Next, it does the same with EOF2 and the write-side of the second pipe
You're doing:
bash << 'EOT'
some-command-that-reads-stdin
EOT
But some-command-that-reads-stdin
's stdin will be that here document as well, as it is started by bash
so inherits the same stdin
.
You could do:
bash /dev/fd/3 3<< 'EOT'
some-command-that-reads-stdin
EOT
So stdin is left untouched, and bash
gets the code from that here document on another fd.
Best Answer
?
gets its input from standard input which is the here document here. You'd need to feed the script todc
using a different file descriptor. On systems with/dev/fd/n
, that could be with:Or you can use ksh-style process substitution (which generally uses
/dev/fd/n
underneath):Or doing away with the here-document and the call to the (generally) external
cat
utility:Some
dc
implementations like GNUdc
allow passing the contents of thedc
script as argument with-e
, so you could use command substitution:Or directly: