sed
CSV 파일에 대해 다음 작업을 어떻게 사용하거나 수행할 수 있습니까 awk
?
- 열 삭제
- 열 복사
- 한 열 이동
200개 이상의 행이 있는 큰 테이블이 있는데 sed
.
답변1
CSV 파일이 쉼표만 구분 기호로 사용하는지 아니면 다음과 같은 미친 내용이 있는지에 따라 다릅니다.
필드 1, "필드, 2", 필드 3
간단한 CSV 파일을 사용한다고 가정합니다.
열 삭제
여러 가지 방법으로 개별 열을 제거할 수 있습니다. 예를 들어 열 2를 사용하겠습니다. 가장 쉬운 방법은 아마도 를 사용하는 것입니다 cut
. 이를 통해 인쇄할 구분 기호 -d
와 필드를 지정할 수 있습니다 -f
. 이렇게 하면 쉼표로 분할하여 필드 1과 필드 3을 끝까지 출력하게 됩니다.
$ cut -d, -f1,3- /path/to/your/file
꼭 사용해야 하는 경우 첫 번째 필드, 번째 필드 및 나머지 필드를 sed
일치시키는 정규식을 작성 하고 번째 필드 출력을 건너뛸 수 있습니다(여기서는 2이므로 첫 번째 그룹이 일치 시간입니다.) :n-1
n
n
n
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
for 루프 방식 에서는 awk
다음과 같습니다(역시 후행 쉼표를 무시함).
$ 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
하지만 시간이 많이 길어지기 시작했습니다.
답변2
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
출력을 포맷할 수도 있습니다.
답변3
필드를 자르고 재배열하는 방법(다른 답변에서 다룸) 외에도 이상한 CSV 필드 문제도 있습니다.
귀하의 데이터가 이 "기발한" 범주에 속한다면앞으로그리고우편 엽서필터링하면 문제가 해결될 수 있습니다. 아래 표시된 필터에서는 문자 \x01
, \x02
, \x03
가 \x04
데이터 어디에도 나타나서는 안 됩니다.
awk
다음은 간단한 필드 덤프에 대한 필터 입니다 .
노트: 다섯 개의 게임유효하지 않거나 불완전한 "참조 필드" 레이아웃이 있지만 행 끝에서는 문제가 없습니다(CSV 파서에 따라 다름). 하지만 물론 이는 다음과 같은 결과로 이어집니다.문제가 있는 예상치 못한 결과현재 상태에서 변경하는 경우줄 끝위치.
고쳐 쓰다;사용자 121196후행 인용 부호 앞에 쉼표가 오는 오류가 지적되었습니다. 여기에 수정 사항이 있습니다.
데이터
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,"
""
여기있어사전 필터, 댓글을 통해 확장하세요.
이것포스트 필터그냥 반전 \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
'
답변4
CSV 데이터를 처리하려면 일반적으로 다음과 같은 CSV 인식 도구를 사용하는 것이 가장 좋습니다.밀러또는csvkit. CSV, 인용 규칙 등에 대해 전혀 모르는 일반적인 텍스트 처리 유틸리티 입니다 sed
.awk
테스트 데이터:
id,name,date of birth
1,"Alfonso, the first",1980-01-01
2,"Betty, the second",1980-01-02
3,"Conny, the third",1982-02-21
name
csvkit 도구를 사용하여 이 필드를 제거하려면:
$ csvcut -C name file
id,date of birth
1,1980-01-01
2,1980-01-02
3,1982-02-21
csvkit을 사용하여 필드를 복사하려면 다음을 수행하세요 name
.
$ csvcut -c id,name,name,"date of birth" file
id,name,name,date of birth
1,"Alfonso, the first","Alfonso, the first",1980-01-01
2,"Betty, the second","Betty, the second",1980-01-02
3,"Conny, the third","Conny, the third",1982-02-21
먼저 date of birth
csvkit을 사용하여 필드를 이동하려면 다음을 수행하십시오.
$ csvcut -c "date of birth",id,name file
date of birth,id,name
1980-01-01,1,"Alfonso, the first"
1980-01-02,2,"Betty, the second"
1982-02-21,3,"Conny, the third"
Miller를 사용하여 이 필드를 제거하려면 다음을 수행하십시오 name
.
$ mlr --csv cut -x -f name file
id,date of birth
1,1980-01-01
2,1980-01-02
3,1982-02-21
Miller를 사용하여 필드를 복사하려면 name
( name2
마지막으로 새 필드로 생성됨):
$ mlr --csv put '$name2 = $name' file
id,name,date of birth,name2
1,"Alfonso, the first",1980-01-01,"Alfonso, the first"
2,"Betty, the second",1980-01-02,"Betty, the second"
3,"Conny, the third",1982-02-21,"Conny, the third"
date of birth
Miller를 사용하여 레코드의 시작 부분으로 이동하려면 :
$ mlr --csv reorder -f "date of birth" file
date of birth,id,name
1980-01-01,1,"Alfonso, the first"
1980-01-02,2,"Betty, the second"
1982-02-21,3,"Conny, the third"