AWK-Befehlsargumentfehler

AWK-Befehlsargumentfehler

Ich habe einen Datensatz, der Kontaktinformationen von Studenten enthält. Der Beispieldatensatz sieht wie folgt aus:

First Name, Last Name, Address, Phone Number
John, Doe, "House # 11, Street xyz, Road, Area",00000000
Sara, Taylor, "Jake Lake%, Apartment #22, Main Road, Area XYZ", 00000000

Ich führe den folgenden Befehl aus, um ihn zu ersetzen,in der Adressspalte an|um es in die Datenbank zu laden.

awk '!(NR%2){gsub(",","|")} {printf RFS $0} {RFS="\""}' RS=\" fileName.txt > output.txt

Das Problem, mit dem ich konfrontiert bin, ist, dass jedes Mal, wenn ich diesen Befehl ausführe, der folgende Fehler zurückgegeben wird: Zunächst lief es einwandfrei

awk: run time error: not enough arguments passed to printf(""Jake Lake%, Apartment #22, Main Road, Area XYZ")

Gibt es dafür eine Lösung? Mir ist aufgefallen, dass%kommt in der Adresse, ist das das Problem?

Antwort1

  1. Aus Gründen der Robustheit sollten Sie niemals printf $0verwenden, sondern immer printf "%s", $0stattdessen, da ersteres fehlschlägt, wenn Ihre Eingabe printfFormatierungszeichen enthält (wie Sie gerade sehen). Dasselbe gilt für die Verwendung printfmit beliebigen Eingabedaten.
  2. Verwenden Sie aus Gründen der Übersichtlichkeit und Robustheit niemals Variablennamen ausschließlich in Großbuchstaben, RFSum beispielsweise Konflikte mit integrierten Variablennamen zu vermeiden und Ihren Code nicht zu verschleiern, indem Sie den Eindruck erwecken, Sie würden eine integrierte Variable verwenden, obwohl dies nicht der Fall ist.
  3. Legen Sie aus Gründen der Lesbarkeit keine Variablen, z. B. RS, nach Ihrem Skript fest, es sei denn, Sie müssen sie für unterschiedliche Eingabedateien auf unterschiedliche Werte festlegen. Legen Sie Variablen vor oder am Anfang Ihres Skripts fest, damit wir beim Lesen Ihres Skripts sehen, dass sie festgelegt werden, bevor wir sehen, dass sie verwendet werden.
  4. Aus Gründen der Effizienz, Einfachheit und Robustheit ist das erste Argument für *sub() ein regulärer Ausdruck und kein String. Verwenden Sie daher darum herum den regulären Ausdruck ( /.../) und nicht den String ( "..."), es sei denn, Sie BRAUCHEN aus irgendeinem Grund einen dynamischen statt eines statischen regulären Ausdrucks.
  5. Wenn Sie zwei Variablen haben, die denselben Wert haben müssen, z. B. RSund RFS, sollten Sie diese aus Gründen der Übersichtlichkeit und Wartbarkeit nicht separat auf denselben Wert setzen, z. B. RS="\""; RFS="\"", sondern entweder gemeinsam auf diesen Wert, z. B. , RS=RFS="\""oder eine auf den anderen, z. B. RS="\""; RFS=RS.

So schreiben Sie den Code in Ihrer Frage richtig:

$ awk -v RS='"' '!(NR%2){gsub(/,/,"|")} {printf "%s%s", rfs, $0; rfs=RS}' file
First Name, Last Name, Address, Phone Number
John, Doe, "House # 11| Street xyz| Road| Area",00000000
Sara, Taylor, "Jake Lake%| Apartment #22| Main Road| Area XYZ", 00000000

Um mehr als das mit einer CSV-Datei unter Verwendung von awk zu tun, sieheWas ist der robusteste Weg, CSV mithilfe von AWK effizient zu analysieren?.

Antwort2

Der Fehler, den Sie erhalten, ist auf die Verwendung der Verkettung des Werts von RFS(einer leeren Variable) und $0als Formatzeichenfolge mit zurückzuführen printf.

Ihre Datei ist eine gültige CSV-Datei, abgesehen von Leerzeichen nach einigen der Trennkommas (was die Anführungszeichen des AddressFelds durcheinander bringt; ein Feld in Anführungszeichen muss das erste Anführungszeichen direkt nach dem Trennzeichen haben). Wir können dies korrigieren, indem wir csvformat(Teil von csvkit vonhttps://csvkit.readthedocs.io/en/latest/):

$ csvformat --skipinitialspace file.csv >fixed-file.csv
$ cat fixed-file.csv
First Name,Last Name,Address,Phone Number
John,Doe,"House # 11, Street xyz, Road, Area",00000000
Sara,Taylor,"Jake Lake%, Apartment #22, Main Road, Area XYZ",00000000

Eine Datenbank, die CSV analysieren kann, sollte dies so lesen können, wie es ist.

Möchten Sie dennoch alle eingebetteten Kommas durch ersetzen |, ändern Sie einfach das Dateitrennzeichen in etwas anderes als ein Komma (ich verwende im Folgenden Tabulatoren), ändern Sie alle verbleibenden Kommas in Pipes und verwenden Sie anschließend wieder Kommas als Trennzeichen.

Wir können dies direkt mit den Originaldaten tun:

$ csvformat --skipinitialspace --out-tabs file.csv | tr ',' '|' | csvformat --tabs >fixed-file.csv
$ cat fixed-file.csv
First Name,Last Name,Address,Phone Number
John,Doe,House # 11| Street xyz| Road| Area,00000000
Sara,Taylor,Jake Lake%| Apartment #22| Main Road| Area XYZ,00000000

Die Kurzvarianten der verschiedenen verwendeten Langoptionen sind -Sfor --skipinitialspace, -Tfor --out-tabsund -tfor --tabs.

verwandte Informationen