Jak mogę użyć dwóch poleceń bash w -exec polecenia find?


32

Czy możliwe jest użycie 2 poleceń w -execczęści findpolecenia?

Próbowałem czegoś takiego:

find . -name "*" -exec  chgrp -v new_group {}  ; chmod -v 770 {}  \;

i dostaję:

find: brakujący argument dla -exec
chmod: nie można uzyskać dostępu {}: brak takiego pliku lub katalogu
chmod: nie można uzyskać dostępu ;: brak takiego pliku lub katalogu

Odpowiedzi:


44

Jeśli chodzi o findpolecenie, możesz także po prostu dodać więcej -execpoleceń z rzędu:

find . -name "*" -exec chgrp -v new_group '{}' \; -exec chmod -v 770 '{}' \;

Zauważ, że w rezultacie to polecenie jest równoważne użyciu

chgrp -v plik nowa_grupa && chmod -v 770 plik

na każdym pliku.

Wszystkie find„s parametry, takie jak -name, -exec, -sizei tak dalej, są rzeczywiście testuje : findbędą działać je jeden po drugim, tak długo jak cały łańcuch dotychczas oceniano na prawdziwe . Tak więc każde kolejne -execpolecenie jest wykonywane tylko wtedy, gdy poprzednie zwróciły wartość true (tzn. 0Status wyjścia poleceń). Ale findrozumie także operatory logiczne, takie jak lub ( -o) i not ( !). Dlatego, aby użyć łańcucha -exectestów niezależnie od poprzednich wyników, należałoby użyć czegoś takiego:

find . -name "*" \( -exec chgrp -v new_group {} \; -o -exec chmod -v 770 {} \; \)

4
+1: Tak, to najbardziej elegancki sposób na zrobienie tego. Jeśli możesz wyjaśnić, dlaczego używasz '{}'(apostrofy wokół nawiasów klamrowych), odwiedź: unix.stackexchange.com/q/8647/4485
— użytkownik nieznany

1
@ użytkownik Niestety nie wiem, czy nadal jest to konieczne. Właśnie zrobiłem test i nie spotkałem się z sytuacją, w której wszystko by to zmieniło. Myślę, że to tylko „dobra praktyka”, która wymrze.
— rozcietrzewiacz

2
Cytaty są ważne dla plików ze spacjami w nazwach.
— naught101

17
find . -name "*" -exec sh -c 'chgrp -v new_group "$0" ; chmod -v 770 "$0"' {} \;

@Gilles: Cuda -cdziwnego obchodzenia się z 0 $ sprawiają, że za każdym razem, gdy na niego patrzę, myślę, że to jest złe, ale zdecydowanie poprawne.
— derobert

Podoba mi się definiowanie jawnej powłoki ...
— djangofan

Ta odpowiedź (i odpowiedź Gilesa) wydaje się lepszą odpowiedzią na zadane pytanie sh -c.

14

Twoje polecenie jest najpierw analizowane przez powłokę na dwa polecenia oddzielone znakiem a ;, co jest równoważne nowej linii:

find . -name "*" -exec chgrp -v new_group {}
chmod -v 770 {} \;

Jeśli chcesz uruchomić polecenie powłoki, jawnie wywołaj powłokę za pomocą bash -c(lub sh -cjeśli nie obchodzi cię, że powłoka jest specjalnie bash):

find . -name "*" -exec sh -c 'chgrp -v new_group "$0"; chmod -v 770 "$0"' {} \;

Zwróć uwagę na użycie {}jako argumentu dla powłoki; jest to zerowy argument (który zwykle jest nazwą powłoki lub skryptu, ale nie ma to tutaj znaczenia), stąd też nazywany "$0".

Możesz przekazać wiele nazw plików do powłoki jednocześnie i sprawić, że powłoka będzie się przez nie iterować, będzie to szybsze. Podaję tutaj _jako nazwę skryptu, a następujące argumenty to nazwy plików, które for x(skrót do for x in "$@") iterują.

find . -name "*" -exec sh -c 'for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done' _ {} +

Zauważ, że odkąd bash 4 lub w zsh, tutaj wcale nie musisz go znaleźć. W bash, uruchom shopt -s globstar(włóż to do swojego ~/.bashrc), aby aktywować tryb **/stojący dla globalnego katalogu rekurencyjnego. (W Zsh jest to aktywne przez cały czas.) Następnie

chgrp -v new_group -- **/*; chmod -v 770 -- **/*

lub jeśli chcesz, aby pliki były iterowane w kolejności

for x in **/*; do
  chgrp -v new_group -- "$x"
  chmod -v 770 -- "$x"
done

Jedną różnicą w stosunku do findpolecenia jest to, że powłoka ignoruje pliki kropkowe (pliki, których nazwa zaczyna się od a .). Aby je uwzględnić, w bash, pierwszy zestaw GLOBIGNORE=.:..; w zsh użyj **/*(D)jako wzorca globu.


Ta odpowiedź (i odpowiedź Glenna) wydaje się lepszą odpowiedzią na zadane pytanie sh -c.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.