How do you use output redirection in combination with here-documents and cat?
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
I just want to point out that using meow
is just as valid as EOF
.
This script will append Meow!
to a file named cat
:
#!/bin/sh
cat <<meow>> cat
Meow!
meow
Save as cats
and make it executable with chmod +x cats
, then run it with ./cats
:
$ ./cats
$ cat cat
Meow!
$ ./cats
$ cat cat
Meow!
Meow!
Explanation:
cat <<meow
is the here document syntax. It instructs the script to pick up the block of text that follows this line, until it encounters the stringmeow
. The contents will then be outputted (or piped along).>> cat
pipes to the file namedcat
.- Using
>
instead of>>
would overwrite the file instead of appending to it. Meow!
is the contents of the here document.meow
is the end marker for the here document. The contents are, with the use of>>
, appended tocat
.
Piping both to stdout and to a file:
To do the piping you request, no here document is required.
cat
can not both output text and pass the text along, but tee
is a perfect match for what you are asking for:
echo echo | tee tee
This will both output the string echo
and write echo
to a file named tee
.
You could also pass the output through cat
, if that is part of the requirement, either with:
echo echo | tee tee | cat </dev/stdin
Or just:
echo echo | tee tee | cat
Contents of file:
$ cat tee
echo