DenCowboy
DenCowboy

Reputation: 15086

How to make bash script fail at the end when an error occurs in a pipe

For now I'm using this in my script:

set -euxo pipefail

This will make my bash script fail immediatly if there is an error in my pipe. When I leave this option my script will run fully and end with exit 0 (no error).

I want to have a mix of both. I want to end the whole script but have exit 1; at the end if there was an error in a pipe.

My script looks like this:

#!/bin/bash
set -euxo pipefail
curl --fail --compressed -u "$CREDS" -X GET --header 'Accept: xxx' --header 'Accept-Language: de-DE' 'https://api/call1' | jq -S "." > "output1.json"
curl --fail --compressed -u "$CREDS" -X GET --header 'Accept: xxx' --header 'Accept-Language: de-DE' 'https://api/call2' | jq -S "." > "output2.json"
cat output1.json
cat output2.json

So I don't want to exit the script if call1 fails. If call1 fails I want to go to call2 and the cat commands before exiting the script with exit code 1.

Upvotes: 2

Views: 741

Answers (2)

KamilCuk
KamilCuk

Reputation: 141060

Subshells.

set -euo pipefail
export SHELLOPTS

(
   set -euo pipefail
   curl --fail --compressed -u "$CREDS" -X GET --header 'Accept: xxx' --header 'Accept-Language: de-DE' 'https://api/call1' | jq -S "." > "output1.json"
) && res1=$? || res1=$?

(
   set -euo pipefail
   curl --fail --compressed -u "$CREDS" -X GET --header 'Accept: xxx' --header 'Accept-Language: de-DE' 'https://api/call2' | jq -S "." > "output2.json"
) && res2=$? || res2=$?

if (( res1 != 0 || res2 != 0 )); then
   echo "Och! Command 1 failed or command 2 failed, what is the meaning of life?"
   exit 1;
fi

Subshell let's you grab the return value of the commands executed in it.

Upvotes: 0

anubhava
anubhava

Reputation: 785196

Don't use set -e as that will make script exit upon first error. Just save your exit codes after call1 and call2 and exit with appropriate exit code after cat commands:

#!/usr/bin/env bash -ux
set -uxo pipefail

curl --fail --compressed -u "$CREDS" -X GET --header 'Accept: xxx' --header 'Accept-Language: de-DE' 'https://api/call1' | jq -S "." > "output1.json"
ret1=$?
curl --fail --compressed -u "$CREDS" -X GET --header 'Accept: xxx' --header 'Accept-Language: de-DE' 'https://api/call2' | jq -S "." > "output2.json"
ret2=$?

cat output1.json
cat output2.json

exit $((ret1 | ret2))

Upvotes: 2

Related Questions