Mengapa `==` berperilaku berbeda di dalam `[...]` dalam zsh dan bash?

9

Saya mendapatkan apa yang saya harapkan ketika melakukan ini di bash:

[ "a" == "a" ] && echo yes

Itu memberi saya yes.

Tetapi ketika saya melakukan ini zsh, saya mendapatkan yang berikut:

zsh: = not found

Mengapa perintah yang sama ( /usr/bin/[) berperilaku berbeda di shell yang berbeda?

Johnson Steward
sumber
5
ini bukan perintah yang sama - ini adalah builtin yang ditemukan sebelum $PATHdicari. dan ==bukan testsintaks yang valid untuk /usr/bin/[anway. Baik =-baik saja.
mikeserv

Jawaban:

18

Itu tidak ada /usr/bin/[di salah satu kerang. Dalam Bash, Anda menggunakan built-in test/ [perintah , dan sama di zsh .

Perbedaannya adalah bahwa zsh juga memiliki =ekspansi : =foomemperluas ke jalur ke fooexecutable. Itu berarti ==diperlakukan sebagai berusaha untuk menemukan perintah yang disebut =diPATH . Karena perintah itu tidak ada, Anda mendapatkan kesalahan

zsh: = not found

yang Anda lihat (dan pada kenyataannya, hal yang sama ini akan terjadi bahkan jika Anda benar-benar menggunakan /usr/bin/[).


Anda dapat menggunakan di ==sini jika Anda benar-benar menginginkannya. Ini berfungsi seperti yang Anda harapkan di zsh:

[ "a" "==" "a" ] && echo yes

karena kutipan mencegah =wordekspansi berjalan. Anda juga dapat menonaktifkan equalsopsi dengan setopt noequals.


Namun, Anda akan lebih baik:

  • Menggunakan tunggal =, tes kesetaraan yang kompatibel dengan POSIX ; atau
  • Lebih baik lagi, menggunakan [[kondisi dengan== baik di Bash dan zsh . Secara umum, [[lebih baik dan lebih aman di sekitar, termasuk menghindari masalah seperti ini (dan lainnya) dengan memiliki aturan penguraian khusus di dalam.
Michael Homer
sumber
Apa perbedaan tepatnya antara [dan [[? (Pencarian di Google hanya [ vs [[memberi saya hasil vs, LOL)
Johnson Steward
2
[[mendukung serangkaian tes yang lebih luas dalam kedua kasus, dan memiliki aturan penguraian khusus yang menghindari perlunya mengutip variabel, operator, dan sebagainya. Jika Anda secara khusus menggunakan Bash atau zsh, gunakan [[. Jika Anda menulis skrip portabel, tulis ke perintah [/ kompatibel POSIX test(yang mungkin atau mungkin bukan perintah nyata pada sistem Anda yang sedang berjalan).
Michael Homer
1
Cukup gunakan di [[sana dan lupakan saja [.
Michael Homer
1
Anda tahu ... saya tidak setuju dengan rekomendasi Anda. [[adalah berbeda mampu. coba ini dengan itu: for f in *; do [ -e "$f" ] && for a in f d h p S b c; do [ "-$a" "$f" ] && for p in r w x u g; do [ "-$p" "$f" ] || p=-; a=$a$p; done && break; done && printf "%s:\t%s\n" "$a" "$f"; done.
mikeserv
3
Nah, =/ ==ini bisa dibilang salah satu kasus di mana [[tidak lebih baik dari [, seperti [[ a == b ]]yang dilakukannya "a" cocok dengan "b" pola dan tidak adalah "a" sama dengan "b" seperti yang Anda harapkan. Itu artinya Anda harus menulis [[ $a == "$b" ]]misalnya. Setidaknya, dengan [perintah, jika Anda tahu cara kerja parsing perintah, Anda tahu Anda harus menulisnya [ "$a" = "$b" ]untuk mencegah operator split + glob seperti pada perintah lain. Dengan mengingat hal itu dan jika Anda tidak menggunakan -a atau -o, [aman dalam implementasi POSIX yang sesuai.
Stéphane Chazelas
2

Dan zsh, dan bash memberikan jawaban yang sama ( typejuga dibangun untuk kedua shell):

$ type -a [
[ is a shell builtin
[ is /usr/bin/[
Jshura
sumber
2

[ adalah perintah shell builtin di bash dan di zsh:

$ type [
[ is a shell builtin

Dari dokumentasi Perintah Shell Builtin :

Perintah builtin terdapat di dalam shell itu sendiri . Ketika nama perintah builtin digunakan sebagai kata pertama dari perintah sederhana (lihat Perintah Sederhana ), shell mengeksekusi perintah secara langsung, tanpa memanggil program lain. Perintah builtin diperlukan untuk mengimplementasikan fungsionalitas yang tidak mungkin atau tidak nyaman untuk didapatkan dengan utilitas terpisah.

Dokumentasi resmi ( $ help test) hanya memungkinkan untuk menggunakan =:

STRING1 = STRING2

Benar jika senarnya sama.

Jadi, ungkapan yang benar adalah:

$ [ "a" = "a" ] && echo yes
yes

Apa yang terjadi adalah bahwa bash agak kurang ketat. Mendukung ==operator dengan [ tampaknya merupakan ekstensi bash dan tidak disarankan untuk menggunakannya:

string1 == string2

string1 = string2

Benar jika senarnya sama. Ketika digunakan dengan perintah [[, ini melakukan pencocokan pola seperti dijelaskan di atas (lihat Conditional Constructs ).

'=' harus digunakan dengan perintah tes untuk kesesuaian POSIX.

Jika Anda ingin menggunakan ==, Anda harus menggunakan [[kata kunci:

$ [[ "a" == "a" ]] && echo yes
yes

Ingatlah bahwa [[itu kurang portabel (bukan POSIX). Tapi bash dan zsh mendukungnya.

zuazo
sumber
1

Di kedua shell, bashdan zsh, [utilitas adalah shell builtin. Ini adalah implementasi shell dari alat itu, digunakan sebagai preferensi terhadap biner /usr/bin/[. Perbedaan hasil yang Anda temui disebabkan oleh implementasi yang berbeda.


Di bash, [utilitas menerima CONDITIONAL EXPRESSIONSsebagai [[perintah majemuk. Menurut halaman manual bashs keduanya =dan ==valid:

string1 == string2
string1 = string2
        True if the strings are equal.  = should be used with the test command for POSIX
        conformance.

Dalam zsh, [utilitas mencoba untuk mengimplementasikan POSIX dan ekstensi-ekstensinya di tempat ini ditentukan. Dalam spesifikasi utilitas tes POSIX tidak ada ==operator yang ditentukan.

kekacauan
sumber