Saya pernah mendengar bahwa printf
itu lebih baik daripada echo
. Saya hanya dapat mengingat satu contoh dari pengalaman saya di mana saya harus menggunakan printf
karena echo
tidak bekerja untuk memasukkan beberapa teks ke dalam beberapa program di RHEL 5.8 tetapi printf
melakukannya. Tapi ternyata, ada perbedaan lain, dan saya ingin menanyakan apa itu juga apakah ada kasus tertentu kapan harus menggunakan satu vs yang lain.
text-processing
echo
printf
amfibi
sumber
sumber
echo -e
?echo -e
tidak berfungsish
, hanya dibash
(untuk beberapa alasan), dan buruh pelabuhan, misalnya, menggunakansh
secara default untukRUN
perintahnyaecho -e
bagi saya bekerja di Terminal Android, yang pada dasarnyash
.Jawaban:
Pada dasarnya, ini masalah portabilitas (dan keandalan).
Awalnya,
echo
tidak menerima opsi apa pun dan tidak memperluas apa pun. Yang dilakukannya hanyalah mengeluarkan argumennya yang dipisahkan oleh karakter spasi dan diakhiri oleh karakter baris baru.Sekarang, seseorang berpikir akan lebih baik jika kita bisa melakukan hal-hal seperti
echo "\n\t"
menampilkan karakter baris baru atau tab, atau memiliki opsi untuk tidak menampilkan karakter baris baru yang tertinggal.Mereka kemudian berpikir lebih keras tetapi alih-alih menambahkan fungsionalitas itu ke shell (seperti di
perl
mana di dalam tanda kutip ganda,\t
sebenarnya berarti karakter tab), mereka menambahkannyaecho
.David Korn menyadari kesalahan itu dan memperkenalkan bentuk baru dari kutipan shell:
$'...'
yang kemudian disalin olehbash
danzsh
tapi itu sudah sangat terlambat pada saat itu.Sekarang ketika UNIX standar
echo
menerima argumen yang berisi dua karakter\
dant
, bukannya menghasilkan mereka, itu menghasilkan karakter tab. Dan begitu ia melihat\c
dalam argumen, ia berhenti mengeluarkan (jadi baris baru yang tertinggal juga bukan keluaran).Kerang / vendor Unix lain / versi memilih untuk melakukannya secara berbeda: mereka menambahkan
-e
opsi untuk memperluas urutan melarikan diri, dan-n
opsi untuk tidak menampilkan baris baru. Beberapa memiliki-E
untuk menonaktifkan urutan melarikan diri, beberapa memiliki-n
tetapi tidak-e
, daftar urutan melarikan diri yang didukung oleh satuecho
implementasi tidak harus sama dengan yang didukung oleh yang lain.Sven Mascheck memiliki halaman yang bagus yang menunjukkan tingkat masalah .
Pada
echo
implementasi yang mendukung opsi, umumnya tidak ada dukungan dari--
untuk menandai akhir dari opsi (echo
builtin dari beberapa shell yang tidak seperti Bourne lakukan, dan zsh mendukung-
untuk itu), jadi misalnya, sulit untuk menghasilkan"-n"
denganecho
di banyak kerang.Pada beberapa shell seperti
bash
¹ atauksh93
² atauyash
($ECHO_STYLE
variabel), perilaku bahkan tergantung pada bagaimana shell dikompilasi atau lingkungan (echo
Perilaku GNU juga akan berubah jika$POSIXLY_CORRECT
ada di lingkungan dan dengan versi 4 ,zsh
denganbsd_echo
pilihannya, beberapa berbasis pdksh denganposix
opsi mereka atau apakah mereka dipanggilsh
atau tidak). Jadi duabash
echo
s, bahkan dari versi yang samabash
tidak dijamin berperilaku sama.POSIX mengatakan: jika argumen pertama adalah
-n
atau argumen apa pun mengandung garis miring terbalik, maka perilaku tersebut tidak ditentukan .bash
gema dalam hal itu bukanlah POSIX dalam hal itu misalnyaecho -e
tidak menghasilkan-e<newline>
seperti yang diperlukan POSIX. Spesifikasi UNIX lebih ketat, melarang-n
dan membutuhkan perluasan beberapa urutan pelarian termasuk yang\c
berhenti mengeluarkan.Spesifikasi itu tidak benar-benar datang ke penyelamatan di sini mengingat bahwa banyak implementasi tidak sesuai. Bahkan beberapa sistem bersertifikat seperti macOS 5 tidak sesuai.
Untuk benar-benar mewakili kenyataan saat ini, POSIX harus benar-benar mengatakan : jika argumen pertama cocok dengan
^-([eEn]*|-help|-version)$
regexp yang diperluas atau argumen apa pun berisi garis miring terbalik (atau karakter yang pengkodeannya berisi pengkodean karakter garis miring terbalik sepertiα
di lokal menggunakan charset BIG5), maka perilakunya adalah tidak ditentukan.Secara keseluruhan, Anda tidak tahu apa yang
echo "$var"
akan dihasilkan kecuali Anda dapat memastikan bahwa$var
itu tidak mengandung karakter backslash dan tidak dimulai dengan-
. Spesifikasi POSIX sebenarnya memberitahu kita untuk menggunakannyaprintf
sebagai gantinya.Jadi itu artinya Anda tidak dapat menggunakan
echo
untuk menampilkan data yang tidak terkontrol. Dengan kata lain, jika Anda menulis skrip dan sedang mengambil input eksternal (dari pengguna sebagai argumen, atau nama file dari sistem file ...), Anda tidak dapat menggunakannyaecho
untuk menampilkannya.Ini bagus:
Ini bukan:
(Meskipun itu akan bekerja OK dengan beberapa
echo
implementasi (non-UNIX compliant) sepertibash
ketikaxpg_echo
opsi tidak diaktifkan dengan satu atau lain cara seperti pada waktu kompilasi atau melalui lingkungan).file=$(echo "$var" | tr ' ' _)
tidak OK di sebagian besar implementasi (pengecualian menjadiyash
denganECHO_STYLE=raw
(dengan peringatan bahwayash
's variabel tidak bisa menahan urutan sewenang-wenang dari byte sehingga tidak nama file sewenang-wenang) danzsh
' secho -E - "$var"
6 ).printf
, di sisi lain lebih dapat diandalkan, setidaknya ketika itu terbatas pada penggunaan dasarecho
.Akan menampilkan konten
$var
diikuti oleh karakter baris baru terlepas dari karakter apa yang dikandungnya.Akan menampilkannya tanpa karakter baris baru.
Sekarang, ada juga perbedaan antara
printf
implementasi. Ada inti fitur yang ditentukan oleh POSIX, tetapi kemudian ada banyak ekstensi. Sebagai contoh, beberapa dukungan%q
untuk mengutip argumen tetapi bagaimana itu dilakukan bervariasi dari shell ke shell, beberapa dukungan\uxxxx
untuk karakter unicode. Perilaku bervariasi untukprintf '%10s\n' "$var"
di multi-byte locales, setidaknya ada tiga hasil yang berbeda untukprintf %b '\123'
Tetapi pada akhirnya, jika Anda tetap menggunakan set fitur POSIX
printf
dan tidak mencoba melakukan sesuatu yang terlalu mewah, Anda keluar dari masalah.Tapi ingat argumen pertama adalah format, jadi tidak boleh berisi data variabel / tidak terkendali.
Yang lebih andal
echo
dapat diimplementasikan menggunakanprintf
, seperti:Subkulit (yang menyiratkan pemijahan proses ekstra di sebagian besar implementasi shell) dapat dihindari menggunakan
local IFS
dengan banyak shell, atau dengan menuliskannya seperti:Catatan
1. bagaimana
bash
'secho
perilaku bisa diubah.Dengan
bash
, pada saat dijalankan, ada dua hal yang mengontrol perilakuecho
(di sampingenable -n echo
atau mendefinisikan kembaliecho
sebagai fungsi atau alias):xpg_echo
bash
opsi dan apakahbash
dalam mode posix.posix
mode dapat diaktifkan jikabash
dipanggil sebagaish
atau jikaPOSIXLY_CORRECT
ada di lingkungan atau denganposix
opsi:Perilaku default pada kebanyakan sistem:
xpg_echo
perluas urutan sesuai kebutuhan UNIX:Itu masih menghormati
-n
dan-e
(dan-E
):Dengan
xpg_echo
dan mode POSIX:Kali ini,
bash
adalah POSIX dan UNIX yang sesuai. Perhatikan bahwa dalam mode POSIX,bash
masih belum memenuhi POSIX karena tidak menghasilkan-e
:Nilai default untuk xpg_echo dan posix dapat didefinisikan pada waktu kompilasi dengan opsi
--enable-xpg-echo-default
dan--enable-strict-posix-default
keconfigure
skrip. Biasanya itulah yang dilakukan versi OS / X terbaru untuk membuatnya/bin/sh
.Tidak ada implementasi / distribusi Unix / Linux yang waras biasanya akan melakukannya untuk. Sebenarnya, itu tidak benar,/bin/bash
saat ini/bin/bash
bahwa Oracle dikirimkan bersama Solaris 11 (dalam paket opsional) tampaknya dibangun dengan--enable-xpg-echo-default
(itu tidak terjadi di Solaris 10).2. Bagaimana
ksh93
'secho
perilaku bisa diubah.Dalam
ksh93
, apakahecho
memperluas urutan lolos atau tidak dan mengenali opsi tergantung pada konten variabel$PATH
dan / atau$_AST_FEATURES
lingkungan.Jika
$PATH
berisi komponen yang mengandung/5bin
atau/xpg
sebelum/bin
atau/usr/bin
komponen maka itu berperilaku cara SysV / UNIX (memperluas urutan, tidak menerima opsi). Jika ia menemukan/ucb
atau/bsd
pertama atau jika$_AST_FEATURES
7 berisiUNIVERSE = ucb
, maka ia berperilaku dengan cara BSD 3 (-e
untuk memungkinkan ekspansi, mengenali-n
).Standarnya tergantung pada sistem, BSD pada Debian (lihat output
builtin getconf; getconf UNIVERSE
dalam versi terbaru dari ksh93):3. BSD untuk echo -e?
Referensi ke BSD untuk penanganan
-e
opsi agak menyesatkan di sini. Sebagian besarecho
perilaku yang berbeda dan tidak kompatibel itu semua diperkenalkan di AT&T:\n
,\0ooo
,\c
Di Programmer Kerja Bench UNIX (berdasarkan Unix V6), dan sisanya (\b
,\r
...) di Unix System III Ref .-n
dalam Unix V7 (oleh Dennis Ritchie Ref )-e
dalam Unix V8 (oleh Dennis Ritchie Ref )-E
sendiri mungkin awalnya berasal daribash
(CWRU / CWRU.chlog dalam versi 1.13.5 menyebutkan Brian Fox menambahkannya pada 1992-10-18, GNUecho
menyalinnya segera setelah di sh-utils-1.8 dirilis 10 hari kemudian)Sementara
echo
builtin darish
atau BSD telah mendukung-e
sejak hari mereka mulai menggunakan shell Almquist untuk itu di awal 90-an,echo
utilitas mandiri hingga hari ini tidak mendukungnya di sana ( FreeBSDecho
masih tidak mendukung-e
, meskipun ia mendukung-n
seperti Unix V7 (dan juga\c
tetapi hanya pada akhir argumen terakhir)).Penanganan
-e
ditambahkan keksh93
'secho
ketika di BSD alam semesta dalam versi ksh93r dirilis pada tahun 2006 dan dapat dinonaktifkan pada saat kompilasi.4. GNU gema perubahan perilaku di 8.31
Sejak coreutils 8.31 (dan ini komit ), GNU
echo
sekarang memperluas escape sequence secara default ketika POSIXLY_CORRECT adalah di lingkungan, untuk mencocokkan perilakubash -o posix -O xpg_echo
'secho
builtin (lihat laporan bug ).5. macOS
echo
Sebagian besar versi macOS telah menerima sertifikasi UNIX dari OpenGroup .
sh
Builtin merekaecho
kompatibel karenabash
(versi yang sangat lama) dibangun denganxpg_echo
diaktifkan secara default, tetapiecho
utilitas yang berdiri sendiri tidak.env echo -n
tidak menghasilkan apa-apa-n<newline>
,env echo '\n'
output\n<newline>
bukan<newline><newline>
.Itu
/bin/echo
adalah salah satu dari FreeBSD yang menekan output baris baru jika argumen pertama adalah-n
atau (sejak 1995) jika argumen terakhir berakhir\c
, tetapi tidak mendukung urutan backslash lainnya yang diperlukan oleh UNIX, bahkan tidak\\
.6.
echo
implementasi yang dapat menghasilkan data sembarang kata demi kataSebenarnya, Anda juga dapat menghitung bahwa FreeBSD / macOS di
/bin/echo
atas (bukan bawaan shell merekaecho
) di manazsh
'secho -E - "$var"
atauyash
'ECHO_STYLE=raw echo "$var"
(printf '%s\n' "$var"
) dapat ditulis:Implementasi yang mendukung
-E
dan-n
(atau dapat dikonfigurasi untuk) juga dapat melakukan:Dan
zsh
'secho -nE - "$var"
(printf %s "$var"
) dapat ditulis7.
_AST_FEATURES
dan ASTUNIVERSE
Itu
_AST_FEATURES
tidak dimaksudkan untuk dimanipulasi secara langsung, itu digunakan untuk menyebarkan pengaturan konfigurasi AST di seluruh eksekusi perintah. Konfigurasi ini dimaksudkan untuk dilakukan melaluiastgetconf()
API (tidak berdokumen) . Di dalamksh93
,getconf
builtin (diaktifkan denganbuiltin getconf
atau dengan memanggilcommand /opt/ast/bin/getconf
) adalah antarmuka untukastgetconf()
Misalnya, Anda harus
builtin getconf; getconf UNIVERSE = att
mengubahUNIVERSE
pengaturan keatt
(menyebabkanecho
berperilaku SysV antara lain). Setelah melakukan itu, Anda akan melihat$_AST_FEATURES
variabel lingkungan berisiUNIVERSE = att
.sumber
echo
memperluas\x
urutan yang bertentangan dengan shell sebagai bagian dari sintaks kutipan adalah bahwa Anda kemudian dapat menghasilkan byte NUL (desain lain yang bisa dibilang salah dari Unix adalah mereka yang tidak dibatasi oleh nol string, di mana separuh dari panggilan sistem (sepertiexecve()
) tidak dapat mengambil urutan byte yang sewenang-wenang)printf
tampaknya menjadi masalah karena sebagian besar implementasi salah. Satu-satunya implementasi yang benar yang saya ketahui ada dibosh
dan halaman dari Sven Maschek tidak mencantumkan masalah dengan null bytes\0
.Anda mungkin ingin menggunakan
printf
opsi pemformatannya.echo
berguna ketika datang untuk mencetak nilai dari suatu variabel atau (sederhana) baris, tapi hanya itu yang ada untuk itu.printf
pada dasarnya dapat melakukan apa yang dapat dilakukan versi C.Contoh penggunaan dan kemampuan:
Echo
:printf
:Sumber:
sumber
echo
untuk mencetak variabel bisa gagal jika nilai variabel berisi meta-karakter.Satu "keuntungan", jika Anda ingin menyebutnya demikian, adalah Anda tidak perlu mengatakannya
echo
untuk menafsirkan urutan pelarian tertentu seperti\n
. Ia tahu untuk menafsirkannya dan tidak akan memerlukan-e
untuk melakukannya.(NB: yang terakhir
\n
diperlukan,echo
menyiratkannya, kecuali jika Anda memberi-n
pilihan)melawan
Perhatikan yang terakhir
\n
diprintf
. Pada akhirnya, itu soal selera dan persyaratan apa yang Anda gunakan:echo
atauprintf
.sumber
/usr/bin/echo
danbash
builtin. Thedash
,ksh
danzsh
builtinecho
tidak perlu-e
beralih untuk memperluas karakter backslash-escape.printf '%s\n' 'foo\bar
.Salah satu kelemahan
printf
adalah kinerja karena shell bawaanecho
jauh lebih cepat. Ini mulai berlaku khususnya di Cygwin di mana setiap instance dari perintah baru menyebabkan overhead Windows yang besar. Ketika saya mengubah program gema-berat saya dari menggunakan/bin/echo
ke gema shell kinerja hampir dua kali lipat. Ini merupakan trade off antara portabilitas dan kinerja. Ini bukan slam dunk untuk selalu digunakanprintf
.sumber
printf
dibangun di sebagian besar shell saat ini (bash, dash, ksh, zsh, yash, beberapa turunan pdksh ... jadi sertakan juga shell yang biasanya ditemukan di cygwin). Satu-satunya pengecualian adalah beberapapdksh
turunan.printf
untuk menghasilkan byte byte, tetapi beberapa implementasi menafsirkan `\ c 'dalam format string walaupun seharusnya tidak.printf
tidak ditentukan oleh POSIX jika Anda menggunakan\c
dalam format string, sehinggaprintf
implementasi dapat melakukan apapun yang mereka inginkan dalam hal itu. Sebagai contoh, beberapa memperlakukannya sama seperti di PWBecho
(menyebabkan printf keluar), ksh menggunakannya untuk\cA
karakter kontrol (untuk argumen format printf dan untuk$'...'
tetapi tidak untukecho
atauprint
!). Tidak yakin apa yang harus dilakukan dengan mencetak NUL byte, atau mungkin Anda mengacu padaksh
'sprintf '\c@'
?