Pipe output and capture exit status in Bash

后端 未结 15 1302
盖世英雄少女心
盖世英雄少女心 2020-11-22 08:07

I want to execute a long running command in Bash, and both capture its exit status, and tee its output.

So I do this:

command | tee out.txt
ST=$?
         


        
15条回答
  •  醉梦人生
    2020-11-22 08:18

    The simplest way to do this in plain bash is to use process substitution instead of a pipeline. There are several differences, but they probably don't matter very much for your use case:

    • When running a pipeline, bash waits until all processes complete.
    • Sending Ctrl-C to bash makes it kill all the processes of a pipeline, not just the main one.
    • The pipefail option and the PIPESTATUS variable are irrelevant to process substitution.
    • Possibly more

    With process substitution, bash just starts the process and forgets about it, it's not even visible in jobs.

    Mentioned differences aside, consumer < <(producer) and producer | consumer are essentially equivalent.

    If you want to flip which one is the "main" process, you just flip the commands and the direction of the substitution to producer > >(consumer). In your case:

    command > >(tee out.txt)
    

    Example:

    $ { echo "hello world"; false; } > >(tee out.txt)
    hello world
    $ echo $?
    1
    $ cat out.txt
    hello world
    
    $ echo "hello world" > >(tee out.txt)
    hello world
    $ echo $?
    0
    $ cat out.txt
    hello world
    

    As I said, there are differences from the pipe expression. The process may never stop running, unless it is sensitive to the pipe closing. In particular, it may keep writing things to your stdout, which may be confusing.

提交回复
热议问题