OS X, bash: ใช้งานได้กับตัวอธิบายไฟล์ที่เปิดน้อยกว่า cat ไม่ทำงาน


10

ในสคริปต์ทุบตีที่ฉันกำลังทำงาน (ซึ่งต้องทำงานบน Ubuntu และ OS X) ฉันต้องเปลี่ยนเส้นทางเอาต์พุตของคำสั่งหลายร้อยไปยังไฟล์
แทนที่จะเพิ่ม&>...พวกเขาทั้งหมดต่อท้ายฉันก็ทำได้

exec 9>&1
exec 5<>/tmp/some-file.txt
exec 1>&5

จนถึงตอนนี้ดีมาก แต่ครึ่งหนึ่งของคำสั่งเหล่านั้นฉันต้องอ่านทุกอย่างที่เขียนไปแล้วในขณะที่เปิดไฟล์ descriptor ไว้
ตอนนี้บน Ubuntu ฉันสามารถทำได้

cat /dev/fd/5

หรือ

tee </dev/fd/5

แต่ใน OS X ไม่มีอะไรถูกพิมพ์เลย (และคำสั่งจะออกทันที)
อย่างไรก็ตามการใช้lessฉันสามารถดูเนื้อหาของไฟล์ทั้งสอง
ฉันสามารถบรรลุผลข้างต้น (ทำงานกับทั้งสองระบบปฏิบัติการ) โดยใช้

less /dev/fd/5 | tee

แต่ดูเหมือนว่าแฮ็ค

ดังนั้นเหตุใดจึงlessเห็นสิ่งที่catไม่สามารถใช้กับ OS X ได้ (หรือลูกหลาน BSD ทุกคนได้รับผลกระทบหรือไม่)
หรือฉันกำลังทำอะไรผิดพลาด?

คำตอบ:


13

บน OS X เช่นเดียวกับทุกระบบที่รองรับยกเว้น Linux การเปิด/dev/fd/xจะเหมือนกับการทำจุดdup(x)fd ที่มากขึ้นหรือน้อยลงไปเป็นคำอธิบายไฟล์แบบเปิดเดียวกันกับบน fd x และโดยเฉพาะอย่างยิ่งจะมีออฟเซ็ตเดียวกันภายในไฟล์

Linux เป็นข้อยกเว้นที่นี่ บน Linux /dev/fd/xเป็น symlink /proc/self/fd/xและ/proc/self/fd/xเป็น pseudo-symlink ไปยังไฟล์ที่เปิดอยู่บน fd x บน Linux เมื่อคุณทำopen("/dev/fd/x", somemode)คุณจะได้รับแบรนด์ใหม่รายละเอียดการเปิดไฟล์xไปยังแฟ้มเดียวกับที่เปิดใน fd ใหม่ที่คุณได้รับนั้นไม่เกี่ยวข้องกับ fd x แต่อย่างใด โดยเฉพาะอย่างยิ่งการชดเชยจะอยู่ที่จุดเริ่มต้นของไฟล์ (ยกเว้นถ้าคุณเปิดด้วยO_APPENDแน่นอน) และโหมด (อ่าน / เขียน / ผนวก ... ) อาจแตกต่างจากหนึ่งใน fd x (คุณสามารถรับได้ สิ่งที่แตกต่างจากสิ่งที่อยู่ใน fd x เช่นปลายท่อเมื่อเปิดในโหมดตรงกันข้าม) (นั่นหมายความว่าจะไม่ทำงานกับซ็อกเก็ตเช่นที่คุณไม่สามารถเปิดได้) ( )

ดังนั้นบน Linux เมื่อคุณทำ

exec 5<> file
echo test >&5

อ็อฟเซ็ต fd 5 อยู่ที่ท้ายไฟล์ ถ้าคุณทำ

cat <&5

คุณไม่ได้รับอะไรเลย

ยังเมื่อคุณ:

cat /dev/fd/5

คุณเห็นtestเพราะcatได้รับ fd แบบอ่านอย่างเดียวเป็นfileไม่เกี่ยวข้องกับ fd 5

ในระบบอื่น ๆ

cat /dev/fd/5

cat รับ fd ที่ซ้ำกับ fd 5 ดังนั้นยังคงมี offset ตรงท้ายไฟล์

เหตุผลที่ใช้งานได้lessคือด้วยเหตุผลบางประการให้lessทำlseek()f บนนั้นไปยังจุดเริ่มต้นของไฟล์ (ทำlseek(1); lseek(0)เพื่อพิจารณาว่าไฟล์นั้นหาได้หรือไม่)

ที่นี่คุณอาจต้องการ fd สำหรับการอ่านและอีกอันสำหรับการเขียนหากคุณต้องการให้ offsets ต่างกัน:

exec 5< file 9>&1 > file

หรือคุณจะต้องเปิดไฟล์อีกครั้งหากยังอยู่ที่นั่นหรือทำlseek()เช่นlessนั้น

ksh93และzshเป็นหอยเดียวที่มีlseek()โอเปอเรเตอร์ในตัวแม้ว่า:

cat <&5 <#((0)) # ksh93
{sysseek 0; cat} <&5 # zsh, zmodload zsh/system to enable that builtin

หรือ:

cat /dev/fd/5 5<#((0))  # ksh93
sysseek -u 5 0; cat /dev/fd/5 # zsh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.