Performances de sed
vs tail
pour supprimer la première ligne d'un fichier
TL; DR
sed
est très puissant et polyvalent, mais c'est ce qui le rend lent, en particulier pour les fichiers volumineux avec de nombreuses lignes.
tail
fait juste une chose simple, mais celle-ci, elle le fait bien et rapidement, même pour des fichiers plus gros avec de nombreuses lignes.
Pour les fichiers de petite et moyenne taille, sed
et tail
fonctionnent de manière similaire rapidement (ou lentement, selon vos attentes). Cependant, pour les fichiers d'entrée plus volumineux (plusieurs Mo), la différence de performances augmente considérablement (un ordre de grandeur pour les fichiers de l'ordre de centaines de Mo), avec des tail
performances nettement supérieures sed
.
Expérience
Préparations générales:
Nos commandes à analyser sont:
sed '1d' testfile > /dev/null
tail -n +2 testfile > /dev/null
Notez que je redirige la sortie à /dev/null
chaque fois pour éliminer la sortie du terminal ou les écritures de fichier comme goulot d'étranglement des performances.
Configurons un disque RAM pour éliminer les E / S disque comme goulot d'étranglement potentiel. J'ai personnellement un tmpfs
monté à /tmp
donc j'ai simplement placé mon testfile
là pour cette expérience.
Ensuite, je crée une fois un fichier de test aléatoire contenant un nombre spécifié de lignes $numoflines
avec une longueur de ligne aléatoire et des données aléatoires à l'aide de cette commande (notez que ce n'est certainement pas optimal, cela devient vraiment lent pour environ> 2 millions de lignes, mais peu importe, ce n'est pas le chose que nous analysons):
cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n "$numoflines" > testfile
Oh, au fait. mon ordinateur portable de test exécute Ubuntu 16.04, 64 bits sur un processeur Intel i5-6200U. Juste pour comparaison.
Timing de gros fichiers:
Mise en place d'un énorme testfile
:
L'exécution de la commande ci-dessus avec numoflines=10000000
produit un fichier aléatoire contenant 10 millions de lignes, occupant un peu plus de 600 Mo - c'est assez énorme, mais commençons par cela, car nous pouvons:
$ wc -l testfile
10000000 testfile
$ du -h testfile
611M testfile
$ head -n 3 testfile
qOWrzWppWJxx0e59o2uuvkrfjQbzos8Z0RWcCQPMGFPueRKqoy1mpgjHcSgtsRXLrZ8S4CU8w6O6pxkKa3JbJD7QNyiHb4o95TSKkdTBYs8uUOCRKPu6BbvG
NklpTCRzUgZK
O/lcQwmJXl1CGr5vQAbpM7TRNkx6XusYrO
Effectuez la course chronométrée avec notre énorme testfile
:
Maintenant, faisons d'abord une seule exécution chronométrée avec les deux commandes pour estimer avec quelle ampleur nous travaillons.
$ time sed '1d' testfile > /dev/null
real 0m2.104s
user 0m1.944s
sys 0m0.156s
$ time tail -n +2 testfile > /dev/null
real 0m0.181s
user 0m0.044s
sys 0m0.132s
On voit déjà un résultat vraiment clair pour les gros fichiers, tail
c'est une amplitude plus rapide que sed
. Mais juste pour le plaisir et pour être sûr qu'il n'y a pas d'effets secondaires aléatoires qui font une grande différence, faisons-le 100 fois:
$ time for i in {1..100}; do sed '1d' testfile > /dev/null; done
real 3m36.756s
user 3m19.756s
sys 0m15.792s
$ time for i in {1..100}; do tail -n +2 testfile > /dev/null; done
real 0m14.573s
user 0m1.876s
sys 0m12.420s
La conclusion reste la même, sed
est inefficace pour supprimer la première ligne d'un gros fichier, tail
doit y être utilisée.
Et oui, je sais que les constructions de boucles de Bash sont lentes, mais nous ne faisons que relativement peu d'itérations ici et le temps qu'une boucle simple prend n'est pas significatif par rapport aux sed
/ tail
runtimes de toute façon.
Timing de petits fichiers:
Mise en place d'un petit testfile
:
Maintenant, pour être complet, regardons le cas le plus courant où vous avez un petit fichier d'entrée dans la plage de Ko. Créons un fichier d'entrée aléatoire avec numoflines=100
, ressemblant à ceci:
$ wc -l testfile
100 testfile
$ du -h testfile
8,0K testfile
$ head -n 3 testfile
tYMWxhi7GqV0DjWd
pemd0y3NgfBK4G4ho/
aItY/8crld2tZvsU5ly
Effectuez la course chronométrée avec notre petit testfile
:
Comme nous pouvons nous attendre à ce que le timing de ces petits fichiers soit de l'ordre de quelques millisecondes par expérience, faisons tout de suite 1000 itérations:
$ time for i in {1..1000}; do sed '1d' testfile > /dev/null; done
real 0m7.811s
user 0m0.412s
sys 0m7.020s
$ time for i in {1..1000}; do tail -n +2 testfile > /dev/null; done
real 0m7.485s
user 0m0.292s
sys 0m6.020s
Comme vous pouvez le voir, les horaires sont assez similaires, il n'y a pas grand-chose à interpréter ou à s'interroger. Pour les petits fichiers, les deux outils sont tout aussi bien adaptés.
sed
est plus portable: "+2" pourtail
fonctionne bien sur Ubuntu, qui utilise GNUtail
, mais ne fonctionnera pas sur BSDtail
.