#! / bin / sh vs #! / bin / bash untuk kemudahalihan maksimum

cherouvim 07/30/2017. 3 answers, 2.886 views
linux bash shell sh

Saya biasanya bekerja dengan pelayan Ubuntu LTS yang dari apa yang saya fahami symlink /bin/sh ke /bin/dash . Banyak distro lain walaupun symlink /bin/sh ke /bin/bash .

Dari itu saya faham bahawa jika skrip menggunakan #!/bin/sh di atas ia mungkin tidak berjalan dengan cara yang sama pada semua pelayan?

Adakah terdapat amalan yang dicadangkan di mana shell digunakan untuk skrip apabila seseorang mahu portabiliti maksimum skrip antara pelayan?

1 Comments
Thorbjørn Ravn Andersen 08/01/2017
Terdapat sedikit perbezaan antara pelbagai cengkerang. Jika mudah alih adalah yang paling penting kepada anda maka gunakan #!/bin/sh dan jangan gunakan apa-apa lagi daripada apa shell asal yang disediakan.

3 Answers


Gordon Davisson 08/01/2017.

Terdapat kira-kira empat tahap mudah alih untuk skrip shell (setakat garis shebang yang berkenaan):

  1. Kebanyakan mudah alih: gunakan #!/bin/sh shebang dan only menggunakan sintaks shell asas yang dinyatakan dalam piawai POSIX . Ini sepatutnya berfungsi pada sistem POSIX / unix / linux yang hampir sama. (Nah, kecuali Solaris 10 dan lebih awal yang mempunyai warisan Bourne warisan yang sebenar, mendahului POSIX supaya tidak mematuhi, sebagai /bin/sh .)

  2. Kedua yang paling mudah alih: gunakan #!/bin/bash (atau #!/usr/bin/env bash ) baris shebang, dan berpegang kepada ciri bash v3. Ini akan berfungsi pada mana-mana sistem yang mempunyai bash (di lokasi yang dijangkakan).

  3. Ketiga yang paling mudah alih: gunakan #!/bin/bash (atau #!/usr/bin/env bash ) garis shebang, dan menggunakan ciri bash v4. Ini akan gagal pada mana-mana sistem yang mempunyai bash v3 (contohnya macOS, yang perlu menggunakannya untuk sebab-sebab pelesenan).

  4. Paling mudah alih: gunakan #!/bin/sh shebang dan gunakan sambungan bash ke sintaks shell POSIX. Ini akan gagal pada mana-mana sistem yang mempunyai sesuatu selain bash untuk / bin / sh (seperti versi Ubuntu baru-baru ini). Tidak pernah melakukan ini; ia bukan sekadar masalah keserasian, ia hanya salah nyata. Malangnya, itu adalah kesilapan ramai orang membuat.

Cadangan saya: gunakan yang paling konservatif dari tiga yang pertama yang membekalkan semua ciri shell yang anda perlukan untuk skrip. Untuk kemudahalihan max, gunakan opsyen # 1, tetapi dalam pengalaman saya, beberapa ciri bash (seperti array) cukup berguna bahawa saya akan pergi dengan # 2.

Perkara paling buruk yang boleh anda lakukan adalah # 4, menggunakan shebang yang salah. Sekiranya anda tidak pasti apakah ciri-ciri asas POSIX dan sambungan bash, sama ada dengan stick bash shebang (opsyen # 2), atau menguji skrip dengan teliti dengan shell yang sangat asas (seperti dash pada pelayan Ubuntu LTS anda). Wiki Ubuntu mempunyai senarai baik bashism untuk diperhatikan .

Terdapat beberapa maklumat yang sangat baik mengenai sejarah dan perbezaan antara cengkerang dalam soalan Unix & Linux "Apa maksudnya untuk menjadi serasi?" dan soalan Stackoverflow "Perbezaan antara sh dan bash" .

Juga, sedar bahawa cangkang bukan satu-satunya perkara yang berbeza antara sistem yang berbeza; jika anda digunakan untuk linux, anda digunakan untuk arahan GNU, yang mempunyai banyak pelanjutan yang tidak standard yang anda tidak dapat temukan di sistem unix lain (misalnya bsd, macOS). Malangnya, tidak ada peraturan mudah di sini, anda hanya perlu mengetahui pelbagai variasi untuk arahan yang anda gunakan.

Salah satu perintah yang paling menjijikkan dari segi kebolehgunaan adalah salah satu yang paling asas: echo . Sebarang masa anda menggunakannya dengan sebarang pilihan (misalnya echo -n atau echo -e ), atau dengan mana-mana pelarian (backslashes) dalam rentetan untuk mencetak, versi yang berbeza akan melakukan perkara yang berbeza. Pada bila-bila masa anda hendak mencetak tali tanpa jejak selepas itu, atau dengan melarikan diri dalam tali, gunakan printf sebaliknya (dan ketahui cara ia berfungsi - ia lebih rumit daripada echo ). Perintah ps juga menjadi kacau .

Satu lagi perkara umum untuk lihat ialah sambungan / GNUish yang terkini untuk sintaks pilihan perintah: format arahan lama (standard) ialah perintah itu diikuti dengan pilihan (dengan satu baris, dan setiap pilihan adalah satu huruf), diikuti oleh hujah arahan. Varian terkini (dan sering tidak mudah alih) termasuk pilihan panjang (biasanya diperkenalkan dengan -- ), membenarkan pilihan untuk datang selepas hujah, dan menggunakan -- untuk memisahkan pilihan dari hujah.

5 comments
12 pabouk 07/30/2017
Pilihan keempat hanyalah idea yang salah. Tolong jangan gunakannya.
3 Gordon Davisson 07/30/2017
@pabouk Saya setuju sepenuhnya, jadi saya menyunting jawapan saya untuk membuat ini lebih jelas.
1 jlliagre 07/30/2017
Kenyataan pertama anda sedikit mengelirukan. Piawaian POSIX tidak menyatakan apa-apa mengenai shebang luar memberitahu menggunakannya membawa kepada tingkah laku yang tidak ditentukan. Selain itu, POSIX tidak menentukan di mana shell posix mesti terletak, hanya namanya ( sh ), jadi /bin/sh tidak dijamin menjadi laluan yang betul. Yang paling mudah alih adalah kemudiannya tidak untuk menentukan apa-apa shebang sama sekali, atau untuk menyesuaikan shebang ke OS yang digunakan.
2 Michael Kjörling 07/30/2017
Saya jatuh ke # 4 dengan skrip saya baru-baru ini, dan tidak dapat memahami mengapa ia tidak berfungsi; Lagipun, arahan yang sama bekerja dengan lancar, dan melakukan apa yang saya mahu mereka lakukan, ketika saya mencubanya secara langsung dalam shell. Sebaik sahaja saya menukar #!/bin/sh ke #!/bin/bash walaupun, skrip berfungsi dengan sempurna. (Untuk pertahanan saya, skrip itu telah berubah dari masa ke masa dari satu yang benar-benar hanya memerlukan sh-isms, kepada yang bergantung pada tingkah laku seperti bash.)
2 jlliagre 07/30/2017
@ MichaelKjörling (sebenarnya) Bourne shell hampir tidak pernah digabungkan dengan distribusi Linux dan tidak patuh POSIX pula. Coklat standard POSIX dicipta daripada tingkah laku ksh , bukan Bourne. Apa yang paling banyak pengagihan Linux yang mengikuti FHS lakukan ialah /bin/sh menjadi pautan simbolik ke shell yang mereka pilih untuk menyediakan keserasian POSIX, biasanya bash atau dash .

Kaz 07/31/2017.

Dalam skrip ./configure yang menyediakan bahasa TXR untuk bangunan, saya menulis prolog berikut untuk mudah alih yang lebih baik. Skrip akan bootstrap sendiri walaupun #!/bin/sh adalah Bourne Shell lama yang tidak mematuhi POSIX. (Saya membina setiap pembebasan pada Solaris 10 VM).

#!/bin/sh

# use your own variable name instead of txr_shell;
# adjust to taste: search for your favorite shells

if test x$txr_shell = x ; then
  for shell in /bin/bash /usr/bin/bash /usr/xpg4/bin/sh ; do
    if test -x $shell ; then
       txr_shell=$shell
       break
    fi
  done
  if test x$txr_shell = x ; then
    echo "No known POSIX shell found: falling back on /bin/sh, which may not work"
    txr_shell=/bin/sh
  fi
  export txr_shell
  exec $txr_shell $0 ${@+"$@"}
fi

# rest of the script here, executing in upgraded shell 

Idea di sini ialah kita mencari shell yang lebih baik daripada yang kita jalankan di bawah, dan menjalankan semula skrip menggunakan shell itu. txr_shell persekitaran txr_shell ditetapkan, supaya skrip yang semula dijalankan tahu bahawa ia adalah contoh rekursif semula yang dijalankan.

(Dalam skrip saya, pemboleh ubah txr_shell kemudiannya digunakan, untuk dua tujuan: pertama ia dicetak sebagai sebahagian daripada mesej bermaklumat dalam output skrip. Kedua, ia dipasang sebagai pembolehubah SHELL di Makefile , supaya make akan menggunakan shell ini juga untuk melaksanakan resipi.)

Pada sistem di mana /bin/sh adalah sengkang, anda dapat melihat bahawa logik di atas akan mencari /bin/bash dan menjalankan semula skrip dengan itu.

Pada kotak Solaris 10, /usr/xpg4/bin/sh akan /usr/xpg4/bin/sh jika tiada Bash dijumpai.

Prolog ditulis dalam dialek shell konservatif, menggunakan test untuk ujian kewujudan fail, dan ${@+"$@"} trick untuk memperluaskan hujah yang memenuhi beberapa cangkang tua yang patah (yang hanya akan menjadi "$@" jika kita dalam shell yang sesuai dengan POSIX).

2 comments
Charles Duffy 07/31/2017
Orang tidak akan memerlukan hacker x jika sebut harga yang tepat sedang digunakan, kerana situasi yang dimandatkan bahawa idiom mengelilingi sekarang-usul ujian doa dengan -a atau -o menggabungkan beberapa ujian.
Kaz 07/31/2017
@CharlesDuffy Memang; test x$whatever yang saya perpetrating ada kelihatan seperti bawang dalam varnis. Jika kita tidak boleh mempercayai shell lama yang pecah untuk melakukan petikan, maka percubaan ${@+"$@"} tidak ada gunanya.

zwol 07/31/2017.

Semua variasi bahasa shell Bourne adalah objektif yang mengerikan berbanding dengan bahasa skrip moden seperti Perl, Python, Ruby, node.js, dan bahkan (boleh dikatakan) Tcl. Sekiranya anda perlu melakukan sesuatu yang sedikit rumit, anda akan lebih bahagia dalam jangka masa panjang jika anda menggunakan salah satu di atas dan bukan skrip shell.

Satu-satunya kelebihan bahasa shell masih mempunyai bahasa-bahasa yang lebih baru ialah something menamakan dirinya /bin/sh dijamin ada pada apa yang dikatakan sebagai Unix. Walau bagaimanapun, sesuatu mungkin tidak patuh kepada POSIX; banyak Unixes milik warisan membekukan bahasa yang dilaksanakan oleh /bin/sh dan utiliti di PATH lalai prior perubahan yang dituntut oleh Unix95 (ya, Unix95, dua puluh tahun yang lalu dan menghitung). Mungkin terdapat satu set Unix95, atau bahkan POSIX.1-2001 jika anda bernasib baik, alat dalam direktori not pada PATH lalai (misalnya /usr/xpg4/bin ) tetapi mereka tidak dijamin wujud.

Walau bagaimanapun, asas-asas Perl more likely untuk hadir pada pemasangan Unix sewenang-wenangnya daripada Bash. (Dengan "asas-asas Perl" maksud saya /usr/bin/perl ada dan ada some , mungkin agak lama, versi Perl 5, dan jika anda bernasib baik, modul yang dikirimkan dengan versi penterjemah itu juga tersedia.)

Oleh itu:

Sekiranya anda menulis sesuatu yang perlu bekerja everywhere - everywhere yang dianggap sebagai Unix (seperti skrip "mengkonfigurasi"), anda perlu menggunakan #! /bin/sh #! /bin/sh , dan anda tidak perlu menggunakan sambungan apa pun. Pada masa kini, saya akan menulis shell patuh POSIX.1-2001 dalam keadaan ini, tetapi saya bersedia untuk menanggalkan POSIXisme jika seseorang meminta sokongan untuk besi berkarat.

Tetapi jika anda not menulis sesuatu yang perlu bekerja di mana-mana, maka ketika anda tergoda untuk menggunakan mana-mana Bashism sama sekali, anda harus berhenti dan menulis semula keseluruhan perkara dalam bahasa skrip yang lebih baik. Masa depan diri anda akan terima kasih.

(Jadi, is sesuai untuk menggunakan sambungan Bash? Untuk pesanan pertama: tidak pernah. Untuk pesanan kedua: hanya untuk memperluaskan persekitaran interaktif Bash - contohnya untuk menyediakan penyiapan tab pintar dan petua mewah.)

Related questions

Hot questions

Language

Popular Tags