If you are doing some work on a file descriptor that you expect you'll want to read again, then you can portably do it in the body of a here-document:
exec 4<somefile 3<<plus
$( printf %s\\n some random lines
cat <&4
)
plus
cat <&3
The solution is not perfect perhaps - there is no portable way, for example, to seek back through the here document file descriptor. And the command substitution will elide trailing blank lines from whatever cat
writes to stdout, but all of these problems are very simply handled.
In the first place, redirections are scoped to their containing compound command, and so it is a small matter to nest these a bit in a loop to handle any repetition you might require. It is also possible to implement a loop within the command sub itself - or even to call out to an interactive shell on /dev/tty
if you want. But most generally I prefer to link a heredoc to a function definition.
fn() { : do something w/ fd3
} 3<<INPUT
$1
$(:gen some output;:maybe cat or head <stdin)
INPUT
while IFS= read -r line; do fn "$line"; done
It is also possible to read one heredoc another writes.
cat 4<<SAVED <<AND
$( cat)
SAVED
$( printf %s\\n some random lines
cat <&4)
AND
Or you could loop like...
until test && cat <&4
do exec 3<&4 4<<IN
$(: gen output; cat <&3)
IN
done 4<infile
And of course you could call something like the fn
above from within as well.
And regarding the trailing blank line problem - if it is a problem - then you can simply echo .
at the tail end of the command sub, then make sure you strip the last line from the fd when you read it like sed \$d <&"$fd"
.
But, while pretty secure, looping over files like this in the shell is usually a bad idea anyway - notice there is at least a fork per generated file? Shells assign fds and utilities handle them - do your loop in a sed
or awk
script and manipulate the file data w/ a standard utility then use the shell to direct it on output - that is usually best practice.
printf "%s\n%s\n" "foo" "bar" >&3
, fd 3 has a read/write pointer at byte 8 of the file. Do you wantcat <&3
to start reading from the beginning of the file rather than from byte 8? – Mark Plotnick Feb 04 '15 at 20:37