Concaténer des milliers de files:> vs >>

J'ai trouvé deux réponses apparemment contradictoires sur StackOverflow aux questions suivantes:

  • Concaténer des milliers de files text sur des centaines de directorys (tout en gardant une certaine structure)
  • Comment concaténer des files dans un sous-directory avec Unix find execute et cat dans un seul file?

La réponse supérieure à la première question suggère:

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

tandis que la réponse supérieure à la deuxième question suggère:

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

Pour autant que je sache, le premier est correct car il utilise l'opérateur >> (append), mais pas le second puisqu'il utilise l'opérateur > que je pensais simplement redirect la sortie vers un file. Cependant, la deuxième réponse a plus de votes (10) et a également été acceptée sans commentaires. Les deux réponses sont-elles correctes? Pourquoi? Quel est le but d'avoir ces deux opérateurs alors?

Le deuxième exemple:

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

Est tout à fait légal et va recréer le file, out.txt chaque fois qu'il est exécuté, tandis que le premier concatène à out.txt s'il s'exécute. Mais les deux commands font essentiellement la même chose.

Ce qui prête à confusion est le xargs -0 cat . Les gens pensent que la redirection vers out.txt fait partie de cette command quand elle ne l'est pas. La redirection se produit après que xargs -o cat a entré une input via STDIN, puis en catifiant cette sortie en tant que stream unique vers STDOUT. Le xargs optimise le chat des files et non leur sortie.

Voici un exemple qui montre ce que je dis. Si nous insérons un pv -l entre le xargs -0 cat et la sortie dans le file out.txt nous pouvons voir le nombre de lignes que cat a écrites.

Exemple

Pour montrer cela, j'ai créé un directory contenant 10 000 files.

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

Chaque file ressemble à ceci:

 $ more file00001.txt contents of file00001.txt 

La sortie de pv :

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

Comme nous pouvons le voir, 10k lignes ont été écrites dans mon file singlefile.rpt . Si xargs nous passait des morceaux de sortie, alors nous verrions cela par une réduction du nombre de lignes qui étaient présentées à pv .

Quel est le but d'avoir ces deux opérateurs alors?

C'est facile: parce qu'il y a différents cas d'utilisation. Parfois, il est utile de tronquer le file cible à la taille 0 en premier, parfois (par exemple, les files journaux), il est plus logique d'append des données à un file.

Dans ce cas, cela n'a aucun sens d'append. Vous voulez un file avec exactement le contenu des files que vous avez sélectionnés et non «un file avec toutes datatables au début et le contenu des files sélectionnés à la fin».

J'irais avec le second. La redirection de stdout est interceptée par bash quand vous tapez enter, donc ce n'est pas comme si vous créez une nouvelle redirection pour chaque ligne de find / xargs (ce qui aurait pu être leur reflection). Si out.txt n'existe pas, il doit être identique, s'il a déjà des données, alors le second réinitialise au less le file au contenu connu (c'est-à-dire, pas de contenu).