4

I have this in a github workflow

      - run: bash --version
      - name: run postgres
        run: |
          set -e
          shopt -s inherit_errexit
          export ID=$(docker run \
            --publish 5432:5432 \
            --network skynet \
            --network-alias db.host \
            --env-file .github/env/postgres \
            --detach ${{ steps.postgres-tag.outputs.data }} )
        shell: bash -euET -o pipefail -O inherit_errexit {0}

this is its run output

GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
  set -e
  shopt -s inherit_errexit
  export ID=$(docker run \
    --publish 5432:5432 \
    --network skynet \
    --network-alias db.host \
    --env-file .github/env/postgres \
    --detach  )
  shell: /bin/bash -euET -o pipefail -O inherit_errexit {0}
  env:
    AWS_DEFAULT_REGION: us-east-1
    AWS_REGION: us-east-1
    AWS_ACCESS_KEY_ID: ***
    AWS_SECRET_ACCESS_KEY: ***
"docker run" requires at least 1 argument.
See 'docker run --help'.

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

minimal reproduction on OS X with bash 5

bash-5.0$ export ID=$(docker run)
"docker run" requires at least 1 argument.
See 'docker run --help'.

Usage:  docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Run a command in a new container
bash-5.0$ echo $?
0
bash-5.0$ docker run
"docker run" requires at least 1 argument.
See 'docker run --help'.

Usage:  docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Run a command in a new container
> echo $?                                                                            # services -> feature/RS2-1228-optimize-build $ ! RC=1
1

However, the shell is not exiting with an error. I understand that normally a subshell with $() will not cause an error to happen... but I thought that setting shopt -s inherit_errexit fixed that. Am I missing something in my code?

1 Answer 1

8

Contrast:

$ bash -e -c 'export a=$(false); echo >&2 "If you see this, the previous command succeeded"'
If you see this, the previous command succeeded
$ bash -e -c 'a=$(false); echo >&2 "If you see this, the previous command succeeded"' 

In your attempt, the command inside the command substitution failed, but the command containing the command substitution succeeded. The status of a command substitution does not influence the status of the containing command if it's an ordinary command, including a call to the export builtin. The status of a command substitution only matters if it's in an assignment: the status of an assignment command is the status of the last command substitution in the command, or 0 if there is no command substitution (assuming there is no error in the assignment itself, such as attempting to assign to a read-only variable).

In order for your script to halt on the first error, you need to enable inherit_errexit and put each command substitution in a separate assignment. It has to be a plain assignment: exporting the variable must be a separate command.

$ bash -e -O inherit_errexit -c 'export a=$(false; echo >&2 "If you see this, errexit is off inside command substitution"); echo >&2 "If you see this, the previous command succeeded"'
If you see this, the previous command succeeded
$ bash -e -O inherit_errexit -c 'a=$(false; echo >&2 "If you see this, errexit is off inside command substitution"); echo >&2 "If you see this, the previous command succeeded"'
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.