대용량 CSV 파일이 많이 있으며 TSV (탭으로 구분 된 형식) 형식으로 원합니다. 합병증은 CSV 파일의 필드에 쉼표가 있다는 것입니다. 예를 들면 다음과 같습니다.
A,,C,"D,E,F","G",I,"K,L,M",Z
예상 출력 :
A C D,E,F G I K,L,M Z
(사이의 공백은 '하드'탭입니다)
이 서버에 Perl, Python 및 coreutils가 설치되어 있습니다.
대용량 CSV 파일이 많이 있으며 TSV (탭으로 구분 된 형식) 형식으로 원합니다. 합병증은 CSV 파일의 필드에 쉼표가 있다는 것입니다. 예를 들면 다음과 같습니다.
A,,C,"D,E,F","G",I,"K,L,M",Z
예상 출력 :
A C D,E,F G I K,L,M Z
(사이의 공백은 '하드'탭입니다)
이 서버에 Perl, Python 및 coreutils가 설치되어 있습니다.
답변:
라는 파일에 추가 csv2tab.sh
하고 실행 가능하게 만드십시오.
#!/usr/bin/env python
import csv, sys
csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))
$ echo 'A,,C,"D,E,F","G",I,"K,L,M",Z' | ./csv2tab.sh
A C D,E,F G I K,L,M Z
$ ./csv2tab.sh < data.csv > data.tsv && head data.tsv
1A C D,E,F G I K,L,M Z
2A C D,E,F G I K,L,M Z
3A C D,E,F G I K,L,M Z
csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))
? 루프도 제거합니다.
python -c 'import csv,sys; csv.writer(sys.stdout, dialect="excel-tab").writerows(csv.reader(sys.stdin))'
. 나는 -m
그런 식으로 작동합니다.
재미를 위해 sed
.
sed -E 's/("([^"]*)")?,/\2\t/g' file
sed
지원하지 않는 경우로 -E
시도하십시오 -r
. 리터럴 탭을 sed
지원하지 않는 경우 \t
리터럴 탭 (많은 쉘, ctrl- v tab) 또는 Bash에 $'...'
C 스타일 문자열을 사용하십시오 (이 경우 백 슬래시를 \2
두 배로 늘려야 함). 따옴표를 유지하려면 \1
대신 사용하십시오 \2
(이 경우 괄호의 내부 쌍은 쓸모 없으며 제거 할 수 있음).
이것은 큰 따옴표 안의 이스케이프 된 큰 따옴표를 처리하려고 시도하지 않습니다. 일부 CSV 방언은 인용 된 큰 따옴표 (sic)를 두 배로하여이를 지원합니다.
csvkit
유틸리티 (Python) 사용 예 :
$ csvformat -T in.csv > out.txt
올바른 CSV 및 TSV 인용 및 이스케이프를 사용하여 스트리밍
apt 및 기타 패키지 관리자에 있습니다.
하나의 옵션은 펄의 Text :: CSV 모듈입니다.
perl -MText::CSV -lne 'BEGIN { $csv = Text::CSV->new() }
print join "\t", $csv->fields() if $csv->parse($_)
' somefile
설명하기 위해
echo 'A,,C,"D,E,F","G",I,"K,L,M",Z' |
perl -MText::CSV -lne 'BEGIN { $csv = Text::CSV->new() }
print join "\t", $csv->fields() if $csv->parse($_)
'
A C D,E,F G I K,L,M Z
perl -lne '
my $re = qr/,(?=(?:[^"]*"[^"]*")*(?![^"]*"))/;
print join "\t", map { s/(?<!\\)"//gr =~ s/\\"/"/gr } split $re;
'
awk -v Q=\" -v FPAT="([^,]*)|(\"[^\"]+\")" -v OFS="\t" '{
for (i=1; i<=NF; ++i)
if ( substr($i, 1, 1) == Q )
$i = substr($i, 2, length($i) - 2)
print $1, $2, $3, $4, $5, $6, $7, $8
}'
결과:
A C D,E,F G I K,L,M Z
열핵 플라이스와 터 솔루션은 libreoffice를 사용해야합니다. https://ask.libreoffice.org/en/question/19042/is-is-possible-to-convert-comma-separated-value-csv-to-tab-separated-value-tsv-via-headless-mode 동안 / 이것이 가능하지는 않지만 잘못되었거나 오래 되었습니까? 다음 명령은 5.3에서 작동합니다.
loffice "-env:UserInstallation=file:///tmp/LibO_Conversion" --convert-to csv:"Text - txt - csv (StarCalc)":9,34,UTF8 --headless --outdir some/path --infilter='csv:44,34,UTF8' *.csv
env
인수는 생략 될 수 있지만,이 방법은 문서를 최근 문서에 표시되지 않습니다.
설명 된 변환을 처리하는 오픈 소스 CSV-TSV 변환기를 작성했습니다. 대용량 CSV 파일을 계속 변환 해야하는 경우 상당히 빠릅니다. 툴은 eBay의 TSV 유틸리티 툴킷 (csv2tsv documentation here ) 의 일부입니다 . 설명 된 입력에 대해서는 기본 옵션으로 충분합니다.
$ csv2tsv file.csv > file.tsv
재미를 위해 정규 표현식 대체는 Vim 에서 수행 할 수 있습니다 . https : //.com/questions/33332871/remove-all-comma-between-quotes-with-a-vim-regex
따옴표가 제거됩니다.
:%s/".\{-}"/\=substitute(submatch(0), ',', '_' , 'g')/g
:%s/,/\t/g
:%s/_/,/g
:%s/"//g
솔루션을 다소 스크립팅하기 위해 위의 네 줄 (산행 콜론)을 파일에 저장할 수 있습니다 (예 :) to_tsv.vim
. Vim 및 Vim 명령 줄 source
의 to_tsv.vim
스크립트 ( https://stackoverflow.com/questions/3374179/run-vim-script-from-vim-commandline/8806874#8806874 에서 수정)를 사용하여 편집 할 각 CSV를 엽니 다 .
:source /path/to/vim/filename/to_tsv.vim
다음은 jq
유틸리티를 사용하여 CSV를 TSV로 변환하는 예입니다 .
$ jq -rn '@tsv "\(["A","","C","D,E,F","G","I","K,L,M","Z"])"'
A C D,E,F G I K,L,M Z
또는:
$ echo '["A","","C","D,E,F","G","I","K,L,M","Z"]' | jq -r @tsv
A C D,E,F G I K,L,M Z
그러나 CSV 형식의 형식이 적절해야하므로 각 문자열을 인용해야합니다.
출처 : 간단한 TSV 출력 형식 .
다음은 @tripleee 의 답변을 간단히 수정 하여 다른 모든 필드와 마찬가지로 최종 필드의 따옴표를 제거합니다.
수정 된 내용을 보여주기 위해 다음은 3 인의 답변과 최종 ' Z '필드 주위에 따옴표가 추가 된 OP의 예제 데이터를 약간 수정 한 것 입니다.
echo 'A,,C,"D,E,F","G",I,"K,L,M","Z"' | sed -r -e 's/("([^"]*)")?,/\2\t/g'
A C D,E,F G I K,L,M "Z"
' Z '주위에 따옴표가 붙어 있음을 알 수 있습니다. 이것은 내부 필드가 처리되는 방식과 다릅니다. 예를 들어, ' G '에는 따옴표가 없습니다.
다음 명령은 두 번째 대체를 사용하여 최종 열을 정리합니다.
echo 'A,,C,"D,E,F","G",I,"K,L,M","Z"' | sed -r -e 's/("([^"]*)")?,/\2\t/g' \
-e 's/\t"([^"]*)"$/\t\1/'
A C D,E,F G I K,L,M Z
'A,,C,"D,E,F","G",I,"K,L,M","Z,A"'
가이 답변에 입력 되면 올바른가 "Z,A"
아닌가로 대체됩니다 . Z A
Z,A