Bagaimana tepatnya “/ bin / [” bekerja?

50

Saya selalu terkejut bahwa di folder /binada [program.

Apakah ini yang disebut ketika kita melakukan sesuatu seperti if [ something ]:?

Dengan memanggil [program secara eksplisit dalam sebuah shell, ia meminta korespondensi ], dan ketika saya memberikan braket penutup sepertinya tidak melakukan apa pun, apa pun yang saya masukkan di antara kurung.

Tak perlu dikatakan, cara biasa untuk mendapatkan bantuan tentang suatu program tidak bekerja, yaitu tidak man [juga tidak [ --helpberfungsi.

Bregalad
sumber
11
@IporSircer [merujuk pada testperintah, bukan expr, jadi seharusnyaman test
Sergiy Kolodyazhnyy
8
man '['berfungsi dengan baik untuk saya - baik Anda lupa mengutip [atau Anda memiliki definisi yang berbeda dari "karya".
Toby Speight
3
Beberapa peringatan: [mengevaluasi argumennya, jadi Anda perlu memiliki ruang di antara semuanya. [ a=b ]bukan perbandingan: itu akan selalu benar (itu adalah string tunggal: "a = b", yang selalu dievaluasi menjadi benar ) Dan Anda harus membatasi jumlah argumen hingga 4 (meskipun implementasi terbaru akan memungkinkan lebih banyak .. membatasi hingga 4 menjadikannya lebih portabel. Misalnya: [ "a" = "b" ]sudah memiliki 4 argumen: "a" "=" "b" dan akhir uji arg yang tidak perlu: "]"). Jika Anda membutuhkan lebih banyak: tes berantai dengan misalnya:if [ "$Var_a" = "foo" ] && [ "$Var_b" = "bar" ] ; then : do something ; fi
Olivier Dulac
1
@OlivierDulac !dengan sendirinya (tidak dihapus dan tidak dikutip) tidak akan diganti, dan bahkan lebih baik if ! [ .... Semua ekspansi bash yang digunakan !termasuk setidaknya pada karakter lain
muru
3
Anda juga harus mencatat bahwa ada [-builtin di bash(dan mungkin juga kerang lain), dan ini bisa digunakan sebagai ganti /bin/[. Juga ada testperintah-, yang pada banyak sistem adalah tautan simbolis ke /bin/[(atau sebaliknya) - tetapi pada yang lain adalah perintah yang terpisah.
Baard Kopperud

Jawaban:

63

Tugas [perintah adalah mengevaluasi ekspresi pengujian. Ia kembali dengan status keluar 0 (itu berarti benar ) ketika ekspresi diselesaikan menjadi benar dan sesuatu yang lain (yang berarti salah ) sebaliknya.

Bukannya tidak melakukan apa-apa, hanya saja hasilnya ditemukan dalam status keluarnya. Dalam sebuah shell, Anda dapat mencari tahu tentang status keluar dari perintah terakhir di $?untuk shell mirip Bourne atau $statusdi sebagian besar shell lainnya (fish / rc / es / csh / tcsh ...).

$ [ a = a ]
$ echo "$?"
0
$ [ a = b ]
$ echo "$?"
1

Dalam bahasa lain seperti perl, status keluar dikembalikan misalnya dalam nilai pengembalian system():

$ perl -le 'print system("[", "a", "=", "a", "]")'
0

Perhatikan bahwa semua kerang mirip Bourne modern (dan fish) memiliki [perintah bawaan. Yang masuk /binbiasanya hanya akan dieksekusi ketika Anda menggunakan shell lain atau ketika Anda melakukan hal-hal seperti env [ foo = bar ]atau find . -exec [ -f {} ] \; -printatau perlperintah di atas ...

The [perintah juga dikenal dengan testnama. Ketika dipanggil sebagai test, itu tidak memerlukan ]argumen penutup .

Meskipun sistem Anda mungkin tidak memiliki halaman manual [, mungkin memiliki satu halaman untuk test. Tetapi sekali lagi, perhatikan bahwa itu akan mendokumentasikan /bin/[atau /bin/testimplementasi. Untuk mengetahui tentang [builtin di shell Anda, Anda harus membaca dokumentasi untuk shell Anda.

Untuk informasi lebih lanjut tentang sejarah utilitas itu dan perbedaannya dengan [[...]]ekspresi pengujian ksh, Anda mungkin ingin melihat pada Tanya Jawab lain di sini .

Stéphane Chazelas
sumber
Bagus, seperti biasa. Anda mungkin ingin menambahkan komentar yang saya tambahkan di bawah pertanyaan @Bregalad? atau mungkin yang ekstra? Dengan begitu, jawabannya akan lebih lengkap pada "bagaimana tepatnya kerjanya" (saya perhatikan Anda sudah memberikan info yang lebih akurat tentang "]" daripada yang saya lakukan ^^)
Olivier Dulac
"Semua kerang mirip Bourne (dan ikan) memiliki [perintah" built-in] Itu benar dalam praktiknya di abad ke-21, tapi saya cukup yakin saya telah menggunakan shell tanpa [. Saya tidak ingat apakah itu varian Bourne atau versi antik abu.
Gilles 'SO- stop being evil'
@Gilles Shell Bourne mengimplementasikan keduanya [dan testsebagai bawaan dengan Unix System III. Sebelum itu, tidak ada [dan testhanya ada perintah biner eksternal.
jlliagre
@Gilles, abu asli memiliki uji builtin (digabung dengan expr), tetapi opsional . Menurut in-ulm.de/ ~mascheck/various/ash , BSD tidak memiliki tes bawaan sampai sekitar tahun 2000. Saya telah menambahkan "modern".
Stéphane Chazelas
Mengapa di dunia ini Anda ingin melakukan find . -exec [ f {} ] \; -print? Perintah itu find . -type f -printakan melakukan hal yang sama dengan jauh lebih efisien ...
Ini bukan nama asliku
41

Saya selalu terkejut bahwa di folder /binada [program.

Anda benar terkejut. Itu salah satu perintah POSIX yang langka, dengan utilitas nol ( :), yang tidak menghormati file perintah yang diizinkan konvensi karakter (kumpulan karakter nama file portabel).

Apakah yang disebut ketika kita melakukan sesuatu seperti if [ something ]:?

Tepatnya tetapi bisa digunakan tanpa ifterlalu.

Dengan memanggil [program secara eksplisit dalam sebuah shell, ia meminta korespondensi ], dan ketika saya memberikan braket penutup sepertinya tidak melakukan apa pun, apa pun yang saya masukkan di antara kurung.

Itu tidak terlihat tetapi benar-benar melakukan hal yang sama daripada ketika digunakan dengan if, yaitu menetapkan status keluar ke 0 (benar) atau apa pun (salah) tergantung pada apa yang Anda masukkan ke dalam kurung. Itu (karena suatu alasan) perilaku yang sama dengan testperintah; satu-satunya perbedaan adalah bahwa ia mencari akhirannya ]. Lihat man testdetailnya.

Tak perlu dikatakan, cara biasa untuk mendapatkan bantuan tentang suatu program tidak bekerja, yaitu tidak man [juga tidak [ --helpberfungsi.

Itu tergantung pada Sistem Operasi Anda. man [pasti bekerja untuk saya di beberapa distribusi Gnu / Linux arus utama tetapi tidak pada Solaris.

[ --helpmungkin bekerja atau tidak tergantung pada implementasi karena melanggar sintaks, melewatkan bagian akhirnya ]. Selain itu, standar POSIX untuk perintah test/[ secara eksplisit mengesampingkan semua opsi, termasuk --penghentian opsi sehingga keduanya [ --help ]dan test --helpperlu kembali truedan diam dengan desain. Perhatikan bahwa apa yang Anda masukkan di dalam kurung atau setelah [dan terlihat seperti pilihan (misalnya -f file, -n string, dan sejenisnya) tidak pilihan tapi operan .

Semua Bourne gaya shell interpreter modern (seperti bash, ksh, dashdan zshuntuk beberapa nama) melaksanakan test/ [utilitas internal sebagai builtin sehingga ketika Anda menggunakannya, halaman manual yang tepat untuk merujuk mungkin salah satu dari shell, bukan testsatu.

Sebelum Unix System III (1981), shell Bourne tidak mengimplementasikan testutilitas sebagai builtin sehingga hanya implementasi perintah biner eksternal yang tersedia. Tidak ada [perintah (internal atau builtin) sampai Unix System III jadi misalnya di bawah Unix Versi 7 Anda harus mengetik:

if test something ; then

dari pada:

if [ something ] ; then
Jlliagre
sumber
"man [pasti bekerja untuk saya di distribusi Gnu / Linux arus utama" Hmm .. Centos (diakui masih 6,8) jelas tidak cukup mainstream :) man testbekerja tetapi tidak man [ Di sisi lain, lingkungan cygwin saya diketahui man [!
Adam
1
@ Adam Ya, Anda benar, itu lebih baru daripada yang saya kira meskipun saya tidak menulis semua distro Linux utama, hanya saja itu bekerja untuk saya (yaitu pada yang saya uji). Yaitu klon OL 7.2 (RHEL 7.2) dan Mint 17.1 (Ubuntu 14.04).
jlliagre
man [tampaknya tidak berfungsi di Manjaro (Arch Linux based). Manual untuk testdaftar [ --helpsebagai doa sah yang harus menunjukkan bantuan, tetapi yang menarik tidak, dan sebaliknya mengeluh tentang yang hilang ], sama dengan --version. Menambahkan ]tidak melakukan apa-apa, jadi sepertinya tidak mungkin untuk mendapatkan bantuan selain dari man test.
Darkhogg
@ Arkhogg Anda dapat mencoba /usr/bin/[ --helpatau /bin/[ --help.
jlliagre
1
@ jlliagre Anda sepenuhnya benar, saya menggunakan builtin. env [ --helpserta /usr/bin/[ --helpbekerja sepenuhnya baik-baik saja (meskipun saya perlu mengutip /usr/bin/[atau mengeluh zsh).
Darkhogg
10

[sebenarnya lebih dikenal sebagai testperintah. Penggunaan khas dari perintah ini hanya untuk mengevaluasi ekspresi dan mengembalikan kondisinya - benar atau salah. Ini sering digunakan dalam if-then-else-fipernyataan, meskipun dapat digunakan di luar ifpernyataan untuk menjalankan perintah lain secara kondisional melalui shell &&atau ||operator, seperti itu.

$ [ -e /etc/passwd  ] && echo "File exists"
File exists

$ test -e /etc/passwd && echo "File exists"
File exists

Lebih khusus lagi, evaluasi dikomunikasikan ke perintah lain melalui status keluar. Beberapa program mungkin memilih untuk mengeluarkan status keluar untuk menandakan berbagai jenis peristiwa - program berhasil diselesaikan, kesalahan jenis tertentu terjadi selama eksekusi, atau kesalahan sintaksis. Dalam hal testperintah, ada yang 0benar, dan yang 1salah. Seperti yang ditunjukkan Stephan, kesalahan sintaksis menghasilkan status keluar dari 2.

Lokasinya tergantung pada sistem Anda, dan itu juga menjelaskan mengapa Anda tidak melihat halaman manual ketika Anda melihatnya man [. Misalnya, pada FreeBSD itu di bawah /bin. Di Linux (atau dalam kasus khusus saya, Ubuntu 16.04) itu ada di /usr/bin/. Jika Anda melakukannya man [atau man testpada sistem Linux, Anda akan melihat dokumentasi yang sama terbuka. Penting juga untuk dicatat bahwa shell Anda mungkin memiliki implementasinya sendiri test.

Perlu juga dicatat bahwa perintah ini memiliki masalah , yang implementasi shell Korn (umumnya dikenal sebagai "ekspresi bersyarat" referensi dengan tanda kurung ganda, [[ "$USER" = "root" ]]) berusaha untuk menyelesaikan. Fitur ini juga digunakan oleh cangkang lain seperti bashdan zsh.

Sergiy Kolodyazhnyy
sumber
/usr/bin/untuk Amazon Linux juga.
franklinsijo
@ StéphaneChazelas Terima kasih. Jawaban diedit sesuai
Sergiy Kolodyazhnyy
3

Tidak man [juga tidak [ --helpberfungsi

Pada beberapa distro (misalnya Ubuntu), man [ikuti symlink ke test(1). Pada yang lain (mis. Lengkungan), ini bukan masalahnya. (Tetapi testhalaman manual tidak mendokumentasikan penggunaan [juga)


type -a [ menunjukkan kepada Anda bahwa ada shell builtin dan executable.

$ type -a [
[ is a shell builtin
[ is /usr/bin/[

bash-builtin [ --helphanya mencetak pesan kesalahan. (Tapi karena itu builtin, Anda dapat menggunakan help [, atau melihat halaman bash man / docs).

/usr/bin/[ --help mencetak hasil bantuan penuh (untuk versi GNU Coreutils), yang dimulai dengan:

$ /usr/bin/[ --help
Usage: test EXPRESSION
  or:  test
  or:  [ EXPRESSION ]
  or:  [ ]
  or:  [ OPTION
Exit with the status determined by EXPRESSION.

      --help     display this help and exit
      --version  output version information and exit

dan kemudian menjelaskan sintaks yang diizinkan untuk EXPRESSION.

Ini adalah cara lain Anda bisa mengetahui [dan testsetara.


BTW, jika Anda memprogram untuk bash (atau menulis one-liners secara interaktif), saya akan merekomendasikan [[sebagai gantinya [. Lebih baik dalam beberapa hal, lihat tautan di jawaban Serg.

Peter Cordes
sumber
2

[perintah mengembalikan status keluar nol jika ekspresi, yang terkandung dalam argumennya, dianggap benar dan status keluar nol jika ekspresi, yang terkandung dalam argumennya, dianggap salah. Itu juga gagal dengan pesan kesalahan jika argumen terakhirnya tidak ](ini dilakukan murni karena alasan estetika).

Misalnya:

[ hello ]
echo "Exit-status of [ hello ] is:" $?
[ abc = abc ]
echo "Exit-status of [ abc = abc ] is:" $?
[ ]
echo "Exit-status of [ ] is:" $?
[ abc = def ]
echo "Exit-status of [ abc = def ] is:" $?

... akan menampilkan:

Status keluar dari [halo] adalah: 0       - karena string yang tidak kosong dianggap benar 
Status keluar dari [abc = abc] adalah: 0   - karena 'abc' benar-benar sama dengan 'abc' 
Status keluar dari [] adalah : 1             - karena string kosong dianggap false 
Status keluar dari [abc = def] adalah: 1   - karena 'abc' benar-benar berbeda dari 'def'

Namun, bash dan banyak shell lain biasanya tidak memanggil /bin/[(atau /usr/bin/[) dalam kasus ini, tetapi panggil perintah built-in dengan perilaku yang persis sama sebagai gantinya (murni untuk alasan kinerja). Untuk memanggil /bin/[(bukan shell built-in surrogate), Anda perlu menentukan pathnya secara eksplisit (misalnya /bin/[ hello ]; Anda tidak perlu awalan ]dengan dirname ☺ ), atau untuk mengkonfigurasi shell agar tidak menggunakan pengganti built-in (misalnya, enable -n [dalam bash).

PS: Seperti yang dikatakan dalam jawaban lain [terkait dengan test. Tapi test, tidak seperti [, tidak memerlukan ]sebagai argumen yang terakhir (dan tidak mengharapkan sama sekali, menambahkan ekstra ]untuk testargumen dapat menyebabkan gagal dengan pesan kesalahan atau kembali hasil yang salah) . Itu /bin/testdan /bin/[dapat menyelesaikan ke file yang sama (misalnya satu adalah symlinked ; dalam hal ini pengalihan perilaku mungkin dilaksanakan dengan menganalisis perintah yang saat ini disebut dalam test/ [kode itu sendiri) atau ke file yang berbeda. Untuk test, shell juga biasanya memanggil pengganti bawaan, kecuali path ditentukan secara eksplisit ( /bin/test) atau dikonfigurasi untuk tidak melakukannya (enable -n test).

PPS: Tidak seperti testdan [, modern iftidak pernah menjadi file nyata. Itu bagian dari sintaks shell (mis. Bash): if commandA; then commandB; fi(baris baru dapat digunakan sebagai ganti titik koma) menyebabkan commandBdieksekusi jika-dan-hanya-jika commandAkeluar dengan status nol. Ini sangat cocok untuk perilaku testatau [, memungkinkan untuk menggabungkan mereka suka if [ "$a" = foo ]; then …; fi (atau if test "$a" = foo; then …; fi- kurang dibaca) . Namun, skrip modern sering menggunakan [[alih-alih testatau [, yang (sebagai if) tidak pernah menjadi file nyata, tetapi selalu menjadi bagian dari sintaks shell.

PPPS: Adapun man- jangan pernah berharap manuntuk memiliki artikel tentang setiap perintah di sistem file Anda. Info pada beberapa (bahkan "nyata", berkas-based) perintah mungkin hilang, info pada beberapa shell built-in mungkin hadir tidak hanya dalam sebuah artikel yang didedikasikan untuk shell tertentu (yang adalah tempat di mana Anda pasti akan menemukan info tentang test, [, if, [[). Namun, banyak distribusi memiliki man-artikel eksplisit untuk testdan [. (Tentang --help, itu tidak dikenali dengan testalasan yang jelas: perlu menangani kasus-kasus diam-diam seperti a=--help; test "$a"; pada beberapa distribusi [ --help(tanpa penutupan ]) masih menunjukkan bantuan, pada beberapa itu tidak.)

sasha
sumber
3
Perhatikan bahwa ifitu adalah perintah hingga Unix V6. Unix V7 (1979) datang dengan shell Bourne (dengan if-then-else-fikonstruknya) dan testperintah baru .
Stéphane Chazelas