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

ข้อความแสดงข้อผิดพลาดถูกเปลี่ยนเส้นทางและstdoutechoข้อความจะถูกส่งไปที่หน้าต่างเทอร์มินัล:

มาดูกันว่ามีอะไรอยู่ในไฟล์ 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ไปยังปลายทางเดียวกันกับสตรีม 1 stdoutกำลังถูกเปลี่ยนเส้นทางไป"

ไม่มีเอาต์พุตที่มองเห็นได้ นั่นเป็นกำลังใจ

ลองตรวจสอบไฟล์ 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

และนั่นคือสิ่งที่เราเห็น

กระแสแห่งสติ

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

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

ตามปกติแล้วความรู้ที่มากขึ้นจะทำให้มีตัวเลือกมากขึ้น