이것은 다른 두 가지 질문의 조합입니다(한 줄에 접두사로 파일을 분할하는 방법그리고헤더를 포함하여 열을 기준으로 파일을 분할하는 방법). 나는 다음과 같이 시작하고 싶습니다 input.csv
:
id,first,second,third
1,a,b,c
333,b,b,b
1,d,e,f
2,d,e,f
1,c,d,e
333,a,a,a
[more lines in the same format]
이 내용에 1.csv
:
id,first,second,third
1,a,b,c
1,d,e,f
1,c,d,e
, 이 콘텐츠는 다음 위치에 있습니다 2.csv
.
id,first,second,third
2,d,e,f
, 이 333.csv
:
id,first,second,third
333,b,b,b
333,a,a,a
, 그건:
- 모든 ID를 다음으로 변경하세요.질소입력하다
N.csv
. - 행을 순서대로 유지원본처럼.
- 제목 포함모든 출력 파일의 원시 파일.
이 또한 매우 빨라야 하므로 while read
루프는 다음과 같습니다.아니요잘라버릴 거예요.
답변1
이 GNU awk 명령은 이 문제를 해결할 수 있습니다.
awk -F ',' 'NR==1{h=$0; next};!seen[$1]++{f=$1".csv"; print h > f};{f=$1".csv"; print >> f; close(f)}' input.csv
경고: 첫 번째 필드에 이스케이프된 쉼표가 있으면 작동하지 않습니다. 다른 분야의 쉼표는 정상적으로 작동합니다.
설명하다:
-F ','
(필드 구분 기호)$1
등이 공백으로 구분된 값이 아닌 CSV 열을 참조하는지 확인합니다.NR==1{h=$0; next}
NR==1
전체 헤더 행을 변수h
( )에 저장하고 해당 행( )을 건너뛰어h=$0
첫 번째 행( )을 특별히 처리합니다next
.!seen[$1]++{f=$1".csv"; print h > f}
$1
특수 문자( ) 가 처음 발생하면 다음 항목을 filename 변수에 저장하고 헤더를 해당 파일( )에 저장하여 처리됩니다 .!seen[$1]
$1
.csv
f
print h > f
{f=$1".csv"; print >> f; close(f)}
현재 행을 파일에 추가하고(print >> f
) 파일 설명자를 닫아(close(f)
) 특정 ID를 가진 모든 행이 처리된 후에 해당 행이 유지되지 않도록 합니다.
보너스: 다른 필드로 바꾸면 $1
예상대로 작동해야 합니다. 즉, 주어진 열에 해당 값이 포함된 행이 포함된 해당 열의 각 고유 값에 대한 파일을 생성해야 합니다.
답변2
(다른 답변으로 모든 사람에게 스팸을 보내서 죄송합니다.) 많은 상황에서 제공된 우아한 awk 버전이 완벽합니다. 하지만 재치 있는 말 이상의 삶이 있으며 우리에게는 종종 더 많은 것이 필요합니다.
- 복잡한 csv 파일을 처리하는 추가 코드를 추가합니다.
- 추가 정규화, 형식 재지정, 처리 단계를 추가합니다.
다음 프레임워크에서는 CSV 파일에 대한 파서를 사용합니다. 이번에는 정수 사용을 피하고 심지어 변수를 엄격하게 선언했습니다!
#!/usr/bin/perl
use strict;
use Parse::CSV;
my %dict=();
my $c = Parse::CSV->new(file => 'a1.csv');
while ( my $row = $c->fetch ) { ## for all records
$dict{$row->[0]} .= join(" :: ",@$row)."\n"; ## process and save
}
for my $k (keys %dict){ ## create the cvs files
open(F,">","$k.cvs") or die;
print F $dict{$k};
close F;
}
- 가장 큰 장점은 더 복잡한 csv 파일을 처리할 수 있다는 것입니다. 이번에는 csv 입력에 ";"이 포함된 문자열이 포함될 수 있으며 여러 줄 필드가 포함될 수 있습니다(csv 사양은 복잡합니다!).
1111,2,3
"3,3,3",a,"b, c, and d"
"a more, complex
multiline record",3,4
- 처리 단계를 설명하기 위해 필드 구분 기호가 ":"로 변경되었습니다.
- 추가 단계를 설명하기 위해 몇 가지 최적화를 추가했습니다. 사전 캐싱을 사용했기 때문에 이 스크립트는 다른 솔루션보다 100배 빠르게 실행되었습니다.
답변3
이것은 답변이 아니라 IObO의 탁월한 답변의 스크롤 방지 변형입니다 ...
awk -F, 'NR==1{h=$0; next} {print seen[$1]++ ? $0 : h "\n" $0 >$1 ".csv"}'
답변4
파이프만 사용하고 다음을 사용하지 않는 구식 버전 awk
:
경고하다:위의 솔루션보다 평균적으로 느리게 실행되며 awk
속도는 입력 파일의 키 수에 따라 달라집니다.
cut -d , -f 1 input.csv | fgrep -v id | sort | uniq | xargs -n1 sh -c '(head -n1 input.csv && egrep "^${0}," input.csv) > ${0}.csv'
그것이 하는 일은:
cut -d , -f 1 input.csv
파일의 각 줄을 문자별로 나누고,
첫 번째 열(-f 1
)을 가져와 키만 유지합니다.fgrep -v id
제목 건너뛰기sort | uniq
각 키 중 하나만 정렬하여 보관하세요.xargs -n1 sh -c '<sub shell>'
각 키에 대해 서브셸 실행head -n1 input.csv
서브셸의 첫 번째 부분은 입력 파일의 헤더를 가져옵니다.- 그런 다음
egrep "^${0}," input.csv
키와 일치하는 행을 잡고명확하지 않을 수도 있지만 이는 행별로 반복되므로 속도가 느립니다. - 마지막으로
> ${0}.csv
출력은 키 이름의 파일에 기록됩니다.