将生成的空字符串作为命令行参数传递

Ale*_*pus 6 bash c arguments

我执行以下操作:

$ ./input ""
Run Code Online (Sandbox Code Playgroud)

输出:

argc 2
argv[1][0] 0
Run Code Online (Sandbox Code Playgroud)

但是,如果我想以基于程序的方式传递(几个)空引号:

$ python -c 'print "\"\""'
""

./input $(python -c 'print "\"\""')
Run Code Online (Sandbox Code Playgroud)

给出:

argc 2
argv[1][0] 22 - (22 hex value for ")
Run Code Online (Sandbox Code Playgroud)

那么我怎样才能生成类似的东西:

$ ./input "" "" "" ""
Run Code Online (Sandbox Code Playgroud)

并获得与示例 1 相同的结果?

Sté*_*las 5

./input $(cmd)
Run Code Online (Sandbox Code Playgroud)

因为,$(cmd)不加引号,这是一个 split+glob 运算符。shell 检索 的输出cmd,删除所有尾随换行符,然后根据$IFS特殊参数的值将其拆分,然后执行文件名生成(例如*.txt转换为当前目录中的非隐藏 txt 文件列表)结果词(后半部分不与zsh)并且在的情况下ksh也执行大括号扩展(例如a{b,c}变成abac)。

的默认值$IFS包含 SPC、TAB 和 NL 字符(在 中也是 NUL zsh,其他 shell 要么删除NUL ,要么阻塞它们)。那些(不是 NUL)也恰好是 IFS 空白字符¹,在涉及 IFS 拆分时会被特别对待。

如果 的输出cmd" a b\nc \n",则 split+glob 运算符将生成"a","b"和 的"c"参数./input。对于 IFS 空白字符,不可能split+glob生成空参数,因为一个或多个 IFS 空白字符的序列被视为一个分隔符。要生成空参数,您需要选择一个不是 IFS 空白字符的分隔符。实际上,任何非空白字符都可以(最好也避免此处所有 shell 不支持的多字节字符)。

因此,例如,如果您这样做:

IFS=:          # split on ":" which is not an IFS-whitespace character
set -o noglob  # disable globbing (also brace expansion in ksh)
./input $(cmd)
Run Code Online (Sandbox Code Playgroud)

如果cmd输出a::b\n,那么 split+glob 运算符将导致"a","""b"参数(注意"s 不是值的一部分,我只是在这里使用它们来帮助显示值)。

使用a:b:\n,取决于外壳,这将导致"a""b""a""b"""。您可以使用以下命令使其在所有 shell 中保持一致

./input $(cmd)""
Run Code Online (Sandbox Code Playgroud)

(这也意味着对于cmd(或仅包含换行符的输出)的空输出,./input将接收一个空参数而不是根本没有参数)。

例子:

cmd() {
  printf 'a b:: c\n'
}
input() {
  printf 'I got %d arguments:\n' "$#"
  [ "$#" -eq 0 ] || printf ' - <%s>\n' "$@"
}
IFS=:
set -o noglob
input $(cmd)
Run Code Online (Sandbox Code Playgroud)

给出:

I got 3 arguments:
 - <a b>
 - <>
 - < c>
Run Code Online (Sandbox Code Playgroud)

另请注意,当您执行以下操作时:

./input ""
Run Code Online (Sandbox Code Playgroud)

这些"是 shell 语法的一部分,它们是 shell 引用运算符。这些"字符不会传递给input.


¹ IFS 空白字符,每个 POSIX 是[:space:]在语言环境中分类的字符,$IFS尽管在 ksh88(POSIX 规范所基于的)和大多数 shell 中,这仍然仅限于 SPC、TAB 和 NL。我发现在这方面唯一符合 POSIX 的 shell 是yash. ksh93并且bash(从 5.0 开始)还包括其他空格(例如 CR、FF、VT...),但仅限于单字节(在某些系统上(例如 Solaris)要小心,其中包括单字节的不间断空格在某些地区)