Bash脚本接收和传递引用的参数


98

我正在尝试获取bash脚本的带引号的参数,以确保嵌套脚本可以安全地接收它们。有任何想法吗?

test.sh

#!/bin/bash
echo $*
bash myecho.sh $*

myecho.sh

#!/bin/bash
 echo $1
 echo $2
 echo $3
 echo $4

样品:

bash test.sh aaa bbb '"ccc ddd"'

结果:

aaa bbb "ccc ddd"
aaa
bbb
"ccc
ddd"

想要的结果

aaa bbb "ccc ddd"
aaa
bbb
ccc ddd

2
我正要问那个问题!好时机。
Scottie T

Answers:


70
#!/bin/bash
echo $*
bash myecho.sh "$@"

请注意,“ $ @”构造不是bash专用的,并且应与任何POSIX shell一起使用(至少与破折号兼容)。还要注意,给定所需的输出,根本不需要额外的报价。IE只是像上面那样调用上面的脚本:

./test.sh 1 2 "3 4"

5
“ $ @”可与任何Bourne shell或Bourne shell派生词(从1978年开始)一起使用,包括Korn和Bash。大约95%的时间使用“ $ @”是正确的,而$ *是错误的。
乔纳森·莱夫勒

真好!但是,知道有人是否可以变量“按原样” 存储在变量中吗?原始$@在函数内部不可用(因为它已被函数参数覆盖)。我试着foovar="$@"foovar=$@+ "$foovar"在功能和没有工作: - /
bitifet

143

您想使用“ $ @”(用$表示)将参数传递给下标。像这样....

ls-color.sh:

#!/bin/bash
/bin/ls --color=auto "$@"    # passes though all CLI-args to 'ls'


至于为什么.....

Bash手册页中

$*-扩展到位置参数(从1开始)。当在双引号内进行扩展时,它将扩展为单个单词,每个参数的值均由IFS特殊变量的第一个字符分隔。也就是说,"$*"等价于 "$1c$2c...",其中c是IFS变量值的第一个字符。如果未设置IFS,则参数之间用空格分隔。如果IFS为null,则参数将插入而不会插入分隔符。

$@-扩展到位置参数,从1开始。当在双引号内进行扩展时,每个参数都会扩展为单独的单词。也就是说,"$@"等同于"$1" "$2" ...如果单词中出现双引号扩展,则第一个参数的扩展与原始单词的开头部分连接,最后一个参数的扩展与原始单词的末尾连接字。当有没有位置参数, "$@"并且$@扩大到什么(即,它们被删除)。


设置一些演示脚本...

echo 'echo -e "\$1=$1\n\$2=$2\n\$3=$3\n\$4=$4"' > echo-params.sh
echo './echo-params.sh $*' > dollar-star.sh
echo './echo-params.sh $@' > dollar-at.sh
echo './echo-params.sh "$*"' > quoted-dollar-star.sh
echo './echo-params.sh "$@"' > quoted-dollar-at.sh
chmod +x *.sh

"$@"-quoted-dollar-at是用于将args重新传递到子shell 的身份转换(〜99%的时间,这就是您的意图):

./quoted-dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2=            
  # $3= 'cc cc'
  # $4= "ddd ddd"

"$*"-quoted-dollar-star 将args粉碎为一个字符串 (约1%的时间,您实际想要此行为,例如在条件条件下:)if [[ -z "$*" ]]; then ...

./quoted-dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa  'cc cc' "ddd ddd"   
  # $2=                     
  # $3=             
  # $4=

$*/ $@-不带引号,这两种形式都剥夺了一个引号,并解释了底层字符串中的空格,但忽略了引号字符(几乎总是这样,这是一个错误):

./dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc                  
  # $3= cc'
  # $4= "ddd

./dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc
  # $3= cc'
  # $4= "ddd

如果您想找点乐子,可以使用“ $ @”将内容嵌套到所需的深度,并根据需要将元素压入和弹出args堆栈。

function identity() {
  "$@"
}
set -x
identity identity identity identity identity echo Hello \"World\"
# + identity identity identity identity identity echo Hello '"World"'
# + identity identity identity identity echo Hello '"World"'
# + identity identity identity echo Hello '"World"'
# + identity identity echo Hello '"World"'
# + identity echo Hello '"World"'
# + echo Hello '"World"'
# Hello "World"

1
感谢您的解释。刚刚将“ $ *”用作grep别名。
2013年

你救了我的一天!
xyz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.