Home > Software design >  bash run command without exiting on error and tell me its exit code
bash run command without exiting on error and tell me its exit code

Time:09-26

From a bash script I want to run a command which might fail, store its exit code in a variable, and run a subsequent command regardless of that exit code.

Examples of what I'm trying to avoid:

Using set:

set  e  # disable exit on error (it was explicitly enabled earlier)
docker exec $CONTAINER_NAME npm test
test_exit_code=$?  # remember exit code of previous command
set -e  # enable exit on error
echo "copying unit test result file to host"
docker cp $CONTAINER_NAME:/home/test/test-results.xml .
exit $test_exit_code

Using if:

if docker exec $CONTAINER_NAME npm test ; then
    test_exit_code=$?
else
    test_exit_code=$?
fi
echo "copying unit test result file to host"
docker cp $CONTAINER_NAME:/home/test/test-results.xml .
exit $test_exit_code

Is there a semantically straightforward way to tell bash "run command without exiting on error, and tell me its exit code"?

CodePudding user response:

I believe you could just use the || operator? Which is equivalent to an "if − else" command.

Would the following address your use case? (otherwise feel free to comment!)

set -e  # implied in a CI context
exit_status=0
docker exec "$CONTAINER_NAME" npm test || exit_status=$?
docker cp "$CONTAINER_NAME:/home/test/test-results.xml" .
exit "$exit_status"

or more briefly:

set -e  # implied in a CI context
docker exec "$CONTAINER_NAME" npm test || exit_status=$?
docker cp "$CONTAINER_NAME:/home/test/test-results.xml" .
exit "${exit_status:-0}"

As an aside, if you are not interested in this exit status code, you can also do something like this:

set -e  # implied in a CI context
docker exec "$CONTAINER_NAME" npm test || :
docker cp "$CONTAINER_NAME:/home/test/test-results.xml" .

For more details on the || : tip, see e.g. this answer on Unix-&-Linux SE:
Which is more idiomatic in a bash script: || true or || :?

CodePudding user response:

Very simply save the return-code if command failed:

#!/usr/bin/env sh

# Implied by CI
set -e

# Initialise exit return code
rc=0

# Run command or save its error return code if it fail
docker exec "$CONTAINER_NAME" npm test || rc="$?"

printf '%s\n' "copying unit test result file to host"

# Run other command regardless if first one failed
docker cp "$CONTAINER_NAME:/home/test/test-results.xml" .

# Exit with the return code of the first command
exit "$rc"

CodePudding user response:

You could use a kind of try catch, to get the exit code and use a simple switch case to run another commands depending on the error exit code:

(
exit 2
#here your command which might fail
)
exit_code=$?

case "$exit_code" in

0)  echo "Success execution"
    #do something
    ;;
1)  echo "Error type 1"
    #do something
    ;;
2)  echo "Error type 2"
    #do something
    ;;
*) echo "Unknown error type: $exit_code"
   ;;
esac
  • Related