Ich versuche, ein kleines Gawk-Skript auszuführen, das bestimmte Shell-Befehle mit ausführt system()
. Ich möchte die Dateiliste mit abrufen find
und das Skript folgendermaßen ausführen:
find <arguments> -printf "%f\n" | script.awk
Das Problem besteht darin, dass diese Dateien Sonderzeichen wie Leerzeichen, Anführungszeichen und Klammern enthalten. Beispiel:
$ ls
'Aujourd'\''hui C'\''est Toi (Orchestral).flac'
Ich habe alle möglichen Zitate ausprobiert, zum Beispiel das folgende:
system("<command> \""$0"\"")
Und das:
system("<command> \'"$0"\'")
Ich erhalte alle möglichen Fehler. Einige dieser Fehler stammen von sh -c
und andere von gawk
...
Gibt es eine Möglichkeit, den Datensatz $0
oder andere Variablen aus dem Gawk-Skript an einen Shell-Befehl zu übergeben, ohne auf all diese Probleme zu stoßen?
Notiz:Ich weiß, dass es einfacher gewesen wäre, die Dateien vorübergehend umzubenennen, aber ich finde es schwieriger, das zu vermeiden.
BEARBEITEN:
Keine der vorgeschlagenen Antworten hat mein Problem gelöst, daher hier eine genauere Beschreibung des Problems: Ich versuche, einen Befehl auszuführen, der2awk-Variablen. Beispiele:
Wenn ich ausführe:
system("metaflac --show-tag=ARTIST \""FILE"\"")
Ich erhalte keine Fehlermeldung, da ich ein Zitat verwende FILE
und es keine doppelten Anführungszeichen enthält, ist alles in Ordnung.
Aber wenn ich ausführe:
system("metaflac --set-tag=ARTIST="AWK_VAR_WITH_ARTIST_VALUE" "\"FILE\")
Selbst wenn ich es zitiere, erhalte ich eine Fehlermeldung metaflac
, dass die FLAC-Datei nicht gefunden wurde. Beim Lesen der Fehlermeldung sehe ich, dass der Dateiname in einzelne Wörter aufgeteilt wurde.
Antwort1
Sie könnten system("<command> \"$0\"")
durch die Fähigkeit von awk ersetzen, in einen Prozess zu schreiben, d. h. print $0 | "pre;<command> \"$v\""
, wo dieVorTeil würde stdin in die Shell-Variable v lesen. In Bash wäre das read -r v
. Sie erhalten beispielsweise Folgendes:
awk 'BEGIN{ cmd="read -r v; ls -ld \"$v\"" }
{ print $0 | cmd; close(cmd); }'
Wenn Sie schlimme Dinge wie Zeilenumbrüche in den Dateinamen behandeln möchten, können Sie in Ihrer Suchfunktion den Weg print0 wählen. Wenn Ihr awk dies akzeptiert RS='\0'
, haben Sie für bash Folgendes:
find . -print0 |
awk -v RS='\0' '
BEGIN{ cmd="read -r -d \"\" v; ls -ld \"$v\"" }
{ print $0 "\x00" | cmd; close(cmd); }'
Antwort2
Im speziellen Fall von Leerzeichen und einfachen Anführungszeichen sollte es ausreichen, die Zeichenfolge in doppelte Anführungszeichen zu setzen:
$ find -name 'Aujour*' -printf "%f\n" | awk '{system("ls -l \""$0"\"")}'
-rw-rw-r-- 1 user user 0 May 26 11:27 Aujourd'hui C'est Toi (Orchestral).flac
Alternativ können Sie, falls Ihre Shell einen Shell-Quote-Formatbezeichner bereitstellt, diesen anstelle von find
‚s internal verwenden -printf
:
$ find -name 'Aujour*' -exec printf '%q\n' {} \; | awk '{system("ls -l "$0)}'
-rw-rw-r-- 1 user user 0 May 26 11:27 ./Aujourd'hui C'est Toi (Orchestral).flac
Von help printf
in bash
zum Beispiel:
%q quote the argument in a way that can be reused as shell input