Escapen von Gawk-Variablen für Shell-Befehle

Escapen von Gawk-Variablen für Shell-Befehle

Ich versuche, ein kleines Gawk-Skript auszuführen, das bestimmte Shell-Befehle mit ausführt system(). Ich möchte die Dateiliste mit abrufen findund 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 -cund andere von gawk...

Gibt es eine Möglichkeit, den Datensatz $0oder 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 FILEund 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 printfin bashzum Beispiel:

%q  quote the argument in a way that can be reused as shell input

verwandte Informationen