Saya bekerja di lingkungan yang relatif heterogen di mana saya dapat menjalankan versi Bash yang berbeda pada node HPC, VM, atau stasiun kerja pribadi saya yang berbeda. Karena saya meletakkan skrip login saya di repo Git, saya ingin menggunakan (ish) yang sama .bashrc
di seluruh papan, tanpa banyak "jika host ini, maka ..." - ketik kekacauan.
Aku seperti perilaku default Bash ≤ 4.1 yang mengembang cd $SOMEPATH
ke cd /the/actual/path
saat menekan Tabtombol. Di Bash 4.2 dan di atasnya, Anda harus shopt -s direxpand
mengaktifkan kembali perilaku ini, dan itu tidak tersedia hingga 4.2.29 . Ini hanyalah satu contoh; shopt
opsi lain yang mungkin terkait , complete_fullquote
(meskipun saya tidak tahu persis apa yang dilakukannya) mungkin juga telah mengubah perilaku default di v4.2.
Namun, direxpand
tidak dikenali oleh versi Bash sebelumnya, dan jika saya coba shopt -s direxpand
di Bash saya .bashrc
, itu menghasilkan pesan kesalahan yang dicetak ke konsol setiap kali saya masuk ke sebuah simpul dengan Bash yang lebih lama:
-bash: shopt: direxpand: invalid shell option name
Apa yang ingin saya lakukan adalah membungkus kondisional shop -s direxpand
untuk mengaktifkan opsi itu pada Bash> 4.1 dengan cara yang kuat, tanpa merusak versi Bash yang lebih lama ( yaitu , tidak hanya mengarahkan output kesalahan ke /dev/null
).
sumber
.bashrc
. Saya masih menginginkan catatan tentang bagaimana menggunakannya$BASH_VERSINFO
untuk menginterogasi versi utama / minor dari shell yang sedang berjalan, untuk perbaikan saya sendiri, itulah sebabnya saya selesai memposting jawaban saya sendiri.:)
Jawaban:
Periksa apakah
direxpand
ada dalam outputshopt
dan aktifkan jika:sumber
grep -q '^direxpand\b'
jika beberapa versi masa depan atau garpu bash memiliki opsi yang berisi ini sebagai substring dan menghapusdirexpand
. Tidak mungkin dalam kasus khusus ini, tetapi tidak mahal untuk menjadi kuat.[ -z "$(shopt -po direxpand 2>&-)" ] || shopt -s direxpand
. Tidak ada lagi masalah regex! :-)[ -n "blah" ] && shopt blah
Cara Anda mengatakannya, Anda mengatakan "jika direxpand tidak didukung, maka jangan lakukan hal ini".set -e
di bagian atas, jadi saya cenderung menggunakan jalan pintas dengan cara ini.Saya tidak melihat apa yang salah dengan mengarahkan ulang kesalahan ke
/dev/null
. Jika Anda ingin kode Anda kuatset -e
, gunakan idiom umum… || true
:Jika Anda ingin menjalankan beberapa kode cadangan jika opsi tidak ada, gunakan status pengembalian
shopt
:Tetapi jika Anda benar-benar tidak suka mengalihkan kesalahan, Anda dapat menggunakan mekanisme penyelesaian untuk melakukan introspeksi. Ini mengasumsikan bahwa Anda tidak memiliki mesin kuno dengan bash ≤ 2.03 yang tidak memiliki penyelesaian terprogram.
Metode ini menghindari forking, yang lambat pada beberapa lingkungan seperti Cygwin. Begitu juga langsung
2>/dev/null
, saya tidak berpikir Anda bisa mengalahkan itu pada kinerja.sumber
compgen
proposal. Itu barang tingkat universitas di sana! Menghindari pengalihan/dev/null
hanya preferensi pribadi. Saya suka meminta izin daripada pengampunan, jika itu masuk akal?:)
compgen -A shopt -X ...
dimaksud.compgen
cara ini di Unix & Linux , saya tidak tahu siapa yang pertama kali mengusulkannya. (Saya berhenti menggunakan bash sebagai shell utama saya sebelum selesai diprogram.) Dalam pemrograman biasanya ide yang buruk untuk meminta izin karena ada risiko bahwa pemeriksaan izin tidak akan cocok dengan apa yang sebenarnya Anda lakukan, baik karena pengkodean kesalahan (di mana Anda tidak cukup memeriksa apa yang Anda pikir Anda periksa) atau karena apa yang Anda periksa berubah sebelum Anda menggunakannya .Ketika Anda tahu pasti bahwa
shopt
opsi tertentu tersedia di rilis utama / minor / patch tertentu dari Bash, Anda dapat memeriksa$BASH_VERSION
variabel atau elemen-elemen$BASH_VERSINFO[]
array untuk mengaktifkannya secara kondisional.Inilah tes untuk Bash 4.2.29 atau lebih tinggi, versi di mana
direxpand
pertama kali diperkenalkan ke seri 4.2:Sunting: Agar lebih jelas, ini adalah solusi yang sangat direkayasa secara berlebihan untuk sekadar mengabaikan pesan kesalahan yang berasal dari skrip login Anda, tetapi saya ingin mendokumentasikannya, untuk perbaikan saya sendiri.
Perhatikan kawat gigi sekitar , yang sedang dibutuhkan, dan penggunaan dan , yang melakukan bilangan bulat daripada (dependen-lokal) perbandingan leksikal. Jika tidak dikutip, RHS operator diperlakukan sebagai pola "ekstglob" dalam Bash / kondisional, seperti yang disebutkan di sini , yang membuat perbandingan "dimulai dengan" yang lebih estetis dibandingkan dengan regex, IMO.
${BASH_VERSINFO[index]}
-eq
-gt
==
[[
]]
The
$BASH_VERSINFO
Array berisi semua informasi yang Anda akan melihat dalam output daribash --version
:Ketika tidak jelas dari dokumentasi yang mendukung
shopt
versi Bash atau mengubah perilaku mereka, metode yang diusulkan oleh Luciano baik-baik saja:... seperti solusi yang diusulkan oleh Gilles hanya mengabaikan kesalahan (
shopt -s direxpand 2>/dev/null
), dan mungkin memeriksa$?
jika benar-benar diperlukan.Referensi: 1 , 2 , 3
Bacaan terkait: Set and Shopt - Why Two?
sumber
if [[ $BASH_VERSION > 4.3 ]];
(yang cocok4.3.0
,5.0
dll., Tetapi juga4.3.0-alpha
. Saya tidak tahu apakah fakta nanti penting.)direxpand
pilihan memang tersedia untuk Bash 4.2, meskipun; Saya telah memverifikasi ini dengan gambar Docker di v4.2.53 dengan menjalankandocker run --rm bash:4.2 bash -c shopt | grep direxpand
(dan, untuk ukuran yang baik, bahwa memang tidak tersedia di v4.1.17 dengan menjalankandocker run --rm bash:4.1 bash -c shopt | grep direxpand
).4.2.0
dan menemukan fakta bahwa itu tidak bekerja di sana. The changelog juga menyebutkan itu ditambahkan dalambash-4.3-alpha
. Saya kira kemudian bahwa seseorang perlu memeriksa${BASH_VERSINFO[2]}
untuk menjadi tepat tentang hal itu, tapi saya tidak tahu rilis titik mana menambahkannya ...