동일한 헤더로 여러 파일을 연결


26

같은 헤더와 다른 벡터가있는 여러 파일이 있습니다. 나는 그것들을 모두 연결해야하지만 첫 번째 파일의 헤더 만 연결하기를 원하고 다른 헤더는 모두 동일하기 때문에 연결하고 싶지 않습니다.

예를 들면 다음과 같습니다. file1.txt

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B 
C

file2.txt

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
D
E 
F

나는 출력이 필요하다

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B
C
D
E 
F

R로 스크립트를 작성할 수 있지만 쉘에서 스크립트가 필요합니까?

답변:


17

R에서 수행하는 방법을 알고 있다면 반드시 R에서 수행해야합니다. 고전적인 유닉스 도구를 사용하면 가장 자연스럽게 awk로 수행됩니다.

awk '
    FNR==1 && NR!=1 { while (/^<header>/) getline; }
    1 {print}
' file*.txt >all.txt

awk 스크립트의 첫 번째 줄은 파일의 첫 번째 줄 ( FNR==1) 과 일치하지만 모든 파일에서 첫 번째 줄 ( )을 제외하고는 제외합니다 NR==1. 이러한 조건이 충족되면식이 while (/^<header>/) getline;실행되어 현재 awk가 regexp와 일치하는 한 awk가 다른 행을 계속 읽습니다 (현재 행 건너 뛰기) ^<header>. awk 스크립트의 두 번째 줄은 이전에 건너 뛴 줄을 제외한 모든 것을 인쇄합니다.


고마워 질. 각 파일은 GB 단위입니다. R은 효율적이지 않습니다. 그래서 내가 물었다.
Jana

@Jana 헤더처럼 보이지만 파일의 맨 위에 있지 않은 행이 있습니까? 그렇지 않은 경우 가장 빠른 방법은 sputnik의 답변grep 에서와 같이 사용하는 것입니다 .
Gilles 'SO- 악마 그만해'

헤더 행은 모든 파일과 유사하지 않으며 각 파일의 맨 위에 있습니다. 그래 grep이 더 빨랐다. 감사합니다
Jana

1
@Jana 그런데 모든 파일에 동일한 수의 헤더 행이 있으면 다른 방법이 있습니다 (더 빠를 것으로 예상됩니다) head -n 10 file1.txt >output.txt && tail -q -n +11 file*.txt >>output.txt(10 개의 헤더 행이있는 경우). 당신의 파일 이름에 숫자가있는 경우 또한, 즉 조심 file9.txt사이에 정렬 file89.txt하고 file90.txt. 파일 숫자가 같은 경우 file001.txt, ..., files009.txt, files010.txt, ..., 다음 files*.txt올바른 순서대로 나열합니다.
Gilles 'SO- 악의를 그만두십시오'

정규식 일치가 필요하지 않은 더 나은 솔루션 ( stackoverflow.com/a/16890695/310441 ) : awk 'FNR==1 && NR!=1{next;}{print}' *.csv
Owen

42

cat+grep위의 " " 와 유사한 또 다른 솔루션은 tailand head:

  1. 첫 번째 파일의 헤더를 출력에 작성하십시오.

    head -2 file1.txt > all.txt

    - head -2파일의 첫 줄 2 개를 가져옵니다.

  2. 모든 파일의 내용을 추가하십시오.

    tail -n +3 -q file*.txt >> all.txt

    -3 번째부터 끝까지 인쇄 행을 -n +3만들고 , 파일 이름 (읽기 )으로 헤더를 인쇄하지 말라고하고 파일 에 추가하며을 덮어 쓰지 않습니다 .tail-qman>>>

그리고 두 명령을 한 줄에 넣을 수 있습니다.

head -2 file1.txt > all.txt; tail -n +3 -q file*.txt >> all.txt

또는 성공 확인을 위해 그들 사이 에 ;두는 대신 &&.


3
: 나는 간단히에 추가로 제안 (head -2 file1.txt ; tail -n +3 -q file*.txt ) > all.txt또는(head -2 file1.txt && tail -n +3 -q file*.txt ) > all.txt
HongboZhu

4

이것을 시도하십시오 :

$ cat file1.txt; grep -v "^<header" file2.txt
<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B 
C
D
E 
F

노트

  • -v플래그 수단의 경기 반전하는
  • ^REGEX 수단은 문자열의 시작
  • 많은 파일이 있으면 할 수 있습니다

:

array=( files*.txt )
{ cat ${array[@]:0:1}; grep -v "^<header" ${array[@]:1}; } > new_file.txt

그것은이다 배열 슬라이싱 기술.


고마워요 sputnick, 그러나 ~ 30 개의 파일 (file1.txt, file2.txt, file3.txt..filen.txt)을 연결할 수 있습니다. 모든 파일 이름을 입력해야합니까 아니면 다른 방법이 있습니까?
Jana


이렇게하면 <header>처음이 아니라 파일의 모든 위치에서 줄 이 제거 됩니다. 데이터에 따라 여기서 문제가되지 않을 수 있습니다.
Gilles 'SO- 악마 그만해'

1
더 간단한 :grep '^<header>' file1.txt >output.txt && grep -v '^<header>' file*.txt >>output.txt
질 '소 악한 그만'

@Gilles : 오랜만에 답을 찾았지만 매우 유용했습니다
Jana

1

tail(GNU, 적어도에) 명령은 초기 라인의 주어진 숫자를 건너 뛸 수 있습니다. 두 번째 줄부터 인쇄하려면, 즉 한 줄 헤더를 건너 뛰려면 다음과 같이하십시오.tail -n+2 myfile

따라서 Bash에서 첫 번째 파일의 두 줄 헤더를 유지하지만 두 번째 파일은 유지하지 않습니다.

cat file1.txt <(tail -n+3 file2.txt) > combined.txt

또는 많은 파일의 경우 :

head -n1 file1.txt > combined.txt
for fname in *.txt
do
    tail -n+3 $fname >> combined.txt
done

특정 문자열이 모든 헤더 행에 존재하지만 나머지 입력 파일에는 존재하지 않는 것으로 알려진 경우 grep -vsputnik이 보여 주듯이 더 간단한 접근 방식입니다.


1

짧은 (반드시 빠른)와 sed:

sed -e '3,${/^<header>/d' -e '}' file*.txt > all.txt

이렇게하면 <header>...3 행부터 시작하여 모든 행이 삭제 되므로 첫 번째 헤더는 유지되고 다른 헤더는 제거됩니다. 헤더에 다른 수의 줄이있는 경우 적절하게 명령을 조정하십시오 (예 : 7대신 6 줄 헤더 사용 3).
헤더의 줄 수를 알 수 없으면 다음과 같이 시도하십시오.

sed '1{
: again
n
/^<header>/b again
}
/^<header>/d
' file*.txt > all.txt

0

array = (* .txt); head -1 $ {array [0]}> all.txt; tail -n +2 -q $ {array [@] : 0} >> all.txt

결합 / 연결 해야하는 동일한 헤더가있는 .txt 파일이있는 폴더를 사용한다고 가정하면이 코드는 txt 파일을 모두 하나의 헤더 로 all.txt에 결합합니다 . 첫 번째 줄 (세미콜론으로 구분 된 줄)은 연결할 모든 텍스트 파일을 수집하고 두 번째 줄은 첫 번째 txt 파일에서 헤더를 all.txt 로 출력 하며 마지막 줄은 헤더없이 수집 된 모든 텍스트 파일을 헤더없이 연결합니다 ( 2 행부터 연결하여 all.txt에 추가하십시오 .


약간의 설명은 미래의 사용자를 돕기 위해 먼 길을 갈 것입니다
Jeff Schaller
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.