Este posibil să utilizați 2 comenzi în partea -exec
din find
comandă?
Am încercat ceva de genul:
find . -name "*" -exec chgrp -v new_group {} ; chmod -v 770 {} \;
și obțin:
găsi: argument lipsă la -exec
chmod: nu poate accesa {}: Nu există un astfel de fișier sau director
chmod: nu poate accesa; >
Comentarii
Răspuns
În ceea ce privește comanda find
, puteți adăuga mai multe comenzi -exec
într-un rând:
find . -name "*" -exec chgrp -v new_group "{}" \; -exec chmod -v 770 "{}" \;
Rețineți că această comandă se află în rezoluția sa t, echivalentul utilizării
chgrp -v fișier new_group & & fișier chmod -v 770
pe fiecare fișier.
Toți parametrii find
„, cum ar fi -name
, -exec
, -size
și așa mai departe, sunt de fapt teste : find
va continua să le ruleze unul câte unul atâta timp cât întregul lanț de până acum a evaluat la adevărat . Deci, fiecare comandă -exec
consecutivă este executată numai dacă cele anterioare au returnat adevărat (adică 0
starea de ieșire a comenzilor). Dar find
înțelege și operatori logici precum sau (-o
) și nu (!
). Prin urmare, pentru a utiliza un lanț de -exec
teste indiferent de de rezultatele anterioare, ar trebui să folosiți așa ceva:
find . -name "*" \( -exec chgrp -v new_group {} \; -o -true \) -exec chmod -v 770 {} \;
Comentarii
- +1: Da, asta ' este cel mai elegant mod de a o face. Dacă puteți explica, de ce utilizați
'{}'
(apostrofe în jurul parantezelor), vă rugăm să vizitați: unix.stackexchange.com/q/ 8647/4485 - @user Din păcate, nu ' nu știu dacă mai este necesar. Am făcut câteva teste chiar acum și nu ' am dat peste o situație în care ar schimba orice. Cred că ' este doar " bună practică " care va dispărea.
- Ghilimelele sunt importante pentru fișierele cu spații în numele lor.
- @ naught101 Nu, ghilimelele pot fi necesare în unele shell-uri non-standard, cum ar fi
fish
șicsh
, dar cu siguranță nu sunt necesare în cochilii de tip POSIX (sh
,dash
,bash
,zsh
,ksh
,yash
).
Răspuns
find . -name "*" -exec sh -c "chgrp -v new_group "$0" ; chmod -v 770 "$0"" {} \;
Comentarii
- @Gilles: Minunile manipulării ciudate a
-c
' de $ 0 mă fac să cred că acest lucru este greșit de fiecare dată când îl privesc, dar este cu siguranță corect. - Îmi place să fie definită coaja explicită …
- Acest răspuns (și Giles ' s an swer) pare răspunsul mai bun pentru întrebarea dată
sh -c
.
Răspuns
Comanda dvs. este analizată mai întâi de către shell în două comenzi separate printr-un ;
, care este echivalent cu o linie nouă:
find . -name "*" -exec chgrp -v new_group {} chmod -v 770 {} \;
Dacă doriți să executați o comandă shell, invocați un shell explicit cu bash -c
(sau sh -c
dacă nu vă pasă că shell-ul este specific bash):
find . -name "*" -exec sh -c "chgrp -v new_group "$0"; chmod -v 770 "$0"" {} \;
Rețineți utilizarea {}
ca argument la cochilie; este argumentul zero (care este în mod normal numele shell-ului sau al scriptului, dar acest lucru nu contează aici), de aceea se face referire ca "$0"
.
Puteți trece mai multe nume de fișiere la shell simultan și puteți face shell-ul să itereze prin ele, va fi mai rapid. Aici trec _
deoarece numele scriptului și următoarele argumente sunt nume de fișiere, pe care for x
(o comandă rapidă pentru for x in "$@"
) iterați peste.
find . -name "*" -exec sh -c "for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done" _ {} +
Rețineți că, din bash 4, sau în zsh, nu trebuie să găsiți deloc aici. În bash, rulați shopt -s globstar
(puneți-l în ~/.bashrc
) pentru a activa **/
în locul unui director de recursive glob. (În zsh, acesta este activ tot timpul.) Apoi
chgrp -v new_group -- **/*; chmod -v 770 -- **/*
sau dacă doriți ca fișierele să fie iterate în ordine
for x in **/*; do chgrp -v new_group -- "$x" chmod -v 770 -- "$x" done
O diferență cu comanda find
este că shell-ul ignoră fișierele punct (fișiere al căror nume începe cu un .
Pentru a le include, în bash, setează mai întâi GLOBIGNORE=.:..
; în zsh, folosește **/*(D)
ca model glob.
Comentarii
- Acest răspuns (și răspunsul lui Glenn ') pare cel mai bun răspuns la întrebarea dată
sh -c
. - Atât
chgrp
, cât șichmod
au un-R
opțiune pentru operație recursivă.
-name "*"
se potrivește cu fiecare nume, deci ' este un test fără opțiune care poate fi eliminat. De asemenea, atâtchmod
, cât șichgrp
are o opțiune-R
pentru operația recursivă.