Cette commande dépend du shell qui génère 5000 arguments et les transmet à printf
qui les ignore ensuite. Bien que cela puisse sembler assez rapide - et est relatif à certaines choses - le shell doit toujours générer toutes ces chaînes en tant qu'args (et les délimiter) et ainsi de suite.
Outre le fait que les H générés ne peuvent pas être imprimés avant que le shell n'itère pour la première fois à 5000, cette commande coûte également en mémoire tout ce qu'il faut pour stocker et délimiter les arguments de chaîne numérique en printf
plus des H. Vous pouvez tout aussi simplement faire:
printf %05000s|tr \ H
... qui génère une chaîne de 5000 espaces - qui, au moins, ne sont généralement qu'un seul octet par et ne coûtent rien à délimiter car ils ne sont pas délimités. Quelques tests indiquent que même pour aussi peu que 5000 octets, le coût de la fourche et du tuyau requis en tr
vaut la peine, même dans ce cas, et c'est presque toujours lorsque les chiffres augmentent.
J'ai couru...
time bash -c 'printf H%.0s {1..5000}' >/dev/null
...et...
time bash -c 'printf %05000s|tr \ H' >/dev/null
Chaque fois environ 5 fois une pièce (rien de scientifique ici - seulement anecdotique) et la version d'extension de l'accolade en moyenne un peu plus de 0,02 seconde de temps de traitement total, mais la tr
version est arrivée à environ 0,012 seconde au total en moyenne - et la tr
version l' a battu à chaque fois. Je ne peux pas dire que je suis surpris - {brace expansion}
est une fonctionnalité raccourcie interactive du shell, mais c'est généralement une chose plutôt inutile à faire pour tout type de script. La forme commune:
for i in {[num]..[num]}; do ...
... quand vous y pensez, il y a vraiment deux for
boucles - la première est interne et implique que le shell doit boucler d'une manière ou d'une autre pour générer ces itérateurs avant de les enregistrer tous et de les réitérer pour votre for
boucle. De telles choses sont généralement mieux faites comme:
iterator=$start
until [ "$((iterator+=interval))" -gt "$end" ]; do ...
... car vous ne stockez que très peu de valeurs et les écrasez au fur et à mesure ainsi que l'itération pendant que vous générez les itérables.
Quoi qu'il en soit, comme le remplissage d'espace mentionné précédemment, vous pouvez également utiliser printf
pour zéros un nombre arbitraire de chiffres, bien sûr, comme:
printf %05000d
Je fais les deux sans arguments parce que pour chaque argument spécifié dans printf
la chaîne de format de quand un argument n'est pas trouvé, la chaîne nulle est utilisée - ce qui est interprété comme un zéro pour un argument numérique ou une chaîne vide pour une chaîne.
C'est l'autre côté (et - à mon avis - plus efficace) de la pièce par rapport à la commande dans la question - alors qu'il est possible de ne rien obtenir de quelque chose comme vous le faites lorsque vous printf %.0
longueurz des chaînes pour chaque argument, il en va de même pour il est possible de tirer quelque chose de rien.
Plus rapide encore pour de grandes quantités d'octets générés que vous pouvez utiliser dd
comme:
printf \\0| dd bs=64k conv=sync
... et w / fichiers réguliers de dd
l » seek=[num]
argument peut être utilisé pour plus grand avantage. Vous pouvez obtenir 64 000 sauts de ligne plutôt que des valeurs nulles si vous ajoutez ,unblock cbs=1
à ce qui précède et à partir de là, vous pouvez injecter des chaînes arbitraires par ligne avec paste
et /dev/null
- mais dans ce cas, s'il est disponible, vous pouvez aussi utiliser:
yes 'output string forever'
Voici dd
quand même quelques exemples:
dd bs=5000 seek=1 if=/dev/null of=./H.txt
... qui crée (ou tronque) un \0NUL
fichier rempli dans le répertoire courant nommé H.txt de taille 5000 octets. dd
recherche directement le décalage et remplit NUL tout derrière.
<&1 dd bs=5000 conv=sync,noerror count=1 | tr \\0 H >./H.txt
... qui crée un fichier du même nom et de la même taille mais rempli de caractères H / H. Il tire parti du dd
comportement spécifié par l'écriture d'au moins un bloc nul complet en cas d'erreur de lecture lorsque noerror
et les sync
conversions sont spécifiées (et - sans count=
- continuerait probablement plus longtemps que vous ne le souhaiteriez) , et redirige intentionnellement un descripteur de fichier en écriture seule sur dd
stdin.
tcsh
ouzsh
,repeat 5000 printf H
est plus facile à comprendre. Avecperl
:print "H" x 5000
(notez que{1..5000}
c'est un opérateur zsh inspiré parperl
l »1..5000
un, puis copié par ksh93 et bash)