Saya membuat file sementara dari skrip bash. Saya menghapusnya di akhir pemrosesan, tetapi karena skrip berjalan cukup lama, jika saya mematikannya atau hanya CTRL-C selama menjalankan, file temp tidak akan dihapus.
Apakah ada cara untuk menangkap kejadian tersebut dan membersihkan file sebelum eksekusi berakhir?
Selain itu, apakah ada praktik terbaik untuk penamaan dan lokasi file temporer tersebut?
Saat ini saya tidak yakin antara menggunakan:
TMP1=`mktemp -p /tmp`
TMP2=`mktemp -p /tmp`
...
dan
TMP1=/tmp/`basename $0`1.$$
TMP2=/tmp/`basename $0`2.$$
...
Atau mungkin adakah solusi yang lebih baik?
bash
exit
temporary-files
skinp
sumber
sumber
Jawaban:
You could set a "trap" to execute on exit or on a control-c to clean up.
trap "{ rm -f $LOCKFILE; }" EXIT
Alternatively, one of my favourite unix-isms is to open a file, and then delete it while you still have it open. The file stays on the file system and you can read and write it, but as soon as your program exits, the file goes away. Not sure how you'd do that in bash, though.
BTW: One argument I'll give in favour of mktemp instead of using your own solution: if the user anticipates your program is going to create huge temporary files, he might want set
TMPDIR
to somewhere bigger, like /var/tmp. mktemp recognizes that, your hand-rolled solution (second option) doesn't. I frequently useTMPDIR=/var/tmp gvim -d foo bar
, for instance.sumber
exec 5<>$TMPFILE
kaitkan deskriptor file 5 ke $ TMPFILE sebagai baca-tulis, dan Anda dapat menggunakan<&5
,>&5
, and/proc/$$/fd/5
(Linux) thereafter. The only problem is that Bash lacksseek
function...trap
: there's no way to trapSIGKILL
(by design, as it immediately terminates execution). So, if that might happen, have a fallback plan (such astmpreaper
). Secondly, traps are not cumulative - if you have more than one action to perform, they must all be in thetrap
command. One way to cope with multiple cleanup actions is to define a function (and you can redefine it as your program proceeds, if necessary) and reference that:trap cleanup_function EXIT
.trap "rm -f $LOCKFILE" EXIT
or I would get a unexpected end of file error.Saya biasanya membuat direktori untuk menempatkan semua file sementara saya, dan kemudian segera setelah itu, buat penangan EXIT untuk membersihkan direktori ini ketika skrip keluar.
MYTMPDIR=$(mktemp -d) trap "rm -rf $MYTMPDIR" EXIT
Jika Anda meletakkan semua file sementara Anda di bawah
$MYTMPDIR
, maka semuanya akan dihapus ketika skrip Anda keluar dalam banyak situasi. Membunuh proses dengan SIGKILL (kill -9) membunuh proses itu segera, jadi penangan EXIT Anda tidak akan berjalan dalam kasus itu.sumber
Anda ingin menggunakan perintah trap untuk menangani keluar dari skrip atau sinyal seperti CTRL-C. Lihat Greg's Wiki untuk detailnya.
Untuk file temporer Anda, gunakan
basename $0
file temporer adalah ide yang bagus, serta menyediakan template yang menyediakan ruang untuk file temp yang cukup:tempfile() { tempprefix=$(basename "$0") mktemp /tmp/${tempprefix}.XXXXXX } TMP1=$(tempfile) TMP2=$(tempfile) trap 'rm -f $TMP1 $TMP2' EXIT
sumber
$()
. Menambahkan tanda kutip ganda juga.tempfile
perintah, sementara semua sistem modern yang wajar yang saya tahu memilikimktemp
perintah.Perlu diingat bahwa jawaban yang dipilih adalah
bashism
, yang artinya solusi sebagaitrap "{ rm -f $LOCKFILE }" EXIT
akan bekerja hanya di bash (tidak akan menangkap Ctrl + c jika shell ada
dash
atau klasiksh
), tetapi jika Anda menginginkan kompatibilitas maka Anda masih perlu menghitung semua sinyal yang ingin Anda jebakan.Juga perlu diingat bahwa ketika skrip keluar dari perangkap untuk sinyal "0" (alias KELUAR) selalu dilakukan yang mengakibatkan eksekusi ganda
trap
perintah.Itulah alasan untuk tidak menumpuk semua sinyal dalam satu baris jika ada sinyal EXIT.
Untuk lebih memahaminya, lihat skrip berikut yang akan berfungsi di berbagai sistem tanpa perubahan:
#!/bin/sh on_exit() { echo 'Cleaning up...(remove tmp files, etc)' } on_preExit() { echo echo 'Exiting...' # Runs just before actual exit, # shell will execute EXIT(0) after finishing this function # that we hook also in on_exit function exit 2 } trap on_exit EXIT # EXIT = 0 trap on_preExit HUP INT QUIT TERM STOP PWR # 1 2 3 15 30 sleep 3 # some actual code... exit
Solusi ini akan memberi Anda lebih banyak kontrol karena Anda dapat menjalankan beberapa kode Anda saat terjadi sinyal aktual sebelum keluar akhir (
preExit
fungsi) dan jika diperlukan Anda dapat menjalankan beberapa kode pada sinyal KELUAR aktual (tahap akhir keluar)sumber
Alternatif menggunakan nama file yang dapat diprediksi dengan $$ adalah celah keamanan yang menganga dan Anda tidak boleh pernah berpikir untuk menggunakannya. Bahkan jika itu hanya skrip pribadi sederhana di PC pengguna tunggal Anda. Ini adalah kebiasaan yang sangat buruk yang tidak boleh Anda dapatkan. BugTraq penuh dengan insiden "file temp tidak aman". Lihat di sini , di sini dan di sini untuk informasi lebih lanjut tentang aspek keamanan file temp.
Saya awalnya berpikir untuk mengutip tugas TMP1 dan TMP2 yang tidak aman, tetapi setelah dipikir-pikir, itu mungkin bukan ide yang baik .
sumber
Saya lebih suka menggunakan
tempfile
yang membuat file di / tmp dengan cara yang aman dan Anda tidak perlu khawatir tentang penamaannya:tmp=$(tempfile -s "your_sufix") trap "rm -f '$tmp'" exit
sumber
Saya tidak percaya bahwa begitu banyak orang menganggap bahwa nama file tidak akan mengandung spasi. Dunia akan macet jika $ TMPDIR pernah ditetapkan ke "direktori sementara".
zTemp=$(mktemp --tmpdir "$(basename "$0")-XXX.ps") trap "rm -f ${zTemp@Q}" EXIT
Spasi dan karakter khusus lainnya seperti tanda kutip tunggal dan tanda kutip dalam nama file harus dipertimbangkan dalam kode sebagai persyaratan kebiasaan pemrograman yang baik.
sumber
${parameter@operator}
ekspansi ditambahkan di Bash 4.4 (dirilis September 2016).trap "rm -f $(printf %q "$zTemp")" EXIT
zTemp
akan diubah nanti dalam skrip. Juga,zTemp
dapat dideklarasikanlocal
ke suatu fungsi; itu tidak perlu variabel skrip global.Anda tidak perlu repot menghapus file tmp yang dibuat dengan mktemp. Mereka akan tetap dihapus nanti.
Gunakan mktemp jika Anda bisa karena ini menghasilkan lebih banyak file unik daripada awalan '$$'. Dan sepertinya lebih banyak cara lintas platform untuk membuat file temp lalu secara eksplisit memasukkannya ke / tmp.
sumber