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

例如,我的脚本名为foo.sh,调用bar.sh。

foo.sh:

bar $1 $2 $3 $4

如何在不显式指定每个参数的情况下做到这一点?


bash和其他类似bourne的炮弹:

bar "$@"

使用“$@”(适用于所有POSIX兼容程序)。

[…), bash提供了“$@”变量,它扩展为所有用空格分隔的命令行参数。

以Bash为例。


如果你确实希望传递相同的参数,请使用“$@”而不是普通的$@。

观察:

$ 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:

#!/usr/bin/env bash
while [ "$1" != "" ]; do
  echo "Received: ${1}" && shift;
done;

只是认为在尝试测试args如何进入脚本时,这可能更有用


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

#!/bin/ksh
find ./ -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 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
=================================

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

例子:

#!/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'

有时你想传递所有的参数,但前面有一个标志(例如——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 $1
echo $2
echo $3
echo $4

结果:

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