我正在编写一个非常简单的脚本,该脚本将调用另一个脚本,并且需要将参数从当前脚本传播到正在执行的脚本。
例如,我的脚本名称是foo.sh
和调用bar.sh
foo.sh:
bar $1 $2 $3 $4
如何在不显式指定每个参数的情况下执行此操作?
我正在编写一个非常简单的脚本,该脚本将调用另一个脚本,并且需要将参数从当前脚本传播到正在执行的脚本。
例如,我的脚本名称是foo.sh
和调用bar.sh
foo.sh:
bar $1 $2 $3 $4
如何在不显式指定每个参数的情况下执行此操作?
Answers:
如果您确实希望传递相同的参数,请使用"$@"
而不是普通格式$@
。
观察:
$ cat foo.sh
#!/bin/bash
baz.sh $@
$ cat bar.sh
#!/bin/bash
baz.sh "$@"
$ cat baz.sh
#!/bin/bash
echo Received: $1
echo Received: $2
echo Received: $3
echo Received: $4
$ ./foo.sh first second
Received: first
Received: second
Received:
Received:
$ ./foo.sh "one quoted arg"
Received: one
Received: quoted
Received: arg
Received:
$ ./bar.sh first second
Received: first
Received: second
Received:
Received:
$ ./bar.sh "one quoted arg"
Received: one quoted arg
Received:
Received:
Received:
'arg with spaces'
为三个示例说明在包含时发生的情况。结果令我感到惊讶。希望你能解释他们。
./foo.sh "arg with spaces"
而且./foo.sh 'arg with spaces'
都是100%相同的,所以我不认为将其添加到给出的示例中的建议会有什么帮助。
对于bash和其他类似Bourne的外壳:
java com.myserver.Program "$@"
exec java com.myserver.Program "$@"
这会使bash在Java中执行,而不是等待它完成。因此,您减少了一个处理插槽。另外,如果父进程(运行您的脚本)正在通过pid监视它,并期望它是“ java”进程,那么如果您不执行exec,则可能会打破一些异常的事情;exec使java继承相同的pid。
args=("$@")
和扩大每个元素作为一个单独的壳“字”(类似于"$@"
)与"${args[@]}"
。
"$@"
,例如如果您在参数中转义了空格,空字符或其他特殊字符,它将失败吗?
$*
。我相信这里有历史的进步;$*
没有按设计工作,因此$@
发明了它来代替它;但是引号规则就是它们的本质,仍然需要在其周围加上双引号(否则它将恢复为已损坏的$*
语义)。
echo "$@"
as 的脚本,./script.sh a "b c" d
那么您将得到a b c d
而不是a "b c" d
,这是非常不同的。
echo
会接收三个参数:("a" "b c" "d"
然后,shell将它们作为字符串扩展的一部分连接在一起)。但是如果你用过的话,你一定for i in "$@"; do echo $i; done
会得到的a⏎b c⏎d
。
我知道这个问题已经得到很好的回答,但这是“ $ @” $ @“ $ *”和$ *之间的比较
测试脚本的内容:
# 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 "================================="
现在,使用各种参数运行测试脚本:
# ./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
=================================
#!/usr/bin/env bash
while [ "$1" != "" ]; do
echo "Received: ${1}" && shift;
done;
只是认为这在尝试测试args如何进入脚本时可能会更有用
$#
""
,''
作为一个论据,如果没有args,也保持沉默。我试图解决此问题,但需要for循环并使用进行计数$#
。我刚刚在末尾添加了此内容:echo "End of args or received quoted null"
如果在包含$@
引号的字符串中包含其他字符,则当有多个参数时,行为非常奇怪,引号内仅包含第一个参数。
例:
#!/bin/bash
set -x
bash -c "true foo $@"
产量:
$ bash test.sh bar baz
+ bash -c 'true foo bar' baz
但是首先要分配一个不同的变量:
#!/bin/bash
set -x
args="$@"
bash -c "true foo $args"
产量:
$ bash test.sh bar baz
+ args='bar baz'
+ bash -c 'true foo bar baz'
"$@"
在bash 的语义内,这实际上是有意义的。它还有助于说明$@
和之间的主要区别$*
以及为什么它们都有用。在bash(1)
手册页的“特殊参数”部分:“ *
-当扩展出现在双引号内时,它将扩展为具有每个参数[…]值的单个单词,"$*"
即等于"$1c$2c..."
,其中c
[ $IFS
]。实际上,在第一个示例中使用$*
代替$@
将获得与第二个版本相同的输出。
"$@"
。再次从手册页中进行:“ @
—当扩展出现在双引号内时,每个参数扩展为一个单独的单词。也就是说,"$@"
等同于"$1"
"$2"
…如果双引号扩展出现在一个单词内,则将连接第一个参数的扩展原始单词的开头部分,最后一个参数的扩展与原始单词的最后部分结合在一起。” ...的确,如果您的代码已经存在bash -c "true foo $@ bar baz"
,则可以像test.sh one two
net 一样运行它bash -c 'true foo one' 'two bar baz'
。
$*
,我似乎忘记了它的存在
$@
我刚开始使用Shell脚本时只是受到关注,我仍然要提醒自己它在那里。看到"$*"
在脚本中使用是很常见的……然后作者意识到这是将所有参数都粉碎了,所以他们会尝试所有复杂的废话和分词"$*"
,或者通过循环来[重新] arg列表一步一步shift
地将它们拉下来...只需使用即可$@
解决。(也帮助bash使用相同的助记符访问数组成员:${var[*]}
对于所有成员而言,它们都是一个单词,一个单词${var[@]}
列表。)
bash -c
的方式完全没有道理。
很多答案在这里建议$@
或$*
有或无报价,但没有一个似乎解释这些真的,为什么你应该这样。因此,让我从以下答案中窃取这一出色的摘要:
请注意,引号会造成所有不同,没有引号,它们的行为相同。
出于我的目的,我需要按原样将参数从一个脚本传递到另一个脚本,为此,最佳选择是:
# 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 $*
注意没有引号,$@
并且在上述情况下也应适用。
bar "$@"
相当于 bar "$1" "$2" "$3" "$4"
请注意,引号很重要!
"$@"
,或,在转义和连接方面$@
,每个行为都会略有不同,如本stackoverflow答案中所述。"$*"
$*
一个密切相关的用例是将所有给定的参数传递到这样的参数中:
bash -c "bar \"$1\" \"$2\" \"$3\" \"$4\""
。
我使用@kvantour答案的变体来实现这一点:
bash -c "bar $(printf -- '"%s" ' "$@")"