Temel olarak, bu bir taşınabilirlik (ve güvenilirlik) sorunudur.
Başlangıçta, echoherhangi bir seçeneği kabul etmedi ve hiçbir şeyi genişletmedi. Tek yaptığı, boşluk karakteriyle ayrılmış ve yeni satır karakteriyle sonlanan argümanlarını göstermekti.
Şimdi, birisi echo "\n\t"newline veya tab karakterleri çıktısı almak veya takip eden newline karakterini çıkarıp vermemek için bir seçeneğe sahip olmamızın iyi olacağını düşündü .
Daha sonra daha zor olduğunu düşünüyorlardı, ancak bu işlevselliği kabuğa eklemek yerine ( perlçift tırnakların içinde, \taslında bir sekme karakteri olduğu gibi), bunu eklediler echo.
David Korn, hatayı fark etti ve yeni bir kabuk alıntı biçimi ortaya koydu: $'...'ki bu daha sonra kopyalandı bashve zsho zamana kadar çok geçti.
Şimdi standart bir UNIX echoiki karakteri içeren bir argüman aldığında \ve tbunları çıkarmak yerine, bir sekme karakteri çıkarır. \cBir argümanda görür görmez , çıktısını durdurur (böylece yeni satırın da çıkışı olmaz).
Diğer mermiler / Unix satıcıları / sürümleri farklı yapmayı seçti: -ekaçış dizilerini genişletmek için bir -nseçenek ve izleyen yeni satırı çıkarmamak için bir seçenek eklediler . Bazılarında var -Ebazılarında, çıkış sıralarını devre dışı bırakmak -ndeğil -e, bir tarafından desteklenen kaçış dizilerinin listesi echouygulaması başka desteklediği şekilde mutlaka aynı değildir.
Sven Mascheck, sorunun boyutunu gösteren hoş bir sayfaya sahiptir .
O günü echoseçeneklerini destekler uygulamaları, bir hiç destek genellikle orada --seçenekler sonunu işaretlemek için ( echodo olmayan bazı Bourne benzeri kabuklarından komutuna destek ve zsh destekleyen -buna da uygun) örneğin bu yüzden, bu çıkışa zor, "-n"ile echode birçok kabukları.
Gibi bazı kabukları üzerinde bash¹ veya ksh93² veya yash( $ECHO_STYLEdeğişken), davranış bile GNU nasıl kabuk derlenmiştir veya çevre (bağlıdır echo'eğer davranışı da değişecektir $POSIXLY_CORRECTortamda ve sürüm ile 4 , zsh' in onun ile bsd_echoseçeneği, bazı posixseçenekleri ile veya pdksh tabanlı olarak adlandırılmış olup olmadıklarını sh). Yani iki bash echoversiyonun aynı versiyondan bile aynı bashşekilde davranması garanti edilmiyor.
POSIX şöyle der: İlk argüman -nya da herhangi bir argüman ters eğik çizgi içeriyorsa, davranış belirtilmez . bashBu bağlamda yankı POSIX değil, örneğin POSIX'in gerektirdiği gibi çıktı echo -evermiyor -e<newline>. UNIX spesifikasyonu daha katıdır, çıktının durdurulması -ndahil olmak üzere bazı kaçış dizilerinin genişlemesini yasaklar ve gerektirir \c.
Bu şartnameler, birçok uygulamanın uyumlu olmadığı göz önüne alındığında, burada kurtarmaya gelmez. MacOS 5 gibi bazı sertifikalı sistemler bile uyumlu değildir.
Mevcut gerçekliği gerçekten temsil etmek için POSIX aslında şunu söylemelidir : ilk argüman ^-([eEn]*|-help|-version)$uzatılmış regexp ile eşleşirse veya herhangi bir argüman ters eğik çizgi içeriyorsa (veya kodlaması αBIG5 karakter dizisini kullanan yerellerde olduğu gibi ters eğik çizgi karakterinin kodlamasını içeren karakterler) ise, o zaman davranış belirtilmemiş.
Sonuçta, echo "$var"bunun $varters eğik çizgi karakterleri içermediğinden ve başlamadığından emin olmadıkça neyin çıkacağını bilemezsiniz -. POSIX özelliği aslında printfbu durumda kullanmamızı söylüyor .
Yani bunun anlamı echokontrolsüz verileri görüntülemek için kullanamamanızdır . Başka bir deyişle, bir komut dosyası yazıyorsanız ve harici girdi alıyorsa (kullanıcıdan argümanlar olarak veya dosya sisteminden dosya adları ...), echogörüntülemek için kullanamazsınız .
Tamamdır:
echo >&2 Invalid file.
Bu değil:
echo >&2 "Invalid file: $file"
(Her ne kadar seçenek bir şekilde veya derleme zamanında veya çevre yoluyla olduğu gibi başka bir şekilde etkinleştirilmemişse ) bazı (UNIX uyumlu olmayan) echouygulamalarla TAMAM çalışacaktır .bashxpg_echo
file=$(echo "$var" | tr ' ' _)çoğu uygulamada TAMAM değildir (istisnalar ile yashbirlikte olan ECHO_STYLE=raw( yashdeğişkenlerin baytların rasgele sıralarını tutamayacağı kadar ihtiraslı) ve zsh's echo -E - "$var"6 ).
printfÖte yandan daha güvenilir üzerinde, en azından bunun temel kullanım ile sınırlıdır ne zaman echo.
printf '%s\n' "$var"
Çıktı içeriğini Will $varolursa olsun içerebilir hangi karakteri bir satır karakteri ile izledi.
printf '%s' "$var"
Sondaki yeni satır karakteri olmadan yazacaktır.
Şimdi, printfuygulamalar arasında da farklılıklar var . POSIX tarafından belirtilen bir dizi temel özellik vardır, ancak daha sonra birçok uzantı vardır. Mesela, bazıları %qargümanları alıntılamak için bir a destekler ancak bunun nasıl yapıldığı, bazı \uxxxxunicode karakterleri destekleyen, kabuktan kabuğa değişir . Davranış printf '%10s\n' "$var", çok baytlı yerel ayarlarda değişir , bunun için en az üç farklı sonuç vardır.printf %b '\123'
Fakat sonunda, POSIX özellik kümesine bağlı printfkalırsanız ve onunla çok süslü bir şey yapmayı denemezseniz, başınız belada demektir.
Ancak ilk argümanın format olduğunu unutmayın, bu nedenle değişken / kontrolsüz veri içermemelidir.
Aşağıdakiler kullanılarak daha güvenilir bir echouygulama yapılabilir printf:
echo() ( # subshell for local scope for $IFS
IFS=" " # needed for "$*"
printf '%s\n' "$*"
)
echo_n() (
IFS=" "
printf %s "$*"
)
echo_e() (
IFS=" "
printf '%b\n' "$*"
)
Alt kabuk (çoğu kabuk uygulamasında fazladan bir işlem oluşturulması anlamına gelir), local IFSbirçok kabuk kullanılarak veya şöyle yazılarak önlenebilir :
echo() {
if [ "$#" -gt 0 ]; then
printf %s "$1"
shift
fi
if [ "$#" -gt 0 ]; then
printf ' %s' "$@"
fi
printf '\n'
}
notlar
1. nasıl bash'ın echodeğiştirilebilir davranışı.
İle bash, çalışma zamanında, davranışlarını kontrol iki şey vardır echo(yanında enable -n echoveya yeniden tanımlıyor echobir fonksiyonu veya takma gibi): xpg_echo bashseçeneği olup olmadığı bashPOSIX modunda. posixeğer modu etkin olabilir basholarak adlandırılır shveya eğer POSIXLY_CORRECTortamda veya ile posixopsiyon:
Çoğu sistemde varsayılan davranış:
$ bash -c 'echo -n "\0101"'
\0101% # the % here denotes the absence of newline character
xpg_echo UNIX'in gerektirdiği şekilde dizileri genişletiyor:
$ BASHOPTS=xpg_echo bash -c 'echo "\0101"'
A
Hala onurlandırıyor -nve -e(ve -E):
$ BASHOPTS=xpg_echo bash -c 'echo -n "\0101"'
A%
İle xpg_echove POSIX modu:
$ env BASHOPTS=xpg_echo POSIXLY_CORRECT=1 bash -c 'echo -n "\0101"'
-n A
$ env BASHOPTS=xpg_echo sh -c 'echo -n "\0101"' # (where sh is a symlink to bash)
-n A
$ env BASHOPTS=xpg_echo SHELLOPTS=posix bash -c 'echo -n "\0101"'
-n A
Bu sefer, bashhem POSIX hem de UNIX uyumludur. POSIX modunda, bashçıktı almadığı için hala POSIX uyumlu olmadığını unutmayın -e:
$ env SHELLOPTS=posix bash -c 'echo -e'
$
Xpg_echo ve posix için varsayılan değerler , komut dosyası için --enable-xpg-echo-defaultve --enable-strict-posix-defaultseçenekleriyle derleme zamanında tanımlanabilir configure. Bu genellikle OS / X’in son sürümlerini oluşturmak için yapar /bin/sh. Aklı başında hiçbir Unix / Linux uygulama / dağıtım için bunu tipik olur /bin/bashgerçi . Aslında bu doğru değil, /bin/bashOracle'ın Solaris 11 ile birlikte (isteğe bağlı bir pakette) birlikte gönderildiği anlaşılıyor --enable-xpg-echo-default(Solaris 10'da böyle değildi).
2. Nasıl ksh93'ın echodavranışı değiştirilebilir.
İçinde ksh93, echokaçış dizilerini genişletip genişletmemek veya seçenekleri tanımak veya tanımak, $PATHve / veya $_AST_FEATURESortam değişkenlerinin içeriğine bağlıdır .
Eğer $PATHiçeren bir bileşeni içeren /5binveya /xpgöncesinde /binveya /usr/binsonra SysV / UNIX şekilde davranmaz bileşen (dizileri genişletir seçenekleri kabul etmez). Bulursa /ucbveya /bsdönce veya $_AST_FEATURES7 içeriyorsa UNIVERSE = ucb, BSD 3 yolunu kullanır ( -egenişlemeyi etkinleştirmek için tanır -n).
Varsayılan sistem bağımlıdır, Debian'daki BSD builtin getconf; getconf UNIVERSE(ksh93'ün son sürümlerinin çıktısına bakınız ):
$ ksh93 -c 'echo -n' # default -> BSD (on Debian)
$ PATH=/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /xpg before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH ksh93 -c 'echo -n' # /5bin before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH _AST_FEATURES='UNIVERSE = ucb' ksh93 -c 'echo -n' # -> BSD
$ PATH=/ucb:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /ucb first -> BSD
$ PATH=/bin:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /bin before /xpg -> default -> BSD
3. Eko-e için BSD?
-eSeçeneğin işlenmesi için BSD referansı burada biraz yanıltıcıdır. Bu farklı ve uyumsuz echodavranışların çoğu AT&T'de tanıtıldı:
\n, \0ooo, \cProgramcı Work Bench'e (Unix V6 dayanarak), UNIX, ve dinlenme (içinde \b, \rUnix Sistem III ...) Ref .
-nUnix V7 içinde (Dennis Ritchie Ref tarafından )
-eUnix V8 içinde (Dennis Ritchie Ref tarafından )
-Ekendisi muhtemelen başlangıçta geldi bash( 1.13.5 sürümündeki CWRU / CWRU.chlog'dan Brian Fox’un 1992-10-18’de eklenmesi, GNU’nun echo10 gün sonra yayımlanan sh-utils-1.8’den kısa bir süre sonra kopyalanması)
İken echobir yerleşik shveya BSD destekledi -eonlar 90'ların bunun için Almquist kabuğunu kullanmaya başladı günden beri, tek başına echobu güne kadar yarar (orada desteklemediği FreeBSDecho hala desteklemiyor -eo destekliyor olsa da, -nbenzeri Unix V7 (ve ayrıca \cancak yalnızca son argümanın sonunda).
Ele alınması -eeklendi ksh93's echoBSD içinde zaman evrenin ve 2006 yılında piyasaya ksh93r sürümünde derleme zamanında devre dışı bırakılabilir.
4. 8.31’de GNU yankı davranış değişikliği
Coreutils 8.31 (ve yana bu taahhüt ), GNU echoşimdi POSIXLY_CORRECT ortamında olduğunda davranışını eşleştirmek için, varsayılan olarak dizilerini kaçış genişletir bash -o posix -O xpg_echo'ın echo(bkz yerleşiğini hata raporu ).
5. macOS echo
MacOS'un çoğu sürümü OpenGroup'tan UNIX sertifikası aldı .
Onların shyerleşik echoöyle olarak uyumludur bashile inşa (çok eski bir sürüm) xpg_echovarsayılan olarak etkin, ancak bunların tek başına echoyarar değildir. env echo -nbunun yerine hiçbir şey çıkarmaz -n<newline>, yerine env echo '\n'çıktı \n<newline>verir <newline><newline>.
Bu /bin/echo, ilk argüman ise newline çıktısını baskılayan FreeBSD'den gelen -nveya son argüman sona erdiğinde (1995'ten beri) \c, ancak UNIX'in gerektirdiği diğer ters eğik çizgi dizilerini bile desteklemeyendir \\.
6. echokeyfi veri verebilecek uygulamalar
Kesinlikle, ayrıca FreeBSD / MacOS o güvenebileceği konuşma /bin/echo(değil onların kabuk yukarıdaki echoyerleşiğini) nerede zsh'ler echo -E - "$var"veya yash' ler ECHO_STYLE=raw echo "$var"( printf '%s\n' "$var") yazılabilir:
/bin/echo "$var
\c"
Destekleyen -Eve -n(veya yapılandırılabilir) uygulamalar da şunları yapabilir:
echo -nE "$var
"
Ve zsh's echo -nE - "$var"( printf %s "$var") yazılabilir
/bin/echo "$var\c"
7. _AST_FEATURESve ASTUNIVERSE
_AST_FEATURESDoğrudan manipüle edilmesi anlamına gelmez, komut yürütme karşısında AST yapılandırma ayarlarını yaymak için kullanılır. Yapılandırma (belgelenmemiş) astgetconf()API üzerinden gerçekleştirilmek içindir . İçinde ksh93, getconfyerleşik ( builtin getconfçağırmakla veya çağırmakla etkindir command /opt/ast/bin/getconf) arayüzastgetconf()
Örneğin builtin getconf; getconf UNIVERSE = att, UNIVERSEayarı değiştirmek için att( echodiğer şeylerin yanı sıra SysV yöntemini kullanmaya neden olmak için) de yapardınız . Bunu yaptıktan sonra, $_AST_FEATURESiçerdiği ortam değişkenini fark edeceksiniz UNIVERSE = att.
echo -e?