Concatenando arquivos e inserir nova linha entre arquivos


127

Tenho vários arquivos com os quais quero concatenar cat. Digamos

File1.txt 
foo

File2.txt
bar

File3.txt
qux

Quero concat para que o arquivo final se pareça com:

foo

bar

qux

Em vez disso, com o costume cat File*.txt > finalfile.txt

foo
bar 
qux

Qual é o caminho certo para fazer isso?


Respostas:


121

Você pode fazer:

for f in *.txt; do (cat "${f}"; echo) >> finalfile.txt; done

Verifique se o arquivo finalfile.txtnão existe antes de executar o comando acima.

Se você tem permissão para usar, awkpode:

awk 'FNR==1{print ""}1' *.txt > finalfile.txt

10
AWK '{print $0}' *.txt
timger

7
Isso tem a falha distinta de que haverá linhas vazias no final (da primeira alternativa) ou no início (segunda alternativa). awk 'FNR==1 && NR > 1 ...'Porém, você pode se proteger facilmente disso.
Tripleee

5
Se você colocar >finalfile.txtapós, donepoderá substituir em vez de anexar, o que removerá o requisito para garantir que o arquivo esteja ausente ou vazio antes do loop.
Tripleee

53

Se você tiver poucos arquivos suficientes para listar cada um deles, poderá usar a substituição de processos no Bash, inserindo uma nova linha entre cada par de arquivos:

cat File1.txt <(echo) File2.txt <(echo) File3.txt > finalfile.txt

1
Lindo! Obrigado.
Bob Kocisko

Isso funcionou muito bem para meus certificados Letsencrypt para criar arquivos .pem.
leeman24

35

Se fosse eu, usaria o sed:

sed -e '$s/$/\n/' -s *.txt > finalfile.txt

Nesse padrão sed, $ tem dois significados: primeiro, corresponde apenas ao número da última linha (como um intervalo de linhas para aplicar um padrão) e, em segundo lugar, ao final da linha no padrão de substituição.

Se a sua versão do sed não tiver -s(processar arquivos de entrada separadamente), você poderá fazer tudo isso como um loop:

for f in *.txt ; do sed -e '$s/$/\n/' $f ; done > finalfile.txt

3
Ou no GNU sed:sed -s '$G' *.txt > finalfile.txt
Ruud Helderman

Apenas um fluxo! essa deve ser a resposta aceita!
Yassine ElBadaoui

cuidado pessoal, acabei de travar meu PC porque usei findno lugar do *.txt, o que significava que o arquivo foi anexado a ele!
Xerus

11

Você pode fazer isso usando, xargsse quiser, mas a ideia principal ainda é a mesma:

find *.txt | xargs -I{} sh -c "cat {}; echo ''" > finalfile.txt

1
Obrigado. Acho xargsmuito mais fácil usar do que loops no bash.
precisa saber é o seguinte

9

Isso funciona no Bash:

for f in *.txt; do cat $f; echo; done

Ao contrário das respostas com >>(anexar), a saída desse comando pode ser canalizada para outros programas.

Exemplos:

  • for f in File*.txt; do cat $f; echo; done > finalfile.txt
  • (for ... done) > finalfile.txt (parens são opcionais)
  • for ... done | less (canalizando para menos)
  • for ... done | head -n -1 (isso retira a linha em branco à direita)

7

Foi assim que fiz no OsX 10.10.3

for f in *.txt; do (cat $f; echo '') >> fullData.txt; done

desde que o simples comando 'eco' sem parâmetros tenha terminado em nenhuma nova linha inserida.


Isso coloca a string no final do arquivo; como faço para inseri-lo entre cada arquivo?
Onassar

3

Em python, isso concatena com linhas em branco entre arquivos (o que ,suprime a adição de uma linha em branco à direita):

print '\n'.join(open(f).read() for f in filenames),

Aqui está o feio one-liner python que pode ser chamado a partir do shell e imprime a saída em um arquivo:

python -c "from sys import argv; print '\n'.join(open(f).read() for f in argv[1:])," File*.txt > finalfile.txt
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.