bashでCSVをTSVに変換する必要があります。私が見つけたこれソリューションはうまく機能しますが、以下のようにすべてのデータセットに対しては機能しません。
たとえば、次のようになりますa.txt
。
a,"test, part2 ""the start""",b
sed
無効な形式:
[ nir ]$ cat a.txt | sed -E 's/("([^"]*)")?,/\2\t/g'
a "test Op. 15 ""the start" b
#^ tab....^ tab..................^ tab
ここに問題があります:欠落,
、追加タブ、追加引用符。
ちなみに、Pythonコードの形式も間違っています。
[ nir ]$ cat a.txt | csv2tsv.py
a "test, part2 ""the start""" b
#^ tab..........................^ tab
ここでの問題は追加の引用符です。
csv2tsv.py
例:
csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))
実際の変換は次のようになります。
a test, part2 "the start" b
#^ tab......................^ tab
この問題を解決する方法についてフィードバックを受けたいですbash
。私はインターネット上で多くの解決策を見ましたが、引用符内の引用符を処理できませんでした。 :)
答え1
そしてmlr
:
mlr -N --icsv --otsvlite cat < file.csv > file.tsv
または:
mlr -N --c2t --quote-none cat < file.csv > file.tsv
ただし、csvフィールドにタブ文字が含まれていると、出力はエスケープされないため、追加のフィールドが発生します。
GNUを使用すると、sed
同じことができます。
sed -E '
# append next line as long as there is not an even number
# of "s, to handle fields with newline. You can omit this line
# if the fields are guaranteed not to contain newlines:
:1; /^([^"]*"[^"]*")*[^"]*$/! {N;b1}
s/$/,/
s/(([^,"]*)|"((""|[^"])*)"),/\2\3\t/g
s/\t$//
s/""/"/g' < file.csv > file.tsv
入力は現在のロケールの有効なテキストと見なされます。まず、ローカライゼーションをsed
無効にしLC_ALL=C sed...
、入力をバイナリとして処理してデコードの問題を回避します(速度が問題になると速度が速くなる可能性があります)。
答え2
ロード可能なCSVモジュールを含むbash 5.1
BASH_LOADABLES_PATH=${BASH/\/bin\//\/lib\/}
enable -f csv csv
csv -a fields "$line"
new_line=$(IFS=$'\t'; echo "${fields[*]}")
declare -p line fields new_line
出力
declare -- line="a,\"test, part2 \"\"the start\"\"\",b"
declare -a fields=([0]="a" [1]="test, part2 \"the start\"" [2]="b")
declare -- new_line="a test, part2 \"the start\" b"
#.....................^ tab......................^ tab
タブを含むフィールドがある場合は効果はありません。
パイプラインから:
IFS=$'\t'
cat file |
while IFS= read -r line; do
csv -a fields "$line"
echo "${fields[*]}"
done |
tail
これはもう少し寛容なbashですが、
IFS=$'\t'
while IFS= read -r line; do
csv -a fields "$line"
echo "${fields[*]}"
done < file | tail