Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I've used this in the past to force bash to print every command it runs (using the -x flag) in the Actions workflow. This can be very helpful for debugging.

https://github.com/jstrieb/just.sh/blob/2da1e2a3bfb51d583be0...



FYI with pipefail enabled, if one of the pipes fails, your step will fail, there will be no error output, you won't know why it failed.

Pipefail also doesn't prevent more complex error states. For example this step from your config:

          curl -L "https://github.com/casey/just/releases/download/${{ matrix.just-version }}/just-${{ matrix.just-version }}-x86_64-apple-darwin.tar.gz" \
            | sudo tar -C /usr/local/bin -xzv just
Here's the different error conditions you will run into:

1. curl succeeds, sudo succeeds, tar succeeds, but just fails to extract from the tarball. Tar reports error, step fails.

2. curl succeeds, sudo succeeds, tar fails. Sudo reports error, step fails.

3. curl succeeds, sudo fails. Shell reports error, step fails.

4. curl begins running. sudo begins running in a subshell/pipe. tar begins running under the sudo pipe, extracting half of the just binary. curl fails due to network error. Due to pipefail being enabled, shell exits immediately. There is no error message. A corrupt executable is left on-disk (which will be attempted to run if your step had failure-skipping enabled)


> there will be no error output, you won't know why it failed

That's probably why the -x is there. (Well, that and if something like curl or sudo fails it tends to output something to stderr...)

> Pipefail also doesn't prevent more complex error states ... A corrupt executable is left on-disk (which will be attempted to run if your step had failure-skipping enabled)

If I'm reading right it seems like you're suggesting is that the case pipefail doesn't handle is if you explicitly ignore the exit code. That doesn't exactly seem like the most concerning catch 22, to be honest.


-x does not show output/errors when pipefail triggers. It tells you a pipe has started, and that's it. No idea what specific part of the pipe failed, or why, or what its return status was.

It's not that pipefail doesn't handle a case, it's that it doesn't tell you what happened. It does not report what failed or why. Your shell just exits with a mystery return code.


The point is that if you run -x you will definitely see plenty of output leading up to the failure. It is true that if the command that fails outputs nothing to stderr, then this may still lead to confusing outcomes, but you will not be staring at empty output, you'll be staring at the commands leading up to the failure.

This is of course no different than if you had set -e and then a command with no pipes failed silently without outputting anything to stderr.

I don't personally see why this is notable in relation to pipefail.


You're supposed to also use `set -e` if you're going to `set -o pipefail`, but of course that requires understanding that `set -e` will not apply to anything happening from inside a function called in a conditional expression -- this is a tremendous footgun.

And if you want to know which command in a pipe failed there's `PIPESTATUS`.


If they're using -e with pipefail you can't check PIPESTATUS because the shell has exited.

If you use pipefail without -e, nothing happens, except the return status of the line is different (and thus using the option is pointless unless you're checking return statuses/PIPESTATUS, which of course nobody who uses this option actually does, because they don't know how it works)

From the Bash manual:

       The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled.  If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully.  If the reserved word !  precedes a pipeline, the exit status of that pipeline is the logical negation of the exit status as described above.  The shell waits for all commands in the pipeline to terminate before returning a value.

       pipefail
               If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully.  This option is disabled by default.
They don't mention how the rightmost command might be the one failing due to the lefthand one failing if it's trying to read data and fails, or from a signal handler, or if you have multiple commands in the pipe and it's the first one that failed, or multiple because (again) maybe they're feeding input to each other and two of them failed, etc.

The use of this option is an anti-pattern. You don't even need it because you can check PIPESTATUS without it.

Everybody uses pipefail because bloggers and people on HN say to use it, but without actually understanding what it's doing.


Yes, it's either or -- or else you can have a pipe in a conditional.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: