Vários arquivos de texto em um grande arquivo de texto

4

Eu quero combinar milhares de pequenos arquivos de texto em um grande arquivo de texto. Eu tenho eles em diretórios com a estrutura: timestamp1/status.txt . Por exemplo: 20130430133144/status.txt . Até agora, eu sei que

cat */* > bigtextfile.txt

funciona para um pequeno número de arquivos. Mas vai funcionar para números mais altos? Gostaria de saber se cat coletará o conteúdo de todos os arquivos e tentará salvar no bigtextfile . Caso contrário, suponho que exista outra maneira de fazer isso, como buscar um arquivo, anexá-lo a bigtextfile , depois buscar outro e assim por diante.

    
por xyz 10.04.2013 / 22:07

3 respostas

5

Nenhum cat não armazenará todos os arquivos antes de começar a escrever.

No entanto, se você tiver um grande número de arquivos, poderá encontrar um problema com o número de argumentos transmitidos para cat . Por padrão, o kernel do linux permite apenas que um número fixo de argumentos seja passado para qualquer programa (não me lembro como obter o valor, mas são alguns milhares na maioria dos casos). Para resolver esse problema, você pode fazer algo assim:

find -mindepth 2 -maxdepth 2 -type f -exec cat {} \; > bigtextfile.txt

Isso basicamente chamará cat separadamente para cada arquivo encontrado por find .

    
por 10.04.2013 / 22:17
10

Em:

cat */* > bigtextfile.txt

O shell expandirá */* para a lista classificada de arquivos correspondentes (não ocultos) e executará cat com esses caminhos de arquivos como argumentos.

cat abrirá cada arquivo por vez e gravará em seu stdout o que ele lê no arquivo. cat não armazenará mais de um buffer cheio de dados (algo como alguns bytes de quilo) por vez na memória.

Um problema que você pode encontrar é que a lista de argumentos para cat é tão grande que atinge o limite do tamanho dos argumentos da chamada de sistema execve() . Então, você pode precisar dividir essa lista de arquivos e executar cat várias vezes.

Você pode usar xargs para isso (aqui com GNU ou BSD xargs para as opções não-padrão -r e -0 ):

printf '%s
find . -mindepth 2 -maxdepth 2 -type f -exec cat {} + > big-file.txt
' */* | xargs -r0 cat -- > big-file.txt

(porque printf é construído no shell, ele não passa pela chamada do sistema execve , portanto, não pelo seu limite).

Ou use find na lista de arquivos e execute quantos comandos forem necessários:

find . -path './*/*' -prune -type f -exec cat {} + > big-file.txt

Ou portavelmente:

ulimit -s unlimited
cat -- */* > big-file.txt

(lembre-se que ao contrário de */* , ele incluirá arquivos ocultos (e arquivos em diretórios ocultos), e não procurará arquivos em links simbólicos para os diretórios, e a lista de arquivos não será ordenada).

Se em uma versão recente do Linux, você pode aumentar o limite do tamanho dos argumentos:

autoload zargs
zargs -- */* -- cat > big-file.txt

Com zsh , você também pode usar zargs :

command -x cat -- */* > big-file.txt

Com ksh93 , você pode usar command -x :

command /opt/ast/bin/cat -- */* > big-file.txt

Todos fazem a mesma coisa, dividem a lista de arquivos e executam quantos comandos cat , conforme necessário.

Com ksh93 novamente, você pode contornar o limite execve() usando o comando cat incorporado:

cat */* > bigtextfile.txt
    
por 10.04.2013 / 22:24
1

Se o número de arquivos for muito grande, o */* dará uma lista de argumentos muito grande. Se assim for, algo ao longo das linhas vai fazer:

find . -name "*.txt" | xargs cat > outfile

(a idéia é usar find para pegar os nomes dos arquivos e transformá-los em um fluxo; xargs divide esse fluxo em partes gerenciáveis para fornecer a cat , que as concatena no fluxo de saída de xargs , e isso vai para outfile ).

    
por 10.04.2013 / 22:21

Tags