ทำไม `sort <(ls -l)` ทำงาน แต่ `sort <(ls -l)` ล้มเหลว?


32

วันนี้ผมกำลังเรียนรู้อะไรบางอย่างเกี่ยวกับ FIFO บทความนี้: รู้เบื้องต้นเกี่ยวกับไปป์cat <(ls -l)ซึ่งกล่าวถึง

ฉันทำการทดลองโดยใช้sort < (ls -l)ซึ่งข้อผิดพลาดปรากฏขึ้น:

-bash: syntax error near unexpected token `('`

จากนั้นฉันก็พบว่าฉันมีช่องว่างเพิ่มเติมในคำสั่งผิด

แต่ทำไมคำสั่งพิเศษนี้จะนำไปสู่ความล้มเหลวนี้ ทำไมสัญลักษณ์การเปลี่ยนเส้นทางจะต้องใกล้เคียงกับ(?


ควรสังเกตว่า * nix shells แยกสิ่งต่าง ๆ ตามช่องว่างซึ่งสร้างโทเค็นที่ Alec กล่าวถึง
ลูกไก่

คำตอบ:


45

เพราะนั่นไม่ใช่<มันมัน<()ต่างกันโดยสิ้นเชิง สิ่งนี้เรียกว่าการทดแทนโปรเซสมันเป็นคุณสมบัติของเชลล์บางตัวที่อนุญาตให้คุณใช้เอาต์พุตของกระบวนการหนึ่งเป็นอินพุตสำหรับอีกกระบวนการหนึ่ง

>และ<ผู้ประกอบการเปลี่ยนเส้นทางการส่งออกและการป้อนข้อมูลจากไฟล์ <()ข้อเสนอที่ผู้ประกอบการที่มีคำสั่ง (กระบวนการ) ไม่ใช่ไฟล์ เมื่อคุณวิ่ง

sort < (ls)

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


3
คำตอบของคุณดี แต่then sort is attempting to read the subshell as its input file→นี้ผิดเพราะ Bash จะไม่แยกวิเคราะห์ไวยากรณ์ ไม่จริงlsหรือไม่sortทำงาน
sleblanc

1
@ sebleblanc fair point ขอย้ำคำตอบขอบคุณ
terdon

1
ไม่มีเชลล์ย่อยในกรณีนี้ < (ls)โทเค็นไม่ถูกต้องที่นี่
cuonglm

@cuonglm ไม่เพราะ bash ถือเป็นข้อผิดพลาดทางไวยากรณ์ ประเด็นของฉันคือว่า(ls)จะทำงานlsใน subshell
terdon

22

เพราะนั่นคือสิ่งที่มันควรจะเป็น

<(...)in bashคือไวยากรณ์สำหรับการทดแทนกระบวนการ kshก็คัดลอกมาจากผู้ประกอบการเหมือนกันใน

<, (, ), |, &, ;กำลังราชสกุลศัพท์พิเศษในการbashที่จะใช้ในการประกอบการในรูปแบบพิเศษในชุดที่แตกต่างกัน <, <(, <<, <&... แต่ละคนมีบทบาทของพวกเขา <สำหรับการเปลี่ยนเส้นทาง <file, < fileจะเปลี่ยนเส้นทางการป้อนข้อมูลจากแฟ้ม <'(file)'จะเปลี่ยนเส้นทางอินพุตจากไฟล์ที่เรียกว่า(file)แต่<(file)เป็นโอเปอเรเตอร์อื่นที่ไม่ใช่โอเปอเรเตอร์การเปลี่ยนเส้นทาง

< (file)จะตามมาด้วย< (file)ในบริบทว่าในbash, (file)ไม่ถูกต้อง (...)สามารถใช้ได้เป็นโทเค็นเดียวในบางบริบทเช่น:

(sub shell)
func () {
  ...
}
var=(foo bar)

แต่ไม่ใช่ค่ะ

sort < (cmd)

ในfishเปลือกมันแตกต่างกัน ในfish, (...)สำหรับแทนคำสั่ง (เทียบเท่า$(...)ในbash) และ<สำหรับการเปลี่ยนเส้นทางอินพุตเช่นในเชลล์คล้ายบอร์น

ดังนั้นในfish:

sort <(echo file)

จะเหมือนกับ:

sort < (echo file)

นั่นคือ:

sort < file

แต่นั่นเป็นสิ่งที่แตกต่างจากbashการทดแทนกระบวนการอย่างสิ้นเชิง

ในyashเชลล์ POSIX เชลล์อื่น<(...)ไม่ได้ใช้สำหรับการทดแทนกระบวนการแต่สำหรับการเปลี่ยนเส้นทางกระบวนการ

ในนั้น,

sort <(ls -l)

ย่อจาก:

sort 0<(ls -l)

เป็นผู้ดำเนินการเปลี่ยนเส้นทาง มันมากหรือน้อยเทียบเท่ากับ:

ls -l | sort

ขณะที่อยู่ในbashนั้น<(ls -l)จะถูกขยายไปยังเส้นทางของไปป์ดังนั้นมันจึงเป็นดังนี้:

ls -l | sort /dev/fd/0

ในzshนั้น(...)มีการใช้งานมากเกินไปในฐานะผู้ดำเนินการ globbing ( (*.txt|*.png)จะขยายไปยังtxtและpngไฟล์) และเป็นตัวระบุ glob ( *(/)ตัวอย่างเช่นขยายไปยังไฟล์ไดเรกทอรี)

ในzshใน:

sort < (ls -l)

ที่(ls -l)จะถือว่าเป็นรอบคัดเลือก ตัวระบุแบบlกลมคือจับคู่กับจำนวนลิงก์และคาดว่าจะมีตัวเลขหลังจากนั้นl(ตามที่ls -ld ./*(l2)จะแสดงรายการไฟล์ที่มี 2 ลิงก์) ดังนั้นนั่นคือสาเหตุที่คุณได้รับzsh: number expectedข้อผิดพลาดที่นั่น

sort < (w)จะได้รับzsh: no matches found: (w)ข้อผิดพลาดแทน(w)ตรงกับไฟล์ที่มีชื่อว่างที่สามารถเขียนได้

sort < (w|cat)จะมีการเรียงลำดับเนื้อหาของwและ / หรือcatไฟล์ในไดเรกทอรีปัจจุบัน ...


ทำไมจึงsort < $(ls -l)ทำให้เกิดข้อผิดพลาดนี้:bash: $(ls -l): ambiguous redirect
Edward Torvalds

@edwardtorvalds เพราะ$(ls -l)ขยายไปมากกว่าหนึ่งคำ ใช้เครื่องหมายคำพูดเพื่อป้องกันการแบ่ง + glob ( sort < "$(echo file)") โปรดทราบว่าพฤติกรรมหรือbashแตกต่างจาก POSIX sh ใน bash นั้นจะแยก + glob ที่นั่นเช่นกันเมื่อไม่มีการโต้ตอบ (ไม่ใช่เมื่อเรียกว่าsh)
Stéphane Chazelas

โดยดูที่ls -l | sort /dev/fd/0ฉันสามารถพูดได้ว่าเอาท์พุทของls -lถูกเก็บไว้ใน/dev/fd/0และsortคำสั่งอ่านมันเพื่อให้ผลลัพธ์ที่ต้องการ ฉันใช้tail -f --retry /dev/fd/0เพื่อตรวจสอบไฟล์นั้น แต่ฉันไม่ได้รับผลลัพธ์ใด ๆ ทำไม? ฉันจะอ่านไฟล์นั้นได้อย่างไร
Edward Torvalds

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