Gunakan #! / Bin / sh atau #! / Bin / bash untuk kompatibilitas Ubuntu-OSX dan kemudahan penggunaan & POSIX

18

Saya tahu bahwa saya bisa menggunakan skrip baris pertama untuk menjalankan shell yang diinginkan.

Akan #!/bin/shdirekomendasikan jika kompatibilitas dengan semua sistem unix adalah persyaratan mutlak?

Dalam kasus saya, satu-satunya OS yang saya pedulikan adalah Ubuntu (Debian) dan OSX. Mengingat itu, dapatkah saya menggunakan #!/bin/bashdan yakin itu akan bekerja pada kedua sistem?
Apakah ini juga akan membuatnya lebih mudah untuk menggunakan skrip dengan sintaks yang lebih modern dan lebih jelas untuk perintah? Apakah menggunakan #!/bin/shjuga berhubungan dengan menggunakan POSIX?

Michael Durrant
sumber
1
Mungkin perlu dicatat bahwa banyak distro sudah mulai bergabung /bindan /usr/bin. Akibatnya, mungkin lebih baik digunakan #!/usr/bin/env <shname>untuk portabilitas akhir-akhir ini.
HalosGhost

Jawaban:

15

Sebagai permulaan, jika Anda dapat membuat asumsi bahwa Bash sudah diinstal sebelumnya (yang, setahu saya adalah kasus pada semua sistem yang Anda daftarkan), gunakan hashbang berikut agar kompatibel:

#!/usr/bin/env bash

ini memanggil apa pun yang bashterjadi untuk dikonfigurasi, tidak peduli apakah itu dalam /binatau /usr/local/bin.

Sementara pada kebanyakan sistem di berbagai (termasuk AIX, Solaris, beberapa rasa BSD), bashberakhir di lokasi yang berbeda, envselalu berakhir pada /usr/bin/env. Triknya, bagaimanapun, bukan milikku tetapi dari penulis Bash Cookbook.

Bagaimanapun, ya Bash akan memungkinkan Anda untuk menggunakan beberapa fitur "modern" yang membuat hidup Anda lebih mudah.

Misalnya tanda kurung ganda:

[[ -f "/etc/debian_version" ]] && echo "This is a Debian flavor"

sedangkan dalam dialek shell tradisional Anda harus menggunakan:

test -f "/etc/debian_version" && echo "This is a Debian flavor"

tetapi yang terbaik tentang tanda kurung ganda adalah mereka memungkinkan ekspresi reguler untuk dicocokkan. The Bash Hacker Wiki akan memberikan banyak trik arah itu.

Anda juga dapat menggunakan ekspresi yang cukup nyaman seperti $((2**10))atau ekspresi aritmatika lainnya sesuai dengan $((expression))sintaks.

Menggunakan backticks untuk subkulit baik-baik saja, meskipun agak ketinggalan jaman. Tetapi kemampuan bersarang dalam $(command ...)doa jauh lebih nyaman karena Anda tidak perlu melarikan diri dari banyak hal pada tingkat subkulit yang berbeda.

Ini hanyalah beberapa hal yang Bash berikan kepada Anda atas shsintaks POSIX umum yang umum .

Tetapi jika Anda ingin lebih banyak kekuatan pada shell (tidak hanya dalam skrip), lihat juga zsh.

0xC0000022L
sumber
Bash adalah alat yang sangat berguna tetapi berhati-hatilah untuk tidak menggunakannya untuk memulai layanan yang mungkin rentan terhadap bug scripting Bash, misalnya access.redhat.com/security/cve/CVE-2014-6271 . Tetap berpegang pada shtugas-tugas tersebut.
Rick-777
1
Rick-777 bahwa kerentanan sangat besar dan menurut pendapat saya komentar Anda FUD. Jika layanan sistem berjalan di bawah bash itu sama sekali tidak rentan terhadap bug itu. Ini hanya rentan terhadap bug itu jika menghentikan proses bash sementara memungkinkan pengguna jarak jauh mengarahkan langsung ke satu atau lebih variabel lingkungan, seperti di FastCGI, dan itupun hanya pada versi bash yang belum ditambal. Pada sistem dengan yang shditautkan bash, kerentanan tidak akan dikurangi dengan menggunakan sh.
Score_Di Bawah
11

Di Debian dan Ubuntu, /bin/shadalah dash, yang merupakan shell yang sesuai dengan POSIX. Jika Anda menentukan #!/bin/sh, Anda harus membatasi diri pada pernyataan POSIX dalam skrip Anda. (Keuntungannya adalah dashmulai lebih cepat daripada bash, sehingga skrip Anda dapat menyelesaikan tugasnya dalam waktu yang lebih singkat.)

Pada banyak (kebanyakan?) Sistem Linux lainnya, /bin/shadalah bash, yang mengapa banyak script yang ditulis dengan #!/bin/shsebagai garis peristiwa mereka meskipun mereka menggunakan bashekstensi.

Jika Anda ingin menggunakan bashekstensi, pendekatan teraman pada semua sistem adalah menentukan #!/bin/bash; dengan cara itu Anda secara eksplisit menyatakan ketergantungan Anda bash. Anda perlu melakukan ini di Debian dan Ubuntu. Sebagai bonus tambahan, ketika dimulai sebagai /bin/sh bashmenonaktifkan beberapa ekstensi (lihat deskripsi bashmode POSIX untuk detail); jadi #!/bin/bashperlu menentukan untuk mendapatkan manfaat penuh dari bash.

Pada OS X /bin/bashjuga tersedia, dan /bin/shini bash. Menentukan #!/bin/bashakan bekerja dengan baik di sana juga.

Stephen Kitt
sumber
5

Ya, baik OSX dan Linux akan datang dengan /bin/bash. Anda harus benar-benar aman. Namun, itu bukan POSIX. Shell POSIX berada /bin/shpada sebagian besar (semua?) Sistem dan itu adalah pendekatan yang paling portabel dan satu-satunya cara agar kompatibel dengan POSIX.

Perhatikan bahwa sementara pada banyak sistem /bin/shmenunjuk ke bash, pada yang lain itu dapat menunjuk ke shell berbeda. Ini adalah symlink ke dashpada Debian dan Ubuntu misalnya. Juga, meskipun /bin/shmerupakan tautan ke bash, perilaku shell berubah ketika disebut sebagai sh(dari man bash, penekanan milikku):

Jika bash dipanggil dengan nama sh, ia mencoba untuk meniru perilaku startup dari versi historis sh sedekat mungkin, sambil menyesuaikan dengan standar POSIX juga. Ketika dipanggil sebagai shell login interaktif, atau shell non-interaktif dengan opsi --login, pertama-tama ia mencoba membaca dan menjalankan perintah dari / etc / profile dan ~ / .profile, dalam urutan itu. Opsi --noprofile dapat digunakan untuk menghambat perilaku ini. Ketika dipanggil sebagai shell interaktif dengan nama sh, bash mencari variabel ENV, memperluas nilainya jika ya
didefinisikan, dan menggunakan nilai yang diperluas sebagai nama file untuk membaca dan mengeksekusi. Karena shell dipanggil sebagai sh tidak berusaha membaca dan menjalankan perintah dari file startup lainnya, opsi --rcfile tidak berpengaruh. Shell non-interaktif yang dipanggil dengan nama sh tidak berusaha membaca file startup lainnya. Ketika dipanggil sebagai sh, bash memasuki mode posix setelah file startup dibaca.

terdon
sumber
2

Jika kompatibilitas dengan "semua sistem Unix" adalah persyaratan mutlak - dan jika tidak, mengapa Anda menulis skrip shell? - maka, ya, Anda harus menggunakan #! /bin/sh, karena Bash tidak dijamin dipasang di mana saja , apalagi masuk /bin.

Sebenarnya jauh lebih buruk dari itu. Jika Anda memerlukan kompatibilitas untuk semua sistem Unix, itu termasuk hal-hal seperti Solaris dan AIX yang membekukan lingkungan shell mereka sekitar tahun 1995. Yang berarti Anda harus menggunakan hal-hal seperti sort +Nsintaks kuno - bahwa sistem yang lebih baru telah jatuh! Dan itu juga berarti tidak ada fungsi shell, tidak ada array, tidak [[ ... ]], tidak ${foo#glob}, tidak $(( ... ))untuk aritmatika, mungkin tanpa $( ... )substitusi perintah gaya, batas atas kecil dan tidak berdokumen tentang seberapa besar input yang bisa didapat, ...

Anda mungkin bisa lolos dengan tidak mengganggu dengan yang banyak kompatibilitas, tetapi jika itu bahkan masalah di tempat pertama, saya sangat menyarankan Anda mempertimbangkan bahasa yang kurang mengerikan daripada shell. Interpreter Perl dasar lebih mungkin tersedia daripada Bash.

zwol
sumber
Terima kasih. Seperti yang pada awalnya dinyatakan "Dalam kasus saya satu-satunya OS yang saya pedulikan adalah Ubuntu (Debian) dan OSX.". Ini adalah hanya 2 sistem yang saya gunakan (dan saya sering menggunakannya) dalam 5 tahun terakhir, jadi itulah mengapa saya menulis skrip shell yang hanya akan bekerja pada mereka. Saya sama sekali tidak membutuhkan naskah universal dan batasan-batasannya.
Michael Durrant
@MichaelDurrant Dalam hal ini, Anda tidak perlu, dan seharusnya tidak, menulis skrip shell. Anda sebaiknya menggunakan banyak bahasa scripting yang lebih baik yang merupakan opsi ketika Anda tidak membutuhkan portabilitas total.
zwol