Z tcshlub zsh, repeat 5000 printf Hjest łatwiejsza do zrozumienia. Z perl: print "H" x 5000(zauważ, że {1..5000}to zsh operator zainspirowany perl„s 1..5000jednym i później kopiowane przez ksh93 i bash)
Stéphane Chazelas
tak, to działa, ale zużywa dużo zasobów na większe powtórzenia, postępuj zgodnie z sugestiami Stéphane Chazelas
Skaperen
1
Zrobiłbym to polecenieyes H|head -5000|tr -d '\012'
Skaperen
dd if=/dev/zero bs=5000 count=1 | tr '\0' H
kojiro,
@Skaepren:yes H| head -n 2500| tr \\n H
mikeserv
Odpowiedzi:
20
To polecenie zależy od powłoki, która generuje 5000 argumentów i przekazuje je, printfa 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 printfplus 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 trjest 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 trtrwał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 trwersja 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ę dwiefor 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 forpętli. Takie rzeczy są zwykle lepiej wykonywane, jak:
... 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ż printfzerować 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 %.0dł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ć, ddtakich 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=1do powyższego, a stamtąd możesz wstrzykiwać dowolne ciągi na linię za pomocą pastei /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 ddprzykładów:
dd bs=5000 seek=1if=/dev/null of=./H.txt
... który tworzy (lub skraca) do \0NULpliku wypełniony bieżącym katalogu o nazwie H.txt o rozmiarze 5000 bajtów. dddąż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 noerrori synckonwersje 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 ddstdin.
Sposób %.0sprzekonwertowania argumentu na ciąg znaków z dokładnością do zera. Zgodnie z man 3 printf, wartość precyzji w takim przypadku daje
[...] the maximum number of characters to be printed from a
string for s and S conversions.
dlatego gdy precyzja wynosi zero, argument łańcuchowy nie jest w ogóle drukowany. Jednak H(który jest częścią specyfikatora formatu) jest drukowany tyle razy, ile jest argumentów, ponieważ zgodnie z printfsekcją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.
W takim przypadku %.0szawsze drukuje jedno wystąpienie poprzedzającego go znaku (znaków), w tym przypadku H. Gdy użyjesz {1..5000}, powłoka rozwija go i staje się:
printf 'H%.0s'1234...5000> H.txt
tzn. polecenie printf ma teraz 5000 argumentów, a dla każdego argumentu otrzymasz jeden H. Nie muszą one być sekwencyjne ani numeryczne:
printf 'H%.0s' a bc fg 1234
wypisuje HHHHH- tzn. liczbę argumentów, w tym przypadku 5.
Uwaga: elipsy w pierwszym przykładzie powyżej nie są wstawiane dosłownie, lecz służą do wskazania sekwencji lub zakresu.
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)yes H|head -5000|tr -d '\012'
dd if=/dev/zero bs=5000 count=1 | tr '\0' H
yes H| head -n 2500| tr \\n H
Odpowiedzi:
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ć:... 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 ...
...i...
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 - itr
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:... 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 dlafor
pętli. Takie rzeczy są zwykle lepiej wykonywane, jak:... 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: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:... i / regularny w pliki
dd
„sseek=[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ć:Oto kilka innych
dd
przykładów:... 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.... 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, kiedynoerror
isync
konwersje są określone (i - bezcount=
- będzie prawdopodobnie trwać dłużej niż można chcieć) i celowo przekierowuje deskryptor pliku tylko do zapisu nadd
stdin.źródło
Sposób
%.0s
przekonwertowania argumentu na ciąg znaków z dokładnością do zera. Zgodnie zman 3 printf
, wartość precyzji w takim przypadku dajedlatego gdy precyzja wynosi zero, argument łańcuchowy nie jest w ogóle drukowany. Jednak
H
(który jest częścią specyfikatora formatu) jest drukowany tyle razy, ile jest argumentów, ponieważ zgodnie zprintf
sekcjąman bash
źródło
W takim przypadku
%.0s
zawsze drukuje jedno wystąpienie poprzedzającego go znaku (znaków), w tym przypadku H. Gdy użyjesz {1..5000}, powłoka rozwija go i staje się:tzn. polecenie printf ma teraz 5000 argumentów, a dla każdego argumentu otrzymasz jeden H. Nie muszą one być sekwencyjne ani numeryczne:
wypisuje
HHHHH
- tzn. liczbę argumentów, w tym przypadku 5.Uwaga: elipsy w pierwszym przykładzie powyżej nie są wstawiane dosłownie, lecz służą do wskazania sekwencji lub zakresu.
źródło