เหตุใดการแทนที่กระบวนการ BASH จึงไม่ทำงานกับคำสั่งบางอย่าง


29

ในบางโอกาสการทดแทนกระบวนการจะไม่ทำงานตามที่คาดไว้ นี่คือตัวอย่าง:

การป้อนข้อมูล:

gcc <(echo 'int main(){return 0;}')

เอาท์พุท:

/dev/fd/63: file not recognized: Illegal seek
collect2: error: ld returned 1 exit status

การป้อนข้อมูล:

แต่มันทำงานได้อย่างที่คาดไว้เมื่อใช้กับคำสั่งอื่น:

grep main <(echo 'int main(){return 0;}')

เอาท์พุท:

int main(){return 0;}

ฉันได้สังเกตเห็นความล้มเหลวที่คล้ายกันกับคำสั่งอื่น ๆ (เช่นคำสั่งคาดหวังว่าไฟล์จากการทดแทนกระบวนการไม่สามารถใช้/dev/fd/63หรือคล้ายกัน) ความล้มเหลวด้วยgccนี้เป็นเพียงล่าสุด มีกฎทั่วไปบางอย่างที่ฉันควรทราบเพื่อกำหนดว่าเมื่อใดการทดแทนกระบวนการจะล้มเหลวด้วยวิธีนี้และไม่ควรใช้?

ฉันใช้ BASH รุ่นนี้บน Ubuntu 12.04 (ฉันเคยเห็นใน arch และ debian):
GNU bash, รุ่น 4.3.11 (1) - ปล่อย (i686-pc-linux-gnu)


1
illegal seekดูเหมือนว่าคำตอบ - |pipeซึ่งbashชี้ให้เห็นว่าโปรแกรมที่เรียกใช้งานนั้นไม่ใช่ไฟล์ที่ค้นหาได้ อาจจะถ้าคุณไม่สามารถประสบความสำเร็จecho data | command /dev/fd/0ในโปรแกรมแล้วคุณจะมีโชคที่คล้ายกัน w <(cmd)/ มันไม่ได้ให้ไฟล์บนดิสก์ - มันแค่ทดแทนอาร์กิวเมนต์ที่ชี้ไปที่ไฟล์อธิบายท่อ
mikeserv

2
ในกรณีนี้แม้ว่า gcc สามารถรับอินพุตมาตรฐานได้ (โดยค่าเริ่มต้น) จะใช้นามสกุลไฟล์เพื่อกำหนดภาษา ดังนั้นลองgcc -xc <(echo 'int main(){return 0;}')(ซึ่งกำหนดภาษาเป็นCอย่างชัดเจน)
ขับขี่เหล็ก

ฉันถูกนำไปที่นี่เพื่อตอบคำถามของฉันเองซึ่งน่าจะเป็นอีกตัวอย่างหนึ่งของเรื่องนี้ superuser.com/questions/1243405 ขอบคุณสำหรับถ้อยคำคำถามที่ดีกว่าที่ฉันสามารถทำได้
Jonathan Hartley

คำตอบ:


33

ผลลัพธ์การทดแทนกระบวนการในไฟล์พิเศษ (เช่น/dev/fd/63ในตัวอย่างของคุณ) ที่ทำหน้าที่เหมือนปลายอ่านของไพพ์ที่มีชื่อ ไฟล์นี้สามารถเปิดและอ่าน แต่ไม่ได้เขียนไม่ได้แสวงหา

คำสั่งที่จัดการกับอาร์กิวเมนต์ของพวกเขาเป็นสตรีมบริสุทธิ์ทำงานในขณะที่คำสั่งที่คาดว่าจะค้นหาในไฟล์ที่พวกเขาได้รับ (หรือเขียนถึงพวกเขา) จะไม่ทำงาน ชนิดของคำสั่งที่ทำงานจะเป็นสิ่งที่มักจะคิดว่าตัวกรอง: cat, grep, sed, gzip, awkฯลฯ ... ตัวอย่างของคำสั่งที่จะไม่ทำงานเป็นบรรณาธิการเหมือนหรือการดำเนินการไฟล์เช่นvimv

gccต้องการที่จะสามารถเข้าถึงแบบสุ่มในไฟล์อินพุตเพื่อตรวจสอบภาษาที่พวกเขาเขียนถ้าคุณให้gccคำแนะนำเกี่ยวกับภาษาของไฟล์อินพุท

gcc -x c <(echo 'int main(){return 0;}')

รูปแบบที่ตรงไปตรงมาง่ายขึ้นโดยไม่ต้องทดแทนกระบวนการยังทำงานได้:

echo 'int main(){return 0;}' | gcc -x c -

bashหมายเหตุว่านี้ไม่ได้เฉพาะเจาะจงกับ เชลล์ทั้งหมดที่สนับสนุนการทดแทนกระบวนการทำงานในลักษณะเดียวกัน


+1 สำหรับการแก้ปัญหา gcc แต่ฉันไม่แน่ใจเกี่ยวกับประเด็นของคุณเกี่ยวกับไฟล์ <()รูปแบบควรกระทำเช่นไฟล์สำหรับ intents และวัตถุประสงค์ ในความเป็นจริงผมไม่ทราบว่าคำสั่งใด ๆ <()ที่คาดว่าไฟล์ที่จะไม่ได้มีความสุขกับ คนที่ไม่ทำงานคือคนที่คาดหวังชื่อไฟล์ไม่ใช่ไฟล์ ยกตัวอย่างเช่นคาดว่าไฟล์และทำงานได้ดีกับgrep -f <()
terdon

4
@terndon แน่นอน<()สร้างชื่อไฟล์(โครงสร้างขยายไปยัง/proc/self/fd/somethingระบบของฉัน) ชื่อนี้เมื่อเปิดทำหน้าที่เหมือนปลายอ่านไปป์ที่มีชื่อ ( S_IFIFO) มากกว่าแฟ้มปกติ ( S_IFREG) ในการที่เป็นสนับสนุนread()และคนอื่น ๆ seek()แต่ไม่
Celada

7
โปรดทราบว่าการzshสนับสนุนรูปแบบที่ 3 ของกระบวนการทดแทนที่ใช้ไฟล์ชั่วคราวโดยเฉพาะอย่างยิ่งสำหรับวัตถุประสงค์ที่:gcc =(echo 'int main(){return 0;}')
Stéphane Chazelas

อาจจะเกี่ยวข้องแต่ทำงานร่วมกับแต่ไม่ได้มี<(echo '...') <(git show ...)ความคิดใดที่เป็นไปได้
Jörn Hees

2
GCC ไม่ "ทำการเข้าถึงแบบสุ่มในไฟล์อินพุตเพื่อตรวจจับภาษาที่ใช้เขียน" มันแค่ดูที่นามสกุลไฟล์ หากชื่อไฟล์ไม่มีส่วนขยาย (หรือมีนามสกุลที่ไม่รู้จัก) GCC ถือว่าไฟล์นั้นเป็นไฟล์วัตถุหรือสคริปต์ตัวเชื่อมโยงและส่งต่อไปยังld(ซึ่งตรวจจับรูปแบบวัตถุ) -xไม่ใช่คำใบ้; มันคือการประกาศ หากคุณระบุ-x f95GCC จะส่งไฟล์ไปยังคอมไพเลอร์ Fortran-95 โดยไม่คำนึงถึงชื่อหรือเนื้อหา ดูgcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Overall-Options.html
RICI
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.