Эта команда зависит от оболочки, генерирующей 5000 аргументов и передающей их, printf
которая затем игнорирует их. Хотя это может показаться довольно быстрым - и относительно некоторых вещей - оболочка все равно должна генерировать все эти строки как аргументы (и разделять их) и так далее.
Помимо того факта, что сгенерированные H не могут быть напечатаны до тех пор, пока оболочка не выполнит итерацию до 5000, эта команда также стоит в памяти все, что требуется для хранения и ограничения числовых строковых аргументов printf
плюс Hs. Так же просто, как вы можете сделать:
printf %05000s|tr \ H
... который генерирует строку из 5000 пробелов, которые, по крайней мере, обычно занимают всего один байт и ничего не стоят для разделения, поскольку они не разделены. Несколько тестов показывают, что даже для всего лишь 5000 байт стоимость вилки и трубы, требуемой для tr
нее, оправдывает себя даже в этом случае, и почти всегда это происходит, когда числа становятся выше.
Я побежал ...
time bash -c 'printf H%.0s {1..5000}' >/dev/null
...и...
time bash -c 'printf %05000s|tr \ H' >/dev/null
Каждый примерно 5 раз за штуку (ничего научного здесь - только анекдотичный), и версия расширения фигурной скобки в среднем tr
занимала чуть более 0,02 секунды в общем времени обработки, но версия в среднем занимала около 0,012 секунды - и tr
версия побеждала каждый раз. Я не могу сказать, что удивлен - {brace expansion}
это полезная функция сокращенной интерактивной оболочки, но обычно она довольно расточительна, когда речь идет о любом виде сценариев. Распространенная форма:
for i in {[num]..[num]}; do ...
... когда вы думаете об этом, на самом деле это два for
цикла - первый является внутренним и подразумевает, что оболочка должна каким-то образом выполнить цикл для генерации этих итераторов, прежде чем сохранять их все и повторять их снова для вашего for
цикла. Такие вещи обычно лучше сделать как:
iterator=$start
until [ "$((iterator+=interval))" -gt "$end" ]; do ...
... потому что вы сохраняете только очень немного значений и перезаписываете их по мере выполнения, а также выполняете итерацию, пока генерируете итерации.
В любом случае, как и в случае с пробелом, упомянутым выше, вы можете также использовать printf
для нумерации произвольное количество цифр, например:
printf %05000d
Я делаю оба без аргументов, потому что для каждого аргумента, указанного в printf
строке формата, когда аргумент не найден, используется пустая строка, которая интерпретируется как ноль для аргумента с цифрой или пустая строка для строки.
Это другая (и, на мой взгляд, более эффективная) сторона медали по сравнению с командой, о которой идет речь, - хотя можно получить что-то от чего-либо, как вы, когда вы printf %.0
длина строк для каждого аргумента, также можно получить что-то из ничего.
Еще быстрее для большого количества сгенерированных байтов, которые вы можете использовать dd
как:
printf \\0| dd bs=64k conv=sync
... и аргумент dd
с обычными файлами seek=[num]
может быть использован для большего преимущества. Вы можете получить 64 тыс. Новых строк, а не нулей, если добавите ,unblock cbs=1
к вышеупомянутому и оттуда можете вставлять произвольные строки в строку с помощью paste
и /dev/null
- но в этом случае, если это доступно для вас, вы также можете использовать:
yes 'output string forever'
Вот еще несколько dd
примеров:
dd bs=5000 seek=1 if=/dev/null of=./H.txt
... который создает (или усекает) в \0NUL
заполненный файл в текущем каталоге с именем H.txt от размера 5000 байт. dd
стремится прямо к смещению и заполняет все NUL за ним.
<&1 dd bs=5000 conv=sync,noerror count=1 | tr \\0 H >./H.txt
... который создает файл с тем же именем и размером, но заполненный символами W / H. Он использует преимущества dd
специфицированного поведения по записи по крайней мере одного полного нулевого блока в случае ошибки чтения, когда указаны noerror
и sync
преобразования (и - без count=
- скорее всего, будет длиться дольше, чем вы хотели) , и намеренно перенаправляет файловый дескриптор, доступный только для записи, в dd
stdin.
tcsh
илиzsh
,repeat 5000 printf H
проще понять. Сperl
:print "H" x 5000
(обратите внимание, что{1..5000}
это оператор zsh, вдохновленный операторомperl
s,1..5000
а затем скопированным ksh93 и bash)