Apakah benar menggunakan / bin / sh dalam hashbang jika Bourne shell tidak tersedia dalam distribusi?

15

Umumnya, skrip shell berisi komentar berikut pada baris pertama dari file script: #!/bin/sh. Menurut penelitian yang saya buat, ini disebut "hash bang" dan ini adalah komentar konvensional. Komentar ini memberi tahu Unix bahwa file ini dijalankan oleh Bourne Shell di bawah direktori /bin.

Pertanyaan saya dimulai pada saat itu. Sampai sekarang saya belum melihat komentar ini seperti #!/bin/bash. Selalu begitu #!/bin/sh. Namun, distribusi Ubuntu tidak memiliki program Bourne Shell. Mereka memiliki Bourne Again Shell (bash).

Dalam hal itu, apakah benar menempatkan komentar #!/bin/shdalam skrip shell yang ditulis dalam distribusi Ubuntu?

Goktug
sumber
1
Lihat jawaban saya untuk pertanyaan serverfault ini: #! / Bin / sh vs #! / Bin / bash untuk portabilitas maksimum .
Gordon Davisson
Lebih umum disebutshebang
fpmurphy

Jawaban:

16

#!/bin/shharus bekerja pada semua distribusi Unix dan Unix-like. Biasanya dianggap sebagai hashbang paling portabel selama skrip Anda tetap sesuai dengan POSIX. The /bin/shshell seharusnya shell yang menerapkan POSIX shell standar, terlepas dari apa shell yang sebenarnya adalah bahwa menyamar sebagai /bin/shshell.


#!/bin/shbiasanya hanya sebuah tautan sekarang karena shell Bourne tidak lagi dipertahankan. Pada banyak sistem Unix /bin/shakan menjadi tautan ke /bin/kshatau /bin/ash, pada banyak sistem Linux berbasis RHEL, itu akan menjadi tautan /bin/bash, namun pada Ubuntu dan banyak sistem berbasis Debian, tautannya /bin/dash. Semua shell, jika dipanggil sebagai sh, akan memasuki mode kompatibilitas POSIX.

Hashbang adalah pengganti yang penting karena memungkinkan portabilitas yang jauh lebih besar daripada metode lain, selama skrip Anda benar-benar sesuai dengan POSIX (diulangi untuk menekankan pentingnya).

Catatan: Ketika bashdipanggil dalam mode POSIX itu masih akan memungkinkan beberapa hal non-POSIX seperti [[, array, dan banyak lagi. Hal-hal itu mungkin gagal pada non- bashsistem.

Jesse_b
sumber
3
"di Ubuntu ini adalah tautan ke / bin / dash" dan secara umum sistem berbasis Debian lainnya. IIRC pada FreeBSD / GhostBSD juga merupakan symlink /bin/ash.
Sergiy Kolodyazhnyy
Agar sepenuhnya portabel, beri jarak antara shebang dan jalur juru (absolut). Beberapa sistem mencari #! /bukan hanya #!.
Simon Richter
5
@SimonRichter Referensi untuk ini akan menyenangkan untuk dilihat.
Kusalananda
@SergiyKolodyazhnyy Versi sh yang terinstal di FreeBSD adalah ash dan bukan symlink.
Rob
2
@ Kusalananda, hmm, halaman ini mengatakan bahwa ini adalah mitos, jadi mungkin bisa diabaikan.
Simon Richter
12

Anda mendapatkannya mundur. /bin/shhampir tidak pernah menjadi Bourne shell hari ini, dan saat itulah it's Anda memiliki masalah ketika Anda menggunakan #! /bin/shbang-bang.

Cangkang Bourne adalah cangkang yang ditulis pada akhir 70-an dan menggantikan cangkang Thompson sebelumnya (juga disebut sh ). Pada awal 80-an, David Korn menulis beberapa ekstensi untuk shell Bourne, memperbaiki beberapa bug dan mendesain kecanggungan (dan memperkenalkan beberapa) dan menyebutnya shell Korn.

Pada awal 90-an, POSIX menentukan sh bahasa berdasarkan subset dari shell Korn dan sebagian besar sistem sekarang telah mengubah mereka /bin/shmenjadi shell Korn atau shell yang sesuai dengan spesifikasi itu. Dalam kasus BSD, mereka secara bertahap mengubah /bin/sh, awalnya (setelah mereka tidak bisa lagi menggunakan shell Bourne untuk alasan lisensi) shell Almquist, klon dari shell Bourne dengan beberapa ekstensi ksh sehingga menjadi sesuai dengan POSIX.

Saat ini, semua sistem POSIX memiliki shell yang disebut sh(paling sering, tetapi tidak harus dalam /bin, POSIX tidak menentukan jalur utilitas yang ditentukan) yang sebagian besar sesuai dengan POSIX. Biasanya didasarkan pada ksh88, ksh93, pdksh, bash, ash atau zsh², tetapi tidak pada shell Bourne karena shell Bourne tidak pernah sesuai dengan POSIX³. Beberapa dari mereka kerang ( bash, zsh, yashdan beberapa pdkshturunannya memungkinkan modus POSIX-compliant ketika dipanggil sebagai shdan kurang compliant sebaliknya).

bash (jawaban GNU ke shell Korn) sebenarnya adalah satu-satunya shell open source (dan bisa dikatakan hanya saat ini dipertahankan karena yang lain umumnya didasarkan pada ksh88 yang belum mendapatkan fitur baru sejak 90-an) yang telah disertifikasi sebagai menjadi POSIX compliant sh (sebagai bagian dari sertifikasi macOS).

Saat Anda menulis skrip dengan #! /bin/sh -she-bang, Anda harus menggunakan shsintaksis standar (dan juga harus menggunakan sintaksis standar untuk utilitas yang digunakan dalam skrip itu jika Anda ingin portabel, itu bukan hanya shell yang terlibat saat menafsirkan shell skrip), maka tidak masalah implementasi apa dari shinterpreter sintaks standar yang digunakan ( ksh, bash...).

Tidak masalah bahwa cangkang tersebut memiliki ekstensi melebihi standar selama Anda tidak menggunakannya. Ini seperti untuk menulis kode C, selama Anda menulis kode C standar dan tidak menggunakan ekstensi satu kompiler (sepertigcc ) atau yang lain, kode Anda harus dikompilasi OK terlepas dari implementasi kompiler asalkan kompiler sesuai.

Di sini, dengan Anda #! /bin/shdia-bang, masalah utama Anda akan menjadi sistem di mana /bin/shadalah Bourne shell yang misalnya tidak mendukung fitur standar seperti $((1+1)), $(cmd), ${var#pattern}... Dalam hal ini Anda mungkin perlu kerja-arounds seperti:

#! /bin/sh -
if false ^ true; then
  # in the Bourne shell, ^ is an alias for |, so false ^ true returns
  # true in the Bourne shell and the Bourne shell only.
  # Assume the system is Solaris 10 (older versions are no longer maintained)
  # You would need to adapt if you need to support some other system
  # where /bin/sh is the Bourne shell.
  # We also need to fix $PATH as the other utilities in /bin are
  # also ancient and not POSIX compatible.
  PATH=`/usr/xpg6/bin/getconf PATH`${PATH:+:}$PATH || exit
  export PATH
  exec /usr/xpg4/bin/sh "$0" "$@"
  # that should give us an environment that is mostly  compliant
  # to the Single UNIX Specification version 3 (POSIX.2004), the
  # latest supported by Solaris 10.
fi
# rest of the script

By the way, Ubuntu /bin/shtidak bashsecara default. Sekarang dashini, sebuah shell yang didasarkan pada NetBSD sh, itu sendiri berdasarkan pada shell Almquist yang sebagian besar sesuai dengan POSIX kecuali bahwa ia tidak mendukung karakter multi-byte. Di Ubuntu dan sistem berbasis Debian lainnya, Anda dapat memilih antara bashdan dashuntuk /bin/shdengan dpkg-reconfigure dash) 4 . shskrip yang dikirimkan dengan Debian harus bekerja sama di kedua shell karena ditulis ke standar kebijakan Debian (superset dari standar POSIX). Anda mungkin akan menemukan mereka juga bekerja OK di zsh's shemulasi atau bosh(mungkin tidak ksh93atau yashyang tidak memilikilocal builtin (yang dibutuhkan oleh kebijakan Debian tapi tidak POSIX)).

Semua sistem dalam lingkup di unix.stackexchange.com memiliki POSIX di sh suatu tempat. Kebanyakan dari mereka memiliki /bin/sh(Anda mungkin menemukan yang sangat jarang yang tidak memiliki /bindirektori tetapi Anda mungkin tidak peduli tentang itu), dan itu umumnya POSIXsh penerjemah (dan dalam kasus yang jarang terjadi, Bourne shell (non-standar) sebagai gantinya ).

Tetapi shapakah satu-satunya shell interpreter yang dapat dieksekusi dapat Anda temukan pada suatu sistem. Untuk shell lainnya, Anda dapat yakin macOS, Cygwin dan sebagian besar distribusi GNU / Linux akan memilikinya bash. OS yang diturunkan SYSV (Solaris, AIX ...) umumnya akan memiliki ksh88, mungkin ksh93. OpenBSD, MirOS akan memiliki turunan pdksh. macOS akan memiliki zsh. Tapi di luar itu, tidak akan ada jaminan. Tidak ada jaminan apakah bashshell yang lain akan dipasang di /binatau di tempat lain (biasanya ditemukan /usr/local/binpada BSD ketika diinstal misalnya). Dan tentu saja tidak ada jaminan versi shell yang akan diinstal.

Perhatikan bahwa #! /path/to/executableini bukan konvensi , ini adalah fitur dari semua kernel mirip Unix ( diperkenalkan pada awal 80-an oleh Dennis Ritchie ) yang memungkinkan mengeksekusi file sewenang-wenang dengan menentukan jalur penerjemah dalam baris pertama yang dimulai dengan #!. Itu bisa saja dapat dieksekusi.

Ketika Anda menjalankan sebuah file yang pertama baris dimulai dengan #! /some/file some-optional-arg, kernel berakhir mengeksekusi /some/filedengan some-optional-arg, jalur script dan argumen asli sebagai argumen. Anda dapat membuat baris pertama #! /bin/echo testuntuk melihat apa yang terjadi:

$ ./myscript foo
test ./myscript foo

Ketika Anda menggunakan /bin/sh -alih-alih /bin/echo test, kernel mengeksekusi /bin/sh - ./myscript foo, shmenginterpretasikan kode konten yang disimpan dalam myscriptdan mengabaikan baris pertama itu sebagai komentar (dimulai dengan #).


¹ Mungkin satu-satunya sistem hari ini di mana salah satu dari kita akan menemukan /bin/shyang didasarkan pada cangkang Bourne adalah Solaris 10. Solaris adalah salah satu dari beberapa Unices yang memutuskan untuk menyimpan cangkang Bourne di sana untuk kompatibilitas ke belakang ( shbahasa POSIX tidak sepenuhnya kompatibel dengan shell Bourne) dan (setidaknya untuk penyebaran desktop dan server penuh) memiliki POSIX di shtempat lain (masuk /usr/xpg4/bin/sh, berdasarkan ksh88), tetapi itu berubah di Solaris 11 di mana /bin/shsekarang ksh93. Yang lain sebagian besar mati.

² The /bin/shMacOS / X duluzsh , tetapi kemudian berubah menjadi bash. Ini bukan zshfokus utama untuk digunakan sebagai shimplementasi POSIX . Its shmodus terutama untuk dapat embed atau panggilan ( source) POSIX shkode zshskrip

³ Baru-baru ini, @schily memperpanjang cangkang OpenSolaris (berdasarkan cangkang SVR4, berdasarkan cangkang Bourne) untuk menjadi sesuai dengan POSIX, dipanggil boshtetapi saya tidak tahu bahwa itu digunakan pada sistem apa pun. Bersamaan dengan ksh88itu menjadikannya shell yang kompatibel dengan POSIX kedua berdasarkan kode shell Bourne

4 Dalam versi yang lebih lama, Anda juga bisa menggunakan mkshatau lebih lkshinkarnasi POSIX . Itulah shell MirOS (sebelumnya MirBSD) berdasarkan pdksh, itu sendiri berdasarkan pada shell Forsyth (implementasi lain dari shell Bourne))

Stéphane Chazelas
sumber
Hal kecil (tentang kode jawaban tengah): Jika Anda tidak menggunakan exec sh "$0" "$@"setelah pengaturan PATH? Itu seharusnya mengambil shdari tempat yang benar, saya akan berpikir.
Kusalananda
1
@ Kusalananda, itu harus bekerja tetapi lebih berisiko karena kita bisa berakhir dalam loop tanpa akhir jika ada sesuatu yang salah (seperti sh dengan izin salah, getconf dimodifikasi ...). Pokoknya, sisanya khusus untuk Solaris 10, jadi kami juga bisa melakukan hardcode semua termasuk konten $PATH.
Stéphane Chazelas
Setiap kutipan untuk OSX menggunakan ksh sebagai shell POSIX-nya. Shell defaultnya dulu tcsh tapi saya tidak ingat bash tidak digunakan terutama karena Korn Shell tidak open source sampai setelah OSX keluar
user151019
1
@ Mark, saya tidak mengatakan OSX pernah menggunakan ksh. Saya memang mengatakan dulu zsh dan mereka beralih ke bash (build khusus bash).
Stéphane Chazelas
1
@ fpmurphy, jika Anda melihat versi awal, bash sudah memihak ksh di mana pun ksh tidak kompatibel dengan shell Bourne. Walaupun Anda harus menunggu hingga bash2 untuk mencapai tingkat fitur yang sama dengan ksh88, awalnya bash sudah memiliki beberapa ekstensi ksh seperti $(...), mode emacs / vi, ekspansi tilde / brace (yang awalnya dari csh), fc, typeset, alias , sintaks fungsi ksh-style ...
Stéphane Chazelas
8

Ya, Anda dapat menggunakan #!/bin/shskrip karena /bin/sh(semoga) disediakan untuk sistem seperti itu, biasanya melalui tautan semacam yang membuat bashberperilaku (lebih atau kurang) seperti sebuah shwasiat. Berikut adalah sistem Centos7, misalnya, yang menghubungkan shke bash:

-bash-4.2$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Dec  4 16:48 /bin/sh -> bash
-bash-4.2$ 

Anda juga dapat menggunakan #!/bin/bashjika Anda menulis bashskrip hanya untuk sistem itu dan ingin menggunakan bashfitur. Namun, skrip tersebut akan mengalami masalah portabilitas, misalnya pada OpenBSD di mana bashhanya diinstal jika admin mengambil masalah untuk menginstalnya (saya tidak) dan kemudian diinstal ke /usr/local/bin/bash, bukan /bin/bash. #!/bin/shSkrip POSIX yang ketat harus lebih portabel.

thrig
sumber
Catatan ini: "Ketika dipanggil sebagai sh, Bash memasuki mode POSIX setelah membaca file startup." - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode
glenn jackman
2
Ketika saya menulis skrip untuk server RHEL di pekerjaan saya, saya menggunakan #!/bin/bashtepat sehingga saya dapat memanfaatkan fitur-fitur non-POSIX.
Monty Harder
@MontyHarder IIRC di RHEL /bin/shitu adalah symlink bash, apakah itu benar? Tapi saya tahu pasti pada CentOS.
Sergiy Kolodyazhnyy
1
@SergiyKolodyazhnyy Ya, di server RHEL saya baru saja memeriksa, itu adalah symlink ke bash. Biner itu tahu nama apa yang digunakan untuk memanggilnya, dan ketika itu disebut shitu bertindak seperti Bourne jadul sh.
Monty Harder
6

Kamu bertanya

apakah benar menempatkan komentar #! / bin / sh dalam skrip shell yang ditulis dalam distribusi ubuntu?

Jawabannya tergantung pada apa yang Anda tulis di skrip shell.

  • Jika Anda benar-benar menggunakan skrip yang kompatibel dengan POSIX portabel, dan tidak menggunakan perintah khusus bash, maka Anda dapat menggunakan/bin/sh .

  • Jika Anda tahu bahwa Anda hanya pernah menggunakan skrip pada mesin dengan bash, dan Anda ingin menggunakan sintaks spesifik bash, maka Anda harus menggunakan/bin/bash

  • Jika Anda ingin memastikan bahwa skrip akan bekerja pada bermacam-macam mesin unix, maka Anda harus menggunakan hanya sintaks yang sesuai dengan POSIX, dan/bin/sh

  • Jika Anda secara teratur menggunakan shell lain (misalnya ksh , zsh atau Tcsh ), dan ingin menggunakan sintaks yang dalam naskah Anda, maka Anda harus menggunakan penerjemah yang sesuai (seperti /bin/ksh93, /bin/zsh, atau /bin/tcsh)

Stobor
sumber
3

"#!" komentar tidak selalu menggunakan /bin/bashatau /bin/sh. Itu hanya mencantumkan apa pun penerjemah yang seharusnya, bukan hanya untuk skrip shell. Misalnya skrip python saya biasanya mulai dengan #!/usr/bin/env python.

Sekarang perbedaan antara #!/bin/shdan #!/bin/bashapakah itu /bin/shtidak selalu merupakan symlink ke /bin/bash. Seringkali tetapi tidak selalu. Ubuntu adalah pengecualian di sini. Saya telah melihat skrip bekerja dengan baik pada CentOS tetapi gagal pada Ubuntu karena penulis menggunakan sintaks khusus bash dengan #!/bin/sh.

aragaer
sumber
1

Maaf untuk menuangkan air dingin pada semua jawaban-jawaban besar yang mengatakan bahwa /bin/shhadir di semua sistem Unix - itu ada, kecuali di sistem Unix yang paling sering digunakan: Android.

Android memiliki cangkangnya /system/bin/sh, dan biasanya tidak ada cara untuk membuat /bin/shtautan, bahkan pada sistem yang sudah di-rooting (karena cara sistem dikunci dengan menggunakan selinux dan kemampuan (7) set pembatas).

Bagi mereka yang akan mengatakan bahwa android tidak sesuai dengan POSIX: tidak semua distribusi Linux dan BSD. Dan keberadaan /bin/shdengan jalan ini tidak diamanatkan oleh standar :

Aplikasi harus mencatat bahwa standar PATHuntuk shell tidak dapat dianggap salah /bin/shatau /usr/bin/sh, dan harus ditentukan dengan interogasi yang PATHdikembalikan oleh getconf PATH, memastikan bahwa pathname yang dikembalikan adalah pathname absolut dan bukan built-in shell.

mosvy
sumber
Sementara semua sistem yang mencoba untuk memenuhi POSIX memiliki banyak bug kesesuaian (termasuk yang bersertifikasi), Android (dan sebagian besar sistem tertanam lainnya seperti router atau OS bola lampu) tidak bermaksud untuk menjadi sesuai dengan POSIX. Android di luar topik di sini kecuali ketika datang ke antarmuka POSIX.
Stéphane Chazelas
@ Christopher, yang mana getconf? Misalnya pada Solaris 11.4, apakah itu yang ada di dalam /usr/bin? Yang di /usr/xpg4/bin(untuk kepatuhan SUSv2), yang di /usr/xpg6/bin(untuk kepatuhan SUSv3)? /usr/xpg7/bin(untuk SUSv4)?
Stéphane Chazelas
@ StéphaneChazelas jika kita ingin menilai niat, saya pikir saya dapat dengan mudah menggali beberapa kutipan Linus Torvalds atau Theo de Raadt yang menyatakan bahwa mereka tidak terlalu peduli tentang POSIX ;-) Dan kebanyakan sistem embedded didasarkan pada linux + busybox, yang hampir tidak serupa dengan POSIX daripada sistem khas Unix. Dan a) android sebenarnya bukan sistem "tertanam" dan b) sistem android bisa dibuat POSIX-compliant tanpa memiliki shell in /bin/sh
mosvy
1
@ Mosvy, apa yang Anda katakan sebagian besar benar. Tetapi Torvalds hanya dapat berbicara untuk kernel Linux. Chet Ramey peduli tentang kepatuhan POSIX untuk bash, RedHat peduli tentang kepatuhan POSIX (mereka mensponsori grup Austin dan duduk di pertemuan kelompok mereka, mereka memelihara banyak perangkat lunak GNU). Idenya adalah bahwa POSIX adalah satu-satunya standar yang dilihat oleh kebanyakan sistem mirip Unix. Pengguna peduli tentang kepatuhan POSIX karena membuatnya lebih mudah untuk memiliki perangkat lunak portabel untuk sistem yang berbeda. Ini tidak ideal tetapi lebih baik daripada tidak sama sekali. Android memiliki API pemrograman sendiri, POSIX tidak benar-benar menjadi perhatian di sana.
Stéphane Chazelas