在 中zsh
,通过全局扩展,我们可以使用该P
标志在每个匹配项前面添加一些文本:
$ ls -1
bar
baz
foo
$ print -- *(P:--file:)
--file bar --file baz --file foo
数组参数有类似的东西吗?如果我写
items=(foo bar baz)
我可以使用一些标志来获得这样的行为吗?
$ print -- ${(...)items}
--file foo --file bar --file baz
答案1
最佳答案取决于您需要修改后的数组的用途。
如果您正在生成命令行参数(如问题中所示),和您正在使用接受标志的工具
--file=foo
作为 的替代品--file foo
,最惯用的方法是使用${^name}
扩展形式:$ items=(foo "two words" baz) $ print -lr -- --file=${^items} --file=foo --file=two words --file=baz
我用来
print -lr
演示扩展会生成一个包含三个元素的数组。如果您调用这样的命令,该命令将看到三个参数。如果要生成命令行参数,则可以将要添加的文本(
--file
在本示例中)放入虚拟数组中,并使用${name:^^arrayname}
扩展形式将其与参数数组组合起来:$ flag=(--file) $ items=(foo "two words" baz) $ print -lr -- ${flag:^^items} --file foo --file two words --file baz
这是一个包含六个元素的数组。这种格式或 (1) 中的格式(或两者)都应该可以被任何用于传递带有关联值的标志的命令行工具所接受。
您可以修改 (1) 中的方法以使用空格而不是等号:
$ items=(foo "two words" baz) $ print -lr -- --file\ ${^items} --file foo --file two words --file baz
(请注意,您有用反斜杠转义空格;使用双引号表示
"--file ${^items}"
其他含义。)这是一个包含三个元素的数组,但每个元素中都嵌入了空格。很少(如果有的话)命令行工具会接受这种格式的标志,但它对于其他类型的文本操作可能很有用。也可以采用
${name/pattern/repl}
扩展的形式。该模式应该以#
(表示它需要在每个数组元素的开头匹配)开头,但否则应该为空(以便每个数组元素都匹配,并且实际上不会替换任何文本)。$ items=(foo "two words" baz) $ print -lr -- ${items/#/--file } --file foo --file two words --file baz
这与 (3) 具有相同的注意事项,并且也比该方法不太惯用。
请注意,当数组元素包含空格时,所有这四种方法都会做正确的事情(即,它们不会突然在空格上分割字符串)。
答案2
您可以使用P
glob 修饰符!如果你坚持的话,一切都可以是一个球体。请注意,我并不是说我真的会想去做这个。我想不出在什么情况下这是最好的方法。但这在技术上是可能的。
% items=(foo bar baz)
% print -lr -- /(P:--file:e\''reply=($items[@])'\')
--file
bar
--file
baz
--file
foo
它的工作原理是创建一个与一个文件名完全匹配的 glob(/
效果很好),使用 glob 限定符e
将一个匹配项替换为任意列表,然后将P
限定符应用于结果。
这只适用于执行通配符的上下文,但这通常是允许数组的情况。
答案3
您可以通过以下方式可移植地执行此操作(或者至少可移植到支持此数组语法的 shell)printf
:
$ items=(foo bar baz)
$ printf -- "--file %s " "${items[@]}"
--file foo --file bar --file baz $
然而,与该print
命令不同的是,它不会添加尾随换行符(这就是为什么您将$
与上面的输出位于同一行)。如果这是一个破坏交易的事情,你可以这样做:
$ printf -- "--file %s " "${items[@]}"; echo ""
--file foo --file bar --file baz