sed
またはawk
を使用してCSVファイルに次のことを行うにはどうすればよいですか?
200行を超える大きなテーブルがありますが、sed
についてはあまり詳しくありません。
フィールドを切り取って再配置する方法(他の回答で説明)とは別に、風変わりなCSVフィールドの問題があります。
データがこの「風変わりな」カテゴリに該当する場合は、preおよびpostフィルタリングを少し行うだけで対応できます。以下に示すフィルターでは、\x01
、\x02
、\x03
、\x04
の文字がデータのどこにも表示されないようにする必要があります。
以下は、単純なawk
フィールドダンプにラップされたフィルターです。
注:field-fiveには無効または不完全な「引用フィールド」レイアウトがありますが、行の最後に無害です(CSVによって異なります)パーサー)。しかし、もちろん、現在のend-of-rowから交換すると、問題のある予期しない結果が発生します。ポジション。
更新; 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 filterであり、コメントで展開されています。
post filterは\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ファイルを使用していることを前提としています。
単一の列はさまざまな方法で取り除くことができます。例として2列目を使用しました。最も簡単な方法は、おそらくcut
を使用することです。これにより、区切り文字-d
と印刷するフィールド-f
を指定できます。これは、カンマと出力フィールド1、およびフィールド3を最後まで分割するように指示します。
$ cut -d, -f1,3- /path/to/your/file
実際にsed
を使用する必要がある場合は、最初のn-1
フィールド、n
thフィールド、および残りに一致する正規表現を記述し、n
th(ここでn
は2なので、最初のグループが一致します1
時間:\{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
のforループでは、次のようになります(ここでも、末尾のコンマは無視されます)。
$ 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は一般にfieldsの概念を扱うのに非常に優れています。スペースで区切られたファイルではなくCSVを処理する場合は、次のように使用できます。
awk -F,
フィールドをスペース(デフォルト)ではなく、コンマとして定義します。オンラインには多くの優れたawkリソースがあり、そのうちの1つを以下にソースとして挙げています。
ソース #3
これは削除に役立ちます
awk '{$2="";$0=$0;$1=$1}1'
入力
a b c d
出力
a c d