숫자 열과 문자열 열이 포함된 쉼표로 구분된 파일이 있습니다. 문자열 열은 따옴표로 묶여 있으며 따옴표 사이에 쉼표가 있을 수 있습니다. 열을 식별하는 방법은 무엇입니까 FS =","
?
샘플 기록
"prabhat,kumar",19,2000,"bangalore,India"
존재하다AWK그것은해야한다
$1 = "prabhat,kumar"
$2 = 19
$3 = "2000"
$4 = "bangalore,india"
설정 FS=","
으로 인해 문제가 발생합니다.
입력은 다음과 같습니다
"prabhat,kumar",19,2000,"bangalore,India","ABC,DEF","GHI",123,"KLM","NOP,QRS"
"prabhat,kumar",19,2000,"bangalore,India","ABC,DEF","GHI",123,"KLM","NOP,QRS"
출력은 다음과 같아야 합니다.
"prabhat,kumar"|19|2000|"bangalore,India"|"ABC,DEF"|"GHI"|123|"KLM"|"NOP,QRS"
"prabhat,kumar"|19|2000|"bangalore,India"|"ABC,DEF"|"GHI"|123|"KLM"|"NOP,QRS"
내가 시도하는 코드:
awk -F"," '{for(i=1;i<=NF;i++){if(i%NF==0){ORS="\n"} {if($i ~ /^\"/ || $i ~ /\"$/) {a=a OFS $i;j++;{if(j%2==0){sub(/^\,/,X,a); print a;j=0;a=""}}} else {print $i}}} {ORS="|"}}' ORS="|" OFS=, p.txt
답변1
먼저, 적합한 CSV 파서를 사용해야 합니다. 예를 들어 Perl에서는 다음을 사용할 수 있습니다 Text::CSV
.
설치
cpanm
(Perl을 사용한다면 나중에 감사할 것입니다)$ sudo apt-get install cpanminus
Debian 기반 시스템을 사용하지 않는 경우 배포판의 패키지 관리자를 사용하여 설치할 수 있습니다.
Text::CSV
모듈 설치$ sudo cpanm Text::CSV
파일을 구문 분석
$ perl -MText::CSV -le ' $csv = Text::CSV->new({binary=>1}); while ($row = $csv->getline(STDIN)){ print "1:$row->[0], 2:$row->[1], 3:$row->[2], 4:$row->[3]"}' < file.csv 1:prabhat,kumar, 2:19, 3:2000, 4:bangalore,India
위에서 볼 수 있듯이 첫 번째 필드는
$row->[0]
, 두 번째 필드$row->[1]
등입니다.
이것이 올바른 방법입니다. 더 간단하지만 지저분한 방법은 인용된 쉼표를 다른 문자로 바꾸는 것입니다. 그런 다음 정상적으로 사용 awk
하고 마지막으로 다시 쉼표로 전환하십시오. 여기서는 이를 사용하고 있지만 ###
필드 중 하나에 절대 나타나지 않을 것이라고 확신하는 모든 것을 사용할 수 있습니다.
$ sed -r 's/("[^",]+),([^",]+")/\1###\2/g' file.csv |
awk -F, '{print $1,$3}' | sed 's/###/,/g'
"prabhat,kumar" 2000
답변2
GNU가 있는 경우 awk
:
$ awk -vFPAT='[^,]*|"[^"]*"' '{ gsub("^\"|\"$","",$1); gsub("^\"|\"$","",$4); print $1 $4} '
prabhat,kumarbangalore,India
$1
출력 형식은 인쇄만 하고 나란히 있기 때문에 약간 보기 흉합니다 $4
. 자신의 취향에 맞게 변경할 수 있다고 확신합니다.
필드 주위에 큰따옴표를 유지해야 하는 경우 이 두 gsub();
함수를 제거하십시오.
설명하다:
일반적으로 awk
레코드의 필드는 (FieldSeparator) 변수의 내용으로 구분되며 FS
기본값은 공백(탭, 공백 및 줄 바꿈)입니다. 구분 기호는 awk
레코드가 끝나는 위치를 알려줍니다. 파일 에서 csv
레코드는 쉼표로 끝나지만( awk
as 로 전달됨 -vFS=,
) 물론 귀하와 같은 예에서는 너무 간단하여 깨질 수 있습니다.
또는 FPAT
(필드 패턴) 정의의 레코드입니다 awk
. 레코드가 끝나는 위치를 지정하는 대신 awk
전체 레코드를 포함하는 정의를 만듭니다. 귀하의 예가 복잡하기 때문에 csv
이것은[^,]*|"[^"]*"
고장은 다음과 같습니다 : -
[^,]
쉼표가 아닌 문자(*
)를 최대한 많이 사용하세요. 두 쉼표 사이의 모든 내용은 필드입니다.- 또는(
|
) - 작은 큰따옴표(
"
) 뒤에 큰따옴표가 없는 경우([^"]
) 가능한 한 여러 번(*
) 다음에 작은 큰따옴표("
)가 나옵니다. 쉼표를 포함하여 큰따옴표 안의 모든 항목은 하나의 필드로 계산됩니다.
답변3
Ruby는 CSV 구문 분석에 매우 편리합니다.
ruby -rcsv -ne 'puts CSV.generate_line(CSV.parse_line($_), :col_sep=>"|")' file
prabhat,kumar|19|2000|bangalore,India|ABC,DEF|GHI|123|KLM|NOP,QRS
prabhat,kumar|19|2000|bangalore,India|ABC,DEF|GHI|123|KLM|NOP,QRS
출력에는 따옴표가 없습니다. 이는 필드 구분 기호가 포함된 필드가 없기 때문입니다. 따옴표가 필요한 경우 모든 필드(정수 포함)를 강제로 따옴표로 묶을 수 있습니다.
ruby -rcsv -ne 'puts CSV.generate_line(CSV.parse_line($_), :col_sep=>"|",:force_quotes=>true)' file
"prabhat,kumar"|"19"|"2000"|"bangalore,India"|"ABC,DEF"|"GHI"|"123"|"KLM"|"NOP,QRS"
"prabhat,kumar"|"19"|"2000"|"bangalore,India"|"ABC,DEF"|"GHI"|"123"|"KLM"|"NOP,QRS"
답변4
이것은 나에게 효과적입니다.
$ echo '"prabhat,kumar",19,2000,"bangalore,India"' |
awk -F, '{print $1,$2,$3,$4,$5,$6}'|
awk -F\" '{print $2,$3,$4}'|awk -F\ '{print $1","$2,$3,$4,$5","$6}'`