sed 또는 awk를 사용하여 CSV 파일을 조작하는 방법은 무엇입니까?

sed 또는 awk를 사용하여 CSV 파일을 조작하는 방법은 무엇입니까?

sedCSV 파일에 대해 다음 작업을 어떻게 사용하거나 수행할 수 있습니까 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-1nnn1\{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출력을 포맷할 수도 있습니다.

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

namecsvkit 도구를 사용하여 이 필드를 제거하려면:

$ 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 birthcsvkit을 사용하여 필드를 이동하려면 다음을 수행하십시오.

$ 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 birthMiller를 사용하여 레코드의 시작 부분으로 이동하려면 :

$ 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"

관련 정보