2013-07-11 46 views
6

我試圖構建一個涉及find的長命令。我有一組我想忽略的目錄,我想將這個目錄格式化爲命令。Bash數組:追加和預先考慮到數組中的每個元素

基本上,我想這個數組轉換:

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} 

追加,但我不知道如何將這些結合起來,同時前插和追加到一個數組中的每個元素。

+0

聽起來很不錯。我認爲你需要有多個級別(副本)的數組來支持每個$ {var/x/y}替換。我使用'$(echo $(echo $ {ig [@]} | sed's/a/b/g; s/c/d/g; s/d/e $ /; s/^ f/g /'))'。祝你好運! – shellter

回答

12

你不能同時做到這一點。幸運的是,你並不需要:

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

echo ${ignore[@]} 

注意括號和雙引號 - 它們確保該數組包含每個替換後三個要素,即使有參與空間。

+0

更好呢!祝你們好運。 – shellter

+1

這真的很性感! – jh314

+0

這是很好的,你試圖引用的名字,但它並不完美,例如如果'忽略'包含'''一些奇怪的東西' – musiphil

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 
+0

哇,這真的很性感 – jh314

+0

這打印' -o -path「$ dir/archive crl cfg」-prune'。 – musiphil

+0

@musiphil請正確複製 - 並運行它bash。它正確地打印我在我的答案中說明的內容。現在雙擊檢查 – jm666

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[@]}" ... 
1

看一看printf,它不工作,以及:

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

相關問題