I’m trying to capture and "store away" (preferably in a variable) the first line of a command output and forward the remainder of the output back to stdin of the next command in a pipe. As an FYI, the purpose is to capture and store the cursor reference of a redis-cli SCAN
invocation, while processing the data returned.
This is what I came up with:
command | { read first_line ; cat ; } | process_rest
echo $first_line
This seems to work as intended in zsh, but not in Bourne Shell ("/bin/sh") or bash. It appears that piping to the command grouping causes a subshell in sh/bash, "swallowing" the first_line variable.
What is the best way to achieve what I’m trying to do? Will I need to "pipe" the first line through a file or fifo instead of trying to set a variable? I also tried using a while read line ; do
construct to filter out the first line and continue processing the rest, but it appears it has the same effect (any variable changes within the do/done block are not reflected in the outer scope).
3
Answers
I think I found a way that works:
This will capture the first line while processing the remainder of the data. The main drawback of this approach is that I cannot easily redirect stdout of process_rest as part of the whole construct anymore. E.g.
One possible solution to this might be to use a fifo:
You may consider using a temporary file :
It’s not the braces. In a POSIX shell, any command sequence involving pipes (
cmd1 | cmd2
) runs both in subshells.To retain the value of
first_line
you must not run theread
in a subshell.With bash process substitution you can do:
or
Bash also has a
lastpipe
option which is available when job control is disabled (typically scripts / non-interactive shells, or when disabled explicitly):BashFAQ 024 has more information and options.