将参数添加到“bash -c”

将参数添加到“bash -c”

假设我想通过 Bash 运行一个命令,如下所示:

/bin/bash -c "ls -l"

根据 Bash 手册页,我也可以这样运行它:

#               don't process arguments after this one
#               |   pass all unprocessed arguments to command
#               |   |
#               V   V
/bin/bash -c ls -- -l

但它似乎不起作用(它似乎被忽略)。我做错了什么,还是我对手册页的解释错误?

男人的相关引用:

如果存在 -c 选项,则从字符串中读取命令。如果字符串后面有参数,它们将被分配给位置参数,从 $0 开始。

A -- 表示选项结束并禁用进一步的选项处理。 -- 之后的任何参数都被视为文件名和参数。

答案1

您对手册页的解释是错误的。首先,表示选项结束的部分--与您要执行的操作无关。-c从那时起,将覆盖命令行的其余部分,因此它不再经过 bash 的选项处理,这意味着将--传递给命令,而不是由 bash 作为选项结束标记进行处理。

第二个错误是额外的参数作为位置参数分配给启动的 shell 进程,而不是作为参数传递给命令。因此,您想要做的事情可以作为以下之一来完成:

/bin/bash -c 'echo "$0" "$1"' foo bar
/bin/bash -c 'echo "$@"' bash foo bar

在第一种情况下,显式传递 echo 参数$0$1在第二种情况下,使用"$@"正常扩展为“除 $0 之外的所有位置参数”。请注意,在这种情况下,我们还必须传递一些要使用的东西$0;我选择了“bash”,因为这$0通常是这样,但其他任何东西都可以。

至于这样做的原因,而不是仅仅将您直接提供的任何参数传递给您列出的命令:请注意,文档说“命令s从字符串中读取”,复数。换句话说,这个方案允许您执行以下操作:

/bin/bash -c 'mkdir -p -- "$1" && cd -P -- "$1" && touch -- "$2"' bash dir file

但是,请注意,实现最初目标的更好方法可能是使用env而不是bash

/usr/bin/env -- "ls" "-l"

如果您不需要 shell 提供的任何功能,则没有理由使用它 -env在这种情况下使用它会更快、更简单并且打字更少。而且您不必费力思考以确保它能够安全地处理包含 shell 元字符或空格的文件名。

答案2

我不确定你的目标是什么,但如果你只是想建立一个鲁布·戈德堡机器– “故意过度设计或过度设计的装置、发明、装置或装置,以非常复杂的方式执行非常简单的任务” – 然后尝试

sh -c 'ls $0' -l

或者

sh -c 'ls $1' supercalifragilisticexpialidocious -l

甚至

sh -c 'ls -$0' l

您应该能够理解这些是如何工作的神极客的回答。作为 德里克·马哈尔评论,需要强调的是,脚本参数(后面的命令字符串 -c)必须用单引号而不是双引号括起来。否则,父 shell(您在其中键入上述命令行)将解析父 shell 上下文中脚本参数中的任何位置参数。例如,

$ set -- The quick brown fox
$ sh -c 'echo "$0" "$1"' foo bar baz
foo bar
$ sh -c "echo '$0' '$1'" foo bar baz
bash The

答案3

这比这一切都简单,而且你已经很接近了。

转义空格,以便整个命令作为单个字符串传递。您的脚本将如下所示:

bash -c "ls\ -l\ $@"

可以添加其他命令,并用未转义的空格分隔,例如

#                  ↓            unescaped
bash -c "cd\ ~/junk ls\ -l\ $@"
#          ↑↑         ↑↑  ↑↑    escaped

junk该命令中和之间的空格ls是唯一未转义的空格,因此它用于分隔两个命令。

相关内容