4

I want to run a series of piped commands which do a lot of audioprocessing. It looks as follows in pseudocode:

command1 | command2 | command3

Of command2 and command3, both take the output of the previous command as input (regular stdin/stdout behaviour).

Now I'd like to execute another command1.1 right after command1, which is in no way connected to the running pipe between command1 and command2, except for it must not be run before command1 has completely finished.

command1 [; after that run command1.1, even if command2 and command3 are still busy] command2 command3

However I have no idea how to do this in bash. I've tried tee, but that makes the command to be run as soon as the pipe is constructed. Any ideas?

Thanks!

4

You can redirect it to a subshell.

command1 & > >(command2 | command3) &
wait $!      # Wait end of process $! (actually the pid of command1)
command_1.1     

Another way is to create a named pipe fifo.
A script should be similar to

MYFIFO=/tmp/myfifo.$$
rm -f $MYFIFO
mkfifo $MYFIFO
command1 > $MYFIFO &
MYPROGRAM_PID=$!
cat $MYFIFO  | command2 | command3 &
wait $MYPROGRAM_PID   # Wait end of process $MYPROGRAM_PID
command_1.1     
4

The important part about this is "after that" - the only concept UNIX pipes have of "after that" is, that they usually close, but they will execute after the first command has started, not after ist has ended.

So what you need to do, is employ a shell script - something which does have the concept of "one after the other":

echo 'command1' > myscript.sh
echo 'command1.1 >&2' >> myscript.sh
chmod 755 myscript.sh

(Ofcourse you can use your favorite editor to achive that), then run

myscript.sh | command2 | command3

What now happens is, that the output of command1 will be the output of the shell script, so your pipe works. Inside your script, the output of command1.1 will be redirected to STDERR of the script, so it is not sent to the pipe, but to the terminal

  • Eugen, the second echo should be echo 'command1.1 >&2' >> myscript.sh – Romeo Ninov Jan 18 '15 at 18:16
  • Maybe better ./myscript.sh than myscript.sh; usually the current directory is not included in the path for security reasons... – Hastur Jan 18 '15 at 18:20
  • @Hastur I left out all pathes - from the OQ I assume, the poster knows his way round – Eugen Rieck Jan 18 '15 at 19:47
  • 2
    @EugenRieck I agree, it was not for you or cunei. We all hope that the answer can be useful for other readers too :-) and, maybe, one of them can miss at a first sight the difference between a command that is somewhere in the PATH and a script that, even if executable (chmod 755) is in the current directory, by default off from the PATH. – Hastur Jan 18 '15 at 20:20
2

The simplest construction would be:

(command1 ; command1.1) | command2 | command3

There are two potential problems with this. If command1.1 produce any output on stdout, it will be sent through the pipe. Additionally command2 will not see EOF on stdin until command1.1 has completed.

If the pipeline is initially invoked in a context where stdout and stderr file descriptors are both pointing to the same file struct, then there is a simple way to fix both problems:

(command1 ; exec 1>&2 command1.1) | command2 | command3

This will cause stdout of command1.1 to point to stderr, which was not redirected by the pipeline.

If initially stdout and stderr might be two different file descriptors, the above approach can be used by temporarily stashing away the initial stdout in another file descriptor number. So unless you absolutely need to keep stdout and stderr from command1.1 separate, I would not take that approach.

For completeness, if you wanted to do that, it could look like this:

(((exec 9>&- command1) ; exec 1>&9 9>&- command1.1) | exec 9>&- command2 | exec 9>&- command3) 9>&1

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.