2

I'm trying to use a named pipe so I can keep stdout for status output from a long process. I could use stderr for status output, but I'd like to keep that for errors. Here is an example:

#!/bin/bash
pipe=$(mktemp -u)
mkfifo $pipe

dd if=/dev/zero of=$pipe bs=1M count=1024 status=progress & cat $pipe > test.bin

# ¿¿¿ Status of dd command ???

rm $pipe

The command isn't exactly what I'm trying to do, but illustrates the combination of using a named pipe for the output of one process feeding into the input of another. In my application, dd is replaced with some long running command, and cat with ssh. This would do what I want, but I don't know how to get the status of the dd command as $? would return the status of the cat command. If this were a pipe, I could use PIPESTATUS but that doesn't seem to work for parallel processes. In the actual application either (or both) commands could fail.

Is there a way to get the status of processes run in parallel? Is there a better way to accomplish this task using something other than named pipes?

1
  • @hophop There is nothing wrong with the dd command in the example. dd is just a stand-in example as I'm not actually using it in the actual application. I need to know if it fails.
    – A. Que
    Feb 7, 2022 at 18:11

1 Answer 1

6

To get the exit status of an asynchronous command, you use wait on its pid:

#!/bin/bash -
pipe=$(mktemp -u) || exit
mkfifo -m 600 -- "$pipe" || exit

dd if=/dev/zero of="$pipe" bs=1M count=1024 status=progress &
dd_pid=$!

cat -- "$pipe" > test.bin
cat_status=$?
wait "$dd_pid"
dd_status=$?

rm -f -- "$pipe"

(also fixing some of the obvious mistakes like not checking for success of those mktemp/mkfifo, unquoted expansions, missing --s).

Note that if dd (or whatever actual command dd is standing-in for in your case) exits before opening $pipe for writing, then cat will hang on its own read-only open() of the fifo indefinitely.

To work around that, you could have the shell open $pipe on another fd for the process that will eventually run dd making sure the pipe is instantiated as soon as cat opens it as well (and assuming dd doesn't arbitrarily close that fd before opening $pipe):

dd if=/dev/zero 3> "$pipe" of="$pipe" bs=1M count=1024 status=progress &
dd_pid=$!
cat -- "$pipe" > test.bin
cat_status=$?
wait "$dd_pid"
dd_status=$?

Similarly, if cat dies before opening the pipe, you'll have the same symmetrical problem, which you could address the same way.

Instead of a named pipe, if your system has /dev/fd/n files, you could probably also use a normal pipe in combination with /dev/fd/n and use bash's $PIPESTATUS to retrieve the exit statuses:

{
  dd if=/dev/zero of=/dev/fd/3 bs=1M count=1024 3>&1 >&5 4<&- 5>&- |
    cat /dev/fd/3 3<&0 <&4 4<&- 5>&- > test.bin
} 4<&0 5>&1

dd_status=${PIPESTATUS[0]} cat_status=${PIPESTATUS[1]}

($PIPESTATUS is bash-specific, but there are alternatives for other shells).

Above, both dd and cat will have the pipe open on their fd 3 (the writing end for dd and the reading end for cat) and they'll open /dev/fd/3 giving them another fd on the pipe like in the workaround above. We use fds 4 and 5 to restore the original stdin and stdout for both (though here cat's stdout is otherwise going to test.bin).

6
  • Why the -f in the rm? When can that be needed?
    – terdon
    Feb 7, 2022 at 18:18
  • @terdon, you generally want -f in scripts, where rm is meant to work unattended. With -f, rm could prompt the user under some circumstances. Feb 7, 2022 at 18:20
  • @StéphaneChazelas This answer mostly works. If dd fails right away (say for permissions failure or file not found), the script hangs. I presume it is because the cat command is waiting for data in the pipe and not getting anything. Thus the wait command is never reached.
    – A. Que
    Feb 7, 2022 at 19:06
  • @A.Que, if dd fails before it can open the pipe for writing, then the shell will block upon opening the pipe, before even starting cat Feb 7, 2022 at 19:18
  • @StéphaneChazelas Ok. How does one recover from this failure mode?
    – A. Que
    Feb 7, 2022 at 19:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .