シェルコマンドで区切られたファイルを変換する必要があります。受信した入力ファイルには2つのバリエーションがあり、1つは二重引用符があり、もう1つは引用符がありません。両方のファイルに区切り文字としてコンマがあります。要件は、ファイルに二重引用符がある場合はコンマをTABで置き換え、引用符を削除することです。それ以外の場合は、単にコンマを置き換えます。変換中に無視する必要があるコンマがフィールドにも含まれている場合、ファイルは引用符付きで送信されます。 単一のコマンドは、RHEL 6.x環境のAwk 3.xで有効でなければなりません。
例えば。二重引用符付きのファイル1:
"Jhon","Carpenter","CA,TX,NJ"
"Mike","Painter","WA,GA,MI"
変換後はタブで区切る必要があります:
Jhon Carpenter CA,TX,NJ
Mike Painter WA,GA,MI
例えば。二重引用符のないファイル2:
EMP1,123456,CA
EMP2,456789,TX
変換後はタブで区切る必要があります:
EMP1 123456 CA
EMP2 456789 TX
この短いsed
スクリプトは、両方のタイプのファイル(または1番目と2番目のタイプの行が混在するファイル)を処理できます。
sed '/"/!s/,/\t/g;s/","/\t/g; s/"//g'
ループしない式をグループ化しないため、スクリプトよりもはるかに高速です。
GNU sed
なので、\t
は機能しますが、それ以外の場合は代わりにリテラルTABを使用します。
csvkit
を使用:
$ csvformat -T file1.csv
Jhon Carpenter CA,TX,NJ
Mike Painter WA,GA,MI
$ csvformat -T file2.csv
EMP1 123456 CA
EMP2 456789 TX
file1.csv
の出力は少し外れているように見えますが、それはタブが正しく並んでいないためです。すべての列の間にタブがあります。
CSVKitは、さまざまなCSV関連のシェルユーティリティのPythonベースのツールボックスです。これは適切なCSV解析を行い、CSVファイルのクエリ、フォーマット、変換に使用できます。
たとえば、最初のファイルに適切なヘッダーがある場合、これをJSONに変換するのは簡単です。
$ csvjson file1.csv
[{"First": "Jhon", "Last": "Carpenter", "Stuff": "CA,TX,NJ"}, {"First": "Mike", "Last": "Painter", "Stuff": "WA,GA,MI"}]
いくつかのアプローチ:
のために file1
(二重引用符付き):
-awkアプローチ:
awk -F'"' '{ r=""; for(i=1;i<NF;i++)
if ($i~/^[[:alnum:]]/) r=(r!="")? r OFS $i : $i; print r }' OFS='\t' file1
-sedアプローチ:
sed 's/","/\t/g; s/"//g;' file1
出力(両方のアプローチ):
Jhon Carpenter CA,TX,NJ
Mike Painter WA,GA,MI
----------
のために file2
(二重引用符なし)-tr
コマンドを適用するだけで十分です:
tr ',' '\t' <file2
出力:
EMP1 123456 CA
EMP2 456789 TX
----------
条件「sameコマンドで両方のファイルタイプで十分なはずです」の統一されたアプローチ:
awk -v quoted=$(grep -cm1 '"' file1) 'BEGIN{ FS=(quoted)? "\"" : ","; }
{ r=""; for(i=1;i<=NF;i++) if(!quoted || $i~/^[[:alnum:]]/) r=(r!="")? r OFS $i : $i;
print r }' OFS='\t' file1
さて、この解決策はKusalanandaの回答ほどエレガントではありませんし、あなたが望むほど速くはないでしょうが、それはうまくいくはずです。
#!/usr/bin/env bash
for file; do
while read -r line; do
if <<< "${line}" grep -F -e '"' > '/dev/null' 2>&1; then
<<< "${line}" \
grep -P -o -e '(?<=")([^,].*?)(?=")' |
tr $'\n' $'\t' | rev | cut -c 2- | rev
else
<<< "${line}" \
tr ',' $'\t'
fi
done < "${file}"
done
例:
$ cat file1
"Jhon","Carpenter","CA,TX,NJ"
"Mike","Painter","WA,GA,MI"
$ cat file2
EMP1,123456,CA
EMP2,456789,TX
$ script.sh file1 file2
Jhon Carpenter CA,TX,NJ
Mike Painter WA,GA,MI
EMP1 123456 CA
EMP2 456789 TX
CSVデータには適切なCSVパーサーが必要です。クサラナンダの答えが好きです。 csvモジュールに付属するRubyのような言語を使用することもできます。
Ruby -rcsv -e '
out = CSV.new($stdout, {:col_sep => "\t"})
CSV.foreach(ARGV.shift) {|row| out << row}
' file1.csv