Написання символу N разів за допомогою команди printf


12

Я знайшов таку команду для повторення символу в Linux:

printf 'H%.0s' {1..5000} > H.txt

Я хочу, наприклад, Hповторити 5000рази. Що %.0sтут означає?


З tcshабо zsh, repeat 5000 printf Hпростіше зрозуміти. З perl: print "H" x 5000(зауважте, що {1..5000}це zsh-оператор, натхненний one perl''s 1..5000та пізніше скопійований ksh93 та bash)
Stéphane Chazelas

так, це працює, але використовує багато ресурсів для більшого повторення, дотримуйтесь пропозицій Стефана Шазеласа
Скаперен

1
Я б зробив цю командуyes H|head -5000|tr -d '\012'
Скаперен

dd if=/dev/zero bs=5000 count=1 | tr '\0' H
Кейро

@Skaepren:yes H| head -n 2500| tr \\n H
mikeserv

Відповіді:


20

Ця команда залежить від оболонки, що генерує 5000 аргументів, і передаючи їх, printfпісля чого їх ігнорує. Хоча це може здатися досить швидким - і відносно деяких речей - оболонка все одно повинна генерувати всі ці рядки як аргументи (і розмежовувати їх) тощо.

Окрім того, що згенеровані Hs не можуть бути надруковані, поки оболонка спочатку не ітералізує 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 разів за шматок (нічого наукового тут - лише анекдотичне) і версія розширення брекетів в середньому за трохи перевищувала 0,02 секунди, але trверсія в середньому склала приблизно 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]можна використовувати аргумент для більшої вигоди. Ви можете отримати 64k нових рядків, а не нульових значень, якщо ви додасте ,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білд поведінку «s виписувати по крайней мере , один повний нуль-блок в разі помилки читання , коли noerrorі syncперетворення вказані (і - без count=- швидше за все , триватиме довше , ніж ви могли б хотіти) , і навмисно переадресовує дескриптор файлу тільки для запису на ddstdin.


8

Засіб %.0sконвертувати аргумент у вигляді рядка з точністю до нуля. Відповідно man 3 printf, значення точності в такому випадку дає

   [ ... ] the  maximum  number  of characters to be printed from a
   string for s and S conversions.

отже, коли точність дорівнює нулю, аргумент рядка взагалі не друкується. Однак H(що є частиною специфікатора формату) друкується стільки разів, скільки є аргументи, оскільки згідно з printfрозділомman bash

The format is reused as necessary to consume all  of  the  argu
ments.  If the format requires more arguments than are supplied,
the extra format specifications behave as if  a  zero  value  or
null  string,  as  appropriate,  had  been supplied. 

7

У цьому випадку %.0sзавжди друкується один екземпляр символів, що передує йому, H у цьому випадку. Коли ви використовуєте {1..5000}, оболонка розширює її, і вона стає:

printf 'H%.0s' 1 2 3 4 ... 5000 > H.txt

тобто команда printf тепер містить 5000 аргументів, і для кожного аргументу ви отримаєте один H. Вони не повинні бути послідовними чи числовими:

printf 'H%.0s' a bc fg 12 34

відбитки HHHHH- тобто кількість аргументів, 5 в даному випадку.

Зауважте, еліпси в першому прикладі вище не вставляються буквально, вони там, щоб вказати послідовність або діапазон.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.