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


23

어떻게 사용하여 CSV 파일에 다음과 같은 작업을 수행 할 수 sed또는 awk?

  • 열 삭제
  • 열 복제
  • 열을 이동

200 개가 넘는 행이있는 큰 테이블이 있으며에 익숙하지 않습니다 sed.


1
크로스에 AskUbuntu
enzotib

@enzotib 링크를 게시 할 수 있습니까?
n0pe

@MaxMackie askubuntu.com/questions/88142/… . 나는이 시간에 모드를 볼 수 없기 때문에 그들이 원한다면 마이그레이션을 요청하는 플래그를 지정했습니다. 그것은 이미 받아 들여진 대답을 가지고 있기 때문에 확실하지 않을 것입니다.
Michael Mrozek

@MichaelMrozek, 흠 이런 상황에서 일반적으로 어떻게됩니까? 우리는 단순히 복제본을 유지합니까?
n0pe

1
사용 가능한 기본 도구 만있는 시스템에서 실행해야하는 경우가 아니면 csv 파일 처리를위한 강력한 명령 줄 도구가 있습니까?를 참조하십시오.
Gilles 'SO- 악의를 멈춰라'

답변:


7

필드를 잘라 내고 다시 정렬하는 방법 (다른 답변에서 다룬 것) 외에도 기발한 CSV 필드 문제가 있습니다.

데이터가이 "변덕스러운"범주에 속하는 경우 약간의 사전사후 필터링으로 처리 할 수 ​​있습니다. 아래에 표시된 필터는 문자가 필요 \x01, \x02, \x03, \x04데이터 어디서나 나타나지 않을 수 있습니다.

다음은 간단한 awk필드 덤프를 감싸는 필터 입니다.

참고 : 필드 5 는 유효하지 않거나 불완전한 "인용 필드"레이아웃을 가지고 있지만 CSV 파서에 따라 행의 끝에 양성입니다. 그러나 현재 행 끝 위치에서 다른 위치로 바꾸면 원치 않는 결과에 문제 가 발생할 수 있습니다 .

최신 정보; user121196 은 쉼표가 후행 따옴표 앞에 올 때 버그를 지적했습니다. 여기 수정이 있습니다.

자료

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
'

이 필터를 기준으로 n 번째 열을 어떻게 삭제 하시겠습니까?
user121196 December

@ user121196-첫 문장에서 언급했듯이이 답변은 CSV 데이터를보다 일관성있게 만드는 방법을 보여줍니다. 따옴표로 묶은 쉼표를 중립 토큰 문자로 대체 하고 이동 / 잘라 내기 / 삭제 쉼표로 되돌립니다 . 다시 말하지만, 이동 / 잘라 내기 / 삭제 단계는 간단한 awk field-dump 로 대체됩니다 .
Peter.O December

1
그것은이 경우에 실패 "," "15111 N. 헤이든 RD, 인트 160."
user121196

@ user121196 : 지적 해 주셔서 감사합니다. 수정 사항으로 답변을 업데이트했습니다.
Peter.O

15

이는 CSV 파일이 구분 기호에만 쉼표를 사용하는지 또는 다음과 같은 광기가 있는지에 따라 다릅니다.

필드 1, "필드, 2", 필드 3

간단한 CSV 파일을 사용한다고 가정합니다.

열 제거

단일 컬럼을 여러 가지 방법으로 제거 할 수 있습니다. 열 2를 예로 사용했습니다. 가장 쉬운 방법은 아마도 cut구분 기호 -d와 인쇄 할 필드를 지정할 수있는을 사용하는 것입니다 -f. 이것은 쉼표와 출력 필드 1, 필드 3을 끝까지 나눕니다.

$ cut -d, -f1,3- /path/to/your/file

실제로을 사용해야하는 경우 sed첫 번째 필드, th 필드 및 나머지와 일치하는 정규 표현식을 작성 n-1하고 nth 출력을 건너 뛸 수 있습니다 n(여기서는 n2이므로 첫 번째 그룹은 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

에서 awkFor 루프 식으로는 (다시 뒤에 쉼표를 무시하고) 같은 것 :

$ 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해결책이 다른 것들로부터 자연스럽게 따라 온다고 생각 하지만, 어리석게 길어지기 시작합니다.


그것은로드 된 답변입니다! +1 :)
jaypal singh

엄청나게 긴? !
Gilles 'SO- 악의를 멈춰라'

12

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 형식 출력


CSV이기 때문에이 (가) 필요합니다 BEGIN { FS=","; OFS=","; }.

1
심지어 FS = OFS = ","도 작동한다고 생각합니다.

5

다음 형식의 공백으로 구분 된 파일이 제공됩니다.

1 2 3 4 5

다음과 같이 awk로 필드 2를 제거 할 수 있습니다.

awk '{ sub($2,""); print}' file

어떤 반환

1  3 4 5

적절한 경우 2 열을 n 열로 바꿉니다.

열 2를 복제하려면

awk '{ col = $2 " " $2; $2 = col; print }' file

어떤 반환

1 2 2 3 4 5

열 2와 3을 전환하려면

awk '{temp = $2; $2 = $3; $3 = temp; print}'

어떤 반환

1 3 2 4 5

awk는 일반적으로 필드 의 개념을 다루는 데 매우 능숙 합니다 . 공백으로 구분 된 파일이 아닌 CSV를 다루는 경우 간단히 사용할 수 있습니다.

awk -F,

공백 대신 필드를 쉼표로 정의합니다 (기본값). 온라인에는 여러 가지 좋은 awk 리소스가 있으며 그중 하나는 아래 소스로 표시됩니다.

# 3의 출처


에 대해 잘 모르지만 awk필드 구분 기호 ,( 필드 구분 기호는 입력을 처리하는 방법을 제어하는 경우에도)로 구분 된 공간을 출력하는 것 같습니다.
Michael Mrozek

@MichaelMrozek : 예, 출력 필드 구분자를 제어하는 ​​것은 OFS awk 변수입니다.
enzotib

예, 대답에서 언급
했듯이

0

이것은 삭제를 위해 작동합니다

awk '{$2="";$0=$0;$1=$1}1'

입력

a b c d

산출

a c d
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.