向“bash -c”添加参数

Sla*_*ast 35 shell bash quoting arguments

假设我想像这样通过 Bash 运行一个命令:

/bin/bash -c "ls -l"
Run Code Online (Sandbox Code Playgroud)

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

#               don't process arguments after this one
#               |   pass all unprocessed arguments to command
#               |   |
#               V   V
/bin/bash -c ls -- -l
Run Code Online (Sandbox Code Playgroud)

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

来自 man 的相关引用:

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

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

god*_*eek 50

您正在错误地解释手册页。首先,关于--发出选项结束信号的部分与您尝试做的事情无关。将-c覆盖从该点的命令行的其余部分,使其不再打算通过在所有bash的选项处理,这意味着--将通过该命令传递,而不是bash作为选项标记的最终处理。

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

/bin/bash -c 'echo "$0" "$1"' foo bar
/bin/bash -c 'echo "$@"' bash foo bar
Run Code Online (Sandbox Code Playgroud)

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

至于原因,它的完成这种方式,而不是刚好路过你直接给你列出命令的任何参数:请注意,文件说“命令小号,多是从字符串读”。换句话说,这个方案允许你做:

/bin/bash -c 'mkdir "$1"; cd "$1"; touch "$2"' bash dir file
Run Code Online (Sandbox Code Playgroud)

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

/usr/bin/env -- "ls" "-l"
Run Code Online (Sandbox Code Playgroud)

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

  • 我认为值得强调的是,您用单引号而不是双引号将脚本参数括起来,否则您运行 /bin/bash 的 shell 将在活动 shell 的上下文中解析脚本参数中的任何位置参数。例如, /bin/bash -c "echo '$0' '$1'" foo bar 结果是 bash 而不是 foo bar。 (2认同)

Sco*_*ott 6

我不确定你的目标是什么,但如果你只是想建造一个鲁布戈德堡机器——“一种故意过度设计或过度设计的装置、发明、装置或装置,以在非常复杂的情况下执行非常简单的任务。复杂的时尚”——然后尝试

sh -c 'ls $0' -l
Run Code Online (Sandbox Code Playgroud)

或者

sh -c 'ls $1' supercalifragilisticexpialidocious -l
Run Code Online (Sandbox Code Playgroud)

甚至

sh -c 'ls -$0' l
Run Code Online (Sandbox Code Playgroud)

您应该能够从 Godlygeek 的回答中了解这些是如何工作的。