Słyszałem, że printf
to lepsze niż echo
. Mogę przypomnieć sobie tylko jedną instancję z mojego doświadczenia, z której musiałem skorzystać, printf
ponieważ echo
nie działałem do dostarczenia tekstu do jakiegoś programu na RHEL 5.8, ale to printf
zrobiłem. Ale najwyraźniej istnieją inne różnice i chciałbym dowiedzieć się, jakie one są, a także czy istnieją konkretne przypadki, w których można użyć jednego kontra drugiego.
text-processing
echo
printf
amfibia
źródło
źródło
echo -e
?echo -e
nie działash
, tylko wbash
(z jakiegoś powodu), a na przykładsh
RUN
echo -e
dla mnie działa w Android Terminal, czyli w zasadziesh
.Odpowiedzi:
Zasadniczo jest to kwestia przenośności (i niezawodności).
Początkowo
echo
nie akceptowałem żadnej opcji i niczego nie rozwijałem. Wszystko, co robił, to wypisywanie argumentów oddzielonych znakiem spacji i kończonych znakiem nowej linii.Teraz ktoś pomyślał, że byłoby miło, gdybyśmy mogli zrobić takie rzeczy, jak
echo "\n\t"
wypisywanie znaków nowej linii lub tabulacji, lub mieć opcję, aby nie wypuszczać końcowego znaku nowej linii.Następnie zastanowili się mocniej, ale zamiast dodania tej funkcji do powłoki (tak jak
perl
tam, gdzie podwójne cudzysłowy\t
faktycznie oznaczają znak tabulacji), dodali jąecho
.David Korn sobie sprawę z błędu i wprowadził nową formę cytatów powłoki:
$'...'
który został później kopiowane przezbash
azsh
ale było zbyt późno do tego czasu.Teraz, gdy standardowy UNIX
echo
otrzymuje argument zawierający dwa znaki\
it
zamiast wypisywać je, wypisuje znak tabulacji. I gdy tylko zobaczy\c
argument, przestaje wypisywać (więc końcowy znak nowej linii też nie jest wypisywany).Inni dostawcy powłok / wersji Unixa wybrali to inaczej: dodali
-e
opcję rozwijania sekwencji specjalnych i-n
opcję nie wysyłania końcowego znaku nowej linii. Niektóre muszą-E
wyłączyć sekwencje specjalne, niektóre mają,-n
ale nie-e
, lista sekwencji specjalnych obsługiwanych przez jednąecho
implementację niekoniecznie jest taka sama jak obsługiwana przez inną.Sven Mascheck ma ładną stronę, która pokazuje skalę problemu .
Z powyższych
echo
implementacjach że opcje pomocy, tam zazwyczaj nie poparcie--
, aby zaznaczyć koniec opcji (naecho
polecenie wbudowane niektórych non-Bourne podobnych muszli zrobienia i zsh obsługuje-
do tego jednak), więc na przykład, trudno jest wyjście"-n"
zecho
w wiele muszli.W niektórych muszli jak
bash
đ lubksh93
² lubyash
($ECHO_STYLE
zmienna), zachowanie nawet zależy powłoki opracowano lub środowiska (GNUecho
"zachowania s będą także zmieniać$POSIXLY_CORRECT
się w środowisku, w wersji 4 ,zsh
jest zbsd_echo
opcją niektóre oparte na pdksh z ichposix
opcją lub czy są wywoływane jakosh
czy nie). Tak więc dwabash
echo
s, nawet z tej samej wersji,bash
nie mają gwarancji, że zachowają się tak samo.POSIX mówi: jeśli pierwszy argument
-n
lub dowolny argument zawiera ukośniki odwrotne, zachowanie jest nieokreślone .bash
echo w tym względzie nie jest POSIX, ponieważ na przykładecho -e
nie jest generowane,-e<newline>
jak wymaga POSIX. Specyfikacja UNIX jest bardziej rygorystyczna, zabrania-n
i wymaga rozszerzania niektórych sekwencji ucieczki, w tym tej,\c
aby zatrzymać wysyłanie.Te specyfikacje tak naprawdę nie przydają się tutaj, biorąc pod uwagę, że wiele implementacji jest niezgodnych. Nawet niektóre certyfikowane systemy, takie jak macOS 5, nie są zgodne.
Aby naprawdę przedstawić aktualną rzeczywistość, POSIX powinien w rzeczywistości powiedzieć : jeśli pierwszy argument pasuje do
^-([eEn]*|-help|-version)$
rozszerzonegoα
wyrażenia regularnego lub dowolny argument zawiera odwrotne ukośniki (lub znaki, których kodowanie zawiera kodowanie znaku odwrotnego ukośnika, tak jak w lokalizacjach używających zestawu znaków BIG5), wówczas zachowanie jest następujące: nieokreślony.Podsumowując, nie wiesz, co
echo "$var"
wyświetli, chyba że możesz upewnić się, że$var
nie zawiera znaków odwrotnego ukośnika i nie zaczyna się od-
. W tym przypadku specyfikacja POSIX mówi nam, abyśmyprintf
zamiast tego używali .Oznacza to, że nie można używać
echo
do wyświetlania niekontrolowanych danych. Innymi słowy, jeśli piszesz skrypt i pobiera on dane zewnętrzne (od użytkownika jako argumenty lub nazwy plików z systemu plików ...), nie możesz go użyćecho
do wyświetlenia.To jest wporządku:
To nie jest:
(Chociaż będzie działać OK z niektórymi (niezgodnymi z UNIX)
echo
implementacjami, takimi jakbash
s, gdyxpg_echo
opcja nie została włączona w taki czy inny sposób, jak w czasie kompilacji lub przez środowisko).file=$(echo "$var" | tr ' ' _)
nie jest w porządku w większości implementacji (wyjątkami sąyash
zECHO_STYLE=raw
(z zastrzeżeniem, żeyash
„s zmienne nie mogą posiadać dowolne sekwencje bajtów, więc nie arbitralne nazwy pliku) izsh
” secho -E - "$var"
6 ).printf
, z drugiej strony jest bardziej niezawodny, przynajmniej gdy ogranicza się do podstawowego użyciaecho
.Wyświetla zawartość
$var
znaku, po którym następuje znak nowej linii, niezależnie od tego, jaki znak może zawierać.Wyprowadzi go bez końcowego znaku nowej linii.
Istnieją także różnice między
printf
implementacjami. Istnieje rdzeń funkcji określonych przez POSIX, ale istnieje wiele rozszerzeń. Na przykład niektórzy popierają a,%q
aby zacytować argumenty, ale sposób wykonania różni się w zależności od powłoki, niektóre obsługują\uxxxx
znaki Unicode. Zachowanie różni sięprintf '%10s\n' "$var"
w przypadku wielobajtowych lokalizacji, istnieją co najmniej trzy różne wynikiprintf %b '\123'
Ale w końcu, jeśli trzymasz się zestawu funkcji POSIX
printf
i nie próbujesz robić z nim nic szczególnego, nie masz problemów.Pamiętaj jednak, że pierwszym argumentem jest format, więc nie powinien zawierać zmiennych / niekontrolowanych danych.
Bardziej niezawodny
echo
można wdrożyć za pomocąprintf
:Podpowłoki (która implikuje spawnowanie dodatkowego procesu w większości implementacji powłoki) można uniknąć za
local IFS
pomocą wielu powłok lub pisząc je w następujący sposób:Uwagi
1. jaki
bash
jestecho
zachowanie może być zmienione.W
bash
czasie wykonywania istnieją dwie rzeczy, które kontrolują zachowanieecho
(obokenable -n echo
lub przedefiniowanieecho
jako funkcji lub aliasu):xpg_echo
bash
opcja ibash
to, czy jest w trybie POSIX.posix
Tryb można włączyć, jeślibash
jest wywoływany jakosh
lubPOSIXLY_CORRECT
w środowisku lub zposix
opcją:Domyślne zachowanie w większości systemów:
xpg_echo
rozwija sekwencje, ponieważ UNIX wymaga:Nadal honoruje
-n
i-e
(i-E
):W
xpg_echo
trybie POSIX i:Tym razem
bash
jest zgodny zarówno z POSIX, jak i UNIX. Zauważ, że w trybie POSIXbash
wciąż nie jest zgodny z POSIX, ponieważ nie wyświetla danych wyjściowych-e
:Domyślne wartości xpg_echo i posix można zdefiniować w czasie kompilacji za pomocą opcji
--enable-xpg-echo-default
i skryptu. Tak zwykle robią ostatnie wersje OS / X, aby je zbudować .Jednakżadne wdrożenie / dystrybucja Uniksa / Linuksa przy zdrowych zmysłach zazwyczaj tego nie zrobiłoby. W rzeczywistości nie jest to prawdą, że Oracle jest dostarczane z Solaris 11 (w pakiecie opcjonalnym), jak się wydaje (tak nie było w Solarisie 10).--enable-strict-posix-default
configure
/bin/sh
/bin/bash
/bin/bash
--enable-xpg-echo-default
2. Jak
ksh93
jestecho
zachowanie może być zmienione.W
ksh93
, czyecho
rozwija sekwencje specjalne czy nie i rozpoznaje opcje, zależy od zawartości zmiennych środowiskowych$PATH
i / lub$_AST_FEATURES
.Jeśli
$PATH
zawiera komponent, który zawiera/5bin
lub/xpg
przed komponentem/bin
lub/usr/bin
, wówczas zachowuje się w sposób SysV / UNIX (rozwija sekwencje, nie akceptuje opcji). Jeśli znajdzie/ucb
lub/bsd
pierwszy lub jeśli$_AST_FEATURES
7 zawieraUNIVERSE = ucb
, zachowuje się w BSD 3 sposób (-e
aby umożliwić ekspansję, rozpoznaje-n
).Domyślnie jest zależne od systemu, BSD na Debianie (zobacz dane wyjściowe
builtin getconf; getconf UNIVERSE
w najnowszych wersjach ksh93):3. BSD dla echa -e?
Odniesienie do BSD do obsługi
-e
opcji jest tutaj nieco mylące. Większość tych różnych i niekompatybilnychecho
zachowań została wprowadzona w AT&T:\n
,\0ooo
,\c
W programisty stole warsztatowym UNIX (w oparciu o Unix V6), a reszta (\b
,\r
...) w System III sygn .-n
w Unix V7 (autor: Dennis Ritchie Ref )-e
w Unix V8 (autor: Dennis Ritchie Ref )-E
sam prawdopodobnie początkowo pochodzi zbash
(CWRU / CWRU.chlog w wersji 1.13.5 wspomina Briana Foxa dodającego go w dniach 1992-10-18, GNUecho
kopiuje go wkrótce w sh-utils-1.8 wydanym 10 dni później)Chociaż
echo
wbudowanesh
lub BSD są obsługiwane-e
od dnia, w którym zaczęły używać powłoki Almquist na początku lat 90., samodzielneecho
narzędzie do dziś tego nie obsługuje ( FreeBSDecho
nadal nie obsługuje-e
, chociaż obsługuje-n
takie jak Unix V7 (i także,\c
ale tylko na końcu ostatniego argumentu)).Obsługa
-e
została dodana doksh93
,echo
gdy we wszechświecie BSD w wersji ksh93r wydanej w 2006 roku i można ją wyłączyć w czasie kompilacji.4. Zmiana zachowania echa GNU w 8.31
Od coreutils 8,31 (i to popełniają ), GNU
echo
teraz rozszerza sekwencje domyślnie po POSIXLY_CORRECT w środowisku, aby dopasować zachowaniebash -o posix -O xpg_echo
„secho
polecenie wbudowane (patrz raport o błędzie ).5. macOS
echo
Większość wersji macOS otrzymała certyfikat UNIX od OpenGroup .
Ich
sh
wbudowaneecho
jest zgodne, ponieważ jestbash
(bardzo stara wersja) wbudowane zxpg_echo
domyślnie włączoną, ale ich samodzielneecho
narzędzie nie jest.env echo -n
wypisuje nic zamiast-n<newline>
,env echo '\n'
wypisuje\n<newline>
zamiast<newline><newline>
.To
/bin/echo
jest ten z FreeBSD, który tłumi wyjście nowej linii, jeśli pierwszy argument to-n
lub (od 1995), jeśli ostatni argument się kończy\c
, ale nie obsługuje żadnych innych sekwencji odwrotnego ukośnika wymaganych nawet przez UNIX\\
.6.
echo
implementacje, które mogą generować dowolne dane dosłownieŚciśle mówiąc, można również liczyć, że FreeBSD / macOS
/bin/echo
powyżej (nie jest toecho
wbudowane w ich powłokę ), gdzie można zapisaćzsh
'echo -E - "$var"
lubyash
'ECHO_STYLE=raw echo "$var"
( sprintf '%s\n' "$var"
):Implementacje, które obsługują
-E
i-n
(lub można je skonfigurować) mogą również wykonywać:I
zsh
„secho -nE - "$var"
(printf %s "$var"
) można zapisać7.
_AST_FEATURES
i ASTUNIVERSE
Nie
_AST_FEATURES
jest przeznaczony do bezpośredniej manipulacji, służy do propagowania ustawień konfiguracji AST podczas wykonywania poleceń. Konfiguracja ma zostać wykonana za pomocą (nieudokumentowanego)astgetconf()
interfejsu API. Wewnątrzksh93
Thegetconf
wbudowane (uruchamiana zbuiltin getconf
lub powołująccommand /opt/ast/bin/getconf
) jest interfejsemastgetconf()
Na przykład powinieneś
builtin getconf; getconf UNIVERSE = att
zmienićUNIVERSE
ustawienie naatt
(powodującecho
między innymi zachowanie SysV). Po wykonaniu tej czynności zauważysz, że$_AST_FEATURES
zmienna środowiskowa zawieraUNIVERSE = att
.źródło
echo
rozszerzenia\x
sekwencji w przeciwieństwie do powłoki jako części składni cytowania jest to, że możesz następnie wyprowadzić bajt NUL (innym prawdopodobnie unikatowym błędnym zaprojektowaniem Uniksa są te rozdzielone zerami ciągi, w których połowa wywołań systemowych (jakexecve()
) nie może przyjmować dowolnych sekwencji bajtów)printf
wydaje się być problemem, ponieważ większość implementacji robi to źle. Jedyna poprawna implementacja, o której wiem, jest dostępna,bosh
a strona Sven Maschek nie wymienia problemów z bajtami zerowymi za pośrednictwem\0
.Możesz użyć
printf
jego opcji formatowania.echo
jest przydatny, jeśli chodzi o drukowanie wartości zmiennej lub (prostej) linii, ale to wszystko.printf
potrafi w zasadzie robić to, co potrafi wersja C.Przykładowe użycie i możliwości:
Echo
:printf
:Źródła:
źródło
echo
do wydrukowania zmiennej może się nie powieść, jeśli wartość zmiennej zawiera metaznaki.Jedną z „zalet”, jeśli chcesz to tak nazwać, jest to, że nie musisz mówić,
echo
aby interpretował pewne sekwencje specjalne, takie jak\n
. Potrafi je interpretować i nie będzie tego wymagać-e
.(Uwaga: ostatni
\n
jest konieczny,echo
implikuje to, chyba że dasz-n
opcję)przeciw
Uwaga ostatni
\n
wprintf
. Na koniec dnia zależy od gustu i wymagań, jakich używasz:echo
lubprintf
.źródło
/usr/bin/echo
ibash
wbudowane.dash
,ksh
Azsh
wbudowanaecho
nie wymaga-e
przełącznika rozszerzyć znaki odwróconego ukośnika.printf '%s\n' 'foo\bar
.Wadą
printf
jest wydajność, ponieważ wbudowana powłokaecho
jest znacznie szybsza. Dotyczy to szczególnie Cygwin, gdzie każde wystąpienie nowego polecenia powoduje duże obciążenie systemu Windows. Kiedy zmieniłem mój program z dużym echem na używanie/bin/echo
echa powłoki, wydajność prawie się podwoiła. Jest to kompromis między przenośnością a wydajnością. Zawsze nie jest to slam wsadowyprintf
.źródło
printf
jest obecnie wbudowany w większość powłok (bash, dash, ksh, zsh, yash, niektóre pochodne pdksh ... więc obejmuje również powłoki zwykle spotykane w cygwin). Jedynymi godnymi uwagi wyjątkami są niektórepdksh
instrumenty pochodne.printf
do wyprowadzania nul bajtów, ale niektóre implementacje interpretują `\ c 'w ciągu formatu, nawet jeśli nie powinny.printf
POSIX jest nieokreślone, jeśli używasz\c
ciągu formatu, więcprintf
implementacje mogą robić, co chcą w tym względzie. Na przykład niektórzy traktują to tak samo jak w PWBecho
(powoduje, że printf kończy działanie), ksh używa go do\cA
znaków kontrolnych (dla argumentu formatu printf i dla,$'...'
ale nie dlaecho
aniprint
!). Nie wiesz, co to ma do czynienia z nadrukiem NUL bajtów, a może jesteś odnosząc się doksh
„sprintf '\c@'
?