在数组的每个元素前面添加一些文本

在数组的每个元素前面添加一些文本

在 中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

最佳答案取决于您需要修改后的数组的用途。

  1. 如果您正在生成命令行参数(如问题中所示),您正在使用接受标志的工具--file=foo作为 的替代品--file foo,最惯用的方法是使用${^name}扩展形式:

    $ items=(foo "two words" baz)
    $ print -lr -- --file=${^items}
    --file=foo
    --file=two words
    --file=baz
    

    我用来print -lr演示扩展会生成一个包含三个元素的数组。如果您调用这样的命令,该命令将看到三个参数。

  2. 如果要生成命令行参数,则可以将要添加的文本(--file在本示例中)放入虚拟数组中,并使用${name:^^arrayname}扩展形式将其与参数数组组合起来:

    $ flag=(--file)
    $ items=(foo "two words" baz)
    $ print -lr -- ${flag:^^items}
    --file
    foo
    --file
    two words
    --file
    baz
    

    这是一个包含六个元素的数组。这种格式或 (1) 中的格式(或两者)都应该可以被任何用于传递带有关联值的标志的命令行工具所接受。

  3. 您可以修改 (1) 中的方法以使用空格而不是等号:

    $ items=(foo "two words" baz)
    $ print -lr -- --file\ ${^items}
    --file foo
    --file two words
    --file baz
    

    (请注意,您用反斜杠转义空格;使用双引号表示"--file ${^items}"其他含义。)这是一个包含三个元素的数组,但每个元素中都嵌入了空格。很少(如果有的话)命令行工具会接受这种格式的标志,但它对于其他类型的文本操作可能很有用。

  4. 也可以采用${name/pattern/repl}扩展的形式。该模式应该以#(表示它需要在每个数组元素的开头匹配)开头,但否则应该为空(以便每个数组元素都匹配,并且实际上不会替换任何文本)。

    $ items=(foo "two words" baz)
    $ print -lr -- ${items/#/--file }
    --file foo
    --file two words
    --file baz
    

    这与 (3) 具有相同的注意事项,并且也比该方法不太惯用。

请注意,当数组元素包含空格时,所有这四种方法都会做正确的事情(即,它们不会突然在空格上分割字符串)。

答案2

您可以使用Pglob 修饰符!如果你坚持的话,一切都可以是一个球体。请注意,我并不是说我真的会去做这个。我想不出在什么情况下这是最好的方法。但这在技术上是可能的。

% 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 

相关内容