Er det mulig å bruke to kommandoer i -exec
delen av find
kommando?
Jeg har prøvd noe sånt som:
find . -name "*" -exec chgrp -v new_group {} ; chmod -v 770 {} \;
og jeg får:
finn: mangler argument til -exec
chmod: får ikke tilgang {}: Ingen slik fil eller katalog
chmod: får ikke tilgang ;: Ingen slik fil eller katalog
Kommentarer
Svar
Når det gjelder find
kommandoen, kan du også bare legge til flere -exec
kommandoer på rad:
find . -name "*" -exec chgrp -v new_group "{}" \; -exec chmod -v 770 "{}" \;
Merk at denne kommandoen er i sin resultat t, tilsvarer bruk av
chgrp -v new_group file & & chmod -v 770 fil
på hver fil.
Alle find
«s parametere som -name
, -exec
, -size
og så videre, er faktisk tester : find
vil fortsette å kjøre dem en etter en så lenge hele kjeden så langt har evaluert til true . Så hver påfølgende -exec
-kommando utføres bare hvis de forrige returnerte true (dvs. 0
exit kommandoer). Men find
forstår også logiske operatorer som eller (-o
) og ikke (!
). Derfor, for å bruke en kjede av -exec
tester uansett av de forrige resultatene, man trenger å bruke noe slikt:
find . -name "*" \( -exec chgrp -v new_group {} \; -o -true \) -exec chmod -v 770 {} \;
Kommentarer
- +1: Ja, det ' er den mest elegante måten å gjøre det på. Hvis du kan forklare hvorfor du bruker
'{}'
(apostrofer rundt klammeparentesene), kan du gå til: unix.stackexchange.com/q/ 8647/4485 - @user Dessverre vet jeg ikke ' om det fortsatt er nødvendig. Jeg testet akkurat nå og har ikke ' ikke kommet over en situasjon der det ville endre noe. Jeg antar at det ' er bare " god praksis " som vil dø ut.
- Sitatene er viktige for filer med mellomrom i navnene.
- @ naught101 Nei, anførselstegnene kan være nødvendige i noen ikke-standardiserte skall, for eksempel
fish
ogcsh
, men er absolutt ikke nødvendig i POSIX-lignende skjell (sh
,dash
,bash
,zsh
,ksh
,yash
).
Svar
find . -name "*" -exec sh -c "chgrp -v new_group "$0" ; chmod -v 770 "$0"" {} \;
Kommentarer
- @Gilles: Underverkene til
-c
' s rare håndtering på $ 0 får meg til å tro at dette er galt hver gang jeg ser på det, men det er definitivt riktig. - Jeg liker at det eksplisitte skallet blir definert …
- Dette svaret (og Giles ' er en svare) virker som det bedre svaret på spørsmålet gitt
sh -c
.
Svar
Kommandoen din blir først analysert av skallet i to kommandoer atskilt med en ;
, som tilsvarer en ny linje:
find . -name "*" -exec chgrp -v new_group {} chmod -v 770 {} \;
Hvis du vil kjøre en shell-kommando, kan du påkalle et skall eksplisitt med bash -c
(eller sh -c
hvis du bryr deg ikke om at skallet er spesifikt bash):
find . -name "*" -exec sh -c "chgrp -v new_group "$0"; chmod -v 770 "$0"" {} \;
Legg merke til bruken av {}
argument til skallet; det er nullverdige argumentet (som vanligvis er navnet på skallet eller skriptet, men dette betyr ikke noe her), derav referert til som "$0"
.
Du kan sende flere filnavn til skallet om gangen og få skallet til å gjentas gjennom dem, det vil være raskere. Her sender jeg _
som manusnavnet og følgende argumenter er filnavn, som for x
(en snarvei for for x in "$@"
) gjentas over.
find . -name "*" -exec sh -c "for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done" _ {} +
Merk at siden bash 4, eller i zsh, trenger du ikke å finne noe her. I bash, kjør shopt -s globstar
(legg det i ~/.bashrc
) for å aktivere **/
som står for en rekursiv katalog glob. (I zsh er dette aktiv hele tiden.) Så
chgrp -v new_group -- **/*; chmod -v 770 -- **/*
eller hvis du vil at filene skal gjentas på i rekkefølge
for x in **/*; do chgrp -v new_group -- "$x" chmod -v 770 -- "$x" done
En forskjell med find
kommandoen er at skallet ignorerer punktfiler (filer hvis navn begynner med en .
For å inkludere dem, i bash, sett først GLOBIGNORE=.:..
; i zsh, bruk **/*(D)
som globmønsteret.
Kommentarer
- Dette svaret (og Glenn ' s svar) virker som det bedre svaret på spørsmålet gitt
sh -c
. - Både
chgrp
ogchmod
har en-R
alternativ for rekursiv drift.
-name "*"
samsvarer med hvert navn, så det ' er en no-op test som kan fjernes. Også bådechmod
ogchgrp
har et-R
alternativ for rekursiv operasjon.