Bash数组:追加并添加到数组中的每个元素

时间:2013-07-11 20:27:28

标签: arrays bash shell formatting

我正在尝试构建一个涉及find的长命令。我有一个我想忽略的目录数组,我想将这个目录格式化为命令。

基本上,我想转换这个数组:

declare -a ignore=(archive crl cfg)

进入这个:

-o -path "$dir/archive" -prune -o -path "$dir/crl" -prune -o -path "$dir/cfg" -prune

这样,我只需将目录添加到数组中,find命令就会相应调整。

到目前为止,我想出了如何使用

进行前置或附加
${ignore[@]/#/-o -path \"\$dir/}
${ignore[@]/%/\" -prune}

但我不知道如何组合它们并同时在数组的每个元素前面添加和附加。

4 个答案:

答案 0 :(得分:12)

你不能同时做到这一点。幸运的是,您不需要:

ignore=( archive crl cfg                    )
ignore=( "${ignore[@]/%/\" -prune}"         )
ignore=( "${ignore[@]/#/-o -path \"\$dir/}" )

echo ${ignore[@]}

注意括号和双引号 - 它们确保每次替换后数组包含三个元素,即使涉及空格也是如此。

答案 1 :(得分:2)

如果我理解正确,

declare -a ignore=(archive crl cfg)
a=$(echo ${ignore[@]} | xargs -n1 -I% echo -o -path '"$dir/%"' -prune)
echo $a

打印

-o -path "$dir/archive" -prune -o -path "$dir/crl" -prune -o -path "$dir/cfg" -prune

仅适用于具有下一个开关的xargs

 -I replstr
         Execute utility for each input line, replacing one or more occurrences of replstr in up to replacements
         (or 5 if no -R flag is specified) arguments to utility with the entire line of input.  The resulting
         arguments, after replacement is done, will not be allowed to grow beyond 255 bytes; this is implemented
         by concatenating as much of the argument containing replstr as possible, to the constructed arguments to
         utility, up to 255 bytes.  The 255 byte limit does not apply to arguments to utility which do not contain
         replstr, and furthermore, no replacement will be done on utility itself.  Implies -x.

 -J replstr
         If this option is specified, xargs will use the data read from standard input to replace the first occur-
         rence of replstr instead of appending that data after all other arguments.  This option will not affect
         how many arguments will be read from input (-n), or the size of the command(s) xargs will generate (-s).
         The option just moves where those arguments will be placed in the command(s) that are executed.  The
         replstr must show up as a distinct argument to xargs.  It will not be recognized if, for instance, it is
         in the middle of a quoted string.  Furthermore, only the first occurrence of the replstr will be
         replaced.  For example, the following command will copy the list of files and directories which start
         with an uppercase letter in the current directory to destdir:

               /bin/ls -1d [A-Z]* | xargs -J % cp -rp % destdir

答案 2 :(得分:2)

通常,您应该努力始终处理引用形式中的每个变量(例如"${ignore[@]}")而不是尝试自己插入引号(就像您应该使用参数化语句而不是在SQL中转义输入一样)因为人工逃避很难完美;例如,假设变量包含引号。

在这方面,我的目标是制作一个数组,其中find的每个参数词都成为一个元素:("-o" "-path" "$dir/archive" "-prune" "-o" "-path" "$dir/crl" "-prune" "-o" "-path" "$dir/cfg" "-prune")(一个12元素数组)。

不幸的是,Bash似乎不支持一种参数扩展形式,其中每个元素都扩展为多个单词。 (p{1,2,3}q扩展为p1q p2q p3q,但a=(1 2 3)p"${a[@]}"q扩展为p1 2 3q。)因此,您需要求助于循环:

declare -a args=()
for i in "${ignore[@]}"
do
    args+=(-o -path "$dir/$i" -prune) # I'm not sure if you want to have
                                      # $dir expanded at this point;
                                      # otherwise, just use "\$dir/$i".
done

find ... "${args[@]}" ...

答案 3 :(得分:1)

看看printf,它也可以完成这项任务:

printf -- '-o -path "$dir/%s" -prune ' ${ignore[@]}