Saya sedang menulis skrip bash, dan kebetulan memperbarui kode (menyimpan file skrip ke disk) ketika skrip sedang menunggu beberapa input dalam satu while
lingkaran. Setelah saya kembali ke terminal dan melanjutkan dengan permintaan skrip sebelumnya, bash memberi kesalahan tentang sintaksis file:
/home/aularon/bin/script: line 58: unexpected EOF while looking for matching `"'
/home/aularon/bin/script: line 67: syntax error: unexpected end of file
Jadi saya mencoba melakukan hal berikut:
1: buat skrip, self-update.sh
sebut saja:
#!/bin/bash
fname=$(mktemp)
cat $0 | sed 's/BEFORE\./AFTER!./' > $fname
cp $fname $0
rm -f $fname
echo 'String: BEFORE.';
Apa yang dilakukan skrip adalah membaca kodenya, mengubah kata 'SEBELUM' menjadi 'SETELAH', kemudian menulis ulang sendiri dengan kode baru.
2nd Run it:
chmod +x self-update.sh
./self-update.sh
Keajaiban ke - 3 ...
aularon@aularon-laptop:~$ ./self-update.sh
String: AFTER!.
Sekarang, saya tidak akan menduga bahwa pada doa yang sama itu akan menghasilkan SETELAH! , pada menjalankan kedua pasti, tetapi tidak pada yang pertama.
Jadi pertanyaan saya adalah: apakah disengaja (berdasarkan desain)? atau itu karena cara bash menjalankan skrip? Baris demi baris atau perintah demi perintah. Apakah ada gunanya perilaku seperti itu? Adakah contohnya?
Sunting: Saya mencoba memformat ulang file untuk menempatkan semua perintah dalam satu baris, itu tidak berfungsi sekarang:
#!/bin/bash
fname=$(mktemp);cat $0 | sed 's/BEFORE\./AFTER!./' > $fname;cp $fname $0;rm -f $fname;echo 'String: BEFORE.';
Keluaran:
aularon@aularon-laptop:~$ ./self-update.sh #First invocation
String: BEFORE.
aularon@aularon-laptop:~$ ./self-update.sh #Second invocation
String: AFTER!.
Saat memindahkan echo
string ke baris berikutnya, pisahkan dari cp
panggilan penulisan ulang ( ):
#!/bin/bash
fname=$(mktemp);cat $0 | sed 's/BEFORE\./AFTER!./' > $fname;cp $fname $0;rm -f $fname;
echo 'String: BEFORE.';
Dan sekarang berfungsi lagi:
aularon@aularon-laptop:~$ ./self-update.sh
String: AFTER!.
Jawaban:
Ini dengan desain. Bash membaca skrip dalam potongan. Jadi itu akan membaca sebagian dari skrip, menjalankan setiap baris yang dapat, dan kemudian membaca potongan berikutnya.
Jadi Anda mengalami sesuatu seperti ini:
Di mana ini menjadi lebih bermasalah adalah bahwa jika Anda mengedit sesuatu sebelum byte 256. Katakanlah Anda menghapus beberapa baris. Kemudian data dalam skrip yang pada byte 256, sekarang di tempat lain, katakanlah pada byte 156 (100 byte sebelumnya). Karena itu, ketika bash terus membaca, itu akan mendapatkan apa yang semula 356.
Ini hanya sebuah contoh. Bash tidak harus membaca 256 byte sekaligus. Saya tidak tahu persis berapa banyak dibaca pada satu waktu, tetapi tidak masalah, perilaku masih sama.
sumber
stat
file untuk melihat apakah itu berubah. Tidak adalseek
panggilan.echo foo
perubahan menjadiecho bar
selamasleep
. Sudah berperilaku seperti itu sejauh versi 2, jadi saya tidak berpikir itu masalah versi.