Do tej pory Nagroda za Bezużyteczne Wykorzystaniecat
jest bardzo dobrze znana, jest też wzmianka o Bezużytecznym Wykorzystaniuecho
(nie dotyczy tego pytania). Zastanawiam się, czy powinna istnieć „ echo
Nagroda za bezużyteczne wykorzystanie w Bash”: Według niektórych nienaukowych pomiarów orurowanie wydaje się być znacznie wolniejsze niż heredoki i tustringi:
Heredocs:
for reps in 1 2 3 do time for i in {1..1000} do cat <<'END' test string END done > /dev/null done real 0m1.786s user 0m0.212s sys 0m0.332s real 0m1.817s user 0m0.232s sys 0m0.332s real 0m1.846s user 0m0.256s sys 0m0.320s
Herestrings
for reps in 1 2 3 do time for i in {1..1000} do cat <<< 'test string' done > /dev/null done real 0m1.932s user 0m0.280s sys 0m0.288s real 0m1.956s user 0m0.248s sys 0m0.348s real 0m1.968s user 0m0.268s sys 0m0.324s
Przekierowanie
for reps in 1 2 3 do time for i in {1..1000} do echo 'test string' | cat done > /dev/null done real 0m3.562s user 0m0.416s sys 0m0.548s real 0m3.924s user 0m0.384s sys 0m0.604s real 0m3.343s user 0m0.400s sys 0m0.552s
Ogólnie rzecz biorąc, heredoki i instrukcje mają mniej więcej tę samą prędkość (jest to tylko jeden zestaw danych z kilku testów), podczas gdy przekierowanie jest konsekwentnie o ponad 50% wolniejsze. Czy coś źle zrozumiałem, czy może to być ogólną zasadą dla komend czytających standardowe dane wejściowe w Bash?
seq
” ;-)cat <<END
vs.cat <<< "test string"
vs.echo "test string" | cat
lubcat <<'END'
vs.cat <<< 'test string'
vs.,echo 'test string' | cat
aby powłoka wykonała taką samą liczbę rozszerzeń na łańcuchach.$(seq $reps)
?Odpowiedzi:
Po pierwsze, skoncentrujmy się na wydajności. Przeprowadziłem testy porównawcze dla nieco innego programu na skądinąd w większości bezczynnym procesorze x86_64 z uruchomionym ściśnięciem Debiana.
herestring.bash
, używając ciągu znaków, aby przekazać wiersz danych wejściowych:heredoc.bash
, używając heredoc, aby przekazać wiersz danych wejściowych:echo.bash
, za pomocąecho
i potoku do przekazania linii danych wejściowych:Dla porównania, skrypty mierzyłem także pod ATT ksh93 i pod myślnikiem (z wyjątkiem tego
herestring.bash
, że myślnik nie ma opisów).Oto mediana z trzech razy:
Wnioski:
echo
a rura jest zauważalnie, ale nie dramatycznie szybsza. (Należy pamiętać, że jest to program zabawkowy: w prawdziwym programie większość czasu przetwarzania byłaby w tym, cotr
oznacza połączenie).Oprócz wydajności istnieje także przejrzystość i przenośność.
<<<
to rozszerzenie ksh93 / bash / zsh, które jest mniej znane niżecho … |
lub<<
. Nie działa w ksh88 / pdksh ani w POSIX sh.Jedynym miejscem, w którym
<<<
jest zapewne znacznie wyraźniejsze, jest heredoc:vs
(Większość powłok nie radzi sobie z zamykaniem nawiasów na końcu wiersza zawierającego
<<EOF
.)źródło
<<<
pochodzirc
i został po raz pierwszy wprowadzony do świata muszli podobnych do Bourne'azsh
.rc
nie dodać do nowej linii spływu, ale wszystkichbash
,zsh
iksh93
zrobić AFAICT.rc
wykorzystuje rurę tam, podczasbash
,zsh
iksh93
użyć pliku tymczasowego jak dla heredocs.<<<
jeszcze mniej przydatny.zsh
ma optymalizację w=(<<<foo)
celu efektywnego utworzenia pliku tymczasowego zawierającego „foo”, który nie wymaga rozwikłania procesu=(echo foo)
.<<<
.Innym powodem używania heredoków (jeśli nie masz ich wystarczająco dużo) jest to, że echo może zawieść, jeśli strumień nie zostanie zużyty. Rozważ
pipefail
opcję „bash” :/bin/true
nie zużywa standardowych danych wejściowych, aleecho yawn
mimo to kończy działanie. Jeśli jednak echo zostanie poproszone o wydrukowanie dużej ilości danych, nie zostanie ono ukończone, dopókitrue
nie zostanie zakończone:141 to SIGPIPE (128 + 13) (dodano 128, ponieważ bash robi to zgodnie z bash (1):
Heredocs nie mają tego problemu:
źródło
pipefail
domyślnie jest wyłączony!pipefail
na początku każdego skryptu. Daj mi wszystkie błędy!Jednym z powodów, dla których możesz chcieć użyć echa, jest przejęcie kontroli nad znakiem nowej linii dodawanym na końcu heredoków i instrukcji:
Trzy znaki
foo
mają długość 3:Jednak ten ciąg znaków składa się z czterech znaków:
Hredok składający się z trzech postaci:
Czwarty znak to znak nowej linii
0x0a
.Jakoś to magicznie pasuje do sposobu, w jaki bash usuwa te znaki nowej linii podczas pobierania wyjścia z podpowłoki:
Oto polecenie, które zwraca cztery znaki:
foo
i\n
. „\ N” jest dodawane przez echo, zawsze dodaje znak nowej linii, chyba że podasz-n
opcję:Jednak przypisując to do zmiennej, końcowy znak nowej linii dodany przez echo jest usuwany:
Więc jeśli miksujesz pliki i zmienne i używasz ich w obliczeniach (np. Nie możesz używać heredoków lub ciągów znaków, ponieważ dodadzą one nową linię.
Jeśli zmienisz instrukcję if do przeczytania
wtedy test przechodzi.
źródło