Mengapa echo "bar" -n berbeda dari echo -n "bar"?


10

Membandingkan

echo -n "bar"

dengan

echo "bar" -n

Yang pertama melakukan apa yang saya pikir seharusnya dilakukan (mencetak "bar" tanpa baris baru), sedangkan yang kedua tidak. Apakah ini bug atau desain? Mengapa berbeda dari banyak program klien karena Anda tidak dapat memindahkan opsi? Misalnya, tail -f /var/log/messagespersis sama dengan tail /var/log/messages -f. Saya terkadang melakukan yang terakhir ketika saya lupa saya menginginkan yang pertama, karena secara internal opsi dan argumen disusun ulang, biasanya dengan getopt .

Pembaruan: ya saya awalnya nerf-ed pertanyaan saya Saya menghapus nerf Anda harus melihat sejarah untuk membuat beberapa jawaban masuk akal.


3
Dari apa yang saya lihat, perbedaan adalah segera jelas. echo -n "bar"memberi "bar", sementara echo "bar" -nmemberi "bar -n"
phunehehe

Jawaban:


18

Seperti yang diamati sebagian besar orang lain, "-n" diartikan secara harfiah jika ditempatkan di mana saja tetapi segera setelah echoperintah.

Secara historis, utilitas UNIX semuanya seperti ini - mereka mencari opsi hanya segera setelah nama perintah. Kemungkinan besar BSD atau GNU yang memelopori gaya yang lebih fleksibel (meskipun saya bisa saja salah), karena bahkan sekarang POSIX menetapkan cara lama sebagai yang benar (lihat Pedoman 9, dan juga man 3 getoptpada sistem Linux). Bagaimanapun, meskipun sebagian besar utilitas Linux saat ini menggunakan gaya baru, ada beberapa ketidaksepakatan seperti echo.

Echoberantakan, standar-bijaksana, dalam bahwa ada setidaknya dua versi yang secara mendasar bertentangan dalam permainan pada saat POSIX muncul. Di satu sisi, Anda memiliki gaya SYSV, yang menafsirkan karakter backslash-lolos tetapi sebaliknya memperlakukan argumennya secara harfiah, tidak menerima opsi. Di sisi lain, Anda memiliki gaya BSD, yang memperlakukan inisial -nsebagai case khusus dan menampilkan benar-benar semua yang lainnya secara harfiah. Dan karena echosangat nyaman, Anda memiliki ribuan skrip shell yang bergantung pada satu perilaku atau yang lain:

echo Usage: my_awesome_script '[-a]' '[-b]' '[-c]' '[-n]'
echo -a does a thing.
echo -b does something else.
echo -c makes sure -a works right.
echo -- DON\'T USE -n -- it\'s not finished! --

Karena semantik "perlakukan semuanya secara harfiah", tidak mungkin bahkan menambahkan opsi baru echotanpa merusak barang-barang. Jika GNU menggunakan skema opsi fleksibel di atasnya, neraka akan hilang.

Kebetulan, untuk kompatibilitas terbaik antara implementasi shell Bourne, gunakan printfdaripadaecho .

DIPERBARUI untuk menjelaskan mengapa echosecara khusus tidak menggunakan opsi yang fleksibel.


Terpilih karena Anda satu-satunya yang menyebutkan itulah perilaku getopt yang diharapkan.
Geoffrey Bachelet

@ jander mengapa gema "ketidaksepakatan"? Saya pikir itu gnu coreutil?
xenoterracide

@ xeno: Saya sudah memperbarui jawaban saya. Pada dasarnya, GNU tidak ingin merusak sesuatu.
Jander

1
Menerima pilihan setelah yang pertama non-pilihan adalah khusus untuk GNU utilitas dan program menggunakan GNU libc 's getopt fasilitas. Pengguna selalu bisa mendapatkan perilaku kompatibel yang mundur dengan mengatur variabel lingkungan POSIXLY_CORRECT.
Gilles 'SANGAT berhenti menjadi jahat'

1
Untuk kasus spesifik echo, ada juga implementasi yang mengenali -eatau -Esebagai opsi. Untuk portabilitas, jangan mulai dengan -atau menggunakan sesuatu seperti printf %s -e.
Gilles 'SANGAT berhenti jahat'

9

Jawaban lainnya sampai pada titik di mana Anda dapat melihat halaman manual untuk melihat bahwa -n menjadi bagian dari string yang ingin digaungkan. Namun saya hanya ingin menunjukkan bahwa mudah untuk menyelidiki hal ini tanpa md5sum dan membuat apa yang terjadi sedikit lebih samar.

[11:07:44][dasonk@Chloe:~]: echo -n "bar"
bar[11:07:48][dasonk@Chloe:~]: echo "bar" -n
bar -n

3
Memberi +1 secara tepat. Jika pipa tidak melakukan apa yang Anda harapkan, uji setiap bagian secara terpisah.
Mikel

6

Wow, penjelasan semua orang cukup panjang.

Sesederhana ini:

-n adalah opsi jika muncul sebelum string, jika tidak maka hanya string lain yang akan digaungkan.

Hapus | md5sum dan Anda akan melihat hasilnya berbeda.


5

Dari pemeriksaan sederhana, ini bukan bug dengan desain ...

echo "bar" -n | md5sum

a3f8efa5dd10e90aee0963052e3650a1

Coba perintah ini sendiri:

echo "bar -n" | md5sum

Anda akan melihat bahwa md5 yang dihasilkan adalah

a3f8efa5dd10e90aee0963052e3650a1

Anda baru saja mencampuradukkan penggunaan -n dalam gema.

Dalam kode sampel pertama Anda

echo -n "bar" | md5sum

-n digunakan untuk mengatakan JANGAN menaruh baris baru setelah gema ini.

Sampel kedua Anda

echo "bar" -n | md5sum

memperlakukan -n sebagai teks literal.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.