패턴으로 파일을 두 부분으로 분할


14

큰 파일을 패턴으로 두 부분으로 나누는 방법은 무엇입니까?

예를 들면 file.txt:

ABC
EFG
XYZ
HIJ
KNL

이 파일 을의 행과 나머지 행 XYZfile1포함 하도록 분할하고 싶습니다 .XYZfile2


XYZ라인이 출력에 포함 되어야합니까 ?
terdon

@terdon 내 경우에는 "XYZ"줄이 file2의 일부가되어서는 안됩니다. 그러나 그렇게 할 수 있다면 대답에 추가하십시오. 다른 경우에 유용 할 수 있습니다.
d.putto

충분합니다.
terdon

답변:


10

로에게 awk당신이 할 수 있습니다 :

awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile


설명 : 첫 번째 awk인수 ( out=file1)는 후속 인수 ( largefile)가 처리 되는 동안 출력에 사용될 파일 이름으로 변수를 정의 합니다. awk프로그램은 변수에 의해 지정된 파일에 모든 행을 출력한다 out( {print >out}). 패턴 XYZ이 발견되면 출력 변수는 새 파일 ( {out="file2}") 을 가리 키도록 재정의되어 후속 데이터 라인을 인쇄하기위한 대상으로 사용됩니다.

참고 문헌 :


14

이것은 직업입니다 csplit:

csplit -sf file -n 1 large_file /XYZ/

silently 사전에 조각 만들기, 파일을 분할 fIX을 file하고 n예를 들어, 하나의 숫자를 사용하여 umbered file0등을 사용하는 것을 주 /regex/일치하는지 선 포함에 분할,하지만하지 regex. 로 분할하는 방법 라인 매칭을 포함 regexA는 추가 +1오프셋 :

csplit -sf file -n 1 large_file /XYZ/+1

이 두 개의 파일을 생성 file0하고 file1. 당신이 절대적으로 필요할 경우라는 이름의 수 file1file2당신은 항상에 빈 패턴을 추가 할 수 csplit명령과 첫 번째 파일을 제거합니다

csplit -sf file -n 1 large_file // /XYZ/+1

생성 file0, file1그리고 file2하지만 file0당신이 안전하게 제거 할 수 있도록 비어 있습니다 :

rm -f file0

이것이 가장 간단한 대답이라고 생각합니다. 패턴을 나열하기 만하면 파일이 순서대로 분할됩니다. 훌륭한!
헨리 블라이스

6

현대 에는 위 의 기본 답변 중 하나의 ksh쉘 변형 (예 : 없음 sed)이 있습니다 sed.

{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1


그리고 ksh단독으로 또 다른 변형 (즉,을 생략 cat) :

{ read in <##XYZ ; print "$in" ; { read <##"" ;} >file2 ;} <largefile >file1


(순수한 ksh솔루션은 성능이 뛰어나며 2.4GB 테스트 파일에서는 sed/ cat기반 접근 방식 의 39-47 초와 비교하여 19-21 초가 필요했습니다 ).


그것은이다 매우 빠르게. 그러나 나는 당신이 필요가 있다고 생각하지 않습니다 read그리고 print당신은 그냥 출력 모두 자신의 가자한다 -. AST 툴킷을 완전히 빌드하고 모든 ksh내장을 컴파일 하면 성능이 향상됩니다 sed. 실제로 그중 하나가 아닌 것이 이상합니다 . 그러나 while <file do당신이 sed그렇게 많이 필요하지 않은 것 같아요 ...
mikeserv

그래도 궁금 awk합니다. 벤치 마크에서 어떻게 수행 되었습니까? 그리고 나는 ksh항상이 싸움에서 이길 것이라고 확신 하지만 GNU sed를 사용하고 있다면 너무 공평하지 않습니다 -GNU sed-unbuffered는 POSIXLY에 대한 열악한 접근 방식입니다. 그것은-프로그램의 정규 작업을 느리게 할 필요가 없습니다-버퍼링은 괜찮습니다- sed완료해야 할 모든 것은 설명자를 잃어 버립니다. 어떤 이유로 든 GNU는 그 정신을 뒤집습니다.
mikeserv

@mikeserv; 리디렉션 패턴 일치는 패턴을 찾을 때까지 수행되며, 표시된 패턴이있는 행은 그림과 같이 명시 적으로 수행되지 않으면 인쇄되지 않습니다. (적어도 그건 내 테스트를 보여 주었다.) 더가 있음을 참고 while; 인쇄는 <##재 지정 연산자 의 정의 된 부작용으로 내재적으로 수행됩니다 . 일치하는 줄만 인쇄하면됩니다. (쉘 기능 구현은 포함 / 제외를 지원하기 위해 가장 유연합니다.) 명시적인 while루프는 상당히 느릴 것으로 예상되지만 확인하지는 않았습니다.
Janis

1
@mikeserv; 아, 알았어요 BTW, 나는 head대신에 read; 조금 느리게 보이지만 더 간결한 코드 : { head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3.
Janis

1
@mikeserv; 좋은 지적; 아니었다. 그러나 내장을 활성화하면 (방금 완료하고 결과를 확인) 이상한 숫자와 동일합니다. (읽기와 비교하여 함수 호출 오버 헤드가있을 수 있습니까?)
Janis

6
{ sed '/XYZ/q' >file1; cat >file2; } <infile

GNU sed에서는 -unbuffered 스위치를 사용해야합니다 . 대부분의 다른 sed것들은 작동해야합니다.

XYZ를 나가려면 ...

{ sed -n '/XYZ/q;p'; cat >file2; } <infile >file1

3

GNU sed로 이것을 시도하십시오 :

sed -n -e '1,/XYZ/w file1' -e '/XYZ/,${/XYZ/d;w file2' -e '}' large_file

sed -e '1,/XYZ/{w file1' -e 'd}' large_file > file2
짧게

1

쉬운 해킹은 대상 패턴의 일치 여부에 따라 STDOUT 또는 STDERR로 인쇄하는 것입니다. 그런 다음 셸의 리디렉션 연산자 를 사용하여 출력을 적절히 리디렉션 할 수 있습니다 . 예를 들어, 펄, 입력 파일을 가정하면이라 f하고, 두 개의 출력 파일 f1f2:

  1. 분할 패턴과 일치하는 선을 버립니다.

    perl -ne 'if(/XYZ/){$a=1; next} ; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2
  2. 일치하는 줄 포함 :

    perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2

또는 다른 파일 핸들로 인쇄하십시오.

  1. 분할 패턴과 일치하는 선을 버립니다.

    perl -ne 'BEGIN{open($fh1,">","f1");open($fh2,">","f2");}
    if(/XYZ/){$a=1; next}$a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
  2. 일치하는 줄 포함 :

    perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
              $a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.