bash 如何传递包含引号/空格的脚本参数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5720194/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 23:49:30  来源:igfitidea点击:

How do I pass on script arguments that contain quotes/spaces?

bashquoting

提问by axon

I'm trying to write a script notify-finishthat can be prepended to any command. When done, it will run the command given by the arguments following, then email the user when the command is complete. Here's what I have:

我正在尝试编写一个notify-finish可以添加到任何命令的脚本。完成后,它将运行由以下参数给出的命令,然后在命令完成时向用户发送电子邮件。这是我所拥有的:

PROG=
# Run command given by arguments
$@
ECODE=$?
echo -e "Subject: `hostname`: $PROG finished\r\nTo: <$USER>\r\n\r\nExited with $ECODE\r\n" | sendmail $USER

This works most of the time, but when arguments contain spaces, the quoting is stripped off.

这在大多数情况下都有效,但是当参数包含空格时,引用将被删除。

Working example:

工作示例:

notify-finished rsync -avz source/ user@remote:dest/

Failing example:

失败的例子:

notify-finished rsync -avz -e 'ssh -c blowfish' source/ user@remote:dest/

In the second case, $@is expanded out to rsync -avz -e ssh -c blowfish source user@remote:dest/, missing the single quotes. It does not work with double-quotes either, nor with $*.

在第二种情况下,$@扩展为rsync -avz -e ssh -c blowfish source user@remote:dest/,缺少单引号。它不适用于双引号,也不适用于$*.

After reading other posts I tried putting the command in an array, but I get the exact same issue:

阅读其他帖子后,我尝试将命令放入数组中,但遇到了完全相同的问题:

CMD=(notify-finished rsync -avz -e 'ssh -c blowfish' source/ user@remote:dest/)
${CMD[@]}

How do I make this work for all arguments?

我如何使所有参数都适用?

回答by Micha? ?rajer

Use "$@"withquotes:

"$@"引号一起使用:

prog=""
"$@"
ecode="$?"
echo "$prog exited with $ecode"

This will pass each argument exactly as it was received. If you don't include the quotes, each element will be split according to $IFS:

这将完全按照收到的方式传递每个参数。如果不包含引号,每个元素将根据以下内容拆分$IFS

  • "$@"is like "$1" "$2" "$3" ..., passing each element as a separate argument.
  • "$*"is like "$1 $2 $3 ...", passing all elements concatenated as a single argument
  • $*and $@is like $1 $2 $3 ..., breaking up each element on whitespace, expanding all globs, and passing each resulting word as a separate element ($IFS).
  • "$@"就像"$1" "$2" "$3" ...,将每个元素作为单独的参数传递。
  • "$*"就像"$1 $2 $3 ...",将所有元素作为单个参数连接在一起
  • $*$@$1 $2 $3 ...,分手每个元件上的空白,扩大所有水珠,并通过每个得到字作为一个单独的元件($IFS)。

The same is true for arrays, such as "${array[@]}"and "${array[*]}"

数组也是如此,例如"${array[@]}""${array[*]}"

回答by Gordon Davisson

Put double-quotes around your variable substitutions to keep them from being parsed (note that this applies to all variables: $@, $1, and $PROG). Also: don't put a $ before a variable name when assigning to it; use #for comments; and, on the last line, the single-quotes will prevent variables from being substituted at all.

在您的变量替换周围加上双引号以防止它们被解析(请注意,这适用于所有变量:$@$1、 和$PROG)。另外:分配给变量名时不要在变量名前加上 $;使用#征求意见; 并且,在最后一行,单引号将完全阻止变量被替换。

PROG=""
shift
# Run program below
"$PROG" "$@"
ECODE=$? # note: this will always be a number, so it doesn't have to be protected with double-quotes
echo -e "Subject: $(hostname): $PROG finished\r\nTo: <$USER>\r\n\r\nExited with $ECODE\r\n' | sendmail "$USER"