finde mit -execdir

15

Wenn ich findmit -execdirrenne, bekomme ich nicht die erwarteten Ergebnisse.

Beispielsweise:

mkdir -p a/b/c
find . -type d -execdir touch foo \;
$ tree a
a
├── b
   ├── c
   └── foo
└── foo

Das Verzeichnis centhält keine fooDatei. Wie kann ich findin jedem Verzeichnis etwas lokal aufrufen und ausführen?

Marcus Junius Brutus
quelle

Antworten:

18

Wechselt für jede übereinstimmende Datei (dh jedes Verzeichnis) findzu dem Verzeichnis, in dem sie enthalten ist (dh zu dem übergeordneten Verzeichnis), und führt den angegebenen Befehl aus. Da der Befehl nicht den Namen der Übereinstimmung verwendet, wird er niemals auf alle Verzeichnisse angewendet. Für diesen bestimmten Verzeichnisbaum tun Sie dies

(cd . && touch foo)        # because ./a matches
(cd ./a && touch foo)      # because ./a/b matches
(cd ./a/b && touch foo)    # because ./a/b/c matches

Um eine Datei in jedem Verzeichnis zu erstellen, können Sie einfach -execanstelle von verwenden -execdir, vorausgesetzt, Ihre Implementierung finderlaubt {}innerhalb eines Arguments (die meisten tun dies, und insbesondere denke ich, alle):

find . -type d -exec touch {}/foo +

Für die POSIX-Portabilität müssten Sie den Verzeichnisnamen und den Dateibasisnamen manuell zusammenstellen.

find . -type d -exec sh -c 'touch "$0/foo"' {} \;

oder (etwas schneller)

find . -type d -exec sh -c 'for d; do touch "$d/foo"; done' _ {} +

Alternativ können Sie den rekursiven Platzhalterabgleich von bash verwenden. Beachten Sie, dass findBash (im Gegensatz zu den entsprechenden Funktionen in ksh und zsh und im Gegensatz zu Ihrem Befehl) unter symbolischen Links zu Verzeichnissen wiederkehrt.

shopt -s globstar
for d in **/*/; do touch -- "$d/foo"; done

Eine zsh-Lösung:

touch ./**/(e\''REPLY+=foo'\')
Gilles 'SO - hör auf böse zu sein'
quelle
Zu man bashIhrer Information : Zustände unter "-c": Argumente nach "command_string" werden Positionsparametern ab $ 0 zugewiesen, "for d" durchläuft jedoch Positionsparameter ab $ 1. "_" ist Text, der $ 0 zugewiesen ist und nicht verwendet wird.
Chad Skeeters
3

Der Befehl wird in jedem Verzeichnis ausgeführt, das eine übereinstimmende Datei enthält. Da ces kein Verzeichnis enthält, stimmt es nicht überein und wird daher dort nicht ausgeführt.

Die Lösung besteht darin, den Verzeichnisnamen wie folgt zum execdir-Argument hinzuzufügen:

find . -type d -execdir touch {}/foo \;
Jenny D
quelle
2

Von man file

   -execdir command {} +
          Like  -exec,  but  the  specified  command is run from the subdirectory containing the matched file

Ihr passendes Verzeichnis befindet sich cin dem bVerzeichnis, in dem die Exec ausgeführt wird. Es würde wie erwartet funktionieren, wenn Sie nach Dateien statt nach Verzeichnissen suchen.

Sie könnten wahrscheinlich erreichen, was Sie wollen, indem Sie die Verzeichnisse an senden, xargsda die vollständige Liste der Verzeichnisse geliefert wird.

Matt
quelle