Muitos arquivos de texto em um grande arquivo de texto

Muitos arquivos de texto em um grande arquivo de texto

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

cat */* > bigtextfile.txt

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

Responder1

Em:

cat */* > bigtextfile.txt

O shell se expandirá */*para a lista classificada de arquivos correspondentes (não ocultos) e será executado catcom esses caminhos de arquivo como argumentos.

catabrirá cada arquivo por vez e escreverá em seu stdout o que lê do arquivo. catnão armazenará mais de um buffer cheio de dados (algo como alguns quilobytes) por vez na memória.

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

Você poderia usar xargspara isso (aqui com GNU ou BSD para opções xargsnão padrão ):-r-0

printf '%s\0' */* | xargs -r0 cat -- > big-file.txt

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

Ou findfaça a lista de arquivos e execute quantos comandos cat forem necessários:

find . -mindepth 2 -maxdepth 2 -type f -exec cat {} + > big-file.txt

Ou portável:

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

(cuidado, porém, ao contrário de */*, ele incluirá arquivos ocultos (e arquivos em diretórios ocultos), não procurará arquivos em links simbólicos para diretórios e a lista de arquivos não será classificada).

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

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

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

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

Com ksh93você pode usar command -x:

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

Todos fazem a mesma coisa, dividem a lista de arquivos e executam quantos catcomandos forem necessários.

Novamente ksh93, você pode contornar o execve()limite usando o catcomando interno:

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

Responder2

Não, catnão armazenará todos os arquivos em buffer antes de começar a gravar.

No entanto, se você tiver um grande número de arquivos, poderá ter problemas com o número de argumentos passados ​​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

Basicamente, isso chamará catseparadamente cada arquivo encontrado por find.

Responder3

Se o número de arquivos for muito grande, a */*lista de argumentos será muito grande. Nesse caso, algo parecido servirá:

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

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

informação relacionada