Concatene vários arquivos com o mesmo cabeçalho


26

Eu tenho vários arquivos com o mesmo cabeçalho e vetores diferentes abaixo disso. Preciso concatenar todos eles, mas quero que apenas o cabeçalho do primeiro arquivo seja concatenado e não quero que outros cabeçalhos sejam concatenados, pois são todos iguais.

por exemplo: 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

Eu preciso que a saída seja

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

Eu poderia escrever um script em R, mas preciso dele com casca?

Respostas:


17

Se você sabe como fazê-lo em R, faça-o de qualquer maneira em R. Com as ferramentas clássicas do unix, isso é feito naturalmente no awk.

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

A primeira linha do script awk corresponde à primeira linha de um arquivo ( FNR==1), exceto se também for a primeira linha em todos os arquivos ( NR==1). Quando essas condições são atendidas, a expressão while (/^<header>/) getline;é executada, o que faz com que o awk continue lendo outra linha (pulando a atual) desde que a atual corresponda ao regexp ^<header>. A segunda linha do script awk imprime tudo, exceto as linhas que foram ignoradas anteriormente.


Obrigado Gilles. Cada um dos meus arquivos está em GBs. R não será eficiente fazer isso. É por isso que eu pedi.
Jana

@Jana Existem linhas que parecem cabeçalhos, mas não estão no topo do arquivo? Caso contrário, a maneira mais rápida é usar grep(como na resposta do sputnik ).
Gilles 'SO- stop be evil' (

Não, as linhas do cabeçalho são semelhantes a todos os arquivos e estão apenas na parte superior de cada arquivo. Sim, grep foi mais rápido. Obrigado ambos
Jana

11
@ Jana Aliás, se todos os seus arquivos tiverem o mesmo número de linhas de cabeçalho, aqui está outra maneira (que espero ser ainda mais rápida): head -n 10 file1.txt >output.txt && tail -q -n +11 file*.txt >>output.txt(se você tiver 10 linhas de cabeçalho). Além disso, se seus arquivos tiverem números em seus nomes, tenha cuidado com a file9.txtclassificação entre file89.txte file90.txt. Se os seus arquivos têm números gosto file001.txt, ..., files009.txt, files010.txt, ..., então files*.txtvou enumerá-los na ordem correta.
Gilles 'SO- stop be evil' (

Uma solução melhor (de stackoverflow.com/a/16890695/310441 ) que não requer correspondência de regex: awk 'FNR==1 && NR!=1{next;}{print}' *.csv
Owen

42

Outra solução, semelhante a " cat+grep" de cima, usando taile head:

  1. Escreva o cabeçalho do primeiro arquivo na saída:

    head -2 file1.txt > all.txt

    - head -2obtém 2 primeiras linhas do arquivo.

  2. Adicione o conteúdo de todos os arquivos:

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

    - -n +3faz taillinhas de impressão do 3º ao final, -qdiz para não imprimir o cabeçalho com o nome do arquivo (lido man), >>adiciona ao arquivo, não o substitui como >.

E com certeza você pode colocar os dois comandos em uma linha:

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

ou em vez de ;colocar &&entre eles para verificação de sucesso.


3
Sugiro para simplificar ainda mais a: (head -2 file1.txt ; tail -n +3 -q file*.txt ) > all.txtou(head -2 file1.txt && tail -n +3 -q file*.txt ) > all.txt
HongboZhu 13/06

4

Tente fazer isso:

$ 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

NOTA

  • a -vbandeira significa inverter a partida do
  • ^no REGEX , significa início da string
  • se você tiver vários arquivos, poderá fazer

:

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

É uma técnica de corte de array .


Obrigado sputnick, Mas eu tenho ~ 30 arquivos (arquivo1.txt, arquivo2.txt, arquivo3.txt..filen.txt) para serem concatenados. Devo digitar todos os nomes de arquivos ou existem outras maneiras de fazê-lo?
Jana

Veja meu post editado com técnica de corte
Gilles Quenot

Isso remove <header>linhas em qualquer lugar dos arquivos, não apenas no começo. Isso pode não ser um problema aqui, dependendo dos dados.
Gilles 'SO- stop be evil' (

11
Mais simples:grep '^<header>' file1.txt >output.txt && grep -v '^<header>' file*.txt >>output.txt
Gilles 'SO- stop be evil'

@Gilles: Notei sua resposta depois de um longo tempo, mas foi muito útil
Jana

1

O tailcomando (no GNU, pelo menos) tem uma opção para pular um determinado número de linhas iniciais. Para imprimir a partir da segunda linha, pular um cabeçalho de uma linha, faça:tail -n+2 myfile

Portanto, para manter o cabeçalho de duas linhas do primeiro arquivo, mas não o segundo, no Bash:

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

Ou, para muitos arquivos:

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

Se uma determinada string está presente em todas as linhas de cabeçalho, mas nunca no restante dos arquivos de entrada, grep -vé uma abordagem mais simples, como mostrou o sputnik.


1

Mais curto (não necessariamente mais rápido) com sed:

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

Isso excluirá todas as linhas que começam com <header>...a linha 3, para que o primeiro cabeçalho seja preservado e os outros cabeçalhos sejam removidos. Se houver um número diferente de linhas no cabeçalho, ajuste o comando de acordo (por exemplo, para cabeçalho de 6 linhas, use em 7vez de 3).
Se o número de linhas no cabeçalho for desconhecido, você pode tentar o seguinte:

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

Supondo que você esteja usando uma pasta com arquivos .txt com o mesmo cabeçalho que precisa ser combinado / concatenado, esse código combinaria os arquivos txt em all.txt com apenas um cabeçalho. a primeira linha (linhas separadas por ponto e vírgula) reúne todos os arquivos de texto para concatenar, a segunda linha gera o cabeçalho do primeiro arquivo txt em all.txt e a última linha concatena todos os arquivos de texto reunidos sem o cabeçalho (iniciando o concatenação da linha 2 em diante) e anexa a all.txt .


um pouquinho de explicação ajudaria bastante os futuros usuários
Jeff Schaller
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.