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


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.