10

我正在尝试构建一个涉及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

4 回答 4

14

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

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

echo ${ignore[@]}

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

于 2013-07-11T20:37:43.883 回答
3

看看printf,它也可以完成这项工作:

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

于 2016-02-22T09:38:03.387 回答
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
于 2013-07-11T21:09:33.280 回答
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[@]}" ...
于 2014-02-27T21:01:13.133 回答