Concatenando vários arquivos de texto em um único arquivo no Bash

305

Qual é a maneira mais rápida e pragmática de combinar todos os arquivos * .txt em um diretório em um arquivo de texto grande?

Atualmente, estou usando o windows com cygwin para ter acesso ao BASH.

O comando shell do Windows também seria bom, mas duvido que exista um.

Yada
fonte

Respostas:

537

Isso anexa a saída a all.txt

cat *.txt >> all.txt

Isso substitui o arquivo all.txt

cat *.txt > all.txt
Robert Greiner
fonte
30
você pode ter um problema no qual ele coloca all.txt em all.txt ... Eu tenho esse problema com o grep algumas vezes, não tenho certeza se o gato tem o mesmo comportamento.
Rmeador
8
@ rmeador sim, isso é verdade, se all.txt já existir, você terá esse problema. Esse problema é resolvido fornecendo ao arquivo de saída uma extensão diferente ou movendo all.txt para uma pasta diferente.
Robert Greiner
2
cat * .txt >> tmp; mv tmp all.txt (e certifique-se de que o all.txt não exista anteriormente)
Renaud
16
Recebo "Lista de argumentos muito longa" - acho que ela não pode lidar com mais de 40.000 arquivos.
Matt
32
Evite a lista de argumentos muito longa com:echo *.txt | xargs cat > all.txt
5heikki 22/09
145

Lembre-se, para todas as soluções fornecidas até agora, o shell decide a ordem em que os arquivos são concatenados. Para Bash, IIRC, essa é a ordem alfabética. Se a ordem for importante, você deve nomear os arquivos adequadamente (01file.txt, 02file.txt, etc ...) ou especificar cada arquivo na ordem em que deseja concatenar.

$ cat file1 file2 file3 file4 file5 file6 > out.txt
Chinmay Kanchi
fonte
33

O comando do shell do Windows typepode fazer isso:

type *.txt >outputfile

O typecomando Type também grava nomes de arquivos no stderr, que não são capturados pelo >operador de redirecionamento (mas serão exibidos no console).

Greg Hewgill
fonte
2
Lembre-se de que, se você colocar o arquivo de saída no mesmo diretório que o arquivo original, isso causará uma duplicação, pois também combinará o novo arquivo de saída duas vezes.
CathalMF
26

Você pode usar o shell do Windows copypara concatenar arquivos.

C:\> copy *.txt outputfile

Da ajuda:

Para anexar arquivos, especifique um único arquivo para o destino, mas vários arquivos para a origem (usando caracteres curinga ou formato arquivo1 + arquivo2 + arquivo3).

Carl Norum
fonte
Esta como o IMHO solução mais limpa com basicamente sem efeitos secundários que os novatos possam tropeçar o suficiente, infelizmente, não se apreciado :-(
Grmpfhmbl
OP pediu Bash.
Big Rich
2
Você leu a pergunta? "Comando shell do Windows também seria bom ..."
Carl Norum
8

Tenha cuidado, porque nenhum desses métodos funciona com um grande número de arquivos. Pessoalmente, usei esta linha:

for i in $(ls | grep ".txt");do cat $i >> output.txt;done

EDIT: Como alguém disse nos comentários, você pode substituir $(ls | grep ".txt")por$(ls *.txt)

EDIT: graças à experiência @gnourf_gnourf, o uso de glob é a maneira correta de iterar arquivos em um diretório. Consequentemente, expressões blasfemas como $(ls | grep ".txt")devem ser substituídas por *.txt(veja o artigo aqui ).

Boa solução

for i in *.txt;do cat $i >> output.txt;done
Jacobe2169
fonte
1
Por que não for i in $(ls *.txt);do cat $i >> output.txt;done?
streamofstars
2
Link de análise obrigatória , juntamente com um voto negativo (e você merece mais de um voto ls | grepnegativo , porque é um antipadrão muito ruim).
gniourf_gniourf
Recebi um voto positivo porque permite testes / operações arbitrárias pelo nome do arquivo antes da saída e é rápido, fácil e bom para a prática. (No meu caso eu queria: for i in *; fazer echo -e "\ n $ i: \ n"; cat $ 1; feito)
Nathan Chappell
A ls *.txtfalha não ocorreria se houver muitos arquivos (erro da lista de argumentos muito longo)?
Rafael Almeida
6

a maneira mais pragmática com o shell é o comando cat. outras maneiras incluem,

awk '1' *.txt > all.txt
perl -ne 'print;' *.txt > all.txt
ghostdog74
fonte
1
Essa deve ser a resposta correta para a maioria das circunstâncias. Se qualquer arquivo de texto sem uma nova linha vazia, o uso do catmétodo acima concatenará a última e a primeira linha dos arquivos adjacentes.
mootmoot
6

Que tal essa abordagem?

find . -type f -name '*.txt' -exec cat {} + >> output.txt
GPrathap
fonte
Como o OP diz que os arquivos estão no mesmo diretório, você pode precisar adicionar -maxdepth 1o findcomando.
codeforester
1
Funciona muito bem com um grande número de arquivos, onde a abordagem da resposta aceita falha
amine
ah eu gostaria de saber o que isso significa mais e redirecionamento duplo significam ...
hello_earth 27/03
Essa deve ser a resposta correta. Funcionará corretamente em um script de shell. Aqui está um método semelhante se você deseja que a saída seja classificada:sort -u --output="$OUTPUT_FILE" --files0-from=- < <(find "$DIRECTORY_NAME" -maxdepth 1 -type f -name '*.txt' -print0)
steveH 27/04
3
type [source folder]\*.[File extension] > [destination folder]\[file name].[File extension]

Por exemplo:

type C:\*.txt > C:\1\all.txt

Isso pegará todos os arquivos txt na pasta C: \ e salvará na pasta C: \ 1 com o nome de all.txt

Ou

type [source folder]\* > [destination folder]\[file name].[File extension]

Por exemplo:

type C:\* > C:\1\all.txt

Isso pega todos os arquivos presentes na pasta e coloca lá Conteúdo em C: \ 1 \ all.txt

Ori
fonte
0

Você pode fazer assim: cat [directory_path]/**/*.[h,m] > test.txt

se você {}incluir a extensão dos arquivos que deseja encontrar, há um problema de sequência.

Michael-zhang
fonte
0

Quando você se deparar com um problema em que ele coloca all.txt em all.txt, tente verificar se all.txt existe ou não, se existir, remova

Como isso:

[ -e $"all.txt" ] && rm $"all.txt"

leo
fonte
cat *.txt > all.txt >substituições de comando all.txt se existir >>adiciona dados ao arquivo existente
Oleg Bondarenko
-4

tudo isso é desagradável ....

ls | grep *.txt | while read file; do cat $file >> ./output.txt; done;

coisas fáceis.

kSiR
fonte
6
Eeek! Não faça isso. Façafind . -iname "*.txt" -maxdepth 1 -exec cat {} >> out.txt \;
Chinmay Kanchi