
学生の連絡先情報を含むデータセットがあります。サンプルデータセットは次のとおりです。
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
次のコマンドを実行して置き換えます、住所欄に|DB にロードします。
awk '!(NR%2){gsub(",","|")} {printf RFS $0} {RFS="\""}' RS=\" fileName.txt > output.txt
私が直面している問題は、このコマンドを実行するたびに次のエラーが返されることです。最初は正常に実行されていました。
awk: run time error: not enough arguments passed to printf(""Jake Lake%, Apartment #22, Main Road, Area XYZ")
解決策はあるのでしょうか?私は気づいたのですが%アドレスに届くのが問題ですか?
答え1
- 堅牢性のために、 は決して行わず
printf $0
、常に を使用してください。printf "%s", $0
前者は、入力に書式設定文字が含まれている場合 (現在表示されているように) に失敗します。任意の入力データでprintf
を使用する場合も同様です。printf
- 明確さと堅牢性のために、すべて大文字の変数名を使用しないでください。たとえば、
RFS
組み込み変数名との衝突を回避したり、実際には組み込み変数を使用していないのに組み込み変数を使用しているように見えることでコードが難読化されるのを回避したりするためです。 - 読みやすさを考慮して、変数 (たとえば、スクリプトの後) は設定しないでください。
RS
ただし、異なる入力ファイルに対して異なる値を設定する必要がある場合を除きます。スクリプトの前または先頭で変数を設定してください。そうすれば、スクリプトを読むときに、変数が使用される前に設定されていることがわかります。 - 効率、シンプルさ、堅牢性のため、*sub() の最初の引数は文字列ではなく正規表現です。そのため、何らかの理由で静的正規表現ではなく動的正規表現が必要な場合を除き、文字列 (
/.../
) 区切り文字ではなく正規表現 ("..."
) 区切り文字を使用してください。 - 明確さと保守性のために、同じ値を持つ必要がある 2 つの変数( と
RS
などRFS
)がある場合、それらを別々に同じ値( など)に設定しないでください。RS="\""; RFS="\""
一緒にその値に設定するか( など)RS=RFS="\""
、一方を他方に設定してください( など)RS="\""; RFS=RS
。
質問内のコードを正しく記述する方法は次のとおりです。
$ 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
awkを使用してCSVでそれ以上のことを行うには、awk を使用して csv を効率的に解析する最も堅牢な方法は何ですか。
答え2
RFS
発生するエラーは、 (空の変数)の値と の連結を の$0
書式文字列として使用したために発生しますprintf
。
ファイルは、区切りのカンマの後にスペースが入っていることを除けば、有効なCSVファイルです(Address
フィールドの引用符がおかしくなります。引用符で囲まれたフィールドでは、区切り文字の直後に最初の引用符が必要です)。これを修正するには、csvformat
(csvkitの一部)を使用します。https://csvkit.readthedocs.io/ja/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
CSV を解析できるデータベースであれば、これをそのまま読み取ることができるはずです。
埋め込まれているすべてのカンマを に置き換えたい場合は|
、ファイルの区切り文字をカンマ以外のものに変更し (以下ではタブを使用します)、残りのすべてのカンマをパイプに変更して、再び区切り文字としてカンマを使用するように戻します。
これを元のデータに対して直接実行できます。
$ 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
使用されるさまざまな長いオプションの短縮形は、-S
の場合、の場合、の場合です。--skipinitialspace
-T
--out-tabs
-t
--tabs