zsh:命令替换和正确引用

zsh: Command substitution and proper quoting

我有一个接受文件名作为参数的脚本P:

P file1 file2 file3 ....

我还有一个脚本G,它生成一个(通常是短列表)文件名,每行一个文件名。在我想用 zsh 编写的主脚本中,我想使用 G 生成要由 P 处理的文件名。天真的尝试是这样的:

P $(G)

这几乎可以正常工作,只是我生活在一个恶意的人喜欢创建带有嵌入空间的文件的世界中。如果 G 会生成这样的文件列表:

one_file 
a file with spaces

P 会被称为

P one_file a file with spaces

而不是

P 'one_file' 'a file with spaces'

一个明显的解决方案是将 GP 粘合在一起,不是通过命令替换,而是通过某种语言的小程序(Ruby、Perl、Python, Algol68,....),它执行 P 的执行并将参数传递给从标准输入读取。

写起来很简单,甚至可以重用。但是,我想知道,zsh 及其一堆好东西是否内置了解决此问题的方法?

这可以通过以下方式实现:

P ${(f)"$(G)"}

这会将 P 称为

P 'one_file' 'a file with spaces'

如果G的输出是

one_file
a file with spaces

解释:

$(G) 周围的双引号告诉 zshG 的输出作为一个单词(在 shell 的意义上单词单词)。

所以只要打电话

P "$(G)"

相当于

P 'one_file
a file with spaces'

这就是 参数扩展标志 f 发挥作用的地方。 ${(f)SOMEVAR} 告诉 zsh 在换行处将 $SOMEVAR 拆分为单词。除了参数(如 SOMEVAR)之外,还可以在 ${...} 类型的参数表达式中使用命令替换(此处为 $(G)),这会导致命令 P ${(f)"$(G)"}.