0

Motivation

I'm in a situation where I have to run multiple bash commands with a single bash invocation without the possibility to write a full script file (use case: Passing multiple commands to a container in Kubernetes). A common solution is to combine commands with ; or &&, for instance:

bash -c " \
echo \"Hello World\" ; \
ls -la ; \
run_some_command "

In practice writing bash scripts like that turns out to be error prone, because I often forget the semicolon leading to subtle bugs.

Inspired by this question, I was experiment with writing scripts in a more standard style by using a heredoc:

bash <<EOF
echo "Hello World"
ls -la
run_some_command
EOF

Unfortunately, I noticed that there is a difference in exit code error handling when using a heredoc. For instance:

bash -c " \
run_non_existing_command ; \
echo $? "

outputs (note that $? properly captures the exit code):

bash: run_non_existing_command: command not found
127

whereas

bash <<EOF
run_non_existing_command
echo $?
EOF

outputs (note that $? fails to capture the exit code compared to standard script execution):

bash: line 1: run_non_existing_command: command not found
0

Why is the heredoc version behaving differently? Is it possible to write the script in the heredoc style and maintaining normal exit code handling?

3
  • for instance: - your instance doesn't combine commands (at least not in a way I define "combine"), it runs bash -c echo "Hello World" and then runs ls -la and run_some_command, all in parent shell. I think you are missing \ slashes Commented Oct 15, 2019 at 12:12
  • @KamilCuk Correct fixed, thanks! Copy paste mistake, when deploying to Kubernetes the `` are handled via YAML multi line strings... The observations should still be valid. Commented Oct 15, 2019 at 12:25
  • No, it's not the same thing. Probably the same thing would be bash -c "echo \"Hello World\" ; ls -la ; run_some_command ;" Commented Oct 15, 2019 at 12:27

1 Answer 1

4

Why is the heredoc version behaving differently?

Because $? is expanded before running the command.

The following will output 1, that is the exit status of false command:

false
bash <<EOF
run_non_existing_command
echo $?
EOF

It's the same in principle as the following, which will print 5:

variable=5
bash <<EOF
variable="This is ignored"
echo $variable
EOF

Is it possible to write the script in the heredoc style and maintaining normal exit code handling?

If you want to have the $? expanded inside the subshell, then:

bash <<EOF
run_non_existing_command
echo \$?
EOF

or

bash <<'EOF'
run_non_existing_command
echo $?
EOF

Also note that:

bash -c \
run_non_existing_command ;
echo $? ;

is just equal to:

bash -c run_non_existing_command
echo $?

The echo $? is not executed inside bash -c.

Sign up to request clarification or add additional context in comments.

2 Comments

Interesting, is there a simple explanation why quoting the EOF gets rid of the necessity to escape the $??
Yes, it was designed this way. See posix shell 2.7.4 Here-Document If any character in word is quoted, .... the here-document lines shall not be expanded.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.