첫 번째 행을 제외하고 파일에서 추가 헤더 행을 제거하십시오.


18

이 장난감 예제와 같은 파일이 있습니다. 내 실제 파일에는 4 백만 줄이 있으며 그중 약 10 줄을 삭제해야합니다.

ID  Data1  Data2
1    100    100
2    100    200
3    200    100
ID  Data1  Data2
4    100    100
ID  Data1  Data2
5    200    200

첫 번째 줄을 제외하고 머리글처럼 보이는 줄을 삭제하고 싶습니다.

최종 파일 :

ID  Data1  Data2
1    100    100
2    100    200
3    200    100
4    100    100
5    200    200

어떻게해야합니까?

답변:


26
header=$(head -n 1 input)
(printf "%s\n" "$header";
 grep -vFxe "$header" input
) > output
  1. 입력 파일의 헤더 행을 변수로 가져옵니다.
  2. 헤더를 인쇄
  3. 파일을 처리하여 grep헤더와 일치하는 줄을 생략하십시오.
  4. 위 두 단계의 출력을 출력 파일로 캡처

2
또는 아마도{ IFS= read -r head; printf '%s\n' "$head"; grep -vF "$head" ; } <file
— iruvar

둘 다 좋은 추가. posix가 최근에 -n 1을 선호하여 헤드에서 -1 구문을 제거했음을 간접적으로 지적한 don_crissti에게 감사합니다.
— Jeff Schaller

3
@JeffSchaller, 최근 12 년 전과 동일합니다. 그리고 head -1그 전에 수십 년 동안 폐기되었습니다.
— Stéphane Chazelas

36

당신이 사용할 수있는

sed '2,${/ID/d;}'

그러면 2 행부터 ID가있는 행이 삭제됩니다.


3
좋은; 또는 패턴 일치에 대해 더 구체적으로 설명하려면 sed '2,${/^ID Data1 Data2$/d;}' file(물론 열 사이에 올바른 수의 공백 사용)
— Jeff Schaller

흠 나는 하나의 명령으로 세미콜론을 생략 할 수 있다고 생각했지만, 좋아.
— bkmoney

제정신이 sed아닙니다.
— mikeserv

전체 편집 승리의 경우 aaaand -i입니다.
— user2066657

4
또는sed '1!{/ID/d;}'
— Stéphane Chazelas

10

중괄호를 좋아하지 않는 사람들을 위해

sed -e '1n' -e '/^ID/d'
  • npass라인 번호를 의미 합니다.1
  • d 로 시작하는 모든 일치하는 줄을 삭제하십시오. ^ID

5
sed '1n;/^ID/d'파일 이름을 줄일 수도 있습니다 . 그냥 제안
— Valentin Bajrami

이것은 또한 IDfoo헤더와 동일하지 않은 행을 인쇄합니다 (이 경우에는 차이가 없을 것 같지만 결코 알 수 없음).
— terdon

6

재미있는 것이 있습니다. sed직접 사용 하여 첫 번째 줄의 모든 복사본을 제거하고 다른 모든 것을 제자리에 그대로 둘 수 있습니다 (첫 번째 줄 자체 포함).

sed '1{h;n;};G;/^\(.*\)\n\1$/d;s/\n.*$//' input

1{h;n;}첫 번째 행을 보류 공간에 넣고 인쇄 한 후 다음 행을 읽고 sed첫 번째 행 의 나머지 명령을 생략합니다 . (또한 두 번째 줄에 대한 첫 번째 1테스트 는 건너 뛰지 만 두 번째 줄 에는 해당 테스트가 적용되지 않으므로 중요하지 않습니다.)

G 패턴 공간에 줄 바꿈 다음에 보류 공간의 내용을 추가합니다.

/^\(.*\)\n\1$/d줄 바꿈 뒤 부분 (즉, 보류 공간에서 추가 된 부분)이 줄 바꿈 앞 부분과 정확히 일치하면 패턴 공간의 내용을 삭제합니다 (따라서 다음 줄로 건너 뛰기). 헤더를 복제하는 행이 삭제되는 위치입니다.

s/\n.*$//G명령 에 의해 추가 된 텍스트 부분을 삭제하여 인쇄되는 내용이 파일에서 텍스트 행만됩니다.

그러나 정규 표현식이 비싸기 때문에 약간 더 빠른 접근 방식은 동일한 조건을 사용하고 (부정) P개행 뒤 부분 (즉, 보류 공간에서 추가 된 부분 ) 이 부분과 정확하게 일치 하지 않으면 개행까지 찢는 것입니다. 줄 바꿈 전에 무조건 패턴 공간을 삭제하십시오.

sed '1{h;n;};G;/^\(.*\)\n\1$/!P;d' input

입력시 출력은 다음과 같습니다.

ID  Data1  Data2
1    100    100
2    100    200
3    200    100
4    100    100
5    200    200


@don_crissti, 재미있는 추가; 감사! 나는 아마도 더 길지만 동등한 것을 선택할 것이다 sed '1{h;n;};G;/^\(.*\)\n\1$/d;P;d' input. 어쨌든 내가 읽기가 더 쉽습니다. :)
— 와일드 카드


5

첫 번째 줄을 미리 알 필요가없는 몇 가지 선택 사항은 다음과 같습니다.

perl -ne 'print unless $_ eq $k; $k=$_ if $.==1; 

이 -n플래그는 perl에게 입력 파일을 반복하여 각 줄을로 저장하도록 지시 $_합니다. 은 $k=$_ if $.==1;첫 번째 줄 (저장 $.하므로, 줄 번호 $.==1로만 1 라인 true가됩니다) $k. print unless $k eq $_인쇄는 하나의 저장과 동일하지 않은 경우, 현재의 행 $k.

다른 방법으로 awk:

awk '$0!=x;(NR==1){x=$0}' file 

여기에서 현재 줄이 변수에 저장된 내용과 같은지 테스트합니다 x. 테스트 $0!=x가 true로 평가되면 (현재 행 $0이와 동일하지 않은 경우 x) true 표현식에서 awk의 기본 조치가 인쇄이므로 행이 인쇄됩니다. 첫 번째 줄 ( NR==1)은로 저장됩니다 x. 현재 행과 일치하는지 확인한 후에이 작업을 수행하므로 x첫 번째 행도 인쇄됩니다.


첫 번째 아이디어는 툴박스의 일반화 된 스크립트이기 때문에 알 필요가 없습니다.
— Mark Stewart

1
그 awk 메소드는 별개의 라인마다 빈 / 거짓 배열 엔트리를 생성합니다; 4M 라인의 경우 모두 다르고 (Q에서 명확하지 않음) 상당히 짧으면 (그렇게 나타남) 아마도 괜찮을지 모르지만 훨씬 더 많거나 긴 라인이 있으면 쓰러지거나 죽을 수 있습니다. !($0 in a)을 만들거나 피하지 않고 테스트하거나, awk는 perl과 같은 논리를 수행 할 수 있습니다 : '$0!=x; NR==1{x=$0}'또는 헤더 행이 비어있을 수있는 경우'NR==1{x=$0;print} $0!=x'
— dave_thompson_085

1
@ dave_thompson_085 라인 당 배열은 어디에 생성됩니까? 당신은 의미 !a[$0]합니까? 왜 항목이 생성 a됩니까?
— terdon

1
그것이 awk가 작동하는 방식이기 때문입니다. gnu.org/software/gawk/manual/html_node/… 특히 "참고"를 참조하십시오 .
— dave_thompson_085

1
@ dave_thompson_085 글쎄, 난 망할거야! 고마워, 나는 그것을 몰랐다. 지금 수정했습니다.
— terdon

4

AWK는 이러한 목적을위한 매우 훌륭한 도구입니다. 샘플 코드는 다음과 같습니다.

$ awk 'NR == 1 {print} NR != 1 && $0!~/ID  Data1  Data2/' rmLines.txt | head -n 10                                
ID  Data1  Data2
1    100    100
     100    200
3    200    100
1    100    100
     100    200
3    200    100
1    100    100
     100    200
3    200    100

고장 :

  • NR == 1 {print} 텍스트 파일의 첫 줄을 인쇄하도록 지시합니다
  • NR != 1 && $0!~/ID Data1 Data2/ 논리 연산자 &&는 AWK에 1과 같지 않고 포함하지 않은 행을 인쇄하도록 지시합니다 ID Data1 Data2. {print}부분 의 부족에 주목하십시오 . awk에서 테스트 조건이 true로 평가되면 라인이 인쇄되는 것으로 가정됩니다.
  • | head -n 10출력을 처음 10 개 라인으로 만 제한하는 작은 추가 사항입니다. AWK부품 자체와 관련이 없으며 데모 목적으로 만 사용됩니다.

파일에서 원하는 경우 다음 > newFile.txt과 같이 명령 끝에 추가하여 명령 출력을 경로 재 지정하십시오 .

awk 'NR == 1 {print} NR != 1 && $0!~/ID  Data1  Data2/' rmLines.txt > newFile.txt

어떻게 유지합니까? 실제로는 꽤 좋습니다.

$ time awk 'NR == 1 {print} NR != 1 && $0!~/ID  Data1  Data2/' rmLines.txt > /dev/null                            
    0m3.60s real     0m3.53s user     0m0.06s system

사이드 노트

생성 된 샘플 파일은 백만에서 백만까지 반복하고 파일의 처음 네 줄을 인쇄하기 위해 수행되었으므로 0.09 초가 걸렸습니다.

awk 'BEGIN{ for(i=1;i<=1000000;i++) printf("ID  Data1  Data2\n1    100    100\n     100    200\n3    200    100\n");  }' > rmLines.txt

이것은 또한 ID Data1 Data2 foo헤더와 동일하지 않은 행을 인쇄합니다 (이 경우에는 차이가 없을 것 같지만 결코 알 수 없음).
— terdon

@terdon 예, 정확히 맞습니다. 그러나 OP는 제거하고자하는 패턴을 하나만 지정했으며 그의 사례는이를지지하는 것으로 보인다
— Sergiy Kolodyazhnyy

3

Awk, 모든 헤더에 자동으로 적응 :

awk '( FNR == 1) {header=$0;print $0;}
     ( FNR > 1) && ($0 != header) { print $0;}'  file1  file2 ....

즉, 첫 번째 줄에서 헤더를 가져 와서 인쇄하면 해당 헤더에서 다음 줄 DIFFERENT가 인쇄됩니다.

FNR = 현재 파일의 레코드 수. 여러 파일을 가질 수 있으며 각 파일에서 동일하게 수행됩니다.


2

완벽을 기하기 위해 @terdon보다 약간 더 우아한 Perl 솔루션 IMO는 다음과 같습니다.

perl -i -p -e 's/^ID.*$//s if $. > 1' file

1
아, 그러나 내 요점은 패턴을 지정하고 대신 첫 줄에서 읽을 필요를 피하는 것이 었습니다. 접근 방식은로 시작하는 모든 줄을 삭제합니다 ID. 이것이 유지되어야하는 행을 삭제하지는 않을 것입니다. 당신은 우아함을 제기하기 때문에, g당신이 사용하는 경우 무의미 ^하고 $. 사실, m///여기서 제외하고 모든 옵션 은 쓸모가 없습니다 s. 사용하지 않는 기능을 활성화합니다. 그래서있어 $, s/^ID.*//s같은 일을 할 것입니다.
— terdon

@terdon, 충분히 공평합니다. 당신은 훨씬 더 보편적입니다!
— KWubbufetowicz

2

질문을 조금 뒤로 밀기 만하면 입력 내용 자체가 여러 TSV 파일을 함께 묶은 결과 일 것 같습니다. 처리 파이프 라인의 단계를 백업 할 수있는 경우 (소유자 또는 담당자와 대화 할 수있는 경우) 먼저 머리글 인식 도구를 사용하여 데이터를 연결함으로써 문제를 해결할 수 있습니다. 여분의 헤더 행을 제거하십시오.

예를 들어, Miller 사용 :

$ cat f1.tsv
ID  Data1 Data2
1 100 100
2 100 200
3 200 100
$ cat f2.tsv
ID  Data1 Data2
4 100 100
$ cat f3.tsv
ID  Data1 Data2
5 200 200

$ cat f1.tsv f2.tsv  f3.tsv
ID  Data1 Data2
1 100 100
2 100 200
3 200 100
ID  Data1 Data2
4 100 100
ID  Data1 Data2
5 200 200

$ mlr --tsvlite cat f1.tsv f2.tsv  f3.tsv
ID  Data1 Data2
1 100 100
2 100 200
3 200 100
4 100 100
5 200 200

1
이 tidbit를 추가해 주셔서 감사합니다. 대부분의 파이프 라인에서 개별 샘플의 파일을 결합하고 병합해야하므로 향후에 매우 유용합니다.
— Gaius Augustus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.