Apa cara yang paling tepat untuk mendistribusikan skrip shell, jika perilaku shell dapat dimodifikasi oleh set
dan karenanya tidak dapat diprediksi?
Misalnya, rm *.txt
tidak akan dieksekusi seperti yang diharapkan pada lingkungan di mana set -f
telah dijalankan. Bagaimana saya memastikan bahwa rm *.txt
menghapus semua file teks dalam direktori saat ini di lingkungan apa pun?
Bagaimana saya memastikan bahwa skrip shell akan berjalan seperti yang diharapkan sebelum mendistribusikannya secara umum?
bash
shell
shell-script
hoge
sumber
sumber
shell_state=$(set +o)
... skrip ...eval "$shell_state"
#!
untuk menentukan opsi shell apa yang Anda inginkan.Jawaban:
Skrip shell biasanya diperlakukan seolah-olah mereka sama dengan jenis file executable lainnya, seperti binari, skrip Python, skrip Perl, atau skrip jenis apa pun. Mereka memiliki shebang di bagian atas yang mengarahkan kernel untuk menjalankannya melalui shell. Mereka diharapkan dipanggil dengan cara yang sama seperti perintah lainnya.
Dengan demikian, sebuah shell baru dimulai setiap kali script dipanggil, dan pengaturan apa pun seperti yang
set -f
ada di shell yang dijalankan atau dalam instance shell lain dalam sistem tidak relevan.Tentu saja mungkin bagi pengguna untuk sumber skrip Anda daripada menjalankannya, misalnya seperti ini:
atau untuk menjalankannya di shell yang memiliki pengaturan non-default seperti ini:
tetapi itu tidak dianggap sebagai cara normal atau menjalankan skrip Anda, dan pengguna yang melakukannya harus mengharapkan apa pun yang mereka dapatkan sebagai hasilnya.
Perhatikan bahwa ada beberapa skrip yang dimaksudkan untuk dipasok, tidak dieksekusi, karena tujuannya adalah untuk hal-hal seperti mengubah cwd atau mengatur variabel lingkungan yang harus tercermin dalam lingkungan shell sumber, tetapi ini adalah minoritas dan biasanya dilakukan sebagai bagian dari protokol yang disepakati. File-file ini dapat dianggap lebih seperti "plugin" untuk sistem apa pun yang mereka harapkan bersumber, tidak sebanyak skrip independen. Sebagai contoh, file
/etc/rc*.d
dengan nama yang berakhir.sh
bersumber dari subsistem skrip startup, tidak dieksekusi, dan didokumentasikan bahwa inilah yang akan terjadi jika Anda menempatkan file dengan nama seperti itu di/etc/rc*.d
dan ketika itu selesai itu dilakukan dengan sengaja. Konvensi penamaan file yang dimaksudkan bersumber alih-alih dieksekusi dengan cara ini juga diikuti di tempat lain, tetapi tidak secara universal.Memang benar bahwa file-file yang dimaksudkan bersumber dengan cara ini harus memperhatikan pengaturan apa yang mungkin ada di lingkungan pemanggil mereka yang mungkin mempengaruhi perilaku shell, tetapi kemudian protokol yang disepakati idealnya menjanjikan lingkungan eksekusi yang dapat diprediksi.
sumber
zsh
memiliki fitur yang memungkinkan untuk mengembalikan opsi ke pengaturan pengetahuan dalam konteks lokal (emulate -L zsh
) yang digunakan secara luas di semua ekstensi yang dikirimkan dengan zsh dan ditulis sebagai kode zsh. Lihat bagaimana sistem penyelesaian bash gagal total jika Anda mengatur beberapa opsi sepertifailglob
.#! /bin/csh -f
bukan#! /bin/csh
misalnya.zshenv
. Hati-hati dengan apa yang Anda masukkanzshenv
karena alasan itu!emulate -L
dalam hal ini) dengan mengomentari salah satu jawaban saya, dan saya menghargainya.~/.zshenv
(di mana Anda ingin memaksakan pengaturan (umumnya env vars) untuk semua zsh's (interaktif atau tidak) dipanggil dengan nama Anda, dan umumnya tidak digunakan kecuali untuk mengatasi beberapa masalah non-zsh lainnya) terpisah dari~/.zshrc
(interaktif shell kustomisasi), jadi itu, fitur, bukan bug. (Anda dapat menggunakan zsh -f) Bug adalah ketika beberapa shell bash non-interaktif membaca Anda~/.bashrc
(seperti lebih dari ssh dan Anda harus menambahkan kode untuk menjaga terhadap itu), atau beberapa bash interaktif (yang login) tidak membacanya (dan lagi, Anda harus menambahkan kode Anda~/.bash_profile
untuk mengatasinya).