ความแตกต่างระหว่าง &> และ 2> & 1 คืออะไร


30

มีสองรูปแบบของการเปลี่ยนเส้นทางที่มีการส่งออกมาตรฐานและข้อผิดพลาดมาตรฐานเข้าออกมาตรฐาน แต่อันไหนดีกว่ากัน? และทำไมจึง&>ถือว่าสมบูรณ์แบบ

ฉันไม่สามารถค้นหาความแตกต่างเพื่อให้บทเรียนมากมายและแม้กระทั่งทุบตีรัฐคู่มือที่ &>ดีกว่า!

ดังนั้นทำไมฉันจะต้องใช้&>และไม่2>&1

ส่วนใหญ่ใช้bashเปลือก


แก้ไข: ขอบคุณสำหรับผู้แสดงความคิดเห็น

เฉพาะ &> ทำงานใน csh หรือ tcsh

ใน ksh เพียง 2> & 1 ใช้งานได้

การใช้เส้นประ> ไฟล์ 2> & 1 การเปลี่ยนเส้นทางเท่านั้น

แล้วอันไหนที่จะใช้เพื่อให้แน่ใจว่าสคริปต์ของฉันเข้ากันได้กับระบบอื่น ๆ ไม่ว่าเชลล์ที่ใช้คืออะไร!


สิ่งที่ดีกว่าคือสิ่งที่คุณต้องทำ สิ่งเหล่านี้ทำสิ่งที่แตกต่างกันมาก คุณใช้เปลือกไหนอยู่?
Skaperen

@Skaperen ใช้ bash
Maythux

1
ทำในสิ่งที่คุณต้องการที่จะประสบความสำเร็จ?
Skaperen

ฉันแค่อยากจะรู้ว่าอะไรคือความแตกต่างสิ่งที่ฉันต้องการคือไม่ได้อยู่ในทั้งสองอย่าง แต่ฉันก็ต้องรู้ว่ามันคือความแตกต่างหรือไม่เพื่อที่ครั้งหนึ่งจะได้รับ preffred เหนือคนอื่น ๆ
Maythux

2
&> somewhereเพียงแค่ชอร์ตชอร์สำหรับ> somewhere 2>&1: ในคำพูดของคู่มือทุบตีพวกเขาจะ "เทียบเท่า symantically"
steeldriver

คำตอบ:


23

หน้าคนทุบตีกล่าวถึงมีสองวิธีที่จะเปลี่ยนเส้นทางstderr และ stdout : และ&> file >& fileตอนนี้สังเกตว่ามันบอกว่าทั้ง stderr และ stdout

ในกรณีนี้>file 2>&1เรากำลังทำการเปลี่ยนเส้นทางของ stdout (1) ไปยังไฟล์ แต่ก็บอก stderr (2) ให้เปลี่ยนเส้นทางไปยังสถานที่เดียวกันกับ stdout! ดังนั้นจุดประสงค์อาจเหมือนกัน แต่ความคิดแตกต่างกันเล็กน้อย กล่าวอีกนัยหนึ่งว่า "จอห์นไปโรงเรียน; ซูซี่ไปที่จอห์นไป"

แล้วความชอบล่ะ? &>เป็นbashสิ่ง ดังนั้นหากคุณกำลังย้ายสคริปต์มันจะไม่ทำ แต่ถ้าคุณมั่นใจ 100% สคริปต์ของคุณจะทำงานเฉพาะในระบบที่มีการทุบตีเท่านั้น - ไม่มีการตั้งค่าใด ๆ

นี่คือตัวอย่างdashของ Debian Amquist Shell ซึ่งเป็นค่าเริ่มต้นของ Ubuntu

$ grep "YOLO" * &> /dev/null
$ grep: Desktop: Is a directory
grep: Documents: Is a directory
grep: Downloads: Is a directory
grep: Music: Is a directory
grep: Pictures: Is a directory
grep: Public: Is a directory
grep: Templates: Is a directory
grep: Videos: Is a directory
grep: YOLO: Is a directory
grep: bin: Is a directory

อย่างที่คุณเห็น stderr ไม่ได้ถูกเปลี่ยนเส้นทาง

หากต้องการแก้ไขการแก้ไขของคุณคุณสามารถใช้คำสั่ง if เพื่อตรวจสอบตัวแปร $ SHELL และเปลี่ยนการเปลี่ยนเส้นทางตามนั้น

แต่สำหรับกรณีส่วนใหญ่> file 2>&1ควรทำงาน


ในแง่เทคนิคเพิ่มเติมฟอร์ม[integer]>&wordเรียกว่าDuplicating Output File Descriptorและเป็นคุณสมบัติที่ระบุโดยมาตรฐานภาษาคำสั่งเชลล์ POSIX ซึ่งได้รับการสนับสนุนโดย POSIX-compliant และเชลล์คล้าย Brourne ส่วนใหญ่

ดูสิ่งที่ & หมายถึงอะไรกันแน่ในการเปลี่ยนเส้นทางเอาต์พุต


แล้วจะเกิดอะไรขึ้นเมื่อใช้กับกระสุนอื่น ๆ
Maythux

zsh รองรับ&>.... @Maythux ในเชลล์ที่ไม่รองรับ&>เช่นdashคุณจำเป็นต้องใช้การ>file 2>&1เปลี่ยนเส้นทางแบบไม่สำคัญ..
heemayl

แล้วอันไหนที่จะใช้ถ้าฉันต้องการให้แน่ใจว่าสคริปต์ของฉันจะเข้ากันได้กับเปลือกหอยที่แตกต่างกัน
Maythux

3
@Maythux >file 2>&1ใช้ สิ่งนี้ใช้ได้กับทุกเปลือกหอย
Sergiy Kolodyazhnyy

1
@ TSJNachos117 shells ที่ตั้งค่าไว้/etc/passwdสำหรับผู้ใช้แต่ละคนคือเชลล์แบบโต้ตอบ โดยปกติสคริปต์ของระบบจะใช้เป็นdash อย่างอื่นเว้นแต่จะระบุไว้เป็นอย่างอื่น เป็นสิ่งที่เป็นค่าเริ่มต้นก็กำหนดโดยสิ่งที่ symlinked เพื่อ/bin/shกรณีใน Ubuntu dashที่ของ ใน RHEL มันคือbashใน FreeBSD มันเป็นtcsh แหล่งและแหล่งอื่น
Sergiy Kolodyazhnyy

6

ฉันมักจะแนะนำให้ทำตามวิธีของบอร์น - เชลล์อีกครั้งในการทำสิ่งต่าง ๆ เนื่องจากทุบตีเป็นเนื้อหา Unix shell ที่ได้รับความนิยมมากที่สุด ทุบตีมักจะใช้อย่างใดอย่างหนึ่งหรือ&> 2>&1IMHO ไม่ใช่ "สมบูรณ์แบบ" ดังนั้นฉันแนะนำให้ลืมเรื่องไร้สาระนั้น ในความเป็นจริงสิ่งที่คุณควรใช้ขึ้นอยู่กับสิ่งที่คุณพยายามจะทำ

2>&1ผสาน stderr กับ stdout ซึ่งอาจมีประโยชน์หากตัวอย่างเช่นคุณต้องการไพพ์ข้อความ stderr ตัวอย่างเช่นถ้าคุณต้องการดูว่าโปรแกรมพิมพ์ข้อความ stderr บางตัวหรือไม่ แต่ไม่ต้องการให้หน้าจอเต็มไปด้วยขยะที่ไม่สำคัญคุณอาจทำสิ่งที่ต้องการprogram 2>&1 | grep crashedซึ่งจะค้นหา stdout และ stderr จากโปรแกรม เรียกว่า "โปรแกรม" สำหรับคำว่า "crashed"

ในทางกลับกันหากคุณไม่ต้องการให้โปรแกรมพิมพ์อะไรคุณสามารถเรียกใช้program &> /dev/nullซึ่งจะเปลี่ยนเส้นทางทั้ง stderr และ stdout เป็น / dev / null ซึ่งเป็นไฟล์พิเศษที่ทำให้สิ่งต่าง ๆ หายไปอย่างน่าอัศจรรย์ หรือหากคุณต้องการบันทึกผลลัพธ์ของโปรแกรม (อาจจะรายงานข้อผิดพลาดหรือบางอย่าง) คุณสามารถเปลี่ยนเส้นทางทั้ง stderr และ stdout เป็นไฟล์: program &> log.txtจะเปลี่ยนเส้นทางข้อมูลทั้งหมดไปยังไฟล์ที่เรียกว่า "log.txt" หากคุณต้องการคุณสามารถเปลี่ยนเส้นทาง stdout และ stderr ผ่านprogram 2> log.txt > log.txtหรือทั้งสองซึ่งจะมีผลเช่นเดียวกับการใช้program 2>&1 | cat > log.txt &>หากคุณทำสิ่งที่ชอบprogram 2>&1 > fileเฉพาะ stdout เท่านั้นที่จะถูกเปลี่ยนเส้นทาง แต่ stderr ยังคงสามารถส่งไปยังโปรแกรมอื่นเช่น cat ซึ่งสามารถเปลี่ยนเส้นทางได้ตามที่แสดงด้านบน อย่างไรก็ตามการพิมพ์&>ง่ายกว่าตัวอย่างใด ๆ ข้างต้นเนื่องจากเกี่ยวข้องกับการพิมพ์อักขระน้อยลง (และเป็นเรื่องง่ายสำหรับมนุษย์ที่จะอ่าน) โปรดทราบว่าprogram 2> log.txt > log.txtอาจมีแนวโน้มที่จะทำงานกับเชลล์ที่ไม่ใช่ bash

PS: ถ้าคุณกังวลเกี่ยวกับคนที่ใช้กระสุนอื่น ๆ มีบางอย่างที่คุณสามารถเพิ่มเข้าไปในบรรทัดแรกของสคริปต์ของคุณที่เรียกว่า "หมายเลขเวทมนตร์" หรือ "shebang" นี่เป็นวิธีที่จะทำให้แน่ใจว่าคอมพิวเตอร์เครื่องอื่น ๆ (โดยเฉพาะผู้ที่ใช้ระบบปฏิบัติการ Unix คล้าย) รู้โปรแกรมที่ใช้ในการเรียกใช้สคริปต์ สคริปต์ที่แตกต่างกันใช้ shebangs ที่แตกต่างกัน Shebang สำหรับสคริปต์ทุบตีมีลักษณะเช่นนี้:

#!/bin/bash

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

PS: ฉันจะไม่โกหก: จนถึงตอนนี้ผมไม่ทราบว่าใครจะใช้แต่เท่าที่ทุบตีไปก็ดูเหมือนว่าจะทำเช่นเดียวกับ>& &>คุณเรียนรู้สิ่งใหม่ทุกวัน.


แม้ว่าฉันจะเห็นด้วยกับคุณเกี่ยวกับการใช้#!บรรทัดเพื่อขออย่างชัดเจนbashแต่ก็ไม่สามารถใช้ได้กับระบบอื่น ๆ เสมอไป บ่อยครั้งที่ผู้พัฒนา / sysadmins ต้องเขียนสคริปต์แบบพกพาสำหรับระบบที่bashอาจไม่พร้อมใช้งานและอาจไม่สามารถติดตั้งbashได้ >file 2>&1เป็นเพียงแบบพกพามาก
Sergiy Kolodyazhnyy

คุณได้รับข้อผิดพลาดในการกลับรายการด้านบนซึ่งไม่ได้ให้ผลลัพธ์ที่คุณต้องการหรือต้องการ เปลี่ยนเส้นทาง stderr ไปยัง stdout จากนั้นเปลี่ยนเส้นทาง stdout ออกจาก stderr บน stdout ดั้งเดิม
ubfan1

Serg: ฉันไม่ได้ตั้งใจจะบอกว่าทุบตีเป็นสากล อย่างไรก็ตามฉันคิดว่ามีคนใช้งานมากกว่าที่จะพูด (t) csh หากคุณไม่รู้ว่ามีคนอื่นกำลังใช้อะไรอยู่และต้องเดาว่าเดาคนอื่นอาจจะเป็นวิธีที่ดีที่สุดของคุณ นอกจากนี้โดยทั่วไปฉันไม่รู้เกี่ยวกับการพกพาเนื่องจากฉันใช้ bash เท่านั้น ความจริงที่>file 2>&1พกพาได้ดีรู้ดี ฉันจะแก้ไขเพื่อให้สะท้อนถึงสิ่งนั้น
TSJNachos117

Ubfan1 ขอบคุณสำหรับข้อมูล ฉันจะไม่เดาในหนึ่งล้านปีที่ทุบตีจะไม่เปลี่ยน stderr ไปยังไฟล์ในกรณีนั้น ฉันเพิ่งแก้ไขคำตอบของฉันเพื่อป้องกันไม่ให้ผู้อื่นทำผิดพลาดเหมือนกัน
TSJNachos117

4

จากคู่มืออ้างอิง Bash -> 3.6.4 การเปลี่ยนเส้นทางเอาต์พุตมาตรฐานและข้อผิดพลาดมาตรฐาน :

โครงสร้างนี้อนุญาตให้ทั้งเอาต์พุตมาตรฐาน (file descriptor 1) และเอาต์พุตข้อผิดพลาดมาตรฐาน (file descriptor 2) ถูกเปลี่ยนเส้นทางไปยังไฟล์ที่มีชื่อคือการขยายตัวของคำ

มีสองรูปแบบสำหรับการเปลี่ยนเส้นทางเอาต์พุตมาตรฐานและข้อผิดพลาดมาตรฐาน:

&>word

และ

>&word

ของทั้งสองรูปแบบเป็นที่ต้องการแรก นี่คือความหมายเทียบเท่า

>word 2>&1

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

ยังดีที่จะอ้างถึงwiki ของ Greg ในอินพุตและเอาต์พุต -> 4.2 การจัดการไฟล์อธิบาย :

เพื่อความสะดวก Bash ยังให้คุณเปลี่ยนเส้นทางอีกรูปแบบหนึ่ง ตัวดำเนินการ &> การเปลี่ยนเส้นทางเป็นจริงเพียงแค่เวอร์ชันที่สั้นกว่าของสิ่งที่เราทำที่นี่ [ 2>&1]; เปลี่ยนเส้นทางทั้ง stdout และ stderr ไปยังไฟล์


4

เหตุใดฉันจึงต้องใช้ &> และไม่ใช่ 2> & 1

2>&1 เป็นเชลล์ Bourne / POSIX มาตรฐาน

&>เป็นส่วนขยายทุบตีและไม่ได้มาตรฐานทางนิตินัย

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

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