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

  • Rețineți că -name "*" se potrivește cu fiecare nume, deci ' este un test fără opțiune care poate fi eliminat. De asemenea, atât chmod, cât și chgrp are o opțiune -R pentru operația recursivă.

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 și csh, 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 și chmod au un -R opțiune pentru operație recursivă.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *