Biasanya, jika Anda mengedit skrip, semua penggunaan skrip yang berjalan rentan terhadap kesalahan.
Sejauh yang saya mengerti, bash (cangkang lain juga?) membaca skrip secara bertahap, jadi jika Anda memodifikasi file skrip secara eksternal, itu mulai membaca hal yang salah. Apakah ada cara untuk mencegahnya?
Contoh:
sleep 20
echo test
Jika Anda menjalankan skrip ini, bash akan membaca baris pertama (katakanlah 10 byte) dan tidur. Saat dilanjutkan, mungkin ada konten yang berbeda dalam skrip mulai dari byte ke-10. Saya mungkin berada di tengah-tengah baris dalam skrip baru. Dengan demikian skrip yang berjalan akan rusak.
Jawaban yang Diterima:
Ya shell, dan bash
khususnya, berhati-hatilah untuk membaca file satu baris dalam satu waktu, sehingga cara kerjanya sama seperti saat Anda menggunakannya secara interaktif.
Anda akan melihat bahwa ketika file tidak dapat dicari (seperti pipa), bash
bahkan membaca satu byte pada satu waktu untuk memastikan tidak membaca melewati \n
karakter. Saat file dapat dicari, file akan dioptimalkan dengan membaca blok penuh sekaligus, tetapi mencari kembali setelah \n
.
Artinya, Anda dapat melakukan hal-hal seperti:
bash << \EOF
read var
var's content
echo "$var"
EOF
Atau tulis skrip yang memperbarui diri. Yang tidak akan dapat Anda lakukan jika tidak memberikan jaminan itu.
Sekarang, Anda jarang ingin melakukan hal seperti itu dan, seperti yang Anda ketahui, fitur itu cenderung lebih sering mengganggu daripada berguna.
Untuk menghindarinya, Anda dapat mencoba dan memastikan Anda tidak mengubah file di tempat (misalnya, mengubah salinan, dan memindahkan salinan di tempatnya (seperti sed -i
atau perl -pi
dan beberapa editor melakukannya misalnya)).
Atau Anda bisa menulis skrip Anda seperti:
{
sleep 20
echo test
}; exit
(perhatikan bahwa penting bahwa exit
berada di baris yang sama dengan }
; meskipun Anda juga bisa memasukkannya ke dalam kurung kurawal tepat sebelum kurung kurawal penutup).
atau:
main() {
sleep 20
echo test
}
main "[email protected]"; exit
Shell perlu membaca skrip hingga exit
sebelum mulai melakukan apapun. Itu memastikan shell tidak akan membaca dari skrip lagi.
Itu berarti seluruh skrip akan disimpan dalam memori.
Itu juga dapat memengaruhi penguraian skrip.
Misalnya, di bash
:
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
Akan menampilkan U+00E9 yang dikodekan dalam UTF-8. Namun, jika Anda mengubahnya menjadi:
{
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
}
\ue9
akan diperluas dalam rangkaian karakter yang berlaku pada saat perintah itu diuraikan yang dalam hal ini adalah sebelum export
perintah dijalankan.
Perhatikan juga bahwa jika source
alias .
perintah digunakan, dengan beberapa shell, Anda akan memiliki masalah yang sama untuk file sumber.
Itu bukan kasus bash
meskipun yang source
perintah membaca file sepenuhnya sebelum menafsirkannya. Jika menulis untuk bash
secara khusus, Anda sebenarnya dapat memanfaatkannya, dengan menambahkan di awal skrip:
if [[ ! $already_sourced ]]; then
already_sourced=1
source "$0"; exit
fi
(Saya tidak akan bergantung pada itu karena Anda dapat membayangkan versi bash
di masa mendatang dapat mengubah perilaku yang saat ini dapat dilihat sebagai batasan (bash dan AT&T ksh adalah satu-satunya shell seperti POSIX yang berperilaku seperti itu sejauh yang dapat diketahui) dan already_sourced
triknya agak rapuh karena mengasumsikan bahwa variabel tidak ada di lingkungan, belum lagi itu mempengaruhi konten variabel BASH_SOURCE)