2013-07-11 11 views
6

Próbuję zbudować długą komendę z udziałem find. Mam szereg katalogów, które chcę zignorować, i chcę sformatować ten katalog w poleceniu.Szyki Bash: dołączanie i poprzedzanie każdego elementu w tablicy

Zasadniczo chcę, aby przekształcić tę tablicę:

declare -a ignore=(archive crl cfg) 

w tym:

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

ten sposób można po prostu dodać katalogi do tablicy, a komenda find będzie odpowiednio dostosować.

Dotychczas I zorientowali się, jak poprzedzić lub dołączyć za pomocą

${ignore[@]/#/-o -path \"\$dir/} 
${ignore[@]/%/\" -prune} 

Ale nie wiem, jak połączyć te i jednocześnie poprzedzić i dołączyć do każdego elementu tablicy.

+0

Brzmi jak dobry pomysł. Myślę, że będziesz musiał mieć wiele poziomów (kopii) tablicy, aby obsługiwać każde podstawienie $ {var/x/y}. Zrobiłem podobne używając czegoś '$ (echo $ (echo $ {ig [@]} | sed/s/a/b/g; s/c/d/g; s/d/e $ /; s/^ f/g/')) '. Powodzenia! – shellter

Odpowiedz

12

Nie możesz tego zrobić jednocześnie. Na szczęście nie trzeba do:

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

echo ${ignore[@]} 

Uwaga nawiasów i cudzysłowów - one upewnić się, że tablica zawiera trzy elementy po każdej substytucji, nawet jeśli znajdują się miejsca związane.

+0

jeszcze lepiej! Powodzenia wszystkim. – shellter

+1

To jest naprawdę sexy! – jh314

+0

Dobrze, że próbowałeś podać nazwy, ale nie jest to doskonałe, np. jeśli 'ignore' zawiera pewne dziwne rzeczy, takie jak' ' – musiphil

2

Jeśli rozumiem prawo,

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

drukuje

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

Działa tylko z xargs co ma następujące przełączniki:

-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

Whoa, to jest naprawdę sexy też – jh314

+0

To drukuje" -o -path "$ dir/archive crl cfg" -prune'. – musiphil

+0

@musiphil proszę, skopiuj dokładnie - i uruchom to witg bash.Przepisuje dokładnie to, co napisałem w mojej odpowiedzi.Twój sprawdziłem to teraz. – jm666

2

Generalnie, należy staraj się zawsze traktować każdą zmienną w podanej formie (np. "${ignore[@]}") zamiast próbować wstawiać cudzysłowy samemu (tak jak powinieneś używać instrukcji sparametryzowanych zamiast ucieczki z danych wejściowych w SQL), ponieważ trudno jest być doskonałym dzięki ręcznemu ucieczce; na przykład załóżmy, że zmienna zawiera znak cudzysłowu.

W związku z tym chciałbym dążyć do stworzenia tablicy, w której każde słowo argumentu za find stanie się elementem: ("-o" "-path" "$dir/archive" "-prune" "-o" "-path" "$dir/crl" "-prune" "-o" "-path" "$dir/cfg" "-prune") (tablica 12-elementowa).

Niestety, Bash nie obsługuje formy rozszerzania parametrów, w której każdy element rozwija się do wielu słów. (p{1,2,3}q rozszerza się p1q p2q p3q, ale z a=(1 2 3), p"${a[@]}"q rozszerza się p1 2 3q.) Więc trzeba uciekać się do pętli:

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

spojrzeć printf, która wykonuje prace, a także:

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

Powiązane problemy