Эта команда зависит от оболочки, генерирующей 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=- скорее всего, будет длиться дольше, чем вы хотели) , и намеренно перенаправляет файловый дескриптор, доступный только для записи, в ddstdin.
tcshилиzsh,repeat 5000 printf Hпроще понять. Сperl:print "H" x 5000(обратите внимание, что{1..5000}это оператор zsh, вдохновленный операторомperls,1..5000а затем скопированным ksh93 и bash)