Ich versuche, in einer bestimmten Zeile variablen Text nach einem anderen variablen Text einzufügen. Unten ist mein bisheriger Versuch, soweit ich das beurteilen kann. Wenn ich die Anführungszeichen umgehen kann, sodass awk
die Variable sichtbar ist und trotzdem angewendet werden kann, sollte es funktionieren, aber ich habe keine Ahnung, wie das geht:
#!/bin/sh
VAR=$(head -n1 ~/Scripts/tmp/file.txt)
VAR1=$(head -n1 ~/Scripts/tmp/file1.txt)
awk '/$VAR/ { print; print "$VAR1"; next }1' ~/Scripts/tmp/file.txt
Antwort1
Um Zeichenfolgen an ein Awk-Skript zu übergeben, übergeben Sie sie über Umgebungsvariablen.
export VAR VAR1
awk '
1
$0 == ENVIRON["VAR"] {print ENVIRON["VAR1"]}
' ~/Scripts/tmp/file.txt
Ich habe Ihr Skript neu organisiert, um die Logik einfacher zu machen. Außerdem habe ich die Regexp-Übereinstimmung durch einen Zeichenfolgenvergleich ersetzt: Mit der Regexp-Übereinstimmung $VAR
würde es als regulärer Ausdruck behandelt, es würde keinen Zeichenfolgenvergleich durchführen. Und es /$VAR/
würde nicht einmal den Wert von verwenden VAR
(das ist Perl-Syntax, nicht awk), den Sie match($0, VAR)
dafür benötigen würden.
Ein Hinweis zu einigen anderen Lösungen, die nicht wirklich funktionieren (sie funktionieren nur, wenn die Variablen keine Sonderzeichen enthalten; welches Zeichen ein Sonderzeichen ist, hängt von der Methode ab):
awk -v awkvar="$VAR" '$0 == awkvar …'
erweitert Backslashes im Zeileninhalt.awk "/$VAR/" …
lässt die Shell den WertVAR
als Awk-Snippet erweitern. Wenn beispielsweisefile.txt
enthält , wird^/ {system("touch ~/naughty")} /
der Befehltouch ~/naughty
ausgeführt.
Ein alternativer Ansatz besteht darin, awk alle Dateien lesen zu lassen.
awk '
BEGIN { VAR1 = getline <"~/Scripts/tmp/file1.txt"; }
NR == 1 {VAR = $0}
1
$0 == ENVIRON["VAR"] {print ENVIRON["VAR1"]}
' ~/Scripts/tmp/file.txt
Antwort2
Eine mögliche AWK-Lösung:
awk '/'$VAR'/ { print; print "'$VAR1'"; next }1'
Trennen Sie die Anführungszeichen um alle Ihre externen Variablen.
Eine andere mögliche Lösung, wie sie im anderen Beitrag zur Übergabe von Variablen vorgeschlagen wird, besteht darin, VAR1 als AWK-Variable zu übergeben. Ich denke jedoch, dass Sie für das Muster mithilfe von VAR trotzdem den Block mit einfachen Anführungszeichen escapen müssen:
awk -v var=$VAR1 '/'$VAR'/ { print; print var; next }1'
Sie könnten stattdessen sed ausprobieren :), es ist speziell für diese Art der Ersetzung konzipiert.
sed "s/$VAR.*/\0\n$VAR1/" ~/Scripts/tmp/file.txt
Wenn Sie mehrere Instanzen von VAR in einer einzigen Zeile haben können, fügen Sie am Ende des sed-Befehls (global) g hinzu, damit er nicht bei der ersten gefundenen Übereinstimmung anhält:
sed "s/$VAR.*/\0 $VAR1/g" ~/Scripts/tmp/file.txt
WICHTIG!: Stellen Sie sicher, dass das Zeichen „/“ nicht in der Variable VAR oder VAR1 vorkommt. Wenn dies möglich ist, müssen Sie es für awk oder sed maskieren. Alternativ können Sie bei sed das Trennzeichen für den Befehl in etwas anderes wie „;“ ändern, zum Beispiel:
sed "s;$VAR.*;\0\n$VAR1;" ~/Scripts/tmp/file.txt
Erklärung des sed-Befehls:
Wir verwenden um den sed-Befehl herum doppelte Anführungszeichen anstelle von einfachen Anführungszeichen, damit Variablen wie VAR und VAR1 durch ihre Werte ersetzt werden. Dies geschieht, bevor der Befehl von sed ausgeführt wird, weshalb Sie, falls / im Variableninhalt vorhanden sein kann, darauf zugreifen müssen (dies gilt auch für awk).
Das „s“ gibt an, dass Sie einen Ersetzungsbefehl in der Form schreiben:
s/<Muster>/<Ersetzungsmuster>/.
Das „/“ unmittelbar nach dem s ist das Trennzeichen, das zum Trennen der Befehlsabschnitte verwendet wird. Wenn Sie also ; eingeben, müssen Sie überall ; verwenden, wie oben gezeigt. Das abzugleichende Muster ist der Inhalt der Variable $VAR. Das Ersetzungsmuster ist \0, was bedeutet, dass das, was dem Muster entspricht, in einer neuen Zeile „\n“ und dem Inhalt von VAR2 gedruckt wird.
UPS, habe den Teil über die Zeile unten nicht gesehen … feste Muster.
Antwort3
Wenn Sie verwenden möchten awk
, müssen Sie die bash
Variable awk
mit der -v
Option übergeben:
awk -v v=$VAR -v v1=$VAR1 '/v/ { print; print v1; next }1' ~/Scripts/tmp/file.txt
Für eine korrektere und detailliertere Lösung lesen Sie bitte Robs Antwort.