Di Unix, kebanyakan editor bekerja dengan membuat file sementara baru yang berisi konten yang diedit. Ketika file yang diedit disimpan, file asli dihapus dan file sementara berganti nama menjadi nama asli. (Ada, tentu saja, berbagai perlindungan untuk mencegah dataloss.) Ini, misalnya, gaya yang digunakan oleh sed
atau perl
ketika dipanggil dengan -i
bendera ("di tempat"), yang sama sekali tidak "di tempat". Seharusnya disebut "tempat baru dengan nama lama".
Ini berfungsi dengan baik karena unix menjamin (setidaknya untuk sistem file lokal) bahwa file yang dibuka terus ada sampai ditutup, bahkan jika itu "dihapus" dan file baru dengan nama yang sama dibuat. (Bukan kebetulan bahwa panggilan sistem unix untuk "menghapus" file sebenarnya disebut "batalkan tautan".) Jadi, secara umum, jika penerjemah shell memiliki beberapa file sumber terbuka, dan Anda "mengedit" file dengan cara yang dijelaskan di atas , shell bahkan tidak akan melihat perubahan karena masih membuka file asli.
[Catatan: seperti halnya semua komentar berbasis standar, di atas tunduk pada beberapa interpretasi dan ada berbagai kasus sudut, seperti NFS. Pedant dipersilakan untuk mengisi komentar dengan pengecualian.]
Tentu saja dimungkinkan untuk memodifikasi file secara langsung; itu hanya sangat tidak nyaman untuk keperluan pengeditan, karena sementara Anda dapat menimpa data dalam file, Anda tidak dapat menghapus atau menyisipkan tanpa menggeser semua data berikut, yang akan menyiratkan banyak menulis ulang. Selain itu, ketika Anda melakukan pemindahan itu, konten file tidak dapat diprediksi dan proses yang membuat file terbuka akan menderita. Untuk menghindari hal ini (seperti halnya sistem basis data, misalnya), Anda memerlukan seperangkat protokol modifikasi yang canggih dan kunci yang didistribusikan; hal-hal yang jauh di luar cakupan utilitas pengeditan file yang khas.
Jadi, jika Anda ingin mengedit file saat sedang diproses oleh shell, Anda memiliki dua opsi:
Anda dapat menambahkan ke file. Ini harus selalu berhasil.
Anda dapat menimpa file dengan konten baru dengan panjang yang persis sama . Ini mungkin atau mungkin tidak berfungsi, tergantung pada apakah shell sudah membaca bagian file atau tidak. Karena sebagian besar file I / O melibatkan buffer baca, dan karena semua shell yang saya tahu membaca seluruh perintah majemuk sebelum menjalankannya, sangat tidak mungkin Anda bisa lolos dengan ini. Tentu tidak akan bisa diandalkan.
Saya tidak tahu adanya kata-kata dalam standar Posix yang sebenarnya membutuhkan kemungkinan untuk menambahkan ke file skrip saat file sedang dieksekusi, sehingga mungkin tidak bekerja dengan setiap shell yang sesuai dengan Posix, apalagi dengan penawaran saat ini dari hampir dan kadang-kadang shell yang sesuai dengan posix. Jadi YMMV. Tapi sejauh yang saya tahu, itu berfungsi baik dengan bash.
Sebagai bukti, inilah implementasi "bebas-loop" dari program bir 99 botol terkenal di bash, yang digunakan dd
untuk menimpa dan menambahkan (penimpaan itu mungkin aman karena menggantikan garis yang saat ini sedang dijalankan, yang selalu merupakan baris terakhir dari file, dengan komentar yang persis sama panjangnya; saya melakukan itu sehingga hasil akhirnya dapat dieksekusi tanpa perilaku modifikasi diri.)
#!/bin/bash
if [[ $1 == reset ]]; then
printf "%s\n%-16s#\n" '####' 'next ${1:-99}' |
dd if=/dev/stdin of=$0 seek=$(grep -bom1 ^#### $0 | cut -f1 -d:) bs=1 2>/dev/null
exit
fi
step() {
s=s
one=one
case $beer in
2) beer=1; unset s;;
1) beer="No more"; one=it;;
"No more") beer=99; return 1;;
*) ((--beer));;
esac
}
next() {
step ${beer:=$(($1+1))}
refrain |
dd if=/dev/stdin of=$0 seek=$(grep -bom1 ^next\ $0 | cut -f1 -d:) bs=1 conv=notrunc 2>/dev/null
}
refrain() {
printf "%-17s\n" "# $beer bottles"
echo echo ${beer:-No more} bottle$s of beer on the wall, ${beer:-No more} bottle$s of beer.
if step; then
echo echo Take $one down, pass it around, $beer bottle$s of beer on the wall.
echo echo
echo next abcdefghijkl
else
echo echo Go to the store, buy some more, $beer bottle$s of beer on the wall.
fi
}
####
next ${1:-99} #