È possibile utilizzare 2 comandi nella -exec
parte di find
comando?
Ho provato qualcosa del tipo:
find . -name "*" -exec chgrp -v new_group {} ; chmod -v 770 {} \;
e ottengo:
find: argomento mancante per -exec
chmod: impossibile accedere {}: nessun file o directory di questo tipo
chmod: impossibile accedere;: nessun file o directory di questo tipo
Commenti
Risposta
Per quanto riguarda il comando find
, puoi anche aggiungere altri -exec
comandi di seguito:
find . -name "*" -exec chgrp -v new_group "{}" \; -exec chmod -v 770 "{}" \;
Nota che questo comando è, nel suo risultato t, equivalente allutilizzo di
chgrp -v new_group file & & chmod -v 770 file
su ogni file.
Tutti i find
“parametri come -name
, -exec
, -size
e così via, sono in realtà test : find
continuerà a eseguirli uno per uno fino a quando lintera catena è stata valutata come true . Quindi ogni comando -exec
consecutivo viene eseguito solo se i precedenti hanno restituito true (cioè 0
stato di uscita dei comandi). Ma find
comprende anche operatori logici come o (-o
) e non (!
). Pertanto, per utilizzare una catena di -exec
test indipendentemente dei risultati precedenti, si dovrebbe usare qualcosa del genere:
find . -name "*" \( -exec chgrp -v new_group {} \; -o -true \) -exec chmod -v 770 {} \;
Commenti
- +1: Sì, quello ' è il modo più elegante per farlo. Se puoi spiegare il motivo per cui utilizzi
'{}'
(apostrofi attorno alle parentesi graffe), visita: unix.stackexchange.com/q/ 8647/4485 - @user Sfortunatamente, non ' non so se è ancora necessario. Ho fatto qualche prova proprio ora e non ' mi sono imbattuto in una situazione in cui cambierebbe qualcosa. Immagino che ' sia solo " buona pratica " che si estinguerà.
- Le virgolette sono importanti per i file con spazi nei nomi.
- @ naught101 No, le virgolette potrebbero essere necessarie in alcune shell non standard, come
fish
ecsh
, ma sicuramente non sono necessari nelle shell simili a POSIX (sh
,dash
,bash
,zsh
,ksh
,yash
).
Risposta
find . -name "*" -exec sh -c "chgrp -v new_group "$0" ; chmod -v 770 "$0"" {} \;
Commenti
- @Gilles: The wonders of
-c
' s strana gestione di $ 0 mi fa pensare che sia sbagliato ogni volta che la guardo, ma è decisamente corretto. - Mi piace che la shell esplicita sia definita …
- Questa risposta (e Giles ' è un swer) sembra la risposta migliore per la domanda data la
sh -c
.
Risposta
Il tuo comando viene prima analizzato dalla shell in due comandi separati da un ;
, che è equivalente a una nuova riga:
find . -name "*" -exec chgrp -v new_group {} chmod -v 770 {} \;
Se desideri eseguire un comando di shell, invoca esplicitamente una shell con bash -c
(o sh -c
se non ti interessa che la shell sia specificamente bash):
find . -name "*" -exec sh -c "chgrp -v new_group "$0"; chmod -v 770 "$0"" {} \;
Nota luso di {}
come argomento alla shell; è largomento zero (che normalmente è il nome della shell o dello script, ma qui non ha importanza), quindi indicato come "$0"
.
Puoi passare più nomi di file alla shell alla volta e far scorrere la shell attraverso di essi, “sarà più veloce. Qui passo _
come nome dello script e i seguenti argomenti sono nomi di file, su cui for x
(una scorciatoia per for x in "$@"
) viene ripetuto.
find . -name "*" -exec sh -c "for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done" _ {} +
Nota che da bash 4, o in zsh, non è necessario trovarlo qui. In bash, esegui shopt -s globstar
(inseriscilo nel tuo ~/.bashrc
) per attivare **/
che sta per una directory glob ricorsiva (in zsh, questo è sempre attivo.) Quindi
chgrp -v new_group -- **/*; chmod -v 770 -- **/*
o se desideri che i file vengano ripetuti in ordine
for x in **/*; do chgrp -v new_group -- "$x" chmod -v 770 -- "$x" done
Una differenza con il comando find
è che la shell ignora i file punto (file il cui nome inizia con .
). Per includerli, in bash, imposta prima GLOBIGNORE=.:..
; in zsh, utilizza **/*(D)
come modello glob.
Commenti
- Questa risposta (e la risposta di Glenn ') sembra la migliore risposta alla domanda data la
sh -c
. - Sia
chgrp
chechmod
hanno un-R
opzione per operazioni ricorsive.
-name "*"
corrisponde a ogni nome, quindi è ' un test non operativo che può essere rimosso. Inoltre, siachmod
chechgrp
ha unopzione-R
per loperazione ricorsiva.