แตกต่างเอาต์พุตจากสองโปรแกรมโดยไม่มีไฟล์ชั่วคราว


145

ว่าฉันมีมากเกินไปโปรแกรมaและbที่ฉันสามารถทำงานด้วยและ./a./b

เป็นไปได้หรือไม่ที่จะกระจายเอาท์พุทโดยไม่ต้องเขียนลงไฟล์ชั่วคราวก่อน?


คำตอบ:


211

ใช้<(command)เพื่อส่งเอาต์พุตของคำสั่งหนึ่งไปยังโปรแกรมอื่นราวกับว่าเป็นชื่อไฟล์ Bash ไพพ์เอาต์พุตของโปรแกรมไปยังไพพ์และส่งชื่อไฟล์/dev/fd/63ไปยังคำสั่ง outer

diff <(./a) <(./b)

ในทำนองเดียวกันคุณสามารถใช้>(command)ถ้าคุณต้องการสิ่งที่เป็นท่อในคำสั่ง

สิ่งนี้เรียกว่า "การทดแทนกระบวนการ" ในหน้า man ของ Bash


1
ข้อเสียเปรียบอย่างหนึ่งที่ต้องระวังคือหาก. / a หรือ. / b ล้มเหลวผู้เรียกจะไม่พบสิ่งนั้น
Alexander Pogrebnyak

5
OP ทำแท็กทุบตีคำถาม แต่สำหรับเร็กคอร์ดสิ่งนี้จะไม่ทำงานในเชลล์อื่น ๆ มันเป็นส่วนขยายทุบตีมาตรฐานยูทิลิตี้ Posix
DigitalRoss

5
ฉันพยายามแก้ปัญหานี้ด้วยโปรแกรม Java -bash: syntax error near unexpected token ('และมีข้อผิดพลาดนี้: -bash: java: No such file or directoryฉันพยายามอีกครั้งโดยไม่มีวงเล็บและได้ มันไม่ทำงานหากคำสั่งมีพารามิเตอร์หรือไม่
สไตล์

1
@DigitalRoss - โซลูชันสามารถขยายไปยังเชลล์อื่นโดยใช้นามแฝง ใน tcsh alias diffcmd bash -c \'diff \<\(sh -c \!:1\) \<\( sh -c \!:2 \)\'ที่อัปลักษณ์ต่อไปนี้การทำงาน: (ตัวอย่างเช่น: diffcmd "ls" "ls -a")
พอลลินช์

สำหรับผู้ที่หลงทางใน Google สิ่งนี้สามารถใช้งานได้ภายใต้ zsh (นอกจากนี้หากคุณต้องการป้อนข้อมูลให้กับสิ่งที่เรียกใช้fseekข้อเสนอ zsh =(./a)ซึ่งสามารถใช้เหมือนกัน<(./a)แต่ใช้ไฟล์ชั่วคราวภายใต้ประทุนซึ่ง zsh จะลบให้คุณ)
ssokolow

26

เพิ่มทั้งคำตอบถ้าคุณต้องการดูการเปรียบเทียบแบบเคียงข้างvimdiffกันใช้:

vimdiff <(./a) <(./b)

บางสิ่งเช่นนี้

ป้อนคำอธิบายรูปภาพที่นี่


vimdiffสร้างมุมมองการเปรียบเทียบความแตกต่างที่สวยงามสมาร์ทและการโต้ตอบ ดูเหมือนว่าจะมาพร้อมกับvimแพ็คเกจในระบบส่วนใหญ่
Tim Visée

vimdiffยังแสดงให้เห็นไม่เพียง แต่บรรทัดที่แตกต่าง แต่ยังรวมถึงส่วนข้อความเฉพาะที่แตกต่างกัน
Anton Tarasenko

20

ทางเลือกหนึ่งคือใช้ไปป์ที่มีชื่อ (FIFO) :

mkfifo a_fifo b_fifo
./a > a_fifo &
./b > b_fifo &
diff a_fifo b_fifo

... แต่วิธีแก้ปัญหาของ John Kugelmanนั้นสะอาดกว่ามาก


คุณควรที่จะลบชื่อ pipes rm a_fifo b_fifoหลังจากที่ใช้พวกเขาด้วย
แฟรงคลินหยู

15

สำหรับทุกคนที่สงสัยนี่คือวิธีที่คุณทำการทดแทนกระบวนการในการใช้Fish shell :

ทุบตี:

diff <(./a) <(./b)

ปลา:

diff (./a | psub) (./b | psub)

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


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

7

เพิ่มอีกเล็กน้อยเพื่อคำตอบที่ดีอยู่แล้ว (ช่วยฉัน!):

คำสั่งdockerแสดงผลช่วยเหลือSTD_ERR(เช่น file descriptor 2)

ฉันต้องการดูว่าdocker attachและdocker attach --helpให้ผลลัพธ์เดียวกัน

$ docker attach

$ docker attach --help

ฉันเพิ่งพิมพ์คำสั่งทั้งสองไปฉันก็ทำสิ่งต่อไปนี้:

$ diff <(!-2 2>&1) <(!! 2>&1)

!! เหมือนกับ! -1 ซึ่งหมายถึงเรียกใช้คำสั่ง 1 ก่อนหน้าคำสั่งนี้ - คำสั่งสุดท้าย

! -2 หมายถึงเรียกใช้คำสั่งสองก่อนหน้านี้

2> & 1 หมายถึงส่ง file_descriptor 2 เอาต์พุต (STD_ERR) ไปยังตำแหน่งเดียวกับ file_descriptor 1 เอาต์พุต (STD_OUT)

หวังว่านี้มีประโยชน์


0

สำหรับ zsh การใช้=(command)จะสร้างไฟล์ชั่วคราวโดยอัตโนมัติและแทนที่=(command)ด้วยพา ธ ของไฟล์เอง ด้วยการทดแทนกระบวนการปกติ$(command)จะถูกแทนที่ด้วยเอาต์พุตของคำสั่ง

คุณสมบัติ zsh นี้มีประโยชน์มากและสามารถใช้เพื่อเปรียบเทียบผลลัพธ์ของสองคำสั่งโดยใช้เครื่องมือ diff เช่น Beyond Compare:

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)

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

อ่านเพิ่มเติมได้ที่นี่: http://zsh.sourceforge.net/Intro/intro_7.html

โปรดสังเกตสิ่งนี้ด้วย:

โปรดทราบว่าเชลล์สร้างไฟล์ชั่วคราวและลบออกเมื่อคำสั่งเสร็จสิ้น

และต่อไปนี้ซึ่งเป็นความแตกต่างระหว่าง$(...)และ=(...):

หากคุณอ่าน man page ของ zsh คุณอาจสังเกตเห็นว่า <(... ) เป็นอีกรูปแบบหนึ่งของการทดแทนกระบวนการซึ่งคล้ายกับ = (... ) มีความแตกต่างที่สำคัญระหว่างทั้งสอง ในกรณี <(... ), เชลล์สร้างไปป์ที่มีชื่อ (FIFO) แทนไฟล์ สิ่งนี้ดีกว่าเนื่องจากไม่ได้เติมระบบไฟล์ให้เต็ม แต่มันไม่ทำงานในทุกกรณี อันที่จริงแล้วถ้าเราแทนที่ = (... ) ด้วย <(... ) ในตัวอย่างด้านบนพวกเขาทั้งหมดจะหยุดทำงานยกเว้น fgrep -f <(... ) คุณไม่สามารถแก้ไขไปป์หรือเปิดเป็นโฟลเดอร์เมลได้ อย่างไรก็ตาม fgrep ไม่มีปัญหาในการอ่านรายการคำจากไปป์ คุณอาจสงสัยว่าเหตุใดแถบ diff <(foo) จึงไม่ทำงานเนื่องจาก foo | งานต่างบาร์ นี่เป็นเพราะ diff สร้างไฟล์ชั่วคราวหากสังเกตว่าข้อโต้แย้งข้อใดข้อหนึ่งของมันคือ - จากนั้นก็คัดลอกอินพุตมาตรฐานไปยังไฟล์ชั่วคราว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.