I am writing a very simple script that calls another script, and I need to propagate the parameters from my current script to the script I am executing.
For instance, my script name is foo.sh
and calls bar.sh
.
foo.sh:
bar 1ドル 2ドル 3ドル 4ドル
How can I do this without explicitly specifying each parameter?
-
1Related: How to pass all arguments passed to my bash script to a function of mine?blong– blong2014年05月22日 15:27:59 +00:00Commented May 22, 2014 at 15:27
-
See also stackoverflow.com/questions/12314451/…Vadzim– Vadzim2016年03月28日 11:55:25 +00:00Commented Mar 28, 2016 at 11:55
-
I had to use this solution for my use caseforresthopkinsa– forresthopkinsa2021年07月10日 02:11:53 +00:00Commented Jul 10, 2021 at 2:11
12 Answers 12
Use "$@"
instead of plain $@
if you actually wish your parameters to be passed the same.
Observe:
$ cat no_quotes.sh
#!/bin/bash
./echo_args.sh $@
$ cat quotes.sh
#!/bin/bash
./echo_args.sh "$@"
$ cat echo_args.sh
#!/bin/bash
echo Received: 1ドル
echo Received: 2ドル
echo Received: 3ドル
echo Received: 4ドル
$ ./no_quotes.sh first second
Received: first
Received: second
Received:
Received:
$ ./no_quotes.sh "one quoted arg"
Received: one
Received: quoted
Received: arg
Received:
$ ./quotes.sh first second
Received: first
Received: second
Received:
Received:
$ ./quotes.sh "one quoted arg"
Received: one quoted arg
Received:
Received:
Received:
6 Comments
-e
, in my case, the echo
cmd will consume it?For bash and other Bourne-like shells:
bar "$@"
10 Comments
$argv:q
will work in some csh variants.exec java com.myserver.Program "$@"
This causes bash to exec into java, rather than wait around for it to complete. So, you are using one less process slot. Also, if the parent process (which ran your script) is watching it via the pid, and expecting it to be the 'java' process, some unusual things could break if you don't do an exec; the exec causes java to inherit the same pid.args=("$@")
and expand each element as a separate shell "word" (akin to "$@"
) with "${args[@]}"
."$@"
, like will it fail if you have escaped spaces in an argument, or null characters, or other special characters?A lot answers here recommends $@
or $*
with and without quotes, however none seems to explain what these really do and why you should that way. So let me steal this excellent summary from this answer:
Syntax | Effective result |
---|---|
$* |
1ドル 2ドル 3ドル ... ${N} |
$@ |
1ドル 2ドル 3ドル ... ${N} |
"$*" |
"1ドルc2ドルc3ドルc...c${N}" |
"$@" |
"1ドル" "2ドル" "3ドル" ... "${N}" |
Notice that quotes makes all the difference and without them both have identical behavior.
Where c is the first character of the value of the IFS
variable. If IFS
is unset, the parameters are separated by spaces. If IFS
is null, the parameters are joined without intervening separators.
For my purpose, I needed to pass parameters from one script to another as-is and for that the best option is:
# file: parent.sh
# we have some params passed to parent.sh
# which we will like to pass on to child.sh as-is
./child.sh $*
Notice no quotes, and $@
should work equally well in above situation.
5 Comments
env --debug
. E.g. put env --debug echo "$*"
inside a function and try executing it with different arguments.$*
passem them not as-is. Maybe it depends on how you define "as-is". Example: If you call ./parent.sh 'a b' c
, then in the parent script 1ドル
would eval to a b
but in the child script 1ドル
would eval to only a
. So this is not what I expect. I expect that both scripts "see" the same arguments and this only works with ./child.sh "$@"
.env -i tcsh -c "cmd $*"
-- $@
was causing issues with tcsh
thinking that the cmd
flags were for tcsh
. $*
fixed things.$*
splits using the first character of IFS
. E.g. a() ( export IFS=',;'; printf '%s\n' "$*"; ); a 1 2 3;
results in 1,2,3
.$*
will pass parameters "as-is". It's much more accurate to say that it will cause your arguments to be word split and then passed on to the second script. "As-is" would imply that they would be passed without splitting them. For this you need "$@"
.Use "$@"
(works for all POSIX compatibles).
[...] , bash features the "$@" variable, which expands to all command-line parameters separated by spaces.
From Bash by example.
7 Comments
$*
. I believe there is historical progression here; $*
did not work as designed, so $@
was invented to replace it; but the quoting rules being what they are, the double quotes around it are still required (or it will revert to the broken $*
semantics).echo "$@"
as ./script.sh a "b c" d
then you just get a b c d
instead of a "b c" d
, which is very much different.echo
receives three arguments: "a" "b c" "d"
(then the shell joins them together as part of its string expansion). But if you'd used for i in "$@"; do echo $i; done
You'd have gotten a⏎b c⏎d
.I realize this has been well answered but here's a comparison between "$@" $@ "$*" and $*
Contents of test script:
# cat ./test.sh
#!/usr/bin/env bash
echo "================================="
echo "Quoted DOLLAR-AT"
for ARG in "$@"; do
echo $ARG
done
echo "================================="
echo "NOT Quoted DOLLAR-AT"
for ARG in $@; do
echo $ARG
done
echo "================================="
echo "Quoted DOLLAR-STAR"
for ARG in "$*"; do
echo $ARG
done
echo "================================="
echo "NOT Quoted DOLLAR-STAR"
for ARG in $*; do
echo $ARG
done
echo "================================="
Now, run the test script with various arguments:
# ./test.sh "arg with space one" "arg2" arg3
=================================
Quoted DOLLAR-AT
arg with space one
arg2
arg3
=================================
NOT Quoted DOLLAR-AT
arg
with
space
one
arg2
arg3
=================================
Quoted DOLLAR-STAR
arg with space one arg2 arg3
=================================
NOT Quoted DOLLAR-STAR
arg
with
space
one
arg2
arg3
=================================
Comments
#!/usr/bin/env bash
while [ "1ドル" != "" ]; do
echo "Received: ${1}" && shift;
done;
Just thought this may be a bit more useful when trying to test how args come into your script
4 Comments
$#
""
, ''
as an argument, also if there were no args it is silent. I tried to fix this, but needs a for loop and counter with $#
. I just added this on the end: echo "End of args or received quoted null"
env --debug <command> <args>
to get a similar output. Example: env --debug echo "$@"
If you include $@
in a quoted string with other characters the behavior is very odd when there are multiple arguments, only the first argument is included inside the quotes.
Example:
#!/bin/bash
set -x
bash -c "true foo $@"
Yields:
$ bash test.sh bar baz
+ bash -c 'true foo bar' baz
But assigning to a different variable first:
#!/bin/bash
set -x
args="$@"
bash -c "true foo $args"
Yields:
$ bash test.sh bar baz
+ args='bar baz'
+ bash -c 'true foo bar baz'
5 Comments
"$@"
in bash. It also helps illustrate the key difference between $@
and $*
, and why they're both useful. From the bash(1)
man page Special Parameters section: "*
— When the expansion occurs within double quotes, it expands to a single word with the value of each parameter [...] That is, "$*"
is equivalent to "1ドルc2ドルc..."
, where c
is [$IFS
]." And indeed, using $*
instead of $@
in your first example would've netted output identical to the second version."$@"
. Again from the man page: "@
— When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@"
is equivalent to "1ドル"
"2ドル"
... If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word." ...And indeed, if your code had been bash -c "true foo $@ bar baz"
, then running it as test.sh one two
would net bash -c 'true foo one' 'two bar baz'
.$*
, I seem to forget that it exists..$@
was just gaining traction when I first started shell scripting, I still have to remind myself it's there. It was common to see "$*"
used in scripts... then the author would realize it was smashing all of their arguments together, so they'd try all manner of complex nonsense with word-splitting "$*"
, or [re]assembling an arg list by looping over shift
to pull them down one by one... just using $@
solves it. (Helps that bash uses the same mnemonic to access array members, too: ${var[*]}
for them all as a word, ${var[@]}
for a list of words.)bash -c
in a way which makes absolutely no sense.My SUN Unix has a lot of limitations, even "$@" was not interpreted as desired. My workaround is ${@}. For example,
#!/bin/ksh
find ./ -type f | xargs grep "${@}"
By the way, I had to have this particular script because my Unix also does not support grep -r
1 Comment
ksh
Sometimes you want to pass all your arguments, but preceded by a flag (e.g. --flag
)
$ bar --flag "1ドル" --flag "2ドル" --flag "3ドル"
You can do this in the following way:
$ bar $(printf -- ' --flag "%s"' "$@")
note: to avoid extra field splitting, you must quote %s
and $@
, and to avoid having a single string, you cannot quote the subshell of printf
.
1 Comment
"
- you really need to use a printf
that supports %q
for this.bar "$@"
will be equivalent to bar "1ドル" "2ドル" "3ドル" "4ドル"
Notice that the quotation marks are important!
"$@"
, $@
, "$*"
or $*
will each behave slightly different regarding escaping and concatenation as described in this stackoverflow answer.
One closely related use case is passing all given arguments inside an argument like this:
bash -c "bar \"1ドル\" \"2ドル\" \"3ドル\" \"4ドル\""
.
I use a variation of @kvantour's answer to achieve this:
bash -c "bar $(printf -- '"%s" ' "$@")"
Comments
Works fine, except if you have spaces or escaped characters. I don't find the way to capture arguments in this case and send to a ssh inside of script.
This could be useful but is so ugly
_command_opts=$( echo "$@" | awk -F\- 'BEGIN { OFS=" -" } { for (i=2;i<=NF;i++) { gsub(/^[a-z] /,"&@",$i) ; gsub(/ $/,"",$i );gsub (/$/,"@",$i) }; print 0ドル }' | tr '@' \' )
Comments
"${array[@]}"
is the right way for passing any array in bash. I want to provide a full cheat sheet: how to prepare arguments, bypass and process them.
pre.sh
-> foo.sh
-> bar.sh
.
#!/bin/bash
args=("--a=b c" "--e=f g")
args+=("--q=w e" "--a=s \"'d'\"")
./foo.sh "${args[@]}"
#!/bin/bash
./bar.sh "$@"
#!/bin/bash
echo 1ドル
echo 2ドル
echo 3ドル
echo 4ドル
result:
--a=b c
--e=f g
--q=w e
--a=s "'d'"