How to implement 'set -o pipefail' in a POSIX way - almost done, expert help needed
command-line, pipe, posix, shell
Solution
My two cents:
#!/bin/sh
# Saving the pid of the main shell is required,
# as each element of the pipe is a subshell.
self=$$
lots_and_fail() {
seq 100
return 1
}
{ lots_and_fail || kill $self; } | sed s/7/3/
This thing seems to do the job. Thoughts?
Problem
I have to implement the BASH `set -o pipefail` option in a POSIX way so that it works on various LINUX/UNIX flavors. To explain a bit, this option enables the user to verify the successful execution of all piped commands. With this option enabled this command `cat app.log | grep 'ERROR'` fails if `cat` fails, otherwise the `cat` error is suppressed. So, I found a really nice solution here: http://cfaj.ca/shell/cus-faq-2.html ``` run() { j=1 while eval "\${pipestatus_$j+:} false"; do unset pipestatus_$j j=$(($j+1)) done j=1 com= k=1 l= for a; do if [ "x$a" = 'x|' ]; then com="$com { $l "'3>&- echo "pipestatus_'$j'=$?" >&3 } 4>&- |' j=$(($j+1)) l= else l="$l \"\$$k\"" fi k=$(($k+1)) done com="$com $l"' 3>&- >&4 4>&- echo "pipestatus_'$j'=$?"' exec 4>&1 eval "$(exec 3>&1; eval "$com")" exec 4>&- j=1 while eval "\${pipestatus_$j+:} false"; do eval "[ \$pipestatus_$j -eq 0 ]" || return 1 j=$(($j+1)) done return 0 } ``` The above-mentioned `run()` function enables the user to invoke the piped commands in such a way: ``` run cmd1 \| cmd2 \| cmd3 ``` If one of the commands fails you get it in `$?` There is a problem however, it does not support the grouping of commands between pipes. I want to be able to invoke something like this: ``` run echo "test" ; grep "test" \| awk '{print}' ``` When I do it, the invocation fails. I cannot get the right modification to support the grouping of commands -- the script is a bit too complex for my bash skills... Could somebody help? Thanks!