Bisakah kita menggunakan folder sementara seperti file sementara
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
yang akan dihancurkan secara otomatis setelah shell keluar ini?
Bisakah kita menggunakan folder sementara seperti file sementara
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
yang akan dihancurkan secara otomatis setelah shell keluar ini?
Jawaban:
Dalam kasus file sementara, contoh Anda dalam pertanyaan akan membuatnya, lalu memutuskan tautannya dari direktori (menjadikannya "menghilang"), dan ketika skrip menutup arsip yang diajukan (mungkin setelah penghentian), ruang yang diambil oleh file tersebut akan dapat direklamasi oleh sistem. Ini adalah cara umum untuk menangani file sementara dalam bahasa seperti C.
Sejauh yang saya tahu, tidak mungkin untuk membuka direktori dengan cara yang sama, setidaknya tidak dengan cara apa pun yang membuat direktori tersebut dapat digunakan.
Cara umum untuk menghapus file dan direktori sementara pada saat penghentian skrip adalah dengan menginstal EXIT
perangkap pembersihan . Contoh kode yang diberikan di bawah ini menghindari keharusan menyulap para pembuat arsip sepenuhnya.
tmpdir=$(mktemp -d)
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"; rm -rf "$tmpdir"' EXIT
# The rest of the script goes here.
Atau Anda dapat memanggil fungsi pembersihan:
cleanup () {
rm -f "$tmpfile"
rm -rf "$tmpdir"
}
tmpdir=$(mktemp -d)
tmpfile=$(mktemp)
trap cleanup EXIT
# The rest of the script goes here.
The EXIT
perangkap tidak akan dieksekusi setelah menerima KILL
sinyal (yang tidak dapat terperangkap), yang berarti bahwa tidak akan ada pembersihan dilakukan kemudian. Namun itu akan dieksekusi ketika mengakhiri karena INT
atau TERM
sinyal (jika berjalan dengan bash
atau ksh
, dalam shell lain Anda mungkin ingin menambahkan sinyal ini setelah EXIT
di trap
baris perintah), atau ketika keluar secara normal karena sampai di akhir skrip atau menjalankan exit
panggilan.
.
dan ..
entri. (Diuji di Linux, saya tidak tahu apakah itu konsisten di semua platform.)
exec another-command
jelas.
Tulis fungsi-shell yang akan dieksekusi ketika skrip Anda jika selesai. Dalam contoh di bawah ini saya menyebutnya 'pembersihan' dan mengatur jebakan yang akan dieksekusi pada tingkat keluar, seperti: 0 1 2 3 6
trap cleanup 0 1 2 3 6
cleanup()
{
[ -d $TMP ] && rm -rf $TMP
}
Lihat posting ini untuk info lebih lanjut.
cleanup
sebelum keluar bersih (0) dan saat menerima SIGHUP (1), SIGINT (2), SIGQUIT (3) dan SIGABRT (6). itu tidak akan berjalan cleanup
ketika skrip keluar karena SIGTERM, SIGSEGV, SIGKILL, SIGPIPE, dll. Ini jelas kurang.
Anda dapat chdir ke dalamnya dan kemudian menghapusnya, asalkan Anda tidak mencoba menggunakan jalur di dalamnya setelah itu:
#! /bin/sh
dir=`mktemp -d`
cd "$dir"
exec 4>file 3<file
rm -fr "$dir"
echo yes >&4 # OK
cat <&3 # OK
cat file # FAIL
echo yes > file # FAIL
Saya belum memeriksa, tetapi kemungkinan besar masalah yang sama ketika menggunakan openat (2) di C dengan direktori yang tidak lagi ada di sistem file.
Jika Anda root dan di Linux, Anda bisa bermain dengan namespace yang terpisah, dan mount -t tmpfs tmpfs /dir
di dalamnya.
Jawaban kanonik (setel perangkap pada EXIT) tidak berfungsi jika skrip Anda dipaksa keluar secara tidak bersih (mis. Dengan SIGKILL); yang dapat meninggalkan data sensitif berkeliaran.
Memperbarui:
Berikut ini adalah utilitas kecil yang mengimplementasikan pendekatan namespace. Ini harus dikompilasi dengan
cc -Wall -Os -s chtmp.c -o chtmp
dan diberikan CAP_SYS_ADMIN
kemampuan file (sebagai root) dengan
setcap CAP_SYS_ADMIN+ep chtmp
Ketika dijalankan (seperti biasa) pengguna sebagai
./chtmp command args ...
ia akan berhenti menggunakan namespace filesystem-nya, me-mount sebuah filesystem tmpfs aktif /proc/sysvipc
, chdir ke dalamnya dan menjalankan command
dengan argumen yang diberikan. tidakcommand
akan mewarisi kemampuan.CAP_SYS_ADMIN
Sistem file itu tidak akan dapat diakses dari proses lain yang tidak dimulai command
, dan itu akan secara ajaib menghilang (dengan semua file yang dibuat di dalamnya) kapan command
dan anak-anaknya mati, tidak peduli bagaimana itu terjadi. Perhatikan bahwa ini hanya unsharing the namespace mount - tidak ada hambatan keras antara command
dan proses lain yang dijalankan oleh pengguna yang sama; mereka masih bisa menyelinap ke dalam ruang namanya baik melalui ptrace(2)
, /proc/PID/cwd
atau dengan cara lain.
Pembajakan "tidak berguna" /proc/sysvipc
tentu saja konyol, tetapi alternatifnya adalah spam /tmp
dengan direktori kosong yang harus dihapus atau sangat menyulitkan program kecil ini dengan garpu dan menunggu. Atau, dir
dapat diubah menjadi misalnya. /mnt/chtmp
dan membuatnya dibuat oleh root pada saat instalasi; jangan membuatnya bisa dikonfigurasi pengguna dan jangan setel ke jalur yang dimiliki pengguna karena hal itu dapat membuat Anda terkena symlink traps dan hal-hal berbulu lainnya yang tidak layak menghabiskan waktu.
chtmp.c
#define _GNU_SOURCE
#include <err.h>
#include <sched.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mount.h>
int main(int argc, char **argv){
char *dir = "/proc/sysvipc"; /* LOL */
if(argc < 2 || !argv[1]) errx(1, "usage: %s prog args ...", *argv);
argv++;
if(unshare(CLONE_NEWNS)) err(1, "unshare(CLONE_NEWNS)");
/* "modern" systemd remounts all mount points MS_SHARED
see the NOTES in mount_namespaces(7); YUCK */
if(mount("none", "/", 0, MS_REC|MS_PRIVATE, 0))
err(1, "mount(/, MS_REC|MS_PRIVATE)");
if(mount("tmpfs", dir, "tmpfs", 0, 0)) err(1, "mount(tmpfs, %s)", dir);
if(chdir(dir)) err(1, "chdir %s", dir);
execvp(*argv, argv);
err(1, "execvp %s", *argv);
}
rm $PWD
kerja, shell masih di dir itu. Tetapi tidak ada file baru yang dapat dimasukkan ke dalam "folder" ini. Yang bisa Anda lakukan hanyalah membaca / menulis dengan file & 3, & 4. Jadi ini masih "file sementara", bukan "folder sementara".
Apakah Anda memerlukan shell tertentu?
Jika zsh adalah opsi, harap baca zshexpn(1)
:
Jika = (...) digunakan alih-alih <(...), maka file yang dilewatkan sebagai argumen akan menjadi nama file sementara yang berisi output dari proses daftar. Ini dapat digunakan sebagai ganti dari <form untuk program yang mengharapkan
lseek
(lihatlseek(2)
) pada file input.[...]
Masalah lain muncul setiap kali suatu pekerjaan dengan substitusi yang memerlukan file sementara tidak diakui oleh shell, termasuk kasus di mana
&!
atau&|
muncul di akhir perintah yang mengandung substitusi. Dalam hal ini file sementara tidak akan dibersihkan karena shell tidak lagi memiliki memori pekerjaan. Solusinya adalah dengan menggunakan subkulit, misalnya,(mycmd =(myoutput)) &!
sebagai subkulit bercabang akan menunggu perintah untuk menyelesaikan kemudian menghapus file sementara.
Sebuah solusi umum untuk memastikan proses substitusi bertahan untuk jangka waktu yang sesuai adalah melewatinya sebagai parameter ke fungsi shell anonim (sepotong kode shell yang dijalankan segera dengan lingkup fungsi). Misalnya, kode ini:
() { print File $1: cat $1 } =(print This be the verse)
menampilkan sesuatu yang menyerupai berikut ini
File /tmp/zsh6nU0kS: This be the verse
Sebagai contoh saya menggunakan ini di rifle (bagian dari manajer file ranger) untuk mendekripsi file dan kemudian menjalankan rifle pada file sementara, yang akan dihapus ketika subproces berakhir. (jangan lupa atur $TERMCMD
)
# ~/.config/ranger/rifle.conf
...
!ext exe, mime octet-stream$, has gpg, flag t = () { rifle -f F "$1" } =(gpg -dq "$1")