어떻게 사용하여 CSV 파일에 다음과 같은 작업을 수행 할 수 sed
또는 awk
?
- 열 삭제
- 열 복제
- 열을 이동
200 개가 넘는 행이있는 큰 테이블이 있으며에 익숙하지 않습니다 sed
.
답변
필드를 잘라 내고 다시 정렬하는 방법 (다른 답변에서 다룬 것) 외에도 기발한 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
'
답변
이는 CSV 파일이 구분 기호에만 쉼표를 사용하는지 또는 다음과 같은 광기가 있는지에 따라 다릅니다.
필드 1, “필드, 2”, 필드 3
간단한 CSV 파일을 사용한다고 가정합니다.
열 제거
단일 컬럼을 여러 가지 방법으로 제거 할 수 있습니다. 열 2를 예로 사용했습니다. 가장 쉬운 방법은 아마도 cut
구분 기호 -d
와 인쇄 할 필드를 지정할 수있는을 사용하는 것입니다 -f
. 이것은 쉼표와 출력 필드 1, 필드 3을 끝까지 나눕니다.
$ cut -d, -f1,3- /path/to/your/file
실제로을 사용해야하는 경우 sed
첫 번째 필드, th 필드 및 나머지와 일치하는 정규 표현식을 작성 n-1
하고 n
th 출력을 건너 뛸 수 있습니다 n
(여기서는 n
2이므로 첫 번째 그룹은 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
에서 awk
For 루프 식으로는 (다시 뒤에 쉼표를 무시하고) 같은 것 :
$ 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
해결책이 다른 것들로부터 자연스럽게 따라 온다고 생각 하지만, 어리석게 길어지기 시작합니다.
답변
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
출력 형식도 지정할 수 있습니다.
답변
다음 형식의 공백으로 구분 된 파일이 제공됩니다.
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 '{$2="";$0=$0;$1=$1}1'
입력
a b c d
산출
a c d