sed
またはを使用してCSVファイルに次のことを行うにはどうすればよいawk
ですか?
- 列を削除する
- 列を複製する
- 列を移動する
200行を超える大きなテーブルがありますが、にあまり詳しくありませんsed
。
sed
またはを使用してCSVファイルに次のことを行うにはどうすればよいawk
ですか?
200行を超える大きなテーブルがありますが、にあまり詳しくありませんsed
。
回答:
フィールドをカットして再配置する方法(他の回答で説明)とは別に、風変わりなCSVフィールドの問題があります。
データがこの「風変わりな」カテゴリに分類される場合、少しの事前および事後フィルタリングがそれを処理できます。次に示すフィルタは、文字を必要とし\x01
、\x02
、\x03
、\x04
どこでもあなたのデータで表示されないようにします。
以下に、単純なawk
フィールドダンプをラップするフィルターを示します。
注: field-fiveには無効または不完全な「引用されたフィールド」レイアウトがありますが、行の最後では無害です(CSVパーサーによって異なります)。しかし、もちろん、現在の行末位置から交換すると、問題のある予期しない結果が発生します。
更新; user121196は、コンマが末尾の引用符の前にある場合のバグを指摘しています。これが修正です。
データ
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,"
""
以下は、コメントで展開されたpreフィルターです。ポストフィルタは、のちょうど逆です。、、\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
'
これは、CSVファイルで区切り文字にのみコンマを使用するか、次のような狂気があるかどうかによって異なります。
フィールド1、「フィールド、2」、フィールド3
これは、単純なCSVファイルを使用していることを前提としています。
1つの列をさまざまな方法で取り除くことができます。例として列2を使用しました。最も簡単な方法はおそらく使用cut
することです。これにより、区切り文字を指定したり、-d
印刷するフィールドを指定したりできます-f
。これは、コンマで分割し、フィールド1、およびフィールド3から最後まで出力するように指示します。
$ cut -d, -f1,3- /path/to/your/file
実際にを使用する必要がある場合はsed
、最初のn-1
フィールド、n
thフィールド、および残りに一致する正規表現を記述し、出力のスキップを行うことができますn
ます(ここでn
は2なので、最初のグループは1
timeに一致します\{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
では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
解決策が他のものから自然に続くと思うが、それは途方もなく長くなり始める
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
出力もフォーマットできます。
次の形式のスペース区切りファイルを指定します。
1 2 3 4 5
次のようにawkでフィールド2を削除できます。
awk '{ sub($2,""); print}' file
返す
1 3 4 5
必要に応じて、列2を列nに置き換えます。
列2を複製するには
awk '{ col = $2 " " $2; $2 = col; print }' file
返す
1 2 2 3 4 5
列2と3を切り替えるには
awk '{temp = $2; $2 = $3; $3 = temp; print}'
返す
1 3 2 4 5
awkは一般に、フィールドの概念を扱うのに非常に優れています。スペースで区切られたファイルではなく、CSVを処理している場合は、単に使用できます
awk -F,
フィールドをデフォルトのスペースではなくコンマとして定義します。オンラインには多くの優れたawkリソースがありますが、そのうちの1つを以下にソースとしてリストします。
#3のソース
awk
が、それは、出力に思わフィールドセパレータであっても、スペースで区切られ,
(それが入力をどのように処理するか、フィールド・セパレータは、単にコントロール)