Temel olarak, bu bir taşınabilirlik (ve güvenilirlik) sorunudur.
Başlangıçta, echo
herhangi 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, \t
aslı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ı bash
ve zsh
o zamana kadar çok geçti.
Şimdi standart bir UNIX echo
iki karakteri içeren bir argüman aldığında \
ve t
bunları çıkarmak yerine, bir sekme karakteri çıkarır. \c
Bir 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: -e
kaçış dizilerini genişletmek için bir -n
seçenek ve izleyen yeni satırı çıkarmamak için bir seçenek eklediler . Bazılarında var -E
bazılarında, çıkış sıralarını devre dışı bırakmak -n
değil -e
, bir tarafından desteklenen kaçış dizilerinin listesi echo
uygulaması başka desteklediği şekilde mutlaka aynı değildir.
Sven Mascheck, sorunun boyutunu gösteren hoş bir sayfaya sahiptir .
O günü echo
seçeneklerini destekler uygulamaları, bir hiç destek genellikle orada --
seçenekler sonunu işaretlemek için ( echo
do 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 echo
de birçok kabukları.
Gibi bazı kabukları üzerinde bash
¹ veya ksh93
² veya yash
( $ECHO_STYLE
değ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_CORRECT
ortamda ve sürüm ile 4 , zsh
' in onun ile bsd_echo
seçeneği, bazı posix
seçenekleri ile veya pdksh tabanlı olarak adlandırılmış olup olmadıklarını sh
). Yani iki bash
echo
versiyonun aynı versiyondan bile aynı bash
şekilde davranması garanti edilmiyor.
POSIX şöyle der: İlk argüman -n
ya da herhangi bir argüman ters eğik çizgi içeriyorsa, davranış belirtilmez . bash
Bu bağlamda yankı POSIX değil, örneğin POSIX'in gerektirdiği gibi çıktı echo -e
vermiyor -e<newline>
. UNIX spesifikasyonu daha katıdır, çıktının durdurulması -n
dahil 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 $var
ters eğik çizgi karakterleri içermediğinden ve başlamadığından emin olmadıkça neyin çıkacağını bilemezsiniz -
. POSIX özelliği aslında printf
bu durumda kullanmamızı söylüyor .
Yani bunun anlamı echo
kontrolsü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ı ...), echo
gö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) echo
uygulamalarla TAMAM çalışacaktır .bash
xpg_echo
file=$(echo "$var" | tr ' ' _)
çoğu uygulamada TAMAM değildir (istisnalar ile yash
birlikte olan ECHO_STYLE=raw
( yash
değ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 $var
olursa olsun içerebilir hangi karakteri bir satır karakteri ile izledi.
printf '%s' "$var"
Sondaki yeni satır karakteri olmadan yazacaktır.
Şimdi, printf
uygulamalar 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ı %q
argümanları alıntılamak için bir a destekler ancak bunun nasıl yapıldığı, bazı \uxxxx
unicode 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ı printf
kalı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 echo
uygulama 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 IFS
birç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 echo
değiştirilebilir davranışı.
İle bash
, çalışma zamanında, davranışlarını kontrol iki şey vardır echo
(yanında enable -n echo
veya yeniden tanımlıyor echo
bir fonksiyonu veya takma gibi): xpg_echo
bash
seçeneği olup olmadığı bash
POSIX modunda. posix
eğer modu etkin olabilir bash
olarak adlandırılır sh
veya eğer POSIXLY_CORRECT
ortamda veya ile posix
opsiyon:
Ç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 -n
ve -e
(ve -E
):
$ BASHOPTS=xpg_echo bash -c 'echo -n "\0101"'
A%
İle xpg_echo
ve 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, bash
hem 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-default
ve --enable-strict-posix-default
seç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/bash
gerçi . Aslında bu doğru değil, /bin/bash
Oracle'ı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 echo
davranışı değiştirilebilir.
İçinde ksh93
, echo
kaçış dizilerini genişletip genişletmemek veya seçenekleri tanımak veya tanımak, $PATH
ve / veya $_AST_FEATURES
ortam değişkenlerinin içeriğine bağlıdır .
Eğer $PATH
içeren bir bileşeni içeren /5bin
veya /xpg
öncesinde /bin
veya /usr/bin
sonra SysV / UNIX şekilde davranmaz bileşen (dizileri genişletir seçenekleri kabul etmez). Bulursa /ucb
veya /bsd
önce veya $_AST_FEATURES
7 içeriyorsa UNIVERSE = ucb
, BSD 3 yolunu kullanır ( -e
geniş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?
-e
Seçeneğin işlenmesi için BSD referansı burada biraz yanıltıcıdır. Bu farklı ve uyumsuz echo
davranışların çoğu AT&T'de tanıtıldı:
\n
, \0ooo
, \c
Programcı Work Bench'e (Unix V6 dayanarak), UNIX, ve dinlenme (içinde \b
, \r
Unix Sistem III ...) Ref .
-n
Unix V7 içinde (Dennis Ritchie Ref tarafından )
-e
Unix V8 içinde (Dennis Ritchie Ref tarafından )
-E
kendisi 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 echo
10 gün sonra yayımlanan sh-utils-1.8’den kısa bir süre sonra kopyalanması)
İken echo
bir yerleşik sh
veya BSD destekledi -e
onlar 90'ların bunun için Almquist kabuğunu kullanmaya başladı günden beri, tek başına echo
bu güne kadar yarar (orada desteklemediği FreeBSDecho
hala desteklemiyor -e
o destekliyor olsa da, -n
benzeri Unix V7 (ve ayrıca \c
ancak yalnızca son argümanın sonunda).
Ele alınması -e
eklendi ksh93
's echo
BSD 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 sh
yerleşik echo
öyle olarak uyumludur bash
ile inşa (çok eski bir sürüm) xpg_echo
varsayılan olarak etkin, ancak bunların tek başına echo
yarar değildir. env echo -n
bunun 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 -n
veya 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. echo
keyfi veri verebilecek uygulamalar
Kesinlikle, ayrıca FreeBSD / MacOS o güvenebileceği konuşma /bin/echo
(değil onların kabuk yukarıdaki echo
yerleş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 -E
ve -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_FEATURES
ve ASTUNIVERSE
_AST_FEATURES
Doğ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
, getconf
yerleşik ( builtin getconf
çağırmakla veya çağırmakla etkindir command /opt/ast/bin/getconf
) arayüzastgetconf()
Örneğin builtin getconf; getconf UNIVERSE = att
, UNIVERSE
ayarı değiştirmek için att
( echo
diğer şeylerin yanı sıra SysV yöntemini kullanmaya neden olmak için) de yapardınız . Bunu yaptıktan sonra, $_AST_FEATURES
içerdiği ortam değişkenini fark edeceksiniz UNIVERSE = att
.
echo -e
?