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 sowohl chmod als auch chgrp 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 und csh, 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 auch chmod haben eine -R Option für rekursiven Betrieb.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.