Tale comando dipende dalla shell che genera 5000 argomenti e li passa a printf
cui li ignora. Mentre può sembrare piuttosto veloce - ed è relativo ad alcune cose - la shell deve comunque generare tutte quelle stringhe come args (e delimitarle) e così via.
Oltre al fatto che gli H generati non possono essere stampati fino a quando la shell non passa per la prima volta a 5000, quel comando costa anche in memoria tutto ciò che serve per archiviare e delimitare gli argomenti di stringa numerici a printf
più gli H. Proprio come puoi semplicemente fare:
printf %05000s|tr \ H
... che genera una stringa di 5000 spazi - che, almeno, di solito sono solo un singolo byte per e non costano nulla da delimitare perché non sono delimitati. Alcuni test indicano che anche per un minimo di 5000 byte il costo della forcella e del tubo richiesti tr
vale la pena anche in questo caso, e quasi sempre accade quando i numeri aumentano.
Mi sono imbattuto...
time bash -c 'printf H%.0s {1..5000}' >/dev/null
...e...
time bash -c 'printf %05000s|tr \ H' >/dev/null
Ciascuno circa 5 volte un pezzo (niente di scientifico qui - solo aneddotico) e la versione di espansione del controvento è stata in media di poco più di 0,02 secondi nel tempo totale di elaborazione, ma la tr
versione è arrivata a circa 0,02 secondi in totale - e la tr
versione ha battuto ogni volta. Non posso dire di essere sorpreso - {brace expansion}
è un'utile funzione di stenografia interattiva della shell, ma di solito è una cosa piuttosto dispendiosa da fare per qualsiasi tipo di scripting. La forma comune:
for i in {[num]..[num]}; do ...
... quando ci pensate, in realtà sono due for
loop: il primo è interno e implicito nel fatto che la shell deve eseguire un ciclo in qualche modo per generare quegli iteratori prima di salvarli tutti e iterarli nuovamente per il for
loop. Queste cose di solito sono fatte meglio come:
iterator=$start
until [ "$((iterator+=interval))" -gt "$end" ]; do ...
... perché memorizzi solo pochissimi valori e li sovrascrivi mentre vai oltre a fare l'iterazione mentre generi gli iterabili.
Ad ogni modo, come il padding spaziale menzionato in precedenza, puoi anche usare printf
per zeropad un numero arbitrario di cifre, ovviamente, come:
printf %05000d
Faccio entrambe le cose senza argomenti perché per ogni argomento specificato nella printf
stringa di formato quando non viene trovato un argomento viene utilizzata la stringa null, che viene interpretata come zero per un argomento digit o una stringa vuota per una stringa.
Questo è l'altro (e - a mio avviso - più efficiente) della medaglia rispetto al comando nella domanda - mentre è possibile non ottenere nulla da qualcosa come si fa quando si printf %.0
allungano le stringhe per ogni argomento, quindi è anche è possibile ottenere qualcosa dal nulla.
Ancora più veloce per grandi quantità di byte generati che puoi usare dd
come:
printf \\0| dd bs=64k conv=sync
... e l' argomento dd
dei file regolari seek=[num]
può essere usato per un maggiore vantaggio. Puoi ottenere 64k newline anziché null se aggiungi ,unblock cbs=1
a quanto sopra e da lì puoi iniettare stringhe arbitrarie per riga con paste
e /dev/null
- ma in tal caso, se è disponibile per te, puoi anche usare:
yes 'output string forever'
Ecco dd
comunque altri esempi:
dd bs=5000 seek=1 if=/dev/null of=./H.txt
... che crea (o tronca) un \0NUL
file riempito nella directory corrente denominata H.txt di dimensione 5000 byte. dd
cerca dritto all'offset e riempie NUL tutto dietro di esso.
<&1 dd bs=5000 conv=sync,noerror count=1 | tr \\0 H >./H.txt
... che crea un file con lo stesso nome e dimensione ma riempito con caratteri maiuscoli / minuscoli. Sfrutta dd
il comportamento specifico di scrivere almeno un blocco null completo in caso di un errore di lettura quando vengono specificate noerror
e le sync
conversioni (e - senza count=
- probabilmente andrebbero avanti più a lungo di quanto si possa desiderare) e reindirizzamenti intenzionali un descrittore di file scrivibile solo allo dd
stdin.
tcsh
ozsh
,repeat 5000 printf H
è più facile da capire. Conperl
:print "H" x 5000
(notare che che{1..5000}
è un operatore di zsh ispirato aperl
's1..5000
uno e poi copiato da ksh93 e bash)