Chúng ta có thể sử dụng các thư mục tạm thời như các tập tin tạm thời
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
cái nào sẽ bị phá hủy tự động sau khi thoát vỏ này?
Chúng ta có thể sử dụng các thư mục tạm thời như các tập tin tạm thời
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
cái nào sẽ bị phá hủy tự động sau khi thoát vỏ này?
Câu trả lời:
Trong trường hợp tệp tạm thời, ví dụ của bạn trong câu hỏi sẽ tạo tệp đó, sau đó hủy liên kết tệp khỏi thư mục (làm cho nó "biến mất") và khi tập lệnh đóng tệp filedescriptor (có thể là khi chấm dứt), khoảng trống được lấy bởi tệp sẽ được hệ thống thu hồi. Đây là một cách phổ biến để xử lý các tệp tạm thời bằng các ngôn ngữ như C.
Theo như tôi biết, không thể mở một thư mục theo cùng một cách, ít nhất là không theo bất kỳ cách nào có thể làm cho thư mục có thể sử dụng được.
Một cách phổ biến để xóa các tệp và thư mục tạm thời khi chấm dứt tập lệnh là cài đặt EXIT
bẫy dọn dẹp . Các ví dụ mã được đưa ra dưới đây để tránh phải hoàn toàn tung hứng các bộ lọc.
tmpdir=$(mktemp -d)
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"; rm -rf "$tmpdir"' EXIT
# The rest of the script goes here.
Hoặc bạn có thể gọi một chức năng dọn dẹp:
cleanup () {
rm -f "$tmpfile"
rm -rf "$tmpdir"
}
tmpdir=$(mktemp -d)
tmpfile=$(mktemp)
trap cleanup EXIT
# The rest of the script goes here.
Các EXIT
bẫy sẽ không được thực hiện sau khi nhận được KILL
tín hiệu (mà không thể bị mắc kẹt), có nghĩa là sẽ không có dọn dẹp biểu diễn sau đó. Tuy nhiên nó sẽ thực thi khi chấm dứt do một INT
hoặc TERM
tín hiệu (nếu chạy với bash
hoặc ksh
, trong vỏ khác mà bạn có thể muốn thêm những tín hiệu sau EXIT
trong trap
dòng lệnh), hoặc khi thoát bình thường do đến ở phần cuối của kịch bản hoặc thực hiện một exit
gọi.
.
và ..
các mục. (Đã thử nghiệm trên Linux, tôi không biết liệu điều đó có nhất quán trên các nền tảng hay không.)
exec another-command
rõ ràng.
Viết hàm shell sẽ được thực thi khi tập lệnh của bạn nếu kết thúc. Trong ví dụ dưới đây, tôi gọi nó là 'dọn dẹp' và đặt bẫy để được thực thi ở các mức thoát, như: 0 1 2 3 6
trap cleanup 0 1 2 3 6
cleanup()
{
[ -d $TMP ] && rm -rf $TMP
}
Xem bài đăng này để biết thêm.
cleanup
trước lối thoát sạch (0) và khi nhận SIGHUP (1), SIGINT (2), SIGQUIT (3) và SIGABRT (6). nó sẽ không chạy cleanup
khi tập lệnh thoát vì SIGTERM, SIGSEGV, SIGKILL, SIGPIPE, v.v ... Điều này rõ ràng là thiếu.
Bạn có thể chdir vào nó và sau đó loại bỏ nó, với điều kiện bạn không cố gắng sử dụng các đường dẫn bên trong nó sau đó:
#! /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
Tôi chưa kiểm tra, nhưng rất có thể đó là vấn đề tương tự khi sử dụng openat (2) trong C với một thư mục không còn tồn tại trong hệ thống tệp.
Nếu bạn đã root và trên Linux, bạn có thể chơi với một không gian tên riêng biệt và mount -t tmpfs tmpfs /dir
bên trong nó.
Các câu trả lời chính tắc (đặt bẫy trên EXIT) sẽ không hoạt động nếu tập lệnh của bạn bị buộc vào một lối thoát ô uế (ví dụ: với SIGKILL); có thể để lại dữ liệu nhạy cảm treo xung quanh.
Cập nhật:
Đây là một tiện ích nhỏ thực hiện cách tiếp cận không gian tên. Nó nên được biên dịch với
cc -Wall -Os -s chtmp.c -o chtmp
và cho CAP_SYS_ADMIN
khả năng tập tin (như root) với
setcap CAP_SYS_ADMIN+ep chtmp
Khi chạy (như một người dùng bình thường) như
./chtmp command args ...
nó sẽ bỏ chia sẻ không gian tên hệ thống tập tin của nó, gắn hệ thống tập tin tmpfs trên /proc/sysvipc
, chdir vào nó và chạy command
với các đối số đã cho. command
sẽ không kế thừa các CAP_SYS_ADMIN
khả năng.
Hệ thống tập tin đó sẽ không thể truy cập được từ một quá trình khác không được bắt đầu command
và nó sẽ biến mất một cách kỳ diệu (với tất cả các tệp được tạo bên trong nó) khi command
và con của nó chết, bất kể điều đó xảy ra như thế nào. Lưu ý rằng đây chỉ là không giới hạn không gian tên gắn kết - không có rào cản cứng giữa command
và các quy trình khác được điều hành bởi cùng một người dùng; họ vẫn có thể lẻn vào trong không gian tên của nó hoặc thông qua ptrace(2)
, /proc/PID/cwd
hoặc bằng cách khác.
Tất nhiên, việc chiếm quyền điều khiển "vô dụng" /proc/sysvipc
là ngớ ngẩn, nhưng giải pháp thay thế sẽ là spam /tmp
với các thư mục trống sẽ phải được gỡ bỏ hoặc làm phức tạp đáng kể chương trình nhỏ này bằng dĩa và chờ đợi. Ngoài ra, dir
có thể được thay đổi thành ví dụ. /mnt/chtmp
và có nó được tạo bởi root khi cài đặt; không làm cho nó có thể được cấu hình bởi người dùng và không đặt nó thành một đường dẫn thuộc sở hữu của người dùng vì điều đó có thể khiến bạn gặp bẫy liên kết và các công cụ lông khác không đáng để dành thời gian.
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
công việc, shell vẫn nằm trong thư mục đó. Nhưng không có tập tin mới nào có thể được đưa vào "thư mục" này. Chỉ bạn có thể làm là đọc / ghi với tệp & 3, & 4. Vì vậy, đây vẫn là "tệp tạm thời", không phải "thư mục tạm thời".
Bạn có yêu cầu một vỏ cụ thể?
Nếu zsh là một tùy chọn, vui lòng đọc zshexpn(1)
:
Nếu = (...) được sử dụng thay vì <(...), thì tệp được truyền dưới dạng đối số sẽ là tên của tệp tạm thời chứa đầu ra của quy trình danh sách. Điều này có thể được sử dụng thay vì <mẫu cho một chương trình dự kiến
lseek
(xemlseek(2)
) trên tệp đầu vào.[...]
Một vấn đề khác phát sinh bất cứ khi nào một công việc thay thế yêu cầu một tệp tạm thời bị từ chối bởi shell, bao gồm cả trường hợp
&!
hoặc&|
xuất hiện ở cuối lệnh có chứa thay thế. Trong trường hợp đó, tệp tạm thời sẽ không được dọn sạch vì shell không còn bất kỳ bộ nhớ nào của công việc. Một cách giải quyết là sử dụng một subshell, ví dụ,(mycmd =(myoutput)) &!
vì subshell rẽ nhánh sẽ đợi lệnh kết thúc rồi gỡ tệp tạm thời.
Một cách giải quyết chung để đảm bảo quá trình thay thế quá trình tồn tại trong một khoảng thời gian thích hợp là chuyển nó dưới dạng tham số cho hàm shell ẩn danh (một đoạn mã shell được chạy ngay lập tức với phạm vi hàm). Ví dụ: mã này:
() { print File $1: cat $1 } =(print This be the verse)
xuất ra một cái gì đó tương tự như sau
File /tmp/zsh6nU0kS: This be the verse
Ví dụ, tôi sử dụng điều này trong súng trường (một phần của trình quản lý tệp kiểm lâm) để giải mã một tệp và sau đó chạy súng trường trên tệp tạm thời, sẽ bị xóa khi kết thúc phụ. (đừng quên thiết lập $TERMCMD
)
# ~/.config/ranger/rifle.conf
...
!ext exe, mime octet-stream$, has gpg, flag t = () { rifle -f F "$1" } =(gpg -dq "$1")