stdin, stdout และ stderr บน Linux คืออะไร
stdin
, stdout
และstderr
สามข้อมูลลำธารสร้างขึ้นเมื่อคุณเปิดคำสั่ง Linux คุณสามารถใช้เพื่อดูว่าสคริปต์ของคุณกำลังถูก piped หรือถูกเปลี่ยนเส้นทาง เราแสดงให้คุณเห็นว่า
สตรีมเข้าร่วมสองคะแนน
ทันทีที่คุณเริ่มที่จะเรียนรู้เกี่ยวกับ Linux และ Unix เหมือนระบบปฏิบัติการคุณจะเจอคำว่าstdin
, และstdout
stederr
นี่คือสตรีมมาตรฐานสามรายการที่สร้างขึ้นเมื่อเรียกใช้คำสั่ง Linux ในการคำนวณสตรีมคือสิ่งที่สามารถถ่ายโอนข้อมูลได้ ในกรณีของสตรีมเหล่านี้ข้อมูลนั้นเป็นข้อความ
กระแสข้อมูลเช่นเดียวกับสายน้ำมีปลายสองด้าน พวกเขามีที่มาและการไหลออก คำสั่ง Linux ที่คุณใช้จะให้ปลายด้านหนึ่งของแต่ละสตรีม ปลายอีกด้านหนึ่งถูกกำหนดโดยเชลล์ที่เรียกใช้คำสั่ง ปลายนั้นจะเชื่อมต่อกับหน้าต่างเทอร์มินัลเชื่อมต่อกับไพพ์หรือเปลี่ยนเส้นทางไปยังไฟล์หรือคำสั่งอื่น ๆ ตามบรรทัดคำสั่งที่เรียกใช้คำสั่ง
สตรีมมาตรฐานของ Linux
ใน Linux stdin
เป็นสตรีมอินพุตมาตรฐาน สิ่งนี้ยอมรับข้อความเป็นอินพุต เอาต์พุตข้อความจากคำสั่งไปยังเชลล์จะถูกส่งผ่านstdout
สตรีม (standard out) ข้อความแสดงข้อผิดพลาดจากคำสั่งจะถูกส่งผ่านstderr
สตรีม (ข้อผิดพลาดมาตรฐาน)
ดังนั้นคุณจะเห็นว่ามีสองกระแสเอาท์พุทstdout
และและสตรีมใส่หนึ่งstderr
stdin
เนื่องจากข้อความแสดงข้อผิดพลาดและเอาต์พุตปกติแต่ละรายการมีท่อร้อยสายของตัวเองเพื่อนำไปยังหน้าต่างเทอร์มินัลจึงสามารถจัดการได้โดยอิสระจากกัน
สตรีมได้รับการจัดการเช่นเดียวกับไฟล์
สตรีมใน Linux เช่นเดียวกับเกือบทุกอย่างจะได้รับการปฏิบัติราวกับว่าเป็นไฟล์ คุณสามารถอ่านข้อความจากไฟล์และเขียนข้อความลงในไฟล์ได้ การดำเนินการทั้งสองนี้เกี่ยวข้องกับกระแสข้อมูล ดังนั้นแนวคิดในการจัดการสตรีมข้อมูลเป็นไฟล์จึงไม่ยืดยาว
ไฟล์แต่ละไฟล์ที่เชื่อมโยงกับกระบวนการจะได้รับการจัดสรรหมายเลขเฉพาะเพื่อระบุ ซึ่งเรียกว่า file descriptor เมื่อใดก็ตามที่จำเป็นต้องดำเนินการกับไฟล์ตัวอธิบายไฟล์จะถูกใช้เพื่อระบุไฟล์
ค่าเหล่านี้ถูกนำมาใช้เสมอสำหรับstdin
, stdout,
และstderr
:
- 0 : stdin
- 1 : stdout
- 2 : stderr
การตอบสนองต่อท่อและการเปลี่ยนเส้นทาง
เพื่อให้ผู้อื่นแนะนำเรื่องได้ง่ายขึ้นเทคนิคทั่วไปคือการสอนหัวข้อที่เรียบง่าย ตัวอย่างเช่นด้วยไวยากรณ์เราได้รับแจ้งว่ากฎคือ“ I ก่อน E ยกเว้นหลัง C” แต่จริงๆแล้วมีข้อยกเว้นสำหรับกฎนี้มากกว่ามีหลายกรณีที่ปฏิบัติตาม
ในทำนองเดียวกันเมื่อพูดคุยเกี่ยวกับstdin
, stdout
และstderr
มันสะดวกที่จะวิ่งออกมาจากความจริงที่ยอมรับว่ากระบวนการที่ไม่รู้มิได้ใส่ใจที่สามลำธารมาตรฐานที่มีการยกเลิก กระบวนการควรดูแลว่าเอาต์พุตกำลังไปที่เทอร์มินัลหรือถูกเปลี่ยนเส้นทางไปยังไฟล์หรือไม่ มันสามารถบอกได้ว่าอินพุตนั้นมาจากคีย์บอร์ดหรือถูกส่งเข้ามาจากกระบวนการอื่นหรือไม่?
อันที่จริงกระบวนการรู้หรืออย่างน้อยที่สุดก็สามารถตรวจสอบได้ว่าควรเลือกตรวจสอบหรือไม่และสามารถเปลี่ยนแปลงพฤติกรรมตามนั้นได้หากผู้เขียนซอฟต์แวร์ตัดสินใจเพิ่มฟังก์ชันดังกล่าว
เราสามารถเห็นการเปลี่ยนแปลงพฤติกรรมนี้ได้ง่ายมาก ลองใช้สองคำสั่งนี้:
ls
ls | แมว
ls
พฤติกรรมคำสั่งแตกต่างกันถ้าเอาท์พุท ( stdout
) จะถูกประปาเข้าไปในคำสั่งอื่น มันเป็น สวิทช์ที่เอาท์พุทคอลัมน์เดียวมันไม่ได้เป็นแปลงที่ดำเนินการโดยls
cat
และls
ทำสิ่งเดียวกันหากเอาต์พุตถูกเปลี่ยนเส้นทาง:
ls> capture.txt
cat capture.txt
เปลี่ยนเส้นทาง stdout และ stderr
มีข้อได้เปรียบในการส่งข้อความแสดงข้อผิดพลาดโดยสตรีมเฉพาะ หมายความว่าเราสามารถเปลี่ยนเส้นทางเอาต์พุตของคำสั่ง ( stdout
) ไปยังไฟล์และยังคงเห็นข้อความแสดงข้อผิดพลาด ( stderr
) ในหน้าต่างเทอร์มินัล คุณสามารถตอบสนองต่อข้อผิดพลาดได้หากต้องการเมื่อเกิดขึ้น นอกจากนี้ยังหยุดข้อความแสดงข้อผิดพลาดจากการปนเปื้อนไฟล์ที่stdout
ถูกเปลี่ยนเส้นทางไป
พิมพ์ข้อความต่อไปนี้ลงในโปรแกรมแก้ไขและบันทึกลงในไฟล์ชื่อ error.sh
#! / bin / bash echo "กำลังจะพยายามเข้าถึงไฟล์ที่ไม่มีอยู่" cat bad-filename.txt
ทำให้สคริปต์ทำงานได้ด้วยคำสั่งนี้:
chmod + x error.sh
บรรทัดแรกของสคริปต์จะสะท้อนข้อความไปยังหน้าต่างเทอร์มินัลผ่าน stdout
สตรีม บรรทัดที่สองพยายามเข้าถึงไฟล์ที่ไม่มีอยู่ stderr
นี้จะสร้างข้อผิดพลาดที่มีการส่งผ่าน
รันสคริปต์ด้วยคำสั่งนี้:
./error.sh
เราจะเห็นว่าทั้งสองสตรีมของเอาต์พุตstdout
และstderr
แสดงในหน้าต่างเทอร์มินัล
ลองเปลี่ยนเส้นทางผลลัพธ์ไปยังไฟล์:
./error.sh> capture.txt
ข้อความแสดงข้อผิดพลาดที่ส่งผ่านstderr
ยังคงถูกส่งไปยังหน้าต่างเทอร์มินัล เราสามารถตรวจสอบเนื้อหาของไฟล์เพื่อดูว่าstdout
ผลลัพธ์ไปที่ไฟล์หรือไม่
cat capture.txt
เอาต์พุตจากstdin
ถูกเปลี่ยนเส้นทางไปยังไฟล์ตามที่คาดไว้
>
สัญลักษณ์การเปลี่ยนเส้นทางทำงานร่วมกับstdout
โดยค่าเริ่มต้น คุณสามารถใช้ตัวอธิบายไฟล์ตัวเลขเพื่อระบุสตรีมเอาต์พุตมาตรฐานที่คุณต้องการเปลี่ยนเส้นทาง
หากต้องการเปลี่ยนเส้นทางอย่างชัดเจน stdout
ให้ใช้คำแนะนำในการเปลี่ยนเส้นทางนี้:
1>
หากต้องการเปลี่ยนเส้นทางอย่างชัดเจน stderr
ให้ใช้คำแนะนำในการเปลี่ยนเส้นทางนี้:
2>
ลองทดสอบของเราอีกครั้งและคราวนี้เราจะใช้2>
:
./error.sh 2> capture.txt
ข้อความแสดงข้อผิดพลาดถูกเปลี่ยนเส้นทางและstdout
echo
ข้อความจะถูกส่งไปที่หน้าต่างเทอร์มินัล:
มาดูกันว่ามีอะไรอยู่ในไฟล์ capture.txt
cat capture.txt
stderr
ข้อความที่อยู่ใน capture.txt ตามที่คาดไว้
เปลี่ยนเส้นทางทั้ง stdout และ stderr
แน่นอนว่าหากเราสามารถเปลี่ยนเส้นทางอย่างใดอย่างหนึ่งstdout
หรือstderr
ไปยังไฟล์โดยอิสระจากกันเราควรจะสามารถเปลี่ยนเส้นทางทั้งสองไฟล์ในเวลาเดียวกันไปยังไฟล์สองไฟล์
ใช่เราทำได้ คำสั่งนี้จะนำstdout
ไปยังไฟล์ที่เรียกว่า capture.txt และstderr
ไปยังไฟล์ที่เรียกว่า error.txt
./error.sh 1> capture.txt 2> error.txt
เนื่องจากทั้งสตรีมของเอาต์พุต - เอาต์พุตมาตรฐานและข้อผิดพลาดมาตรฐานถูกเปลี่ยนเส้นทางไปยังไฟล์จึงไม่มีเอาต์พุตที่มองเห็นได้ในหน้าต่างเทอร์มินัล เราจะกลับไปที่พรอมต์บรรทัดคำสั่งราวกับว่าไม่มีอะไรเกิดขึ้น
ตรวจสอบเนื้อหาของแต่ละไฟล์:
cat capture.txt
cat error.txt
เปลี่ยนเส้นทาง stdout และ stderr ไปยังไฟล์เดียวกัน
เรียบร้อยเรามีสตรีมเอาต์พุตมาตรฐานแต่ละรายการไปยังไฟล์เฉพาะของตัวเอง การรวมกันเพียงอื่น ๆ ที่เราสามารถทำได้คือการส่งทั้งในstdout
และstderr
ไปยังแฟ้มเดียวกัน
เราสามารถบรรลุสิ่งนี้ได้ด้วยคำสั่งต่อไปนี้:
./error.sh> capture.txt 2> & 1
มาทำลายมันลง
- ./error.sh : เปิดไฟล์สคริปต์ error.sh
- > capture.txt : เปลี่ยนเส้นทาง
stdout
สตรีมไปยังไฟล์ capture.txt เป็นชวเลข>
1>
- 2> & 1 : ใช้คำสั่ง &> เปลี่ยนเส้นทาง คำสั่งนี้ช่วยให้คุณสามารถบอกเชลล์เพื่อให้สตรีมหนึ่งไปยังปลายทางเดียวกันกับสตรีมอื่น ในกรณีนี้เรากำลังพูดว่า "เปลี่ยนเส้นทางสตรีม 2
stderr
ไปยังปลายทางเดียวกันกับสตรีม 1stdout
กำลังถูกเปลี่ยนเส้นทางไป"
ไม่มีเอาต์พุตที่มองเห็นได้ นั่นเป็นกำลังใจ
ลองตรวจสอบไฟล์ capture.txt และดูว่ามีอะไรอยู่ในนั้น
cat capture.txt
ทั้งสตรีมstdout
และstderr
สตรีมถูกเปลี่ยนเส้นทางไปยังไฟล์ปลายทางเดียว
ที่จะมีการส่งออกของกระแสการเปลี่ยนเส้นทางและโยนทิ้งไปอย่างเงียบ ๆ /dev/null
ที่ตรงออกไป
การตรวจจับการเปลี่ยนเส้นทางภายในสคริปต์
เราได้พูดถึงวิธีที่คำสั่งสามารถตรวจจับได้ว่าสตรีมใดกำลังถูกเปลี่ยนเส้นทางหรือไม่และสามารถเลือกที่จะปรับเปลี่ยนพฤติกรรมตามนั้นได้ เราจะทำสิ่งนี้ให้สำเร็จในสคริปต์ของเราเองได้หรือไม่? ใช่เราทำได้ และเป็นเทคนิคที่ง่ายมากในการทำความเข้าใจและใช้งาน
พิมพ์ข้อความต่อไปนี้ลงในโปรแกรมแก้ไขและบันทึกเป็น input.sh
#! / bin / bash ถ้า [-t 0]; จากนั้น echo stdin ที่มาจากแป้นพิมพ์อื่น ๆ echo stdin ที่มาจากท่อหรือไฟล์ fi
ใช้คำสั่งต่อไปนี้เพื่อให้สามารถเรียกใช้งานได้:
chmod + x input.sh
ส่วนที่ฉลาดคือการทดสอบภายในวงเล็บเหลี่ยม -t
(Terminal) ตัวเลือกผลตอบแทนจริง (0) ถ้าไฟล์ที่เกี่ยวข้องกับการยุติไฟล์อธิบายในหน้าต่าง terminal เราได้ใช้ไฟล์อธิบาย 0 stdin
เป็นอาร์กิวเมนต์ในการทดสอบซึ่งหมายถึง
หากstdin
เชื่อมต่อกับหน้าต่างเทอร์มินัลการทดสอบจะพิสูจน์ได้ว่าเป็นจริง หากstdin
เชื่อมต่อกับไฟล์หรือไปป์การทดสอบจะล้มเหลว
เราสามารถใช้ไฟล์ข้อความที่สะดวกเพื่อสร้างอินพุตให้กับสคริปต์ ที่นี่เราใช้ชื่อ dummy.txt
./input.sh <dummy.txt
ผลลัพธ์แสดงให้เห็นว่าสคริปต์รับรู้ว่าอินพุตไม่ได้มาจากแป้นพิมพ์ซึ่งมาจากไฟล์ หากคุณเลือกคุณสามารถปรับเปลี่ยนพฤติกรรมของสคริปต์ของคุณได้
นั่นคือด้วยการเปลี่ยนเส้นทางไฟล์มาลองใช้กับไพพ์
cat dummy.txt | ./input.sh
สคริปต์จะรับรู้ว่าอินพุตของมันกำลังถูกส่งไปยังมัน หรืออย่างแม่นยำกว่านั้นก็จะรับรู้อีกครั้งว่าstdin
สตรีมไม่ได้เชื่อมต่อกับหน้าต่างเทอร์มินัล
มาเรียกใช้สคริปต์โดยไม่ใช้ไปป์หรือเปลี่ยนเส้นทาง
./input.sh
stdin
กระแสเชื่อมต่อกับหน้าต่าง terminal และสคริปต์ที่รายงานตามนี้
ในการตรวจสอบสิ่งเดียวกันกับสตรีมเอาต์พุตเราต้องมีสคริปต์ใหม่ พิมพ์สิ่งต่อไปนี้ลงในตัวแก้ไขและบันทึกเป็น output.sh
#! / bin / bash ถ้า [-t 1]; จากนั้น echo stdout จะไปที่หน้าต่างเทอร์มินัลอื่น ๆ echo stdout กำลังถูกเปลี่ยนเส้นทางหรือ piped fi
ใช้คำสั่งต่อไปนี้เพื่อให้สามารถเรียกใช้งานได้:
chmod + x input.sh
การเปลี่ยนแปลงที่สำคัญเพียงอย่างเดียวของสคริปต์นี้อยู่ในการทดสอบในวงเล็บเหลี่ยม เรากำลังใช้หลัก 1 stdout
ที่จะเป็นตัวแทนอธิบายไฟล์สำหรับ
มาทดลองใช้งาน cat
เราจะท่อส่งออกผ่าน
./output | แมว
สคริปต์รับรู้ว่าเอาต์พุตไม่ได้ไปที่หน้าต่างเทอร์มินัลโดยตรง
นอกจากนี้เรายังสามารถทดสอบสคริปต์โดยเปลี่ยนเส้นทางผลลัพธ์ไปยังไฟล์
./output.sh> capture.txt
ไม่มีเอาต์พุตไปยังหน้าต่างเทอร์มินัลเราจะกลับไปที่พรอมต์คำสั่งโดยไม่โต้ตอบ ตามที่เราคาดหวัง
เราสามารถดูภายในไฟล์ capture.txt เพื่อดูสิ่งที่ถูกบันทึก ใช้คำสั่งต่อไปนี้เพื่อดำเนินการดังกล่าว
cat capture.sh
อีกครั้งการทดสอบอย่างง่ายในสคริปต์ของเราตรวจพบว่าstdout
สตรีมไม่ได้ถูกส่งไปยังหน้าต่างเทอร์มินัลโดยตรง
หากเรารันสคริปต์โดยไม่มีไปป์หรือการเปลี่ยนเส้นทางควรตรวจพบว่าstdout
กำลังส่งตรงไปยังหน้าต่างเทอร์มินัล
./output.sh
และนั่นคือสิ่งที่เราเห็น
กระแสแห่งสติ
การรู้วิธีดูว่าสคริปต์ของคุณเชื่อมต่อกับหน้าต่างเทอร์มินัลหรือไปป์หรือกำลังถูกเปลี่ยนเส้นทางช่วยให้คุณสามารถปรับเปลี่ยนพฤติกรรมได้
เอาต์พุตการบันทึกและการวินิจฉัยอาจมีรายละเอียดมากหรือน้อยขึ้นอยู่กับว่ากำลังไปที่หน้าจอหรือไปที่ไฟล์ ข้อความแสดงข้อผิดพลาดสามารถบันทึกลงในไฟล์อื่นนอกเหนือจากเอาต์พุตของโปรแกรมปกติ
ตามปกติแล้วความรู้ที่มากขึ้นจะทำให้มีตัวเลือกมากขึ้น