ในการบันทึกไฟล์ descriptor คุณทำซ้ำมันใน fd อื่น การบันทึกเส้นทางไปยังไฟล์ที่เกี่ยวข้องนั้นไม่เพียงพอคุณจะต้องบันทึกโหมดการเปิดแฟล็กการเปิดตำแหน่งปัจจุบันภายในไฟล์และอื่น ๆ และแน่นอนสำหรับท่อหรือซ็อกเก็ตนิรนามที่ไม่สามารถใช้งานได้เนื่องจากไม่มีเส้นทาง สิ่งที่คุณต้องการที่จะบันทึกเป็นรายละเอียดการเปิดไฟล์ที่ FD หมายถึงและทำซ้ำ FD เป็นจริงกลับ FD ใหม่เพื่อเดียวกันคำอธิบายเปิดแฟ้ม
ในการทำซ้ำไฟล์ descriptor ไปยังอีกอันหนึ่งด้วย Bourne-like shell ไวยากรณ์คือ:
exec 3>&1
ด้านบน fd 1 ถูกทำซ้ำไปยัง fd 3
สิ่งที่ fd 3 เปิดอยู่ก่อนหน้านี้จะถูกปิด แต่โปรดทราบว่า fds 3 ถึง 9 (โดยปกติจะมากถึง 99 ด้วยyash
) สงวนไว้สำหรับจุดประสงค์นั้น (และไม่มีความหมายพิเศษที่ตรงกันข้ามกับ 0, 1 หรือ 2) เชลล์รู้ว่าจะไม่ใช้สิ่งเหล่านี้เพื่อธุรกิจภายในของตัวเอง เหตุผลเดียวที่ fd 3 น่าจะเปิดไว้ล่วงหน้าก็คือเพราะคุณทำมันในสคริปต์1หรือผู้โทรรั่วไหลออกมา
จากนั้นคุณสามารถเปลี่ยน stdout เป็นอย่างอื่น:
exec > /dev/null
และในภายหลังเพื่อเรียกคืน stdout:
exec >&3 3>&-
( 3>&-
กำลังจะปิดตัวอธิบายไฟล์ซึ่งเราไม่ต้องการอีกต่อไป)
ตอนนี้ปัญหาที่เกิดขึ้นนั้นยกเว้นใน ksh ทุกคำสั่งที่คุณใช้หลังจากนั้นexec 3>&1
จะสืบทอด fd 3 นั่นคือการรั่วไหลของ fd โดยทั่วไปไม่ใช่เรื่องใหญ่ แต่อาจทำให้เกิดปัญหา
ksh
ตั้งค่าแฟล็กclose-on-execบน fds เหล่านั้น (สำหรับ fds มากกว่า 2) แต่เชลล์อื่นและเชลล์อื่นไม่มีวิธีการตั้งค่าแฟล็กนั้นด้วยตนเอง
การทำงานกับเชลล์อื่น ๆ คือการปิด fd 3 สำหรับแต่ละคำสั่งทุกคำสั่งเช่น:
exec 3>&-
exec > file.log
ls 3>&-
uname 3>&-
exec >&3 3>&-
ยุ่งยาก. นี่คือวิธีที่ดีที่สุดที่จะไม่ใช้exec
เลย แต่เปลี่ยนเส้นทางกลุ่มคำสั่ง:
{
ls
uname
} > file.log
ที่นั่นมันเป็นเชลล์ที่ระมัดระวังในการบันทึก stdout และเรียกคืนมันในภายหลัง (และมันทำภายในโดยการทำซ้ำบน fd (เหนือ 9, สูงกว่า 99 สำหรับyash
) ด้วยชุดแฟล็ก close-on-exec
หมายเหตุ1
ตอนนี้การจัดการ fds 3 ถึง 9 อาจยุ่งยากและมีปัญหาหากคุณใช้อย่างกว้างขวางหรือในฟังก์ชั่นโดยเฉพาะอย่างยิ่งถ้าสคริปต์ของคุณใช้รหัสบุคคลที่สามซึ่งอาจใช้ fds เหล่านั้น
เปลือกบาง ( zsh
, bash
, ksh93
ทั้งหมดเพิ่มคุณลักษณะ ( แนะนำโดยโอลิเวอร์ Kiddle ของzsh
) รอบเวลาเดียวกันในปี 2005 หลังจากที่มันถูกกล่าวถึงในหมู่นักพัฒนาของพวกเขา) มีไวยากรณ์ทางเลือกในการกำหนด FD ฟรีครั้งแรกสูงกว่า 10 แทนซึ่งจะช่วยในกรณีนี้:
myfunction() {
local fd
exec {fd}>&1
# stdout was duplicated onto a new fd above 10, whose actual value
# is stored in the fd variable
...
# it should even be safe to re-enter the function here
...
exec >&"$fd" {fd}>&-
}