อินพุตมาตรฐานของโปรแกรมหนึ่งสามารถส่งผ่านเป็นอาร์กิวเมนต์ไปยังโปรแกรมอื่นได้อย่างไร


17

สมมติว่ามีโปรแกรมอยู่ซึ่งใช้เวลาสองข้อโต้แย้ง ไฟล์อินพุตและไฟล์เอาต์พุต

จะเกิดอะไรขึ้นถ้าฉันไม่ต้องการบันทึกไฟล์เอาต์พุตนี้ลงในดิสก์ แต่จะผ่านมันไปยังstdinโปรแกรมอื่นโดยตรง มีวิธีที่จะบรรลุเป้าหมายนี้หรือไม่?

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

ตัวอย่างของการใช้ภาพนี้คือ:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" stdin(echo)

เชลล์ที่ฉันใช้อยู่นั้นมันทุบตี


1
cat <file | cmd /dev/fd/0ทำงานได้ดีที่สุด
mikeserv

ไม่ทำงานสำหรับฉัน พยายามด้วย: cat < README.txt | cp /dev/fd/0. มันบอกว่าcp: missing destination file operand after ‘/dev/fd/0’ Try 'cp --help' for more information.
Dziugas

1
program input-file /dev/stdout | another-program? ยังทราบว่าechoอ่านอะไรจาก stdin
yegegashi

1
@Dziugas - ไม่แน่นอน - คุณไม่สามารถcpไฟล์ได้ที่ไหนเลย จะพิมพ์echo 1 2 3| cp /dev/fd/0 /dev/tty 1 2 3และโดยวิธีการ/dev/fd/[num]มีแนวโน้มที่จะทำงานมากกว่า/dev/std(in|out|err)ในกรณีส่วนใหญ่ ดูความสามารถในการพกพาของลิงค์ตัวอธิบายไฟล์เกี่ยวกับสิ่งที่คุณคาดหวังในการทำงาน
mikeserv

1
โปรแกรม UNIX ที่ดีจะเขียนไปยังเอาต์พุตมาตรฐานโดยปล่อยให้ผู้ใช้ตัดสินใจว่าต้องการเปลี่ยนเส้นทางไปยังไฟล์หรือไพพ์ไปยังคำสั่งอื่นหรือไม่
Jorge Bucaran

คำตอบ:


13

หากโปรแกรมรองรับการเขียนไปยังไฟล์ descriptor ใด ๆ แม้ว่าจะไม่สามารถหาได้คุณสามารถใช้/dev/stdoutเป็นไฟล์เอาต์พุต นี่คือ symlink /proc/self/fd/1ในระบบของฉัน ตัวอธิบายไฟล์ 1 คือ stdout


สิ่งนี้แก้ไขข้อสงสัยของฉัน ดังนั้นจึงไม่มีวิธีที่จะทำเมื่อโปรแกรมต้องการค้นหา?
Dziugas

3
หากคุณพยายามป้องกันการเข้าถึงดิสก์คุณสามารถเขียนไฟล์ใน / dev / shm / อย่างไรก็ตามหากคุณไม่ต้องการไฟล์ใด ๆ ในระบบไฟล์เท่าที่ฉันรู้ไม่มีวิธีที่จะค้นหา ท่อ การค้นหาไปข้างหน้าหมายความว่าจะต้องบัฟเฟอร์ทุกอย่างในหน่วยความจำจนกว่าจะถึงจุดนั้นไปข้างหน้าและการค้นหาย้อนหลังหมายถึงการบัฟเฟอร์ทุกอย่างในหน่วยความจำ
TiCPU

pdftotextเช่นสาธารณูปโภคอื่น ๆ จำนวนมาก (แต่ไม่ใช่ทั้งหมด) ก็รองรับ-เช่นกัน (ซึ่งจะทำงานได้แม้ในระบบที่ไม่รองรับ / dev / stdout หรือที่ / dev / stdout ไม่ทำงานตามที่คาดไว้เช่นบน Linux ที่ stdout ไม่ ท่อ) pdftotext file.pdf - | wc -c
Stéphane Chazelas

11

จากpdftotextหน้าคน:

หากไฟล์ข้อความเป็น´- 'ข้อความจะถูกส่งไปยัง stdout

ดังนั้นในกรณีนี้ทั้งหมดที่คุณต้องการคือ:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" -

หรือถ้าคุณต้องการไพพ์นี้ไปยัง STDIN ของโปรแกรมอื่น:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" - | another_prog

การใช้-แทนชื่อไฟล์เป็นข้อตกลงหลาย ๆ ยูทิลิตี้ที่ตามมา (รวมถึง pdftotext) เมื่อเราต้องการอินพุตจาก STDIN หรือเอาต์พุตไปยัง STDOUT อย่างไรก็ตามยูทิลิตี้บางอย่างไม่ปฏิบัติตามอนุสัญญานี้ ในกรณีนั้นวิธีที่ใช้สำนวนนี้ในการทุบตีคือการใช้การทดแทนกระบวนการ :

my_utility "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" >( cat )

ที่นี่>( )พฤติกรรมส่วนใหญ่เหมือนไฟล์ที่ส่งผ่านไปmy_utilityแต่แทนที่จะเป็นไฟล์จริงสตรีมจะถูกไพพ์เข้าสู่ stdin ของกระบวนการที่มีอยู่นั่นคือ cat ดังนั้นที่นี่ข้อความในที่สุดควรส่งออกตามที่ต้องการ

การใช้ระฆังปลุก UUOCcatเกือบทุกครั้งในฟอรัมเช่นนี้ ผมยืนยันว่าถ้ายูทิลิตี้ไม่สนับสนุน-แล้วนี้คือการใช้ประโยชน์ของcatแต่ถ้ามีวิธีการใดที่จะทำเปลี่ยนตัวกระบวนการนี้โดยไม่ได้catแล้วฉันหูของทุกคน ;-)

อย่างไรก็ตามหาก (ตามคำถาม) ปลายทางสุดท้ายของสตรีมคือ STDIN ของโปรแกรมอื่นดังนั้นcatสามารถยกเลิกได้:

my_utility "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" >( another_prog )

2
และขอให้ฉัน backpedal อีกครั้ง: ถ้าprog2เขียนไปยัง stdout ดีกว่าเพราะรูปแบบรอให้เสร็จสมบูรณ์ (เช่นก่อนที่เชลล์จะออกพรอมต์ถัดไปหรือไปที่คำสั่งถัดไป (เช่นหลังจากหรือ)) ในขณะที่- ไม่มีแบบฟอร์มรอให้กรอกให้สมบูรณ์เท่านั้น นอกจากนี้หลังจากที่รูปแบบเป็นสถานะออกจากขณะที่ในที่อื่น ๆคือสถานะออกจาก (คุณจ่ายเงินของคุณและคุณเลือกได้)prog1 input_file >( cat ) | prog2prog1 input_file >( prog2 )catprog2;&&catprog1cat$?prog2$?prog1
สกอตต์

4

หากสนับสนุนเปลือกของคุณพวกเขาวิธีที่ง่ายที่สุดในการทำกิจวัตรเช่นจะใช้ทดแทนกระบวนการ : และ<(…) >(…)สิ่งนี้ใช้ได้ใน bash, zsh และ ksh และหอยอื่น ๆ ตัวอย่างเช่น:

$ sort <(printf "b\nc\na\n")
a
b
c
$ ls
foo
$ cp <(find . -name foo) bar
$ ls
bar  foo

อย่างไรก็ตามสิ่งนี้จะไม่ช่วยในตัวอย่างที่คุณระบุเนื่องจากpdftotextจะบันทึกในไฟล์ข้อความ ในขณะที่ตัวเลือกที่ดีที่สุดของคุณ (นอกเหนือจากการใช้งานที่ชัดเจน-) คือการใช้/dev/stdoutตามที่แนะนำโดย @TiCPU คุณสามารถใช้คุณลักษณะเชลล์อื่นได้ โครงสร้าง!:Nหมายถึงอาร์กิวเมนต์ Nth ของคำสั่งก่อนหน้า ดังนั้นคุณสามารถทำได้:

$ pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf"  out.txt
$ cat !:2

1
ในขณะที่ฉันตกลงว่าcat <()จะมีประโยชน์ในบางสถานการณ์ในสถานการณ์นี้ แต่มันไม่ทำงานเลย ปัญหาที่เกิดขึ้น (อธิบายได้ไม่ดีมากโดย OP ผมต้องยอมรับ) คือว่าpdftotextเวลาสองขัดแย้ง: แฟ้มใส่และไฟล์ที่ส่งออก ถ้าอาร์กิวเมนต์ที่สองหายไปมันจะไม่สร้างอะไรcat <(pdftotext "file.pdf")เลย หนึ่งสามารถโกงpdftotextคำสั่งโดยให้>(cat)เป็นอาร์กิวเมนต์ที่สองเช่น Digital Trauma ตอบ แต่cat <()ไม่มีจุดหมายที่นี่ เห็นได้ชัดว่าในpdftotextกรณีที่ดีที่สุดคือใช้-เป็นชื่อไฟล์เอาต์พุต
jimmij

1
@Scott ฉันจะตอบ UUOC อย่างไร คุณจะทำกระบวนการทดแทนโดยไม่ใช้แมวได้อย่างไร >( )จะส่งกระแสข้อมูลไปยังกระบวนการใดก็ตามที่อยู่ภายในอย่างมีประสิทธิภาพดังนั้นเราจึงจำเป็นต้องมีcatที่นี่เพื่อส่งออกกระแสข้อมูลนั้น โดยปกติเราควรจะทำสิ่งที่ชอบpdftotext input.pdf -แต่เห็นได้ชัดว่าpdftotextไม่สนับสนุน-พารามิเตอร์เพื่อส่งออกโดยตรงไปยัง stdout แทนที่จะเป็นไฟล์ - ลองใช้
Digital Trauma

1
@ DigitalTrauma ไม่ใช่ uuoc ฉันเชื่อว่า cat เป็นวิธีที่เร็วที่สุดที่คุณจะได้รับในกรณีของการพิมพ์ แต่ในความเป็นจริงคุณสามารถใช้คำสั่งอื่น>(grep something)เพื่อให้มีประโยชน์มากขึ้น BTW ฉันpdftotext 3.04 ทำสนับสนุน-เป็นไฟล์ที่ส่งออกดังนั้นฉันเล็ก ๆ น้อย ๆ ประหลาดใจโดยการสนทนาทั้งหมด
jimmij

1
@terdon ฉันเกลียดที่จะเป็นคนขี้เหนียว แต่ดูเหมือนจะไม่ทำงาน โดยเฉพาะมันไม่แตกต่างกันที่ทำงานpdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf"ซึ่งทำให้เอาท์พุทในไฟล์ที่เรียกว่าC BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.txtแต่ไม่มีข้อความใดที่จะถูกส่งออกไปยัง STDOUT สำหรับการไพพ์ไปยังโปรแกรมอื่น
Digital Trauma

1
@ DigitalTrauma ที่ไม่ได้เป็น stickler! ฉันเป็นคนงี่เง่า ขอบคุณสำหรับการชี้ให้เห็นและโปรดอย่าขอโทษเมื่อชี้ให้เห็นข้อผิดพลาด ฉันจะค่อนข้างผิดพลาดชี้ให้ฉันและเรียนรู้อะไรมากกว่าปล่อยให้มันมีเกียรติทั้งหมดที่น่าสงสัย
terdon

-2
cmd tty

ttystdoutส่งกลับชื่อของอาคารที่เชื่อมต่อกับ


ฉันไม่แน่ใจว่าวิธีนี้ตอบคำถามซึ่งเกี่ยวกับการรวมคำสั่ง; บางทีคุณอาจขยายตัวอย่างของวิธีที่คุณจะประสบความสำเร็จ
dhag

ผมคิดว่าคุณจะบอกว่าจะตรวจสอบกับชื่อของสถานีและจากนั้นใช้ไฟล์ที่เป็นเอาท์พุทเช่นtty pdftotext file.pdf /dev/pts/2ในกรณีนี้ฉันเห็นด้วย
jimmij

ที่สามารถตัวย่อ / อัตโนมัติเพื่อ; ซึ่งโดยทั่วไปจะเป็นเทียบเท่ากับ แต่วิธีการนี้อนุมานว่าเป้าหมายคือการแสดงผลของ(เช่นใน terminal) และที่ไม่ได้เป็นสิ่งที่เป็นคำถามที่ถาม (ดูการแสดงความคิดเห็นเกี่ยวกับคำตอบของ terdonชี้แจงบางอย่างเกี่ยวกับความหมายของคำถาม) prog1  input_file $(tty)prog1  input_file /dev/ttyprog1
สกอตต์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.