
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 -v
Option 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 = $1
sollte lauten week="$1"
.
Übrigens,Setzen Sie Befehlsersetzungen immer in Anführungszeichen.. Wenn beispielsweise TOKEN
ist *
, wird es durch die Liste der Dateien im aktuellen Verzeichnis ersetzt.
awk -v "group=$TOKEN"
Dies wird jedoch nicht group
auf den Wert von gesetzt TOKEN
, da awk die rechte Seite der Zuweisung als Literal in der awk-Syntax behandelt. Wenn der Wert von beispielsweise TOKEN
die 7-stellige Zeichenfolge ist foo\bar
, wird die awk-Variable group
auf die 6-stellige Zeichenfolge gesetzt, foo␈ar
wobei ␈
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 ENVIRON
Array zu verwenden.
Außerdem verwenden Sie die Variable group
nirgendwo 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 TOKEN
ist GROUP2
, ein Feld mit GROUP24
nicht ü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 $0
die 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.