ทำไมเปลี่ยนเส้นทางผลลัพธ์ไปที่ 2> & 1 และ 1> & 2


36

ฉันเจอคำสั่งหลายอย่างที่ใช้2>&1และ1>&2แต่ฉันก็ไม่สามารถเข้าใจถึงวัตถุประสงค์ของการใช้มันและเมื่อไรที่ฉันควรจะใช้มัน

สิ่งที่ฉันเข้าใจ

ฉันรู้ว่า1เป็นตัวแทนของมาตรฐานและ2แสดงถึงข้อผิดพลาดมาตรฐาน ฉันเข้าใจว่า2>&1รวมเอาท์พุทของ2ไป1และกลับกัน

สิ่งที่ฉันไม่ได้รับ

  1. ฉันควรใช้เมื่อใด
  2. มันมีจุดประสงค์อะไร

คำตอบ:


39

บางครั้งคุณต้องการเปลี่ยนเส้นทางทั้งสอง stdout และ stderr ไปยังตำแหน่งเดียวกันนี่คือเมื่อ>&มีการใช้งาน - มันชี้ไฟล์ descriptor หนึ่งไปยังอีก


ตัวอย่างเช่นหากคุณต้องการเขียนทั้ง stdout และ stderr ไปที่ไฟล์เดียวกัน (ไม่ว่าจะเป็น/dev/nullหรือoutput.txt) คุณสามารถเปลี่ยนเส้นทางแยกจากกันด้วย

app 1>/dev/null 2>/dev/null

หรือคุณสามารถเปลี่ยนไฟล์ descriptor หนึ่งไฟล์ไปยังไฟล์และอีก file descriptor เป็นไฟล์แรก:

app 1>/dev/null 2>&1

app 2>/dev/null 1>&2

ในตัวอย่างแรก2>&1ไฟล์ descriptor # 2 ชี้ไปยังตำแหน่งที่ # 1 ชี้ไปแล้ว ตัวอย่างที่สองประสบความสำเร็จเหมือนกันโดยเริ่มจาก stderr แทน

อีกตัวอย่างหนึ่งมีหลายกรณีที่ stdout (file descriptor # 1) ชี้ไปยังตำแหน่งที่ต้องการแล้ว แต่คุณไม่สามารถอ้างถึงได้ด้วยชื่อ (อาจเกี่ยวข้องกับไปป์ซ็อกเก็ตหรืออื่น ๆ ) สิ่งนี้มักจะเกิดขึ้นเมื่อใช้การขยายกระบวนการ ( ` `หรือ$( )ตัวดำเนินการ) ซึ่งปกติจะจับเฉพาะ stdout แต่คุณอาจต้องการรวม stderr ไว้ในนั้น ในกรณีนี้คุณจะใช้>&เพื่อชี้ stderr ไปที่ stdout:

out=$(app 2>&1)

อีกตัวอย่างที่พบบ่อยคือเพจเจอร์หรือgrepหรือยูทิลิตี้ที่คล้ายกันเนื่องจากไปป์|ทำงานได้เฉพาะบน stdout เท่านั้นคุณจะเปลี่ยนเส้นทาง stderr ไปเป็น stdout ก่อนที่จะใช้ไปป์:

app 2>&1 | grep hello

วิธีที่จะทราบว่าของ2>&1หรือ1>&2ถูกต้อง? ตั้งขึ้นแล้วอธิบายไฟล์ไปทางขวาของ>&และอธิบายไฟล์ที่คุณต้องการที่จะเปลี่ยนเส้นทางไปทางด้านซ้าย ( 2>&1หมายถึง "point file descriptor # 2 to file descriptor # 1")


เชลล์บางตัวมีทางลัดสำหรับการเปลี่ยนเส้นทางทั่วไป นี่คือตัวอย่างจาก Bash:

  • 1> สามารถย่อให้เหลือเพียง >

  • 1>foo 2>&1ถึง>&fooหรือ&>foo

  • 2>&1 | program ไปยัง |& program


ฉันไม่รู้ว่าการทำเช่นapp 1>/dev/null 2>&1นั้นหมายความว่า 2> & 1 จะชี้ไปที่ไฟล์ที่ 1 กำลังเปลี่ยนเส้นทางไปแล้ว ฉันคิดว่าฉันสามารถทำได้อย่างง่ายดายapp > /dev/null &>?
PeanutsMonkey

the already set up fd goes to the right of >&, and the fd you want to redirect goes to the leftฉันกำลังมีความเข้าใจเวลาที่ยากลำบาก คุณหมายถึงอะไรโดย file descriptor ที่ตั้งค่าแล้ว มันหมายถึงอะไรถูกต้องหรือไม่
PeanutsMonkey


ขออภัยถ้าคุณไม่ต้องการสอนฉันฉันไม่ปฏิบัติตามคำแถลงที่คุณทำไว้ก่อนหน้านี้
PeanutsMonkey

1
ใช้ตัวอธิบายไฟล์แต่ละไฟล์ทีละไฟล์จากซ้ายไปขวาและใช้กฎเหล่านั้นตามลำดับ หากคุณเป็นครั้งแรก stdout โดยตรงไปยังแฟ้มแล้ว stderr เปลี่ยนเส้นทางไปยังที่ที่ stdout เราตอนนี้ชี้แล้ว stderr stdout และจะไปไฟล์เดียวกัน หากคุณสลับการเปลี่ยนเส้นทางทั้งสองไปรอบ ๆ คุณจะได้ผลลัพธ์ที่แตกต่างกัน (เปลี่ยนเส้นทาง stderr ไปที่ที่ stdout กำลังดำเนินการอยู่ ) จากนั้นเลื่อน stdout ไปที่ไฟล์อื่น
เจสัน

2

สถานการณ์เดียวเมื่อคุณต้องการคือเมื่อคุณต้องการแสดงผลstraceในเพจเจอร์ straceพิมพ์เอาต์พุตไปที่ข้อผิดพลาดมาตรฐานและไพพ์โดยทั่วไปเชื่อมต่อเอาต์พุตมาตรฐานกับอินพุตมาตรฐานดังนั้นคุณต้องใช้การเปลี่ยนทิศทาง:

strace -p $pid 2>&1 | less

คุณหมายถึงpipes generally connect standard output to standard inputอะไร
PeanutsMonkey

2
ฉันหมายถึงไพพ์ ( |) ใช้เอาต์พุตมาตรฐานของคำสั่งแรกและเชื่อมต่อกับอินพุตมาตรฐานของคำสั่งที่สอง
jpalecek

2

บางครั้งคุณต้องการเปลี่ยนเส้นทางทั้งstdout( 1) และstderr( 2) ไปยังตำแหน่งเดียวกัน ( /dev/nullเช่น) วิธีหนึ่งในการบรรลุเป้าหมายนี้คือ:

$ program 1>/dev/null 2>/dev/null

แต่คนส่วนใหญ่ลดระยะนี้โดยเปลี่ยนเส้นทางstderrไปstdoutด้วย2>&1:

$ program 1>/dev/null 2>&1

รุ่นที่สั้นกว่าคือ:

$ program >&- 2>&-

1

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

1: เมื่อคุณต้องการจัดการกับผลลัพธ์ของข้อผิดพลาดมาตรฐานและมาตรฐานออก


คุณหมายถึงอะไรโดยการจัดการ? ความเข้าใจของฉันคือสิ่งที่เปลี่ยนเส้นทางไปยัง>2ถูกส่งไปยัง / dev / null หรือว่าฉันเข้าใจผิด
PeanutsMonkey

นั่นไม่ถูกต้อง โดยจัดการฉันหมายถึงท่อไป grep หรือสิ่งที่คล้ายกัน ดูที่นี่สำหรับตัวอย่าง
soandos

0

ฉันใช้มันเพื่อเริ่มงานเดี่ยว:

someProgram 2>&1 >& my.log &

จากนั้นฉันสามารถออกจากระบบและบางโปรแกรมจะยังคงทำงานอยู่ ฟังก์ชั่นนี้มีให้ในหน้าจอ GNU, tmux และโปรแกรมอื่น ๆ - แต่ที่นี่สามารถทำได้โดยไม่ต้องพึ่งพาภายนอก


1
ใช้งานได้ตราบใดที่ไม่มี SIGHUP ส่งไปยังโปรแกรม ใช้ดีกว่าnohupหรือdisownในกรณีเช่นนี้
slhck

@slhck: ตกลง แต่ถ้าฉันไม่ส่ง SIGHUP ไปที่รายการ - ไม่มีใครทำใช่ไหม
Adobe

ไม่สถานีควบคุมจะเตือนกระบวนการออกจากระบบด้วย SIGHUP ในทางปฏิบัติหากคุณใช้เปลือกระยะไกลผ่าน SSH และออกกระบวนการของคุณจะตายเช่นกัน
slhck

@slhck: ไม่เป็นความจริง: ฉันใช้มันสองสามปี - ฉันออกจากระบบของ ssh และกระบวนการยังคงทำงานอยู่
Adobe

ฉันจะต้องดูรายละเอียดเพิ่มเติมนี้ แต่เพียงแค่การวางโปรแกรมในพื้นหลังไม่ได้ผลสำหรับฉันในทุกกรณีและแน่นอนไม่สามารถใช้กับเครื่องท้องถิ่นของฉันได้ Zsh และ Bash ทำตัวแตกต่างกันที่นี่เช่นกัน
slhck

0

ลองนึกภาพมีไดเรกทอรีชื่อtryที่มีสามไฟล์เหล่านี้:file file1 and file2.

ตอนนี้รันคำสั่งนี้:

cat file file1 file2 file3

สามไฟล์แรกเปิดขึ้น แต่catมีข้อผิดพลาดเกิดขึ้นขณะเปิดไฟล์ที่สี่เนื่องจากไม่มีอยู่

ตอนนี้ทำงาน:

cat file file1 file2 file3 1>outfile 2>&1

คุณจะไม่เห็นผลใด ๆ บนหน้าจอ: ประการแรก1>outfileจะเปลี่ยนเส้นทางผลลัพธ์ของคำสั่งไปoutfileแล้วมันจะเปลี่ยนเส้นทาง ( 2>&1) ข้อผิดพลาดโยนในขณะที่พยายามที่จะเปิดการfile3outfile

1>&2 ทำงานคล้ายกันและเปลี่ยนเส้นทางสตรีมข้อผิดพลาดไปยังเอาต์พุตมาตรฐาน

หวังว่านี่จะช่วยได้!


0

สถานการณ์จำลองทางเลือก: คำสั่งเทอร์มินัลแสดงเอาต์พุตไปยังเทอร์มินัลอื่น

ใช้ttyคำสั่งในแต่ละเทอร์มินัลเพื่อระบุ:

$ tty
/dev/pts/0

$ tty
/dev/pts/1

สมมติว่า TTY เหล่านี้เพื่อเปลี่ยนเส้นทาง stdout แรกไปเป็นวินาทีให้รันสิ่งนี้ในเทอร์มินัลแรก:

exec 1>/dev/pts/1

หมายเหตุ: ตอนนี้เอาต์พุตคำสั่งทุกรายการจะแสดงบน pts / 1

ในการกู้คืนพฤติกรรมเริ่มต้น stdout ของ pts / 0:

exec 1>/dev/pts/0

ดูวิดีโอนี้สำหรับการสาธิต


0

กรณีเมื่อ re-directing stderr ไปยัง stdout ได้รับการครอบคลุมแล้วที่นี่ (เช่นใช้เพื่อกรองข้อผิดพลาด (grep))

อีกกรณีหนึ่งกำลังเปลี่ยนเส้นทาง stdout ไปยัง stderr usecase ทั่วไป (อย่างน้อยสำหรับฉัน) คือการส่งคำเตือน / ข้อความแสดงข้อผิดพลาดที่พิมพ์ด้วย "echo" (ใน shellscripts ของฉัน) ไปยัง stderr (เพื่อให้พวกเขาสามารถดึงดูดความสนใจของผู้ใช้ได้ง่ายขึ้น)

ตัวอย่างเช่น,

echo "file \"${file\" does not exist..." 1>&2
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.