Bash 数组:将数组中的每个元素附加和前置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17602847/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash arrays: appending and prepending to each element in array
提问by jh314
I'm trying to build a long command involving find. I have an array of directories that I want to ignore, and I want to format this directory into the command.
我正在尝试构建一个涉及find. 我有一系列要忽略的目录,我想将此目录格式化为命令。
Basically, I want to transform this array:
基本上,我想转换这个数组:
declare -a ignore=(archive crl cfg)
into this:
进入这个:
-o -path "$dir/archive" -prune -o -path "$dir/crl" -prune -o -path "$dir/cfg" -prune
This way, I can simply add directories to the array, and the findcommand will adjust accordingly.
这样,我可以简单地将目录添加到数组中,find命令会相应地进行调整。
So far, I figured out how to prepend or append using
到目前为止,我想出了如何使用
${ignore[@]/#/-o -path \"$dir/}
${ignore[@]/%/\" -prune}
But I don't know how to combine these and simultaneously prepend and append to each element of an array.
但我不知道如何组合这些并同时添加和附加到数组的每个元素。
回答by choroba
You cannot do it simultaneously. Fortunately, you do not need to:
你不能同时做。幸运的是,您不需要:
ignore=( archive crl cfg )
ignore=( "${ignore[@]/%/\" -prune}" )
ignore=( "${ignore[@]/#/-o -path \"$dir/}" )
echo ${ignore[@]}
Note the parentheses and double quotes - they make sure the array contains three elements after each substitution, even if there are spaces involved.
注意括号和双引号——它们确保数组在每次替换后包含三个元素,即使涉及空格。
回答by jm666
If I understand right,
如果我理解正确的话
declare -a ignore=(archive crl cfg)
a=$(echo ${ignore[@]} | xargs -n1 -I% echo -o -path '"$dir/%"' -prune)
echo $a
prints
印刷
-o -path "$dir/archive" -prune -o -path "$dir/crl" -prune -o -path "$dir/cfg" -prune
Works only with xargswhat has the next switches:
仅适用于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
-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
回答by musiphil
In general, you should strive to always treat each variable in the quoted form (e.g. "${ignore[@]}") instead of trying to insert quotation marks yourself (just as you should use parameterized statements instead of escaping the input in SQL) because it's hard to be perfect by manual escaping; for example, suppose a variable contains a quotation mark.
通常,您应该努力始终以引用形式(例如"${ignore[@]}")处理每个变量,而不是尝试自己插入引号(就像您应该使用参数化语句而不是在 SQL 中对输入进行转义一样),因为手动很难做到完美逃跑;例如,假设一个变量包含一个引号。
In this regard, I would aim at crafting an array where each argument word for findbecomes an element: ("-o" "-path" "$dir/archive" "-prune" "-o" "-path" "$dir/crl" "-prune" "-o" "-path" "$dir/cfg" "-prune")(a 12-element array).
在这方面,我的目标是制作一个数组,其中每个参数词 forfind成为一个元素:(("-o" "-path" "$dir/archive" "-prune" "-o" "-path" "$dir/crl" "-prune" "-o" "-path" "$dir/cfg" "-prune")一个 12 元素的数组)。
Unfortunately, Bash doesn't seem to support a form of parameter expansion where each element expands to multiple words. (p{1,2,3}qexpands to p1q p2q p3q, but with a=(1 2 3), p"${a[@]}"qexpands to p1 2 3q.) So you need to resort to a loop:
不幸的是,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[@]}" ...
回答by setempler
Have a look at printf, which does the job as well:
看看printf,它也可以完成这项工作:
printf -- '-o -path "$dir/%s" -prune ' ${ignore[@]}
printf -- '-o -path "$dir/%s" -prune ' ${ignore[@]}

