在Bash外壳脚本中传播所有参数

我正在编写一个非常简单的脚本来调用另一个脚本,我需要将参数从当前脚本传播到我正在执行的脚本。

例如,我的脚本名称是foo.sh并调用bar.sh

foo.sh:

bar $1 $2 $3 $4

如何在不明确指定每个参数的情况下执行此操作?

602988 次浏览

对于bash和其他类似Bourne的shell:

bar "$@"

使用"$@"(适用于所有POSIX兼容)。

[…],bash具有“$@”变量,它扩展到所有由空格分隔的命令行参数。

Bash的例子

使用"$@"而不是普通的$@如果你真的希望你的参数传递相同。

观察:

$ cat no_quotes.sh#!/bin/bashecho_args.sh $@
$ cat quotes.sh#!/bin/bashecho_args.sh "$@"
$ cat echo_args.sh#!/bin/bashecho Received: $1echo Received: $2echo Received: $3echo Received: $4
$ ./no_quotes.sh first secondReceived: firstReceived: secondReceived:Received:
$ ./no_quotes.sh "one quoted arg"Received: oneReceived: quotedReceived: argReceived:
$ ./quotes.sh first secondReceived: firstReceived: secondReceived:Received:
$ ./quotes.sh "one quoted arg"Received: one quoted argReceived:Received:Received:
#!/usr/bin/env bashwhile [ "$1" != "" ]; doecho "Received: ${1}" && shift;done;

只是觉得这在尝试测试args如何进入您的脚本时可能会更有用

我的SUN Unix有很多限制,甚至“$@”也没有按预期解释。我的解决方法是 ${@}. 例如,

#!/bin/kshfind ./ -type f | xargs grep "${@}"

顺便说一句,我必须有这个特殊的脚本,因为我的Unix也不支持grep-r

工作正常,除非您有空格或转义字符。我找不到在这种情况下捕获参数并将其发送到脚本内部的ssh的方法。

这可能是有用的,但它是如此丑陋

_command_opts=$( echo "$@" | awk -F\- 'BEGIN { OFS=" -" } { for (i=2;i<=NF;i++) { gsub(/^[a-z] /,"&@",$i) ; gsub(/ $/,"",$i );gsub (/$/,"@",$i) }; print $0 }' | tr '@' \' )

我知道这已经得到了很好的回答,但这里有一个 "$@" $@ "$*" 和$*之间的比较

测试脚本内容:

# cat ./test.sh#!/usr/bin/env bashecho "================================="
echo "Quoted DOLLAR-AT"for ARG in "$@"; doecho $ARGdone
echo "================================="
echo "NOT Quoted DOLLAR-AT"for ARG in $@; doecho $ARGdone
echo "================================="
echo "Quoted DOLLAR-STAR"for ARG in "$*"; doecho $ARGdone
echo "================================="
echo "NOT Quoted DOLLAR-STAR"for ARG in $*; doecho $ARGdone
echo "================================="

现在,使用各种参数运行测试脚本:

# ./test.sh  "arg with space one" "arg2" arg3=================================Quoted DOLLAR-ATarg with space onearg2arg3=================================NOT Quoted DOLLAR-ATargwithspaceonearg2arg3=================================Quoted DOLLAR-STARarg with space one arg2 arg3=================================NOT Quoted DOLLAR-STARargwithspaceonearg2arg3=================================

如果您在带引号的字符串中包含$@和其他字符,当有多个参数时,行为非常奇怪,引号中仅包含第一个参数。

示例:

#!/bin/bashset -xbash -c "true foo $@"

产量:

$ bash test.sh bar baz+ bash -c 'true foo bar' baz

但首先分配给不同的变量:

#!/bin/bashset -xargs="$@"bash -c "true foo $args"

产量:

$ bash test.sh bar baz+ args='bar baz'+ bash -c 'true foo bar baz'

有时您想传递所有参数,但前面有一个标志(例如--flag

$ bar --flag "$1" --flag "$2" --flag "$3"

您可以通过以下方式做到这一点:

$ bar $(printf -- ' --flag "%s"' "$@")

注:为了避免额外的字段拆分,您必须引用%s$@,并且为了避免使用单个字符串,您不能引用printf的子shell。

bar "$@"将等价于bar "$1" "$2" "$3" "$4"

请注意,引号很重要!

"$@"$@"$*"$*在转义和连接方面的行为略有不同,如本stackoverflow答案所述。

一个密切相关的用例是在参数中传递所有给定参数,如下所示:

bash -c "bar \"$1\" \"$2\" \"$3\" \"$4\""

我使用@kvantour答案的变体来实现这一点:

bash -c "bar $(printf -- '"%s" ' "$@")"

这里有很多答案推荐$@$*有引号和没有引号,但似乎没有一个能解释这些引号的真正作用以及为什么你应该这样做。所以让我从这个答案中窃取这个精彩的总结:

+--------+---------------------------+| Syntax |      Effective result     |+--------+---------------------------+|   $*   |     $1 $2 $3 ... ${N}     |+--------+---------------------------+|   $@   |     $1 $2 $3 ... ${N}     |+--------+---------------------------+|  "$*"  |    "$1c$2c$3c...c${N}"    |+--------+---------------------------+|  "$@"  | "$1" "$2" "$3" ... "${N}" |+--------+---------------------------+

请注意,引号会产生所有差异,没有它们,两者都有相同的行为。

为了我的目的,我需要按原样将参数从一个脚本传递到另一个脚本,为此最好的选择是:

# 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 $*

注意没有引号和$@应该在上面的情况下工作。

"${array[@]}"是在bash中传递任何数组的正确方式。我想提供一个完整的备忘单:如何准备参数、绕过和处理它们。

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 $1echo $2echo $3echo $4

结果:

--a=b c--e=f g--q=w e--a=s "'d'"