sedまたはawkを使用してCSVファイルを操作する方法は?

sedまたはawkを使用してCSVファイルを操作する方法は?

sedCSVファイルに対して次の操作をどのように使用または実行できますかawk

  • 列を削除
  • 列のコピー
  • 1列移動

200行以上の大きなテーブルがありますsed

答え1

CSVファイルがカンマのみを区切り文字として使用するのか、それとも次のようなクレイジーな内容があるのか​​によって異なります。

フィールド 1、「フィールド、2」、フィールド 3

単純なCSVファイルを使用するとします。

列を削除

さまざまな方法で個々の列を削除できます。たとえば、列2を使用します。最も簡単な方法はおそらくを使用することですcut。これにより、印刷する区切り文字-dとフィールドを指定できます-f。これにより、コンマに分割してフィールド1とフィールド3を最後まで出力します。

$ cut -d, -f1,3- /path/to/your/file

必ず使用する必要がある場合は、最初のフィールド、3番目のフィールド、および残りのフィールドを一致させる正規表現を作成し、2番目のフィールドの出力をスキップsedできます(ここでは2なので、最初のグループは一致時間です)。n-1nnn1\{1\}

$ sed 's/\(\([^,]\+,\)\{1\}\)[^,]\+,\(.*\)/\1\3/' /path/to/your/file

これを行うにはいくつかの方法がありますが、awkその中に特にエレガントな方法はありません。ループを使用できますが、for末尾のコンマを処理するのは次のように痛いです。

$ awk -F, '{for(i=1; i<=NF; i++) if(i != 2) printf "%s,", $i; print NL}' /path/to/your/file

フィールド1を出力し、それを使用してsubstrフィールド2以降のすべてを完了する方が簡単です。

$ awk -F, '{print $1 "," substr($0, length($1)+length($2)+3)}' /path/to/your/file

しかし、追加の列では面倒です。

列のコピー

これはデフォルトでsedは以前と同じ式ですが、ターゲット列をキャプチャし、代替項目にグループを複数回含めます。

$ sed 's/\(\([^,]\+,\)\{1\}\)\([^,]\+,\)\(.*\)/\1\3\3\4/' /path/to/your/file

forループ方式では、awk次のようになります(やはり末尾のコンマを無視します)。

$ awk -F, '{
for(i=1; i<=NF; i++) {
    if(i == 2) printf "%s,", $i;
    printf "%s,", $i
}
print NL
}' /path/to/your/file

方法substr:

$ awk -F, '{print $1 "," $2 "," substr($0, length($1)+2)}' /path/to/your/file

(tcdylはより良いアプローチを提案しました。彼の答え)

列の移動

このソリューションは他のソリューションに自然に従うと思いますsedが、時間がかかり始めました。

答え2

awk最高の選択です。awkフィールドを数字で印刷する...

awk 'BEGIN { FS=","; OFS=","; } {print $1,$2,$3}' file

列を印刷せずに削除するには:

 awk 'BEGIN { FS=","; OFS=","; } {print $1,$3}' file

順序を変更するには:

awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file

出力ファイルにリダイレクトします。

awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file > output.file

awk出力をフォーマットすることもできます。

awk形式の出力

答え3

フィールドを切り取り、並べ替える方法(他の回答でダールーム)に加えて、奇妙なCSVフィールドの問題もあります。

あなたのデータがこの「奇妙な」カテゴリに属している場合今後そして郵便はがきフィルタリングすると問題を解決できます。以下のフィルタでは、文字、、、\x01\x02データのどこにも表示されません。 \x03\x04

awk以下は単純なフィールドダンプのフィルタです。

メモ: 五つのゲーム無効または不完全な「参照フィールド」レイアウトがありますが、行の終わりには問題ありません(CSVパーサーによって異なります)。しかし、もちろん、これは次のような結果につながります。問題のある予期しない結果現在の状態から変更する場合行末場所。

修正する。ユーザー 121196末尾の引用符の前にコンマが続くエラーが指摘されました。ここに修正があります。

データ

cat <<'EOF' >file
field one,"fie,ld,two",field"three","field,\",four","field,five
"15111 N. Hayden Rd., Ste 160,",""
EOF

パスワード

sed -r 's/^/,/; s/\\"/\x01/g; s/,"([^"]*)"/,\x02\1\x03/g; s/,"/,\x02/; :MC; s/\x02([^\x03]*),([^\x03]*)/\x02\1\x04\2/g; tMC; s/^,// ' file |
  awk -F, '{ for(i=1; i<=NF; i++) printf "%s\n", $i; print NL}' |
    sed -r 's/\x01/\\"/g; s/(\x02|\x03)/"/g; s/\x04/,/g' 

出力:

field one
"fie,ld,two"
field"three"
"field,\",four"
"field,five

"15111 N. Hayden Rd., Ste 160,"
""

ここにいる事前フィルタ、コメントで拡張します。
これポストフィルターただ反転\x01\x02、、、\x03\x04

sed -r '
    s/^/,/                # add a leading comma delimiter
    s/\\"/\x01/g          # obfuscate escaped quotation-mark (\")
    s/,"([^"]*)"/,\x02\1\x03/g    # obfuscate quotation-marks
    s/,"/,\x02/           # when no trailing quote on last field  
    :MC                   # obfuscate commas embedded in quotes
    s/\x02([^\x03]*),([^\x03]*)/\x02\1\x04\2/g
    tMC
    s/^,//                # remove spurious leading delimiter
'

答え4

CSVデータを処理するには、通常、次のCSV認識ツールを使用するのが最善です。ミラーまたはcsvkit。 CSV、引用規則などについて全く知らない一般的なテキスト処理ユーティリティですsedawk

テストデータ:

id,name,date of birth
1,"Alfonso, the first",1980-01-01
2,"Betty, the second",1980-01-02
3,"Conny, the third",1982-02-21

namecsvkitツールを使用してこのフィールドを削除するには:

$ csvcut -C name file
id,date of birth
1,1980-01-01
2,1980-01-02
3,1982-02-21

csvkitを使用してフィールドをコピーするには、次の手順を実行しますname

$ csvcut -c id,name,name,"date of birth" file
id,name,name,date of birth
1,"Alfonso, the first","Alfonso, the first",1980-01-01
2,"Betty, the second","Betty, the second",1980-01-02
3,"Conny, the third","Conny, the third",1982-02-21

まずdate of birth、csvkitを使用してフィールドを移動するには、次の手順を実行します。

$ csvcut -c "date of birth",id,name file
date of birth,id,name
1980-01-01,1,"Alfonso, the first"
1980-01-02,2,"Betty, the second"
1982-02-21,3,"Conny, the third"

Millerを使用してこのフィールドを削除するには、次の手順を実行しますname

$ mlr --csv cut -x -f name file
id,date of birth
1,1980-01-01
2,1980-01-02
3,1982-02-21

Millerを使用してフィールドをコピーするにはnamename2最後に新しいフィールドとして作成されます):

$ mlr --csv put '$name2 = $name' file
id,name,date of birth,name2
1,"Alfonso, the first",1980-01-01,"Alfonso, the first"
2,"Betty, the second",1980-01-02,"Betty, the second"
3,"Conny, the third",1982-02-21,"Conny, the third"

date of birthMiller を使用してレコードの先頭に移動するには:

$ mlr --csv reorder -f "date of birth" file
date of birth,id,name
1980-01-01,1,"Alfonso, the first"
1980-01-02,2,"Betty, the second"
1982-02-21,3,"Conny, the third"

関連情報