Note: Question does not duplicate Ignoring specific errors in a shell script .
Suppose it is needed to capture the leading characters of a encoded representation of a file.
In shell (tested in Bash), it is easy to use the following form:
encoded="$(< file base64 | head -c16)"
The statement functions desired, except under certain alterations to the environment.
Consider the following:
set -o errexit -o pipefail
shopt -s inherit_errexit
encoded="$(< file base64 | head -c16)"
The final line would cause termination of a script, because of the non-zero return status (141) given by base64, unhappy with closed pipe. The return status is propagated to the pipe and then to the invoking shell.
The undesired effect requires a workaround, such as follows:
set -o errexit -o pipefail
shopt -s inherit_errexit
encoded="$((< file base64 || :) | head -c16)"
The : has the same effect as would have the keyword true, to evaluate as a non-error.
However, this approach leads to a further unwanted effect.
The following shows a variation with a different error:
set -o errexit -o pipefail
shopt -s inherit_errexit
encoded="$((< /not/a/real/file base64 || :) | head -c16)"
echo $?
The printed code is zero. Now, a true error has been masked.
The most obvious solution, as follows, is rather verbose
set -o errexit -o pipefail
shopt -s inherit_errexit
encoded="$((< /not/a/real/file base64 || [ $? == 141 ]) | head -c16)"
echo $?
Is a more compact form available? Is any environment alteration available such that statements masks only the particular status code, without the explicit inline expression?
First off, apparently, to actually provoke the 141 error the file needs to be fairly, large, e.g.
head -c 1000000 /dev/urandom > file
now, as you said, this script sh.sh will terminate before showing encoded: ...:
#!/bin/bash
set -o errexit -o pipefail
shopt -s inherit_errexit
encoded="$(< file base64 | head -c16)"
echo "encoded: $encoded"
instead of checking for the error code, you could let base64 continue to pipe the rest of its data to /dev/null by invoking cat > /dev/null after head is done:
#!/bin/bash
set -o errexit -o pipefail
shopt -s inherit_errexit
encoded="$(< file base64 | ( head -c16 ; cat > /dev/null ) )"
echo "encoded: $encoded"
now you will get encoded: NvyX2Zx4nTDjtQO8 or whatever.
And this does not mask other errors like the file not existing:
$ ./sh.sh
./sh.sh: line 5: file: No such file or directory
However, it will be less efficient because the whole file will be read.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With