Concatenando milhares de arquivos: vs

6

Eu encontrei duas respostas aparentemente contraditórias no StackOverflow para as seguintes perguntas:

A primeira resposta à primeira pergunta sugere:

find . -name *.txt -print0 | xargs -0 cat >> out.txt

enquanto a resposta principal da segunda pergunta sugere:

find . -name *.txt -print0 | xargs -0 cat > out.txt

Até onde eu sei, o primeiro está correto, pois ele usa o operador >> (append), mas não o segundo, pois ele usa o operador > , que eu acho que simplesmente redireciona a saída para um arquivo. No entanto, a segunda resposta tem mais votos (10) e também foi aceita sem comentários. Ambas as respostas estão corretas? Por quê? Qual é o propósito de ter esses dois operadores então?

    
por Amelio Vazquez-Reina 20.05.2013 / 02:51

3 respostas

14

O segundo exemplo:

find . -name '*.txt' -print0 | xargs -0 cat > out.txt

É completamente legal e recriará o arquivo, out.txt cada vez que for executado, enquanto o primeiro concatenará para out.txt se for executado. Mas ambos os comandos estão fazendo essencialmente a mesma coisa.

O que causa confusão é o xargs -0 cat . As pessoas acham que o redirecionamento para out.txt faz parte desse comando quando não é. O redirecionamento está ocorrendo após xargs -o cat ter recebido entrada via STDIN e, depois, enviado essa saída como um fluxo único para STDOUT. O xargs está otimizando o envio dos arquivos e não sua saída.

Aqui está um exemplo que mostra o que estou dizendo. Se inserirmos um pv -l entre o xargs -0 cat e a saída para o arquivo out.txt , poderemos ver quantas linhas o cat escreveu.

Exemplo

Para mostrar isso, criei um diretório com 10.000 arquivos.

for i in 'seq -w 1 10000';do echo "contents of file$i.txt" > file$i.txt;done

Cada arquivo é semelhante a este:

$ more file00001.txt 
contents of file00001.txt

A saída de pv :

$ find . -name '*.txt' -print0 | xargs -0 cat | pv -l > singlefile.rpt
  10k 0:00:00 [31.1k/s] [  <=> 

Como podemos ver, 10 mil linhas foram escritas no meu arquivo singlefile.rpt . Se xargs estivesse passando nos grupos de saída, veríamos isso reduzindo o número de linhas que estavam sendo apresentadas para pv .

    
por 20.05.2013 / 03:22
5

What is the purpose of having these two operators then?

Isso é fácil: porque há diferentes casos de uso. Às vezes é útil truncar o arquivo de destino para o tamanho 0 primeiro, às vezes (por exemplo, arquivos de log) faz mais sentido anexar dados a um arquivo.

Neste caso, não faz sentido acrescentar. Você quer um arquivo com exatamente o conteúdo dos arquivos selecionados e não "um arquivo com os dados no início e o conteúdo dos arquivos selecionados no final".

    
por 20.05.2013 / 03:54
2

Eu iria com o segundo. O redirecionamento do stdout é capturado pelo bash quando você pressiona enter, então não é como se você criasse um novo redirecionamento para cada linha de find / xargs (que pode ter sido o pensamento deles). Se out.txt não existir, eles devem ser idênticos, se já tiverem dados, então o segundo, pelo menos, redefine o arquivo para o conteúdo conhecido (ou seja, sem conteúdo).

    
por 20.05.2013 / 02:59