To polecenie zależy od powłoki, która generuje 5000 argumentów i przekazuje je, printf
a następnie je ignoruje. Chociaż może się to wydawać dość szybkie - i jest związane z niektórymi rzeczami - powłoka musi nadal generować wszystkie te ciągi jako argumenty (i rozgraniczać je) i tak dalej.
Oprócz faktu, że wygenerowane Hs nie może zostać wydrukowane, dopóki powłoka nie wykona iteracji po raz pierwszy do 5000, to polecenie kosztuje również w pamięci wszystko, czego potrzeba, aby przechowywać i ograniczać argumenty ciągów liczbowych do printf
plus Hs. Tak samo po prostu możesz zrobić:
printf %05000s|tr \ H
... który generuje ciąg 5000 spacji - które przynajmniej są zwykle tylko jednym bajtem na i nic nie kosztują, ponieważ nie są rozdzielane. Kilka testów wskazuje, że nawet za 5000 bajtów koszt widelca i wymaganej rury tr
jest tego wart nawet w tym przypadku i prawie zawsze ma miejsce, gdy liczba rośnie.
Pobiegłem ...
time bash -c 'printf H%.0s {1..5000}' >/dev/null
...i...
time bash -c 'printf %05000s|tr \ H' >/dev/null
Każde około 5 razy w kawałku (tutaj nic naukowego - tylko anegdotyczne) i wersja rozszerzenia nawiasów średnio tr
trwało nieco ponad 0,02 sekundy w łącznym czasie przetwarzania, ale wersja pojawiła się w przybliżeniu w sumie około 0,012 sekundy - i tr
wersja pobiła go każdego razu. Nie mogę powiedzieć, że jestem zaskoczony - {brace expansion}
jest to przydatna interaktywna funkcja skrótu powłoki, ale zwykle jest raczej marnotrawstwem w przypadku wszelkiego rodzaju skryptów. Wspólna forma:
for i in {[num]..[num]}; do ...
... kiedy się nad tym zastanowić, to tak naprawdę dwie for
pętle - pierwsza jest wewnętrzna i implikuje to, że powłoka musi się w jakiś sposób zapętlić, aby wygenerować te iteratory przed zapisaniem ich wszystkich i powtórzeniem ich dla for
pętli. Takie rzeczy są zwykle lepiej wykonywane, jak:
iterator=$start
until [ "$((iterator+=interval))" -gt "$end" ]; do ...
... ponieważ przechowujesz tylko kilka wartości i nadpisujesz je podczas pracy, a także wykonujesz iterację podczas generowania iteracji.
W każdym razie, podobnie jak wspomniane wcześniej wypełnienie spacji, możesz również printf
zerować dowolną liczbę cyfr, na przykład:
printf %05000d
Robię oba bez argumentów, ponieważ dla każdego argumentu określonego w printf
łańcuchu formatu, gdy argument nie zostanie znaleziony, używany jest łańcuch zerowy - co jest interpretowane jako zero dla argumentu cyfrowego lub pusty ciąg dla łańcucha.
Jest to druga (i - moim zdaniem - bardziej wydajna) strona medalu w porównaniu z poleceniem w pytaniu - podczas gdy nie można nic z niczego uzyskać, tak jak robisz, gdy printf %.0
długości ciągów dla każdego argumentu, więc również jest można uzyskać coś z niczego.
Jest jeszcze szybszy dla dużych ilości generowanych bajtów, których możesz użyć, dd
takich jak:
printf \\0| dd bs=64k conv=sync
... i / regularny w pliki dd
„s seek=[num]
argument może być używany do większej przewagi. Możesz uzyskać 64 tys. Nowych linii zamiast zer, jeśli dodasz ,unblock cbs=1
do powyższego, a stamtąd możesz wstrzykiwać dowolne ciągi na linię za pomocą paste
i /dev/null
- ale w takim przypadku, jeśli jest on dostępny, możesz również użyć:
yes 'output string forever'
Oto kilka innych dd
przykładów:
dd bs=5000 seek=1 if=/dev/null of=./H.txt
... który tworzy (lub skraca) do \0NUL
pliku wypełniony bieżącym katalogu o nazwie H.txt o rozmiarze 5000 bajtów. dd
dąży prosto do przesunięcia i NUL-wypełnia wszystko za nim.
<&1 dd bs=5000 conv=sync,noerror count=1 | tr \\0 H >./H.txt
... który tworzy plik o tej samej nazwie i rozmiarze, ale wypełniony znakami w / H. To wykorzystuje dd
„s spec''d zachowań pisać co najmniej jeden pełny blok zerowy w przypadku błędu odczytu, kiedy noerror
i sync
konwersje są określone (i - bez count=
- będzie prawdopodobnie trwać dłużej niż można chcieć) i celowo przekierowuje deskryptor pliku tylko do zapisu na dd
stdin.
tcsh
lubzsh
,repeat 5000 printf H
jest łatwiejsza do zrozumienia. Zperl
:print "H" x 5000
(zauważ, że{1..5000}
to zsh operator zainspirowanyperl
„s1..5000
jednym i później kopiowane przez ksh93 i bash)