Ist es möglich, 2 Befehle im -exec
Teil von find
Befehl?
Ich habe Folgendes versucht:
find . -name "*" -exec chgrp -v new_group {} ; chmod -v 770 {} \;
und ich erhalte:
find: fehlendes Argument für -exec
chmod: kann nicht auf {} zugreifen: Keine solche Datei oder kein solches Verzeichnis
chmod: kann nicht zugreifen ;: Keine solche Datei oder kein solches Verzeichnis
Kommentare
- Beachten Sie, dass
-name "*"
jedem Namen entspricht. ' ist also ein No-Op-Test, der entfernt werden kann. Außerdem sind sowohlchmod
als auchchgrp
verfügt über eine Option-R
für die rekursive Operation.
Antwort
Für den Befehl find
können Sie auch einfach weitere -exec
-Befehle hintereinander hinzufügen:
find . -name "*" -exec chgrp -v new_group "{}" \; -exec chmod -v 770 "{}" \;
Beachten Sie, dass dieser Befehl in seinem Ergebnis ist t, entspricht der Verwendung von
chgrp -v new_group file & & chmod -v 770-Datei
für jede Datei.
Alle find
-Parameter wie -name
, -exec
, -size
usw. sind tatsächlich Tests : find
führt sie weiterhin einzeln aus, solange die gesamte Kette bisher als true ausgewertet wurde. Daher wird jeder aufeinanderfolgende Befehl -exec
nur ausgeführt, wenn die vorherigen true (dh 0
beendet den Status der Befehle). find
versteht jedoch auch logische Operatoren wie oder (-o
) und nicht (!
). Um eine Kette von -exec
-Tests zu verwenden, , unabhängig davon, der vorherigen Ergebnisse, Man müsste so etwas verwenden:
find . -name "*" \( -exec chgrp -v new_group {} \; -o -true \) -exec chmod -v 770 {} \;
Kommentare
- +1: Ja, das ' ist die eleganteste Art, dies zu tun. Wenn Sie erklären können, warum Sie
'{}'
(Apostrophe um die geschweiften Klammern) verwenden, besuchen Sie bitte: unix.stackexchange.com/q/ 8647/4485 - @user Leider weiß ich ' nicht, ob es noch notwendig ist. Ich habe gerade einen Test durchgeführt und habe ' keine Situation gefunden, in der sich etwas ändern würde. Ich denke, es ist ' nur " gute Praxis ", die aussterben wird.
- Die Anführungszeichen sind wichtig für Dateien mit Leerzeichen im Namen.
- @ naught101 Nein, die Anführungszeichen werden möglicherweise in einigen nicht standardmäßigen Shells benötigt, z. B.
fish
undcsh
, werden jedoch in POSIX-ähnlichen Shells definitiv nicht benötigt (sh
,dash
,bash
,zsh
,ksh
,yash
).
Antwort
find . -name "*" -exec sh -c "chgrp -v new_group "$0" ; chmod -v 770 "$0"" {} \;
Kommentare
- @Gilles: Die Wunder der seltsamen Behandlung von
-c
' von $ 0 lässt mich denken, dass dies jedes Mal falsch ist, wenn ich es mir anschaue, aber es ist definitiv richtig. - Ich mag es, wenn die explizite Shell definiert wird …
- Diese Antwort (und Giles ' s an swer) scheint die bessere Antwort auf die Frage zu sein, wenn man die
sh -c
berücksichtigt.
Antwort
Ihr Befehl wird zuerst von der Shell in zwei Befehle analysiert, die durch ein ;
getrennt sind, was einer neuen Zeile entspricht:
find . -name "*" -exec chgrp -v new_group {} chmod -v 770 {} \;
Wenn Sie einen Shell-Befehl ausführen möchten, rufen Sie eine Shell explizit mit bash -c
(oder sh -c
if auf Es ist Ihnen egal, dass die Shell speziell Bash ist):
find . -name "*" -exec sh -c "chgrp -v new_group "$0"; chmod -v 770 "$0"" {} \;
Beachten Sie die Verwendung von {}
als Argument zur Shell; Es ist das nullte Argument (das normalerweise der Name der Shell oder des Skripts ist, aber das spielt hier keine Rolle) und wird daher als "$0"
bezeichnet.
Sie können mehrere Dateinamen gleichzeitig an die Shell übergeben und die Shell durchlaufen lassen. Dies wird schneller. Hier übergebe ich _
als Skriptnamen und die folgenden Argumente Dateinamen, die for x
(eine Verknüpfung für for x in "$@"
) durchlaufen.
find . -name "*" -exec sh -c "for x; do chgrp -v new_group "$x"; chmod -v 770 "$x"; done" _ {} +
Beachten Sie, dass Sie seit Bash 4 oder in zsh hier überhaupt nichts finden müssen. Führen Sie in Bash (in Ihr ~/.bashrc
), um **/
zu aktivieren, das für einen rekursiven Verzeichnisglob steht. (In zsh ist dies ständig aktiv.) Dann
chgrp -v new_group -- **/*; chmod -v 770 -- **/*
oder wenn die Dateien in der Reihenfolge
for x in **/*; do chgrp -v new_group -- "$x" chmod -v 770 -- "$x" done
Ein Unterschied zum Befehl find
besteht darin, dass die Shell Punktdateien ignoriert (Dateien, deren Name mit .
beginnt ) Um sie in bash aufzunehmen, setzen Sie zuerst GLOBIGNORE=.:..
; verwenden Sie in zsh **/*(D)
als Glob-Muster.
Kommentare
- Diese Antwort (und die Antwort von Glenn ') scheint die bessere Antwort auf die Frage zu sein, die angesichts der
sh -c
. - Sowohl
chgrp
als auchchmod
haben eine-R
Option für rekursiven Betrieb.