จะไปป์ stdout ขณะที่เก็บไว้บนหน้าจอได้อย่างไร (และไม่ใช่ไฟล์เอาต์พุต)


234

ฉันต้องการส่งออกมาตรฐานของโปรแกรมในขณะที่เก็บไว้บนหน้าจอ

ด้วยตัวอย่างง่ายๆ ( echoใช้ที่นี่เป็นเพียงภาพประกอบเท่านั้น):

$ echo 'ee' | foo
ee <- ผลลัพธ์ที่ฉันต้องการดู

ฉันรู้ว่าทีสามารถคัดลอก stdout ไปยังไฟล์ได้ แต่นั่นไม่ใช่สิ่งที่ฉันต้องการ
$ echo 'ee' | tee output.txt | foo

ฉันพยายาม
$ echo 'ee' | tee /dev/stdout | fooแต่มันใช้งานไม่ได้ตั้งแต่เอาท์พุททีไป/dev/stdoutเป็น pipfoo


6
โปรดทราบว่าใช้echo 'ee' | tee /dev/stderrงานได้ดังนั้นหากความต้องการ"บนหน้าจอ"ของคุณเป็นที่พึงพอใจโดย stderr ก็จะทำเช่นนั้น
nh2

คำตอบ:


344

นี่เป็นวิธีการแก้ปัญหาที่ทำงานได้กับการใช้งาน Unix / Linux ใด ๆ สมมติว่ามันเป็นไปตามPOSIXมาตรฐาน มันทำงานได้ในสภาพแวดล้อม Unix ที่ไม่ใช่เช่นcygwinกัน

echo 'ee' | tee /dev/tty | foo

ข้อมูลอ้างอิง: ข้อกำหนดจำเพาะฐานของ Open Group ฉบับที่ 7 IEEE Std 1003.1, 2013 Edition, §10.1 :

/ dev / TTY

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

สภาพแวดล้อมบางอย่างเช่น Google Colab ได้รับรายงานว่าไม่ควรนำไปใช้/dev/ttyในขณะที่ยังคงมีttyคำสั่งคืนอุปกรณ์ที่ใช้งานได้ นี่คือวิธีแก้ปัญหา:

tty=$(tty)
echo 'ee' | tee $tty | foo

หรือกับบอร์นเชลล์โบราณ:

tty=`tty`
echo 'ee' | tee $tty | foo

5
@static_rtti ทำไมคุณไม่สนใจคำตอบของฉันในแต่ละปี
jlliagre

1
@PaulBissex /dev/ttyเป็นอุปกรณ์ Unix บังคับ คุณกำลังทำงานอยู่ในคุก BSD หรือไม่?
jlliagre

1
@ PaulBissex นั่นเป็นการนำไปปฏิบัติหรือข้อผิดพลาดในการกำหนดค่า ติดตั้ง / dev หรือไม่ สิ่งที่แสดง "ls -l / dev / tty / dev / tty * / dev"? ดูlists.freebsd.org/pipermail/freebsd-bugs/2012-November/... forums.freebsd.org/threads/...
jlliagre

1
และคุณสามารถเรียงซ้อนteeเช่นนี้cat some.log | tee /dev/tty | tee -a other.log | grep -i 'foo' >> foo.logต่อ 1) นำทั้งหมดไปที่คอนโซล 2) นำไปต่อท้ายไฟล์อื่นทั้งหมด 3) นำfooบรรทัดไปยังไฟล์อื่น
Jesse Chisholm

1
Google Colab ไม่มี/dev/ttyแต่ผลลัพธ์ของttyใช้งานได้
Tom Hale

69

อีกสิ่งที่ควรลองคือ:

echo 'ee' | tee >(foo)

>(foo)เป็นเปลี่ยนตัวกระบวนการ


1
ถ้าฉันต้องการไพพ์เอาต์พุตของ foo ไปยังแถบอื่น?
Jack Tang

3
@ JackTang - ฉันคิดว่าการวางท่อเพิ่มเติมในผลลัพธ์fooจะต้องเป็นส่วนหนึ่งของการทดแทนกระบวนการ นี่คือตัวอย่าง:echo 'ee' | tee file.txt >(wc -c | tr -d ' ')
Nick Chammas

1
นี่เป็นวิธีแก้ปัญหาสำหรับฉันใน FreeBSD (ไม่ / dev / tty)
Paul Bissex

9
@ Nick Chammas echo 'ee' | tee >(cat) | foo | barเพื่อรักษาท่อปกติคุณสามารถสลับผลของที:
Vaelus

18

การเข้าถึง "/ dev / stdout" ถูกปฏิเสธในบางระบบ แต่การเข้าถึงเทอร์มินัลผู้ใช้จะได้รับจาก "/ dev / tty" การใช้ "wc" สำหรับ "foo" ตัวอย่างด้านบนใช้งานได้ (บน linux, OSX และอื่น ๆ ) เป็น:

% echo 'Hi' | tee /dev/tty | wc Hi 1 1 3

หากต้องการเพิ่มการนับที่ด้านล่างของรายการไฟล์ที่ตรงกันฉันใช้สิ่งต่อไปนี้:
% ls [A-J]* | tee /dev/tty | wc -l

เพื่อหลีกเลี่ยงการจำทั้งหมดนี้ฉันกำหนดนามแฝง:
% alias t tee /dev/tty
% alias wcl wc -l

เพื่อให้ฉันสามารถพูดได้:
% ls [A-J]* | t | wcl


POSTSCRIPT: สำหรับเด็กที่อายุน้อยกว่าซึ่งอาจพูดปดที่การออกเสียงเป็น "titty" ฉันอาจเพิ่มว่า "tty" เคยเป็นตัวย่อทั่วไปสำหรับเทอร์มินัล "teletype" ซึ่งใช้ม้วนกระดาษสีเหลืองและมีปุ่มกลมที่มักจะ ติด



8

ก่อนอื่นคุณต้องหาเทอร์มินัลที่เกี่ยวข้องกับหน้าจอของคุณ (หรือหน้าจอใดที่คุณต้องการให้เอาท์พุทแสดงผล):

tty

จากนั้นคุณสามารถทีออฟเอาต์พุตไปยังเทอร์มินัลนั้นและไพพ์สำเนาอื่น ๆ ผ่านโปรแกรม foo ของคุณ:

echo ee | tee /dev/pty/2 | foo

1
oneliner: t = $ (tty) echo ee | ที $ t | foo | bar
Jack Tang

5
@ JackTang มันดีกว่าจริง ๆ แต่tก็ไร้ประโยชน์ คุณสามารถใช้echo ee | tee $(tty) | fooแต่ก็ยังมีคำสั่งที่ไร้ประโยชน์ ( tty) เนื่องจากความจริง/dev/ttyก็ใช้งานได้
jlliagre
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.