bash 联机帮助页对该选项的说明如下-c
:
-c 如果存在 -c 选项,则从第一个非选项参数 command_string 读取命令。如果 command_string 之后有参数,则第一个参数将分配给 $0,任何剩余参数将分配给位置参数。对 $0 的赋值设置了 shell 的名称,该名称用于警告和错误消息。
从上面我希望下面的代码在其输出中是等效的:
# or possibly (`bash -c date date +%z`)
$ bash -c date +%z
Wed Oct 18 10:02:47 PM UTC 2023
$ date +%z
+0000
# The first command gives the output of `date` without the format specifier.
然而,我的 bash(GNU bash,版本 5.2.15)似乎从未评估额外的命令行位置参数。选项后第一个参数之后的所有内容-c
都会被默默丢弃。也许我误解了手册页。
如何将多个参数bash -c
作为单词(底层的 arg 向量)而不是一个字符串 ( bash -c "date +%z"
) 传递给命令?这可能吗?
语境
我问这个问题的目的是了解 bash 如何期望传递命令参数,以便通过execve()
另一个程序(包装外壳)中的函数系列之一将它们正确地输入到 bash 中。
答案1
第一个参数分配给 $0
$0 不是第一个参数,$1 是。此外,您需要使用命令字符串中的参数。
bash -c 'date "$1"' zero +%z
答案2
这里,
bash -c date +%z
-c
is之后的第一个非选项参数date
,是 Bash 将解析和运行的 shell 代码。之后的参数被分配给 shell 或脚本名称$0
(此处为+%z
),然后是位置参数$1
,$2
...(此处全部未设置)。
该字符串+%z
不会被丢弃,但由于该命令date
不使用$0
(或$1
等),因此它不会影响 shell 的操作。但是,如果 shell 必须打印错误消息,则会使用它。例如:
$ /bin/bash -c datexxx +%z
+%z: datexxx: command not found
该脚本找不到该命令datexxx
,因此它确实输出了一条错误消息,并在其前面加上了我们为脚本指定的名称 ( +%z
)。
要使用后面的参数-c
和 shell 代码,您需要传递一个使用脚本名称$0
或位置参数的命令$1
...,例如:
% bash -c 'echo "script name: $0", first arg: "$1"' foo bar doo
script name: foo, first arg: bar
不过,如果您想按原样将参数列表传递给另一个命令,您宁愿使用"$@"
(带引号)将所有位置参数作为不同字段扩展(就像您用于"$1" "$2" ...
所有设置的位置参数一样)。
所以(假设 GNU 日期为-d
):
% bash -c 'date "$@"' my-inline-script +"%F %T" -d '1 Jan 2001'
2001-01-01 00:00:00
(同样,只有当 shell 需要打印错误消息时my-inline-script
才会$0
使用它。上面的示例应该说明为什么在那里放置一些描述性内容是有意义的。无论如何,我们需要向那里传递一些$0
之前填充的值位置参数。)
答案3
的参数-c
必须是一个字符串。其余的将是参数$0
, $1
, ...
例子:
bash -c 'echo name=$0 params=$*' a b c
输出:name=a params=b c
此处单引号的使用很重要。因为它不允许当前 shell 填充等的值$0
。$*
如果您想从当前 shell 中获取值,请使用双引号。例如:
X=42
bash -c "echo $X"
输出:42
混合单引号和双引号也是可能的。只要后面的参数仍然-c
是一个字符串。
X=42
bash -c "echo $X"' 0=$0 $*'
输出:(42 0=bash
这里$0
默认为bash
)