1

Consider the following script1:

#!/bin/bash
bash <<END
printf "%s\n" "$@"
END

Surprisingly (to me), the $@ inside the heredoc gets expanded first, and then quoted, so this is the output:

$ /tmp/test.sh "a a" b c
a a b c

If I remove the quotes, I get the simplistic $@ behavior:

$ /tmp/test.sh "a a" b c
a
a
b
c

Neither option gives the desired output. I tried using an array like args=("$@"), but then the expansion behaves the same way. I tried placing the "result" in a variable like args="$@", but that just gives me back "a a b c".

Any ideas how to get the output to be like the following?

a a
b
c

1 Obviously, this is very simplified. In reality I'm using the heredoc to execute a script with docker run, but it is immaterial to this question.

4

In a here document, the shell performs “dollar substitutions” ($foo, $(some command), `some command`, $((x+1)), and backslash to protect \`$). Here documents are expanded like double-quoted strings. To avoid this, use a quote on the end marker for the here document, which then behaves like a single-quoted string (no expansion at all).

bash <<'END'
printf "%s\n" "$@"
END

This won't do what you want since "$@" is expanded by the inner bash and it doesn't receive any arguments. The easy direct solution, which may or may not work in your real use case, is to forward the arguments to the inner bash.

bash /dev/stdin "$@" <<'END'
printf "%s\n" "$@"
END

If you can't pass arguments to the inner bash in your real use case, you may be able to pass them through environment variables. But you can only pass one string per environment variable, so this isn't convenient if you have a variable number of strings to pass.

export widget_count="$1" data_source="$2" frobnicator="$3"
…
bash <<'END'
printf "%s\n" "$widget_count" "$data_source" "$frobnicator"
END

As a last resort, you may need to quote the values to pass them through. To quote a string for shell syntax:

  1. Replace ' by '\''.
  2. Add ' at the beginning and ' at the end.
-1

Since the question is how to get the desired output, I believe this will work for your purposes.

I tried declaring your desired desired print statement inside a function like so:

function test_function {
    printf "%s\n" "$@"
}

Then ran it in bash with your desired inputs

bash-3.2$ function test_function {
>     printf "%s\n" "$@"
> }
bash-3.2$ cat << EOF
> $(test_function "a a" b c)
> EOF
a a
b
c
1
  • 1
    This doesn't answer the question, which is about how to pass the arguments to another shell process (running inside a Docker environment). Jun 15 '20 at 20:14

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.