มีวิธีปิด descriptor ไฟล์ที่เปิดทั้งหมดโดยไม่ต้องมีรายการที่ชัดเจนของพวกเขามาก่อนหรือไม่?
มีวิธีปิด descriptor ไฟล์ที่เปิดทั้งหมดโดยไม่ต้องมีรายการที่ชัดเจนของพวกเขามาก่อนหรือไม่?
คำตอบ:
หากต้องการตอบอย่างแท้จริงให้ปิดตัวอธิบายไฟล์ที่เปิดอยู่ทั้งหมดสำหรับbash
:
for fd in $(ls /proc/$$/fd); do
eval "exec $fd>&-"
done
อย่างไรก็ตามนี่ไม่ใช่ความคิดที่ดีเพราะจะปิดตัวอธิบายไฟล์พื้นฐานที่เชลล์ต้องการสำหรับอินพุตและเอาต์พุต หากคุณทำสิ่งนี้ไม่มีโปรแกรมใดที่คุณรันจะมีเอาต์พุตของพวกเขาปรากฏขึ้นที่เครื่อง (เว้นแต่พวกเขาจะเขียนลงในtty
อุปกรณ์โดยตรง) หากข้อเท็จจริงในการปิดการทดสอบของฉันstdin
( exec 0>&-
) เพียงแค่ทำให้เชลล์แบบโต้ตอบออก
สิ่งที่คุณอาจต้องการทำจริงๆคือการปิดตัวอธิบายไฟล์ทั้งหมดที่ไม่ได้เป็นส่วนหนึ่งของการทำงานพื้นฐานของเชลล์ เหล่านี้เป็น 0 stdin
, 1 stdout
และ stderr
2 ที่ด้านบนของเชลล์นี้บางเชลล์ก็ดูเหมือนว่าไฟล์ descriptors อื่น ๆ เปิดอยู่ ในbash
ตัวอย่างเช่นคุณมี 255 (ยังสถานี I / O) และdash
ผมมี 10 ซึ่งจุดที่จะต้อง/dev/tty
มากกว่าที่เฉพาะเจาะจงtty
/ pts
อุปกรณ์ปลายทางจะใช้ หากต้องการปิดทุกอย่างนอกเหนือจาก 0, 1, 2 และ 255 ในbash
:
for fd in $(ls /proc/$$/fd); do
case "$fd" in
0|1|2|255)
;;
*)
eval "exec $fd>&-"
;;
esac
done
โปรดทราบด้วยว่าeval
จำเป็นต้องใช้เมื่อเปลี่ยนเส้นทางตัวอธิบายไฟล์ที่มีอยู่ในตัวแปรถ้าไม่bash
จะขยายตัวแปร แต่พิจารณาว่าเป็นส่วนหนึ่งของคำสั่ง (ในกรณีนี้มันจะลองexec
คำสั่ง0
หรือ1
คำอธิบายไฟล์ใดก็ตามที่คุณพยายามปิด)
หมายเหตุ: การใช้ glob แทนls
เช่น ( /proc/$$/fd/*
) ดูเหมือนว่าจะเปิดตัวอธิบายไฟล์เพิ่มเติมสำหรับ glob ดังนั้นจึงls
เป็นทางออกที่ดีที่สุดที่นี่
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการพกพาของ/proc/$$/fd
โปรดดูPortability ของการเชื่อมโยงอธิบายไฟล์ หาก/proc/$$/fd
ใช้งานไม่ได้แล้วลดลงในทดแทนสำหรับ$(ls /proc/$$/fd)
ใช้lsof
(ถ้าที่มีอยู่) $(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-)
จะเป็น
/proc
ใช้งานได้กับ Linux เท่านั้น
/proc/PID/fd
แบบพกพาไม่ได้ แต่การบอกว่า/proc
ใช้งานได้กับ Linux เท่านั้นไม่ใช่คำสั่งที่ถูกต้อง
<&-
แบบฟอร์มมันแตกต่าง / จำเป็นหรือไม่?
ในเวอร์ชันล่าสุดของ Bash (4.1 ขึ้นไป, ปี 2009 และใหม่กว่า) คุณสามารถระบุไฟล์ descriptor เพื่อปิดโดยใช้ตัวแปรเชลล์:
for fd in $(ls /proc/$$/fd/); do
[ $fd -gt 2 ] && exec {fd}<&-
done
คุณลักษณะดังกล่าวอยู่ใน Korn shell แล้ว (ตั้งแต่ปี 1993?) แต่เห็นได้ชัดว่าใช้เวลาพอสมควรในการเจาะเข้าสู่ Bash
ล้าง descriptor ไฟล์ทั้งหมดยกเว้น i / o / e ของเชลล์ปัจจุบัน แต่ยังไม่รวมสิ่งที่จัดเตรียมไว้เป็นอาร์กิวเมนต์
clear_fds() {
for fd in $(compgen -G "/proc/$BASHPID/fd/*"); do
fd=${fd/*\/}
if [[ ! " $* " =~ " ${fd} " ]]; then
case "$fd" in
0|1|2|255)
;;
*)
eval "exec $fd>&-"
;;
esac
fi
done
}
อีกวิธีหนึ่งโดยไม่มี "eval" เลยคือการใช้แบบฟอร์ม:
$ exec {var_a}>> file.txt
$ echo $var_a
10
$ ls -l /proc/self/fd/10
l-wx------ 1 0 0 64 Dec 11 18:32 /proc/self/fd/10 -> /run/user/0/tmp/file.txt
$ echo "aaaaa" >&$var_a
$ cat file.txt
aaaaa
$ exec {var_a}>&-
$ ls /proc/self/fd/10
ls: cannot access '/proc/self/fd/10': No such file or directory
ไม่เคอร์เนลสามารถปิดได้ครั้งละหนึ่ง FD เท่านั้นและ bash ไม่มี "คำสั่งกลุ่ม" สำหรับ FDs
for fd in $(ls -1 /proc/27343/fd); do echo exec $fd">&"-; done
ลบecho
และ"
หลังจากการทดสอบ
หากนี่ไม่ใช่สำหรับเชลล์เอง แต่เพื่อให้รันคำสั่งคุณสามารถใช้งานnohup
ได้
>&-
ไม่สามารถเป็นพารามิเตอร์ การเปลี่ยนเส้นทางจะถูกแยกวิเคราะห์ก่อนการขยายพารามิเตอร์
exec {fd}>&-
ทำงานทุกวันนี้