ลำดับความสำคัญของการเปลี่ยนเส้นทาง stdin และ stdout ใน Bash


9

คำถามของฉันเกี่ยวกับการเปลี่ยนเส้นทางที่สำคัญคือทุบตี สมมติว่าคุณมีคำสั่ง:

cmd1 < cmd2 > cmd3

มันจะแปลเป็น:

(cmd1 < cmd2) > cmd3

หรือ

cmd1 < (cmd2 > cmd3)

คำตอบ:


11

ระบุมาตรฐาน POSIXว่าการเปลี่ยนเส้นทางเปลือกจากซ้ายไปขวา; นั่นคือคำสั่งสำคัญ:

การสร้าง2>&1มักใช้เพื่อเปลี่ยนเส้นทางข้อผิดพลาดมาตรฐานไปยังไฟล์เดียวกับเอาต์พุตมาตรฐาน ตั้งแต่การเปลี่ยนเส้นทางเกิดขึ้นตั้งแต่ต้นจนจบลำดับของการเปลี่ยนเส้นทางมีความสำคัญ ตัวอย่างเช่น:

ls > foo 2>&1

fooนำทั้งสองส่งออกมาตรฐานและข้อผิดพลาดมาตรฐานไปยังแฟ้ม อย่างไรก็ตาม:

ls 2>&1 > foo

เพียงนำออกมาตรฐานไปยังแฟ้มเนื่องจากข้อผิดพลาดมาตรฐานได้รับการคัดลอกเป็นมาตรฐานการส่งออกก่อนที่จะออกมาตรฐานได้รับคำสั่งให้ไฟล์foofoo

bash ดำเนินการตามส่วนนี้ของมาตรฐาน:

$ ls doesnotexist > foo 2>&1
$ cat foo
ls: cannot access doesnotexist: No such file or directory
$ ls doesnotexist 2>&1 > foo
ls: cannot access doesnotexist: No such file or directory
$ cat foo
$ 

สำหรับท่อ:

เนื่องจากการกำหนดไปป์ไลน์ของอินพุตมาตรฐานหรือเอาต์พุตมาตรฐานหรือทั้งสองเกิดขึ้นก่อนการเปลี่ยนเส้นทางจึงสามารถแก้ไขได้โดยการเปลี่ยนเส้นทาง ตัวอย่างเช่น:

$ command1 2>&1 | command2

ส่งทั้งส่งออกมาตรฐานและข้อผิดพลาดมาตรฐานของการเข้ามาตรฐานของcommand1command2


นั่นถือว่าเป็น Bash shell ซึ่งเป็น POSIX-Complient
fpmurphy

1
ฉันไม่ได้รับมัน เนื่องจากคุณกล่าวว่าคำสั่งซื้อจากซ้ายไปขวาไม่ควรls > foo 2>&1หมายถึงเปลี่ยนเส้นทาง stdout เป็น foo จากนั้นเปลี่ยนเส้นทาง stderr ไปยัง stdout ดังนั้นสิ่งนี้จึงไม่ได้ผล คำสั่งที่สองในทำนองเดียวกันควรทำงาน ฉันหายไปนี่อะไร
Deepak Mittal

1
@fpmurphy bashเป็นไปตาม POSIX โดยทั่วไปยกเว้นในสถานการณ์ที่ระบุไว้ที่นี่ซึ่งbashพฤติกรรมเริ่มต้นแตกต่างกัน เพื่อให้bashสอดคล้องมากขึ้นคุณสามารถใช้--posixตัวเลือก
Matt Eckert

@dpacmittal ตัวอย่างแรกls > foo 2>&1ดำเนินการเช่นนี้: ครั้งแรกออกมาตรฐานถูกเปลี่ยนเส้นทางไปแล้วข้อผิดพลาดมาตรฐานถูกเปลี่ยนเส้นทางไปออกมาตรฐานซึ่งขณะนี้ไฟล์foo fooตัวอย่างที่สองls 2>&1 > foo, ดำเนินการดังนี้: ข้อผิดพลาดมาตรฐานถูกเปลี่ยนเส้นทางไปยังเอาต์พุตมาตรฐานก่อนที่จะเปลี่ยนเส้นทางเอาต์พุตfooมาตรฐานดังนั้นข้อผิดพลาดมาตรฐานจะถูกสะท้อนแบบโลคัลแทนที่จะถูกชี้นำไปยังไฟล์
Matt Eckert

4
@dpacmittal .. ls 2>&1 >foo บางทีคุณอาจคิดแบบนี้ stderr จาก 'ls' ถูกเปลี่ยนเส้นทางไปยัง stdout สิ่งนี้จะเกิดขึ้น! มันจะไปที่ stdout ที่ได้รับมอบหมายในปัจจุบันไปโดยไม่คำนึงถึงคำสั่งเพิ่มเติมใด ๆ ที่เกี่ยวข้องกับ stdout .. (เพราะนี่เป็นคำสั่งนายก / แรก ) .. จากนั้นก็มาอีกคำสั่งที่บอกว่า stdout จะไป "foo", และมันจะ ... จำไว้ว่า: stderr ไม่ได้แปลงไปสู่การเป็น stdout จริง ๆ .. มันแค่ไปที่ที่ stdout ได้รับมอบหมายในเวลาที่มีคำสั่ง (เช่นอาคารผู้โดยสาร)
Peter.O

4

ฉันเดาไม่ เครื่องหมายวงเล็บคู่หมายถึง sub-shell แต่ในกรณีนี้จะไม่มีการเริ่มเชลล์ย่อยเนื่องจากการเปลี่ยนเส้นทาง ทุบตีเพียงฟีดcmd2เข้า stdin stdout cmd3และฟีดเข้าไป

ฉันคิดว่าคุณหมายถึงอะไรเช่นcmd1 | cmd2 | cmd3? เพราะไฟล์ของคุณcmd2และcmd3ปกติแล้วจะเป็น "cmds" แทน

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