Är det möjligt att använda två kommandon i -exec
delen av find
kommando?
Jag har provat något som:
find . -name "*" -exec chgrp -v new_group {} ; chmod -v 770 {} \;
och jag får:
hitta: saknar argument till -exec
chmod: kan inte komma åt {}: Ingen sådan fil eller katalog
chmod: kan inte komma åt;: Ingen sådan fil eller katalog
Kommentarer
Svar
När det gäller kommandot find
kan du bara lägga till fler -exec
kommandon i rad:
find . -name "*" -exec chgrp -v new_group "{}" \; -exec chmod -v 770 "{}" \;
Observera att det här kommandot är i sitt resultat t, motsvarande att använda
chgrp -v new_group file & & chmod -v 770-fil
i varje fil.
Alla find
”-parametrar som -name
, -exec
, -size
och så vidare är faktiskt test : find
kommer att fortsätta köra dem en efter en så länge hela kedjan hittills har utvärderats till true . Så varje kommande -exec
-kommando körs endast om de föregående returnerade true (dvs. 0
kommandona avsluta status). Men find
förstår också logikoperatorer som eller (-o
) och inte (!
). Därför att använda en kedja av -exec
testar oavsett av föregående resultat, man skulle behöva använda något så här:
find . -name "*" \( -exec chgrp -v new_group {} \; -o -true \) -exec chmod -v 770 {} \;
Kommentarer
- +1: Ja, det ' är det mest eleganta sättet att göra det. Om du kan förklara varför du använder
'{}'
(apostrof runt hängslen), besök: unix.stackexchange.com/q/ 8647/4485 - @user Tyvärr vet jag inte ' om det fortfarande är nödvändigt. Jag testade just nu och har inte ' inte stött på en situation där det skulle ändra någonting. Jag antar att det ' är bara " god praxis " som kommer att dö ut.
- Citaten är viktiga för filer med mellanslag i deras namn.
- @ naught101 Nej, citaten kan behövas i vissa icke-standardiserade skal, till exempel
fish
ochcsh
, men behövs definitivt inte i POSIX-liknande skal (sh
,dash
,bash
,zsh
,ksh
,yash
).
Svar
find . -name "*" -exec sh -c "chgrp -v new_group "$0" ; chmod -v 770 "$0"" {} \;
Kommentarer
- @Gilles: Underet av
-c
' s udda hantering på $ 0 får mig att tro att det här är fel varje gång jag tittar på det, men det är definitivt korrekt. - Jag gillar att det explicita skalet definieras …
- Detta svar (och Giles ' är en svara) verkar som det bättre svaret på frågan med tanke på
sh -c
.
Svar
Ditt kommando analyseras först av skalet i två kommandon åtskilda av en ;
, vilket motsvarar en ny rad:
find . -name "*" -exec chgrp -v new_group {} chmod -v 770 {} \;
Om du vill köra ett skalkommando, anropa ett skal uttryckligen med bash -c
(eller sh -c
om du bryr dig inte om att skalet är specifikt bash):
find . -name "*" -exec sh -c "chgrp -v new_group "$0"; chmod -v 770 "$0"" {} \;
Observera att {}
används argument till skalet; det är nollargumentet (som normalt är namnet på skalet eller skriptet, men detta spelar ingen roll här), och hänvisas därför till "$0"
.
Du kan skicka flera filnamn till skalet åt gången och göra skalet itera igenom dem, det kommer att vara snabbare. Här skickar jag _
som manusnamn och följande argument är filnamn, som for x
(en genväg för for x in "$@"
) itererar över.
find . -name "*" -exec sh -c "for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done" _ {} +
Observera att eftersom bash 4, eller i zsh, inte behöver hitta alls här. I bash, kör shopt -s globstar
(lägg det i din ~/.bashrc
) för att aktivera **/
som står för en rekursiv katalogglob. (I zsh är detta aktiv hela tiden.) Då
chgrp -v new_group -- **/*; chmod -v 770 -- **/*
eller om du vill att filerna ska upprepas i ordning
for x in **/*; do chgrp -v new_group -- "$x" chmod -v 770 -- "$x" done
En skillnad med kommandot find
är att skalet ignorerar punktfiler (filer vars namn börjar med .
För att inkludera dem, i bash, ställ först in GLOBIGNORE=.:..
; i zsh, använd **/*(D)
som globmönster.
Kommentarer
- Detta svar (och Glenn ' s svar) verkar vara det bättre svaret på frågan med tanke på
sh -c
. - Både
chgrp
ochchmod
har en-R
alternativ för rekursiv operation.
-name "*"
matchar alla namn, så det är ' ett no-op-test som kan tas bort. Bådechmod
ochchgrp
har ett-R
-alternativ för rekursiv operation.