2

I just noticed that some of my CI jobs returned OK even though compilation failed. This was essentially because the bash command called to compile the code, while failing and returning 1, had its output piped through sed to add some colours etc to the output.

In essence, this boils down to the following

$ false; echo $? # returns 1
$ true; echo $? # returns 0
$ false | sed 's/^/OUTPUT: /' # returns 0 because sed returns 0
$ true | sed 's/^/OUTPUT: /' # returns 0 because sed returns 0

I know that on bash, there's PIPESTATUS, so I can use ${PIPESTATUS[0]} to get the exit code of the command ran before the pipe. But how do I make a wrapper around any command so that its output is piped to sed and then the exit code of the command itself is returned (discarding the exit code of sed)?

To make it really versatile, let's say I want to pipe the output of any command to sed to add a colored prefix before each line of output:

$ PREFIX="$(printf '\033[1;31m')OUTPUT: $(printf '\033[0m')"
$ ls | sed "s/^/$PREFIX/"

As argued above, because of the pipe to sed, this will return 0 regardless of what ls returns, and will display the directory contents with each line preceded by a red OUTPUT: .

Can I define a function, alias etc (let's call it "wrap") to make me call e.g. wrap ls *.txt in such a way that ls *.txt is executed, the output piped through the sed pattern, and the exit code of ls *.txt itself is returned, so that

$ wrap ls *.txt
OUTPUT: file1.txt
OUTPUT: file2.txt
$ echo $? # displays 0 (assuming there is at least one .txt file)
$ wrap ls *.foo
ls: No such file or directory
$ echo $? # displays 1 (assuming there is NO .foo file)
JHH
  • 8,567
  • 8
  • 47
  • 91
  • 2
    `set -o pipefail`? [Do not parse ls](https://unix.stackexchange.com/questions/128985/why-not-parse-ls-and-what-to-do-instead). Or just `command > >(sed 's/^/OUTPUT: /')`? – KamilCuk Feb 17 '21 at 12:22
  • 1
    A silly hack is to do `whatever | sed whatever | grep .` which fails if there is no output from `sed`. This obviously works only if you always expect output from your `sed` script, or if it could produce a partial result even if the first command fails. – tripleee Feb 17 '21 at 12:25
  • @JHH : What do you mean by _output_? stdout, stderr, or both? – user1934428 Feb 17 '21 at 12:53
  • @user1934428 Just stdout. – JHH Feb 18 '21 at 18:39

1 Answers1

1

Try:

function wrap
{
    "$@" | sed 's/^/OUTPUT: /'
    return "${PIPESTATUS[0]}"
}
pjh
  • 6,388
  • 2
  • 16
  • 17