Say I have a command I'm running in my script who's first line in stderr
is something I need. I'm using stderr
because stdout
is already being used for transferring some other data. I still need the rest of stderr
for user feedback, so I still want to display everything after the first line.
cmd() {
ssh [email protected] '
printf "stderr data line 1 (important)\n" 1>&2
printf "stdout data line 1\n"
printf "stderr data line 2\n" 1>&2
printf "stdout data line 2\n"
printf "stdout data line 3\n"
printf "stderr data line 3\n" 1>&2'
}
# What sort of shell magic would I need to extract
# only the 1st line of stderr?
cmd > store_stdout_to_this_file ??? read -a first_line_of_stderr
echo "$first_line_of_stderr"
I can't use a pipe, as pipes only pipe stdout, and even if I were to rearrange them, then the other end of the pipe is in a different process space.
CodePudding user response:
I see several methods to do this, all with different limitations and oddities. Probably the simplest is to redirect stderr to a background subshell (via process substitution) that runs read
once, then cat
:
cmd >outputfile 2> >(read firstline; echo "First line is: '$firstline'"; cat -u)
But that puts the first-line processing in a subshell, so any variables it sets will be lost when that shell exits. I suppose you could have it write the line to another file, and then read that from the main script afterward...
Another possibility is to put the command you're trying to capture in the process substitution, and read
and cat
in the main shell:
{ read firstline; cat -u; } < <(cmd 2>&1 >outputfile)
echo "First line is: '$firstline'"
Note that the output redirection from cmd
must be done inside the process-substituted part (since its stdout is being sent to the read
-cat
part), and the 2>&1
must be first so stderr doesn't go to the same place.
CodePudding user response:
You can do like this:
line=
while read -r; do
[[ -z $line ]] && line="$REPLY" || echo "$REPLY"
done < <(cmd 2>&1 >out.log)
stderr data line 2
stderr data line 3
# check $line
echo "$line"
stderr data line 1 (important)
i.e. redirect stderr to stdout first and then redirect stdout to out.log
and finally pipe output using head -n 1
.