Es gibt wenige Probleme.
>>
in Ihrem ersten Befehl wird von Ihrer aktuellen Shell als Umleitung zu einer Datei interpretiert, deren Name buchstäblich benannt ist {}
, sofern diese nicht in Anführungszeichen gesetzt ist.
*.ovpn
kann durch Shell-Globbing erweitert werden, bevor es ausgeführt wird find
. Dies ist der Fall, wenn sich im aktuellen Verzeichnis mindestens ein Objekt befindet, das dem Muster entspricht. Sie möchten dies zitieren. Vergleichen Sie diese Frage .
Sie bekommen, Can't open echo
weil Sie tatsächlich sagen sh
, dass Sie sich öffnen sollen echo
. Um einen Befehl auszuführen, benötigen Sie sh -c
.
find
ohne Angabe des Pfads ist nicht portierbar (vergleiche diese Frage ). Während Sie damit umgehen können, erwähne ich das Problem, um die Antwort für andere Benutzer nützlicher zu machen.
Dies ist die verbesserte Version Ihres ersten Befehls, der irgendwie funktioniert (führen Sie ihn nicht aus, lesen Sie weiter):
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "{}"' \;
Beachten Sie, dass ich in {}
Anführungszeichen ein Zitat setzen musste . Diese Anführungszeichen werden von "gesehen" sh
und lassen Dateinamen mit Leerzeichen usw. als Umleitungsziele fungieren. Ohne Anführungszeichen können Sie mit like enden, echo "line to append" >> foo bar.ovpn
was äquivalent ist echo "line to append" bar.ovpn >> foo
. Zitat macht es echo "line to append" >> "foo bar.ovpn"
stattdessen.
Leider werden Dateinamen mit "
dieser Syntax gebrochen.
Der richtige Weg zu passieren, {}
um sh
nicht in der Befehlsfolge enthält aber ihren Inhalt als separates Argument zu übergeben:
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$0"' {} \;
$0
innerhalb der Befehlsfolge an das unsere Premieren Argument erweitert sh
wird nach -c '…'
. Jetzt auch "
in Dateiname wird die Syntax nicht gebrochen.
Normalerweise (wie in einem Skript), um auf das erste Argument zu verweisen, das Sie verwenden $1
. Dies ist der Grund, warum einige Benutzer lieber ein Dummy-Argument verwenden würden $0
, wie dieses:
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$1"' dummy {} \;
Wenn es ein Skript $0
wäre, würde es zu seinem Namen erweitert. Deshalb ist es nicht ungewöhnlich, dass dies dummy
tatsächlich der Fall ist sh
(oder bash
, wenn jemand anruft bash -c …
usw.):
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$1"' sh {} \;
Aber warte! find
ruft sh
für jede einzelne Datei ein separates auf. Ich erwarte nicht, dass Sie Tausende .ovpn
Dateien haben, aber im Allgemeinen möchten Sie viele Dateien verarbeiten, ohne unnötige Prozesse zu erzeugen. Wir können den Ansatz optimieren, tee -a
indem in einem einzigen Prozess in mehrere Dateien geschrieben werden kann:
find . -name '*.ovpn' -exec sh -c 'echo "line to append" | tee -a "$@" >/dev/null' sh {} +
Beachten Sie {} +
, dass dies mehrere Pfade gleichzeitig durchläuft. Innerhalb des Befehls, den sh -c
wir ausführen "$@"
, rufen wir sie mit ab, was zu erweitert wird "$1" "$2" "$3" …
. In diesem Fall ist ein Dummy-Argument (nicht verwendet) $0
ein Muss.
Im Allgemeinen gibt es auch dieses Thema: Warum ist printf
besser als echo
? In diesem Fall verwenden Sie jedoch echo
keine Optionen, und die Zeichenfolge ist statisch. Sie sollte also in Ordnung sein.