Kapan saya harus menggunakan #! / Bin / bash dan kapan #! / Bin / sh?

104

Kapan #!/bin/bashlebih tepat daripada #!/bin/shdalam skrip shell?

Hendré
sumber
55
Ketika Anda menggunakan bashfungsi dan sintaks daripada shfungsi dan sintaksis.
Mokubai
3
Jika itu membantu siapa pun, saya perhatikan itu vimakan menyoroti bash-ism jika skrip Anda memiliki #!/bin/shshebang. Saya hanya mengubahnya bashjika semuanya menjadi cukup berbulu untuk mulai membutuhkan fitur bash.
SeldomNeedy
@SeldomNeedy Beberapa hal yang disorot secara default berfungsi dengan baik di setiap shell POSIX. $(...)sangat menjengkelkan. Juga, beberapa di antaranya tidak jelas [ <(...)dan cmd >& filetidak mendapatkan sorotan kesalahan, misalnya, mereka tidak memiliki sorotan khusus untuk apa yang mereka maksud, dengan atau tanpa g:is_bash]
Random832
@ Random832 Sepertinya ada beberapa aktivitas pada topik ini baru-baru ini di pelacak isu vim .
SeldomNeedy

Jawaban:

150

Pendeknya:

  • Ada beberapa shell yang menerapkan superset dari spesifikasi sh POSIX . Pada sistem yang berbeda, /bin/shmungkin tautan ke ash, bash, dash, ksh, zsh, & c. (Akan selalu kompatibel dengan sh - tidak pernah csh atau ikan.)

  • Selama Anda tetap berpegang pada shfitur saja, Anda dapat (dan mungkin bahkan harus) menggunakan #!/bin/shdan skrip harus bekerja dengan baik, tidak peduli yang shell itu.

  • Jika Anda mulai menggunakan fitur khusus bash (misalnya array), Anda harus secara spesifik meminta bash - karena, bahkan jika /bin/shsudah memanggil bash pada sistem Anda , mungkin tidak pada sistem orang lain , dan skrip Anda tidak akan berjalan di sana. (Hal yang sama tentu saja berlaku untuk zsh dan ksh.) Anda dapat menggunakan shellcheck untuk mengidentifikasi bashism.

  • Meskipun skrip ini hanya untuk penggunaan pribadi, Anda mungkin memperhatikan bahwa beberapa OS berubah /bin/shselama peningkatan - misalnya pada Debian dulu bash, tetapi kemudian diganti dengan tanda hubung yang sangat minimal. Script yang menggunakan bashism tapi #!/bin/shtiba - tiba pecah.

Namun:

  • Bahkan #!/bin/bashtidak terlalu benar. Pada sistem yang berbeda, bash mungkin hidup di /usr/binatau /usr/pkg/binatau /usr/local/bin.

  • Opsi yang lebih andal adalah #!/usr/bin/env bash, yang menggunakan $ PATH. (Meskipun envalat itu sendiri juga tidak dijamin ketat, /usr/bin/envmasih berfungsi pada lebih banyak sistem daripada yang /bin/bashdilakukan.)

grawity
sumber
10
Jawaban bagus. Apakah Anda bermaksud menjadikannya CW?
Mokubai
3
Hanya komentar jika bash dijalankan sejak /bin/shsaat itu maka ia akan mencoba meniru shfitur (lihat halaman manual ), tidak yakin fitur spesifik bash tersedia dalam mode ini. envtool adalah alat posix yang harus ditemukan di sebagian besar distribusi, tetapi saya tidak yakin karena beberapa mungkin tidak menghargai posix.
Brice
8
Tidak, pada kenyataannya POSIX secara khusus menyatakan bahwa ia tidak dapat diasumsikan berada di /bin: " Aplikasi harus mencatat bahwa PATH standar untuk shell tidak dapat dianggap sebagai / bin / sh atau / usr / bin / sh, dan harus ditentukan dengan menginterogasi PATH yang dikembalikan oleh getconf PATH, memastikan bahwa pathname yang dikembalikan adalah pathname absolut dan bukan sebuah shell built-in ". Lihat juga pertanyaan ini dan, khususnya jawaban ini .
terdon
12
Hmm, well, jadi itu berarti POSIX tidak benar-benar mendefinisikan cara portabel untuk membuat #!skrip berfungsi?
grawity
4
POSIX sh bukan Bourne: ini lebih merupakan turunan dari ksh awal daripada turunan langsung dari Bourne. Membedakannya mudah: echo foo ^ catmemancarkan foo ^ catdalam POSIX sh, dan memancarkan hanya foodalam Bourne (seperti ^karakter pipa di sana).
Charles Duffy
18

Gunakan shebang yang sesuai dengan shell yang sebenarnya Anda gunakan untuk mengembangkan dan men-debug skrip Anda. Yaitu jika shell login Anda bash, dan Anda menjalankan skrip Anda sebagai executable di terminal Anda, gunakan #!/bin/bash. Jangan hanya berasumsi bahwa karena Anda belum menggunakan array (atau bashfitur apa pun yang Anda ketahui), Anda aman untuk memilih shell apa pun yang Anda suka. Ada banyak perbedaan halus antara shell ( echo, fungsi, loop, sebut saja) yang tidak dapat ditemukan tanpa pengujian yang tepat.

Pertimbangkan ini: jika Anda pergi #!/bin/bashdan pengguna Anda tidak memilikinya, mereka akan melihat pesan kesalahan yang jelas, kira-kira seperti

Error: /bin/bash not found

Sebagian besar pengguna dapat memperbaiki ini dalam waktu kurang dari satu menit dengan menginstal paket yang sesuai. Di sisi lain, jika Anda mengganti shebang dengan #!/bin/shdan mengujinya pada sistem /bin/shyang memiliki symlink /bin/bash, pengguna Anda yang tidak memiliki bashakan bermasalah. Mereka kemungkinan besar akan melihat pesan kesalahan samar seperti:

Error in script.sh line 123: error parsing token xyz

Mungkin perlu waktu berjam-jam untuk memperbaikinya, dan tidak akan ada petunjuk tentang cangkang mana yang seharusnya mereka gunakan.

Tidak banyak alasan mengapa Anda ingin menggunakan shell yang berbeda di shebang. Salah satu alasannya adalah ketika shell yang Anda gunakan tidak tersebar luas. Yang lain adalah untuk mendapatkan kinerja shyang secara signifikan lebih cepat pada beberapa sistem, DAN skrip Anda akan menjadi hambatan kinerja. Dalam hal ini, uji skrip Anda secara menyeluruh dengan shell target, lalu ubah shebang.

Dmitry Grigoryev
sumber
@ Rushur, saya tidak mendapatkan komentar Anda. Shebang pasti akan menentukan shell mana yang akan digunakan untuk menjalankan skrip, apakah menurut Anda jawaban saya menyiratkan sebaliknya?
Dmitry Grigoryev
1
Lupakan. Saya salah memahami bagian "mengapa Anda ingin menggunakan" ...
Hastur
6

Anda seharusnya hanya menggunakan #! /bin/sh.

Anda seharusnya tidak menggunakan ekstensi bash (atau zsh, atau fish, atau ...) dalam skrip shell.

Anda harus hanya pernah menulis skrip shell yang bekerja dengan setiap pelaksanaan bahasa shell (termasuk semua "utilitas" program yang pergi bersama dengan shell itu sendiri). Saat ini Anda mungkin dapat menggunakan POSIX.1-2001 ( tidak -2008) sebagai otoritatif untuk kemampuan shell dan utilitas, tetapi perlu diketahui bahwa suatu hari Anda mungkin diminta untuk mem-porting skrip Anda ke sistem lawas (mis. Solaris atau AIX) yang cangkangnya dan utilitasnya dibekukan sekitar tahun 1992.

Apa, serius ?!

Ya, serius.

Begini masalahnya: Shell adalah bahasa pemrograman yang mengerikan . Satu-satunya hal yang telah terjadi adalah bahwa /bin/shadalah satu-satunya juru bahasa script yang setiap instalasi Unix dijamin miliki.

Inilah hal lainnya: beberapa iterasi dari interpreter inti Perl 5 ( /usr/bin/perl) lebih mungkin tersedia pada instalasi Unix yang dipilih secara acak daripada (/(usr|opt)(/(local|sfw|pkg)?)?/bin/bash. Bahasa scripting lain yang bagus (Python, Ruby, node.js, dll. - Saya bahkan akan memasukkan PHP dan Tcl dalam kategori itu ketika membandingkan dengan shell) juga kira-kira tersedia sebagai bash dan shell diperluas lainnya.

Oleh karena itu, jika Anda memiliki opsi untuk menulis skrip bash, Anda memiliki opsi untuk menggunakan bahasa pemrograman yang tidak buruk.

Sekarang, skrip shell sederhana , jenis yang hanya menjalankan beberapa program secara berurutan dari pekerjaan cron atau sesuatu, tidak ada yang salah dengan membiarkannya sebagai skrip shell. Tetapi skrip shell sederhana tidak membutuhkan array atau fungsi atau [[bahkan. Dan Anda hanya harus menulis skrip shell rumit ketika Anda tidak punya pilihan lain. Skrip autoconf, misalnya, adalah skrip shell yang benar. Tetapi skrip-skrip tersebut harus dijalankan pada setiap inkarnasi /bin/shyang relevan dengan program yang sedang dikonfigurasi. dan itu berarti mereka tidak dapat menggunakan ekstensi apa pun. Anda mungkin tidak perlu peduli dengan Unix lama yang sudah dipatenkan belakangan ini, tetapi Anda mungkin harus peduli dengan BSD sumber terbuka saat ini, beberapa di antaranya tidak menginstalbashsecara default, dan lingkungan tertanam yang memberi Anda hanya shell minimal dan busybox.

Kesimpulannya, saat Anda mendapati diri Anda menginginkan fitur yang tidak tersedia dalam bahasa shell portabel, itu adalah tanda bahwa skrip menjadi terlalu rumit untuk tetap menggunakan skrip shell. Tulis ulang dalam bahasa yang lebih baik.

zwol
sumber
4
Maaf tapi itu agak konyol. Ya, jika Anda menulis sesuatu yang akan i) didistribusikan dan ii) ke lingkungan yang berbeda, Anda harus tetap berpegang pada dasar sh. Namun, itu jauh dari pernyataan bahwa Anda tidak boleh menggunakan kerang lainnya. Ada ribuan (mungkin lebih banyak) skrip yang ditulis setiap hari dan sebagian besar dari mereka hanya akan berjalan pada satu mesin. Saran Anda masuk akal pada kode produksi, tetapi tidak untuk pekerjaan "sysdaminy" harian yang ditulis untuk sebagian besar skrip. Jika saya tahu bahwa skrip saya hanya akan digunakan oleh saya dan di mesin Linux, bash baik-baik saja.
terdon
1
@terdon Intinya adalah bahwa jika Anda memiliki pilihan untuk menulis skrip bash, maka Anda juga memiliki opsi untuk menulis skrip perl (atau apa pun), dan ini selalu merupakan pilihan yang lebih baik.
zwol
@terdon Jawabannya tentu tidak konyol, komentar Anda malah naif. Skrip Shell mengerikan untuk di-debug dibandingkan dengan Perl dan semacamnya, yang dengannya seseorang dapat dengan mudah menggunakan IDE lengkap dengan debugging grafis dan semuanya. Selain itu, sebagian besar skrip yang ditulis setiap hari untuk beberapa hal kecil yang harus dilakukan cenderung diubah dan diubah lagi, tumbuh, disalin sebagai contoh untuk kolega atau internet dll. Kemungkinan besar tidak ada alasan untuk mengambil risiko seperti itu.
Thorsten Schöning
@ ThorstenSchöning kataku agak konyol. Jika ini adalah Unix & Linux atau bahkan Stack Overflow, saya bahkan mungkin setuju. Jika kita berbicara tentang praktik terbaik umum, atau programmer profesional, tentu saja yang terbaik adalah tetap berpegang pada POSIX sh dasar. Namun, ini adalah Super User , sebuah situs yang ditujukan untuk pengguna akhir dan memberitahu orang-orang untuk tidak pernah menggunakan bash atau zsh ketika menulis skrip shell, menurut pendapat saya, ekstrem.
terdon
@terdon Sebenarnya, lebih penting, menurut saya, untuk mencegah pengguna akhir menulis skrip shell yang rumit. Para profesional rata-rata memiliki tingkat keterampilan yang lebih tinggi (sehingga mereka lebih mungkin mampu mengatasi perangkap skrip shell yang kompleks), harus tahu dengan presisi lingkungan mana yang mereka butuhkan untuk dibawa-bawa, dan dibayar untuk tidak menyerah dalam frustrasi.
zwol
4

Umumnya jika waktu lebih penting daripada fungsi, Anda akan menggunakan shell yang lebih cepat. sh sering disebut dengan tanda hubung dan cenderung digunakan untuk tugas cron root atau operasi batch di mana setiap (nano) detik diperhitungkan.

mckenzm
sumber
2
Memuat interpreter shell tambahan dari sistem file dapat meniadakan keuntungan seperti itu, dan apa pun di mana nanoseconds (yang berada dalam urutan yang sama besarnya dengan siklus mesin yang sebenarnya) dihitung adalah domain C dan programmer bahasa assembly.
rackandboneman
Nanoseconds hanya membuat perbedaan dalam pekerjaan cron jika Anda memiliki miliaran, dan cron tidak akan mampu menangani begitu banyak pula.
Dmitry Grigoryev
1
Bahkan jika mckenzm sedikit dibesar-besarkan, tidak dapat disangkal bahwa memiliki lebih banyak kinerja lebih baik! Jangan terpaku pada bagian "nano". (Nanoseconds bahkan tidak dihitung dalam C kecuali jika itu adalah loop dalam pada sistem real-time atau semacamnya!)
jpaugh
1
@jpaugh Kecuali Anda bekerja dengan sistem (peninggalan) yang mengasumsikan operasi tertentu akan memakan waktu setidaknya satu periode waktu tertentu. Itu terjadi!
JAB
3

Agar lebih singkat, gunakan shjika portabilitas di sebagian besar sistem adalah yang paling penting dan bashjika Anda ingin menggunakan beberapa fitur spesifiknya, seperti array, jika versi bash mendukungnya.

Spencer Williams
sumber
1
  • sh (untuk kebanyakan kasus), bash jika diperlukan secara khusus (atau ksh, atau apa pun)

Jalan teraman. ketika hard coded, akan menjadi / usr / bin / shellOfChoicetetapi konvensi baru yang saya coba gunakan selalu sekarang - karena 'lokasi default' melalui perubahan yang PATH dapat ubah adalah:

#! / usr / bin / env sh atau
#! / usr / bin / env bash
atau untuk misalnya, skrip perl
#! / usr / bin / env perl -w

Tentu saja, ketika Anda memiliki alasan untuk skrip TIDAK PERNAH secara otomatis mengambil PATH baru kemudian terus memilikinya hard-kode - dan kemudian / usr / bin / sesuatu harus menjadi jalan yang paling mungkin untuk digunakan.

Michael Felt
sumber