ファイルの列5の値に基づいて.CSVファイルをフィルタリングし、これらのレコードを新しいファイルに印刷します。

ファイルの列5の値に基づいて.CSVファイルをフィルタリングし、これらのレコードを新しいファイルに印刷します。

次の形式の.CSVファイルがあります。

"column 1","column 2","column 3","column 4","column 5","column 6","column 7","column 8","column 9","column 10
"12310","42324564756","a simple string with a , comma","string with or, without commas","string 1","USD","12","70%","08/01/2013",""
"23455","12312255564","string, with, multiple, commas","string with or, without commas","string 2","USD","433","70%","07/15/2013",""
"23525","74535243123","string , with commas, and - hypens and: semicolans","string with or, without commas","string 1","CAND","744","70%","05/06/2013",""
"46476","15467534544","lengthy string, with commas, multiple: colans","string with or, without commas","string 2","CAND","388","70%","09/21/2013",""

ファイルの5番目の列には異なる文字列があります。 5番目の列の値に基づいてファイルをフィルタリングする必要があります。 5番目のフィールドに「文字列1」の値を持つレコードのみを含む現在のファイルの新しいファイルが必要であるとします。

これを行うには、次のコマンドを試しました。

awk -F"," ' { if toupper($5) == "STRING 1") PRINT }' file1.csv > file2.csv

しかし、以下のようにエラーが発生しました。

awk: { if toupper($5) == "STRING 1") PRINT }
awk: ^ syntax error
awk: { if toupper($5) == "STRING 1") PRINT }
awk: ^ syntax error

その後、次のコマンドを使用しましたが、奇妙な結果が出ました。

awk -F"," '$5="string 1" {print}' file1.csv > file2.csv

出力:

"column 1" "column 2" "column 3" "column 4" string 1 "column 6" "column 7" "column 8" "column 9" "column 10
"12310" "42324564756" "a simple string with a comma" string 1 without commas" "string 1" "USD" "12" "70%" "08/01/2013" ""
"23455" "12312255564" "string with string 1 commas" "string with or without commas" "string 2" "USD" "433" "70%" "07/15/2013" ""
"23525" "74535243123" "string with commas string 1 "string with or without commas" "string 1" "CAND" "744" "70%" "05/06/2013" ""
"46476" "15467534544" "lengthy string with commas string 1 "string with or without commas" "string 2" "CAND" "388" "70%" "09/21/2013" ""

PS:安全のために文字列が小文字か大文字かどうかわからないので、toupperコマンドを使用しました。私のコードにどのような問題があるのか​​、そしてAWK検索パターンを使用するときに文字列のスペースが重要かどうかを知る必要があります。

答え1

awk -F '","'  'BEGIN {OFS=","} { if (toupper($5) == "STRING 1")  print }' file1.csv > file2.csv 

出力

"12310","42324564756","a simple string with a , comma","string with or, without commas","string 1","USD","12","70%","08/01/2013",""
"23525","74535243123","string , with commas, and - hypens and: semicolans","string with or, without commas","string 1","CAND","744","70%","05/06/2013",""

私はこれがあなたが望むものだと思います。

答え2

CSVの問題は標準がないことです。 CSV形式のデータを頻繁に処理する必要がある場合は、単に","フィールド区切り文字として使用するよりも強力な方法を見つけたい場合があります。この場合、PerlのText::CSVCPANモジュールはそのタスクに適しています。

$ perl -mText::CSV_XS -WlanE '
    BEGIN {our $csv = Text::CSV_XS->new;} 
    $csv->parse($_); 
    my @fields = $csv->fields(); 
    print if $fields[4] =~ /string 1/i;
' file1.csv
"12310","42324564756","a simple string with a , comma","string with or, without commas","string 1","USD","12","70%","08/01/2013",""
"23525","74535243123","string , with commas, and - hypens and: semicolans","string with or, without commas","string 1","CAND","744","70%","05/06/2013",""

答え3

csvgrepcsvkitから

awkを使用する最も安定した方法は、FPAT次のものを使用することです。https://stackoverflow.com/questions/45420535/whats-the-most-robust-way-to-efficiently-parse-csv-using-awk/45420607#45420607残念ながら、FPAT引用符内のリテラル改行文字も処理できません。

代わりに、よりスマートになりたい場合に使用できるさまざまなCSV CLIツールがあります。 pipバージョンを介してインストールするのは非常に簡単な方法です(Pythonベースのため、必ずしも最速ではありませんが)はcsvgrepcsvkitで提供されています。

pip install csvkit

これにより、一致しない行を取得できます。

csvgrep -H -c5 -r '^string 1$' mytest.csv

コマンドの説明:

  • -H: 最初の行はタイトル行ではありません。
  • -i:駅マッチ
  • -c5:5番目の列で動作
  • -r:次の正規表現に一致します。

具体的な例:

printf '00,01,02,03,string 1,"04,\n""05"\n10,11,12,13,string 2,"14,\n""15"\n' > nohead.csv
printf 'col1,col2,col3,col4,col5,col6\n00,01,02,03,string 1,"04,\n""05"\n10,11,12,13,string 2,"14,\n""15"\n' > head.csv

それから:

csvgrep -H -c5 -r '^string 1$' nohead.csv | tail -n+2

出力:

00,01,02,03,string 1,"04,
""05"

不快なダミーヘッダーを追加するtailため、パイプで接続します。-H

a,b,c,d,e,f
00,01,02,03,string 1,"04,
""05"

私達は-i一致を元に戻すことができます:

csvgrep -H -i -c5 -r '^sstring 1$' nohead.csv | tail -n+2

出力:

10,11,12,13,string 2,"14,
""15"

ヘッダーがある場合は、列名を使用できます。

csvgrep -c col5 -r '^string 1$' head.csv

出力:

col1,col2,col3,col4,col5,col6
00,01,02,03,string 1,"04,
""05"

csvkit 1.0.7、Ubuntu 23.04でテストされました。

答え4

awk 'BEGIN {FS = "," }'  '{ (if toupper($5)  == "STRING 1") print; }'  file1.csv > file2.csv

関連情報