bash - 在数组中的每个项目之前添加一个元素

bash - 在数组中的每个项目之前添加一个元素

grep我有一个包含要从另一个程序的输出中排除的字符串的数组。我需要-e在每个元素之前添加一个。例如:

exclude=("$0" /usr/sbin/crond)
needs-restarting | grep -Fwiv "${exclude[@]}"

现在我知道在这种情况下我可以在每个元素前面添加--regexp=(或只是-e),如下所示: exclude=( "${exclude[@]/#/--regexp=}" )

但在一般情况下,我该怎么办呢?我想出了这个,但也许有更简单的方法。

i=0
for elem in "${exclude[@]}"; do
  exclude[i]='-e'
  exclude[i+1]="$elem"
  ((i+=2))
done
declare -p exclude

答案1

bash4.4+ 中,你可以这样做:

readarray -td '' array < <(
  ((${#array[@]})) && printf -- '-e\0%s\0' "${array[@]}"
)

这里用作\0分隔符,因为 bash 变量无论如何都不能包含 NUL 字节。如果您知道数组不会为空,则可以跳过((${#array[@]})) &&.

例子:

  • 前:
    bash-5.0$ array=($'a\nb' '' 'c d' e)
    bash-5.0$ typeset -p array
    declare -a array=([0]=$'a\nb' [1]="" [2]="c d" [3]="e")
    
  • 后:
    bash-5.0$ typeset -p array
    declare -a array=([0]="-e" [1]=$'a\nb' [2]="-e" [3]="" [4]="-e" [5]="c d" [6]="-e" [7]="e")
    

在 中zsh,您可以使用其数组压缩运算符:

opt=-e
(($#array == 0)) || array=("${(@)opt:^^array}")

或者这个复杂的:

set -o extendedglob # for (#m)
array=("${(Q@)"${(@z)array//(#m)*/-e ${(qq)MATCH}}"}")

-e <the-element-quoted>我们用(with the flag)替换每个元素qq,然后使用z将引用解析回元素列表(其中-e<the-element-quoted>然后被分隔出来),并Q删除引号(以及@用于保留空元素(如果有)的引号内) )。

答案2

您可以稍微简化您建议的循环:

exclude_args=()
for elem in "${exclude[@]}"; do
  exclude_args+=('-e' "$elem")
done
exclude=("${exclude_args[@]}")   # Optional, if you want to replace the original array's contents

相关内容