Ese comando depende de que el shell genere 5000 argumentos y se los pase y printf
luego los ignore. Si bien puede parecer bastante rápido, y es relativo a algunas cosas, el shell aún debe generar todas esas cadenas como args (y delimitarlas), etc.
Además del hecho de que las Hs generadas no pueden imprimirse hasta que el shell se itera por primera vez a 5000, ese comando también cuesta en la memoria todo lo que se necesita para almacenar y delimitar los argumentos de cadena numérica printf
más las Hs. Así de simple puedes hacer:
printf %05000s|tr \ H
... que genera una cadena de 5000 espacios, que, al menos, suelen ser de un solo byte y no cuesta nada delimitarlos porque no están delimitados. Algunas pruebas indican que incluso por tan solo 5000 bytes, el costo de la horquilla y la tubería requerida tr
vale la pena incluso en este caso, y casi siempre es cuando los números aumentan.
Corrí...
time bash -c 'printf H%.0s {1..5000}' >/dev/null
...y...
time bash -c 'printf %05000s|tr \ H' >/dev/null
Cada una de aproximadamente 5 veces por pieza (nada científico aquí, solo anecdótico) y la versión de expansión del aparato ortopédico promedió un poco más de .02 segundos en el tiempo total de procesamiento, pero la tr
versión llegó a alrededor de .012 segundos en promedio en promedio, y la tr
versión la superó cada vez. No puedo decir que me sorprenda, {brace expansion}
es una característica útil de la taquigrafía de la shell interactiva, pero generalmente es algo bastante inútil para cualquier tipo de scripting. La forma común:
for i in {[num]..[num]}; do ...
... cuando lo piensas, en realidad son dos for
bucles: el primero es interno e implica que el shell debe realizar un bucle de alguna manera para generar esos iteradores antes de guardarlos e iterarlos nuevamente para tu for
bucle. Tales cosas generalmente se hacen mejor como:
iterator=$start
until [ "$((iterator+=interval))" -gt "$end" ]; do ...
... porque almacena solo unos pocos valores y los sobrescribe a medida que avanza, así como realiza la iteración mientras genera los iterables.
De todos modos, al igual que el relleno de espacio mencionado anteriormente, también puede usar printf
para poner a cero un número arbitrario de dígitos, por supuesto, como:
printf %05000d
Hago ambas cosas sin argumentos porque para cada argumento especificado en printf
la cadena de formato cuando no se encuentra un argumento, se usa la cadena nula, que se interpreta como un cero para un argumento de dígitos o una cadena vacía para una cadena.
Este es el otro lado (y, en mi opinión, más eficiente) de la moneda en comparación con el comando en la pregunta, mientras que es posible no obtener nada de algo como lo hace cuando printf %.0
alarga las cadenas para cada argumento, también lo es Es posible obtener algo de la nada.
Aún más rápido para grandes cantidades de bytes generados que puede usar dd
como:
printf \\0| dd bs=64k conv=sync
... y w / archivos normales dd
's seek=[num]
argumento pueden ser utilizados en forma más adecuada. Puede obtener 64k nuevas líneas en lugar de nulos si agrega ,unblock cbs=1
a lo anterior y desde allí podría inyectar cadenas arbitrarias por línea con paste
y /dev/null
, pero en ese caso, si está disponible para usted, también podría usar:
yes 'output string forever'
Aquí hay algunos dd
ejemplos más de todos modos:
dd bs=5000 seek=1 if=/dev/null of=./H.txt
... que crea (o trunca) un \0NUL
archivo lleno en el directorio actual llamado H.txt de tamaño 5000 bytes. dd
busca directamente al desplazamiento y NUL-llena todo detrás de él.
<&1 dd bs=5000 conv=sync,noerror count=1 | tr \\0 H >./H.txt
... que crea un archivo del mismo nombre y tamaño pero lleno de caracteres w / H. Aprovecha dd
el comportamiento específico de escribir al menos un bloque nulo completo en caso de un error de lectura cuando se especifican noerror
y las sync
conversiones (y, sin count=
, probablemente durarían más de lo que podría desear) , y redirige intencionalmente un descriptor de archivo de solo escritura en dd
la entrada estándar.
tcsh
ozsh
,repeat 5000 printf H
es más fácil de entender. Conperl
:print "H" x 5000
(nota que esto{1..5000}
es un operador zsh inspirado enperl
's1..5000
uno y más tarde copiado por ksh93 y bash)