AWK: Übergeben von Shellvariablen an awk

AWK: Übergeben von Shellvariablen an awk

Ich versuche, eineVariableAnzahl der Argumente aus dem Shell-Skript an eine Mustererkennungs-Teilmenge einer Tabelle. Hier ist mein bisheriger Versuch:

Die Datei „infile“:

    ID,GROUP
    1,GROUP2    
    2,GROUP2    
    3,GROUP4    
    4,GROUP4    
    5,GROUP5    
    6,GROUP5    
    7,GROUP23   
    8,GROUP23   
    9,GROUP23   

Die Datei subset.sh:

    #!/bin/sh
    rm -f outfile_$week

    week = $1
    shift

    for TOKEN in "$@"
    do

    echo "adding records for" $TOKEN

    awk -F "," -v group = $TOKEN '{ if(FNR > 2 && $2 ~/group/){print $0} }' infile >> outfile_$week
    done

Ich habe auch „group = "$TOKEN", „group = $TOKEN" und dann beides mit einfachen Anführungszeichen probiert. Ich sende es so:

    sh subset.sh 061314 GROUP2 GROUP23

Der Fehler, den ich bekomme, ist erstaunlich wenig informativ

    Usage: awk [-F fs][-v Assignment][-f Progfile|Program][Assignment|File] ...

Ich bin für jede Hilfe sehr dankbar, danke!

EDIT: Ich habe versucht zu laufen

    awk -F "," -v group ="GROUP1" '{ if(FNR > 2 && $2 ~/group/){print $0} }' infile

ohne Erfolg ... (derselbe Fehler wie oben). Kennt jemand einen Grund, warum dies passieren könnte?

Antwort1

Sie sollten schreiben:

-v group="$TOKEN"

anstelle von -v group = $TOKEN, was zu einem Syntaxfehler in führt awk.

Antwort2

Klingt, als ob Sie Folgendes möchten:

awk -F, '
  BEGIN {
    for (i = 1; i < ARGC; i++) group[ARGV[i]]
    ARGC=0
  }
  NR >= 2 && $2 in group' "$@" < infile

Oder wenn Sie die Argumente wirklich als reguläre Ausdrücke betrachten möchten, um sie mit der zweiten Spalte abzugleichen:

awk -F, '
  BEGIN {
    for (i = 1; i < ARGC; i++) group[ARGV[i]]
    ARGC=0
  }
  NR >= 2 {
    for (i in group) if ($2 ~ i) {print; next}
  }' "$@" < infile

Antwort3

Ihr unmittelbares Problem sind die Leerzeichen um das Gleichheitszeichen. Das Argument für die -vOption sollte eine Zuweisung sein. Awk erkennt ein Argument für -v, gefolgt von einem Skript ( =), gefolgt von Dateinamen (dem Wert von TOKEN, Ihrem Skript und Ihren Dateinamen).

Sie haben weiter oben im Shell-Skript einen ähnlichen Fehler gemacht: week = $1sollte lauten week="$1".

Übrigens,Setzen Sie Befehlsersetzungen immer in Anführungszeichen.. Wenn beispielsweise TOKENist *, wird es durch die Liste der Dateien im aktuellen Verzeichnis ersetzt.

awk -v "group=$TOKEN"

Dies wird jedoch nicht groupauf den Wert von gesetzt TOKEN, da awk die rechte Seite der Zuweisung als Literal in der awk-Syntax behandelt. Wenn der Wert von beispielsweise TOKENdie 7-stellige Zeichenfolge ist foo\bar, wird die awk-Variable groupauf die 6-stellige Zeichenfolge gesetzt, foo␈arwobei ein Backspace-Zeichen (Byte-Wert 8) ist.

Der direkteste Weg, eine Variable an ein Awk-Skript zu übergeben, besteht darin, sie in die Umgebung zu exportieren und über das ENVIRONArray zu verwenden.

Außerdem verwenden Sie die Variable groupnirgendwo im awk-Skript. Der reguläre Ausdruck /group/stimmt mit jedem String überein, der den 5-stelligen String enthält group. Wenn Sie prüfen möchten, ob das Feld genau den Wert von hat group(so dass z. B. wenn der Wert von TOKENist GROUP2, ein Feld mit GROUP24nicht übereinstimmt), verwenden Sie den Gleichheitsoperator ==.

  export TOKEN
  awk -F "," '{ if (FNR > 2 && $2 == ENVIRON["TOKEN"]){print $0} }' infile >> outfile_$week

Hier ist das gesamte Skript, noch etwas vereinfacht, um die Bedingungs-Aktions-Syntax von awk zu verwenden (wobei die Aktion hier weggelassen wird, da dies print $0die Standardeinstellung ist) und um zu vermeiden, dass die Ausgabedatei jedes Mal geöffnet wird:

#!/bin/sh
week="$1"
shift
for TOKEN in "$@"
do
  echo "adding records for" $TOKEN
  awk -F "," 'FNR > 2 && $2 == ENVIRON["TOKEN"]' infile 
done >"outfile_$week"

SehenAntwort von Stéphane Chazelasfür eine fortgeschrittenere Möglichkeit zur Verwendung von awk, bei der die Eingabedatei nicht mehrfach verarbeitet werden muss.

verwandte Informationen