stdin, stdout และ stderr บน Linux คืออะไร
เผยแพร่แล้ว: 2022-01-29 stdin
, stdout
และ stderr
เป็นสตรีมข้อมูลสามสตรีมที่สร้างขึ้นเมื่อคุณเรียกใช้คำสั่ง Linux คุณสามารถใช้เพื่อบอกว่าสคริปต์ของคุณถูกวางหรือเปลี่ยนเส้นทางหรือไม่ เราแสดงให้คุณเห็นว่า
สตรีมเข้าร่วมสองคะแนน
ทันทีที่คุณเริ่มเรียนรู้เกี่ยวกับระบบปฏิบัติการที่คล้ายกับ Linux และ Unix คุณจะเจอเงื่อนไข stdin
, stdout
และ stederr
นี่คือสตรีมมาตรฐานสามสตรีมที่สร้างขึ้นเมื่อรันคำสั่ง Linux ในการคำนวณ สตรีมคือสิ่งที่สามารถถ่ายโอนข้อมูลได้ ในกรณีของสตรีมเหล่านี้ ข้อมูลนั้นเป็นข้อความ
กระแสข้อมูล เช่น ธารน้ำ มีสองปลาย พวกเขามีแหล่งที่มาและการไหลออก คำสั่ง Linux ใดก็ตามที่คุณใช้จะมีปลายด้านหนึ่งของแต่ละสตรีม ปลายอีกด้านหนึ่งถูกกำหนดโดยเชลล์ที่เรียกใช้คำสั่ง ปลายทางนั้นจะเชื่อมต่อกับหน้าต่างเทอร์มินัล เชื่อมต่อกับไพพ์ หรือเปลี่ยนเส้นทางไปยังไฟล์หรือคำสั่งอื่นๆ ตามบรรทัดคำสั่งที่เรียกใช้คำสั่ง
สตรีมมาตรฐานของลินุกซ์
ใน Linux stdin
เป็นสตรีมอินพุตมาตรฐาน นี้ยอมรับข้อความเป็นข้อมูลเข้า เอาต์พุตข้อความจากคำสั่งไปยังเชลล์ถูกส่งผ่านสตรีม stdout
(เอาต์พุตมาตรฐาน) ข้อความแสดงข้อผิดพลาดจากคำสั่งจะถูกส่งผ่านสตรีม stderr
(ข้อผิดพลาดมาตรฐาน)
ดังนั้นคุณจะเห็นว่ามีสองเอาต์พุตสตรีม stdout
และ stderr
และหนึ่งอินพุตสตรีม stdin
เนื่องจากข้อความแสดงข้อผิดพลาดและเอาต์พุตปกติแต่ละรายการมีท่อร้อยสายเพื่อนำไปยังหน้าต่างเทอร์มินัล จึงสามารถจัดการแยกจากกันได้
สตรีมได้รับการจัดการเหมือนไฟล์
สตรีมใน Linux—เหมือนกับเกือบทุกอย่าง—จะถือว่ามันเป็นไฟล์ คุณสามารถอ่านข้อความจากไฟล์ และเขียนข้อความลงในไฟล์ได้ การกระทำทั้งสองนี้เกี่ยวข้องกับกระแสข้อมูล ดังนั้นแนวคิดในการจัดการกระแสข้อมูลในฐานะไฟล์จึงไม่ได้ยืดเยื้อมากนัก
แต่ละไฟล์ที่เกี่ยวข้องกับกระบวนการจะได้รับการจัดสรรหมายเลขเฉพาะเพื่อระบุ สิ่งนี้เรียกว่าตัวอธิบายไฟล์ เมื่อใดก็ตามที่จำเป็นต้องดำเนินการกับไฟล์ ตัวอธิบายไฟล์จะถูกใช้เพื่อระบุไฟล์
ค่าเหล่านี้มักใช้สำหรับ stdin
, stdout,
และ stderr
:
- 0 : stdin
- 1 : stdout
- 2 : stderr
การตอบสนองต่อท่อและการเปลี่ยนเส้นทาง
เพื่อให้การแนะนำของผู้อื่นง่ายขึ้น เทคนิคทั่วไปคือการสอนหัวข้อในรูปแบบที่เรียบง่าย ตัวอย่างเช่น ด้วยไวยากรณ์ เราได้รับแจ้งว่ากฎคือ "ฉันก่อน E ยกเว้นหลัง C" แต่จริงๆ แล้ว มีข้อยกเว้นสำหรับกฎนี้มากกว่าที่มีกรณีที่ปฏิบัติตาม
ในทำนองเดียวกัน เมื่อพูดถึง stdin
, stdout
, และ stderr
เป็นการสะดวกที่จะแยกแยะสัจพจน์ที่ยอมรับได้ว่ากระบวนการไม่รู้และไม่สนใจว่าสตรีมมาตรฐานทั้งสามจะสิ้นสุดลงที่ใด กระบวนการควรดูแลว่าผลลัพธ์จะถูกส่งไปยังเทอร์มินัลหรือถูกเปลี่ยนเส้นทางไปยังไฟล์หรือไม่? มันสามารถบอกได้หรือไม่ว่าอินพุตนั้นมาจากคีย์บอร์ดหรือถูกส่งมาจากกระบวนการอื่น?
อันที่จริง กระบวนการรู้ดี—หรืออย่างน้อยก็หาได้ ควรจะเลือกตรวจสอบ—และมันสามารถเปลี่ยนพฤติกรรมของมันได้ตามนั้น ถ้าผู้สร้างซอฟต์แวร์ตัดสินใจเพิ่มฟังก์ชันนั้น
เราสามารถเห็นการเปลี่ยนแปลงพฤติกรรมนี้ได้อย่างง่ายดายมาก ลองสองคำสั่งนี้:
ลส
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
ข้อความแสดงข้อผิดพลาดถูกเปลี่ยนเส้นทางและข้อความ echo
stdout
ถูกส่งไปยังหน้าต่างเทอร์มินัล:
มาดูกันว่าในไฟล์ 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 : ใช้คำสั่งเปลี่ยนเส้นทาง &> คำแนะนำนี้ช่วยให้คุณบอกเชลล์เพื่อให้สตรีมหนึ่งไปยังปลายทางเดียวกันกับสตรีมอื่น ในกรณีนี้ เรากำลังพูดว่า “redirect stream 2,
stderr
, ไปยังปลายทางเดียวกันกับที่ stream 1,stdout
ถูกเปลี่ยนเส้นทางไป”
ไม่มีผลลัพธ์ที่มองเห็นได้ นั่นเป็นกำลังใจ
ลองตรวจสอบไฟล์ capture.txt และดูว่ามีอะไรอยู่ในนั้น
cat capture.txt
ทั้งสตรีม stdout
และ stderr
ถูกเปลี่ยนเส้นทางไปยังไฟล์ปลายทางเดียว
หากต้องการให้เอาต์พุตของสตรีมถูกเปลี่ยนเส้นทางและถูกโยนทิ้งไปอย่างเงียบๆ ให้นำเอาต์พุตไปที่ /dev/null
การตรวจจับการเปลี่ยนเส้นทางภายในสคริปต์
เราได้พูดคุยกันถึงวิธีที่คำสั่งสามารถตรวจจับได้ว่าสตรีมใดถูกเปลี่ยนเส้นทางหรือไม่ และสามารถเลือกที่จะปรับเปลี่ยนลักษณะการทำงานตามนั้นได้ เราสามารถทำสิ่งนี้ให้สำเร็จในสคริปต์ของเราเองได้หรือไม่? ใช่เราทำได้ และเป็นเทคนิคที่ง่ายมากที่จะเข้าใจและนำไปใช้
พิมพ์ข้อความต่อไปนี้ในเอดิเตอร์และบันทึกเป็น input.sh
#!/bin/bash ถ้า [ -t 0]; แล้ว echo stdin มาจากแป้นพิมพ์ อื่น echo stdin มาจากไพพ์หรือไฟล์ fi
ใช้คำสั่งต่อไปนี้เพื่อให้ปฏิบัติการได้:
chmod +x อินพุต.sh
ส่วนที่ฉลาดคือการทดสอบภายในวงเล็บเหลี่ยม อ็อพชัน -t
(เทอร์มินัล) คืนค่า true (0) หากไฟล์ที่เกี่ยวข้องกับ file descriptor สิ้นสุดลงในหน้าต่างเทอร์มินัล เราใช้ file descriptor 0 เป็นอาร์กิวเมนต์ในการทดสอบ ซึ่งแสดงถึง stdin
หาก stdin
เชื่อมต่อกับหน้าต่างเทอร์มินัล การทดสอบจะพิสูจน์ได้ว่าเป็นจริง หาก stdin
เชื่อมต่อกับไฟล์หรือไพพ์ การทดสอบจะล้มเหลว
เราสามารถใช้ไฟล์ข้อความที่สะดวกเพื่อสร้างอินพุตให้กับสคริปต์ได้ ที่นี่เราใช้อันหนึ่งเรียกว่า dummy.txt
./input.sh < dummy.txt
ผลลัพธ์แสดงว่าสคริปต์รับรู้ว่าอินพุตไม่ได้มาจากแป้นพิมพ์ แต่มาจากไฟล์ หากคุณเลือก คุณสามารถเปลี่ยนพฤติกรรมของสคริปต์ได้ตามความเหมาะสม
นั่นคือการเปลี่ยนเส้นทางไฟล์มาลองใช้กับไพพ์
cat dummy.txt | ./input.sh
สคริปต์รับรู้ว่ากำลังส่งอินพุตเข้าไป หรือแม่นยำกว่านั้น มันรับรู้อีกครั้งว่าสตรีม stdin
ไม่ได้เชื่อมต่อกับหน้าต่างเทอร์มินัล
มารันสคริปต์กันโดยไม่มีไพพ์หรือเปลี่ยนเส้นทาง
./input.sh
สตรีม stdin
เชื่อมต่อกับหน้าต่างเทอร์มินัล และสคริปต์จะรายงานสิ่งนี้ตามนั้น
ในการตรวจสอบสิ่งเดียวกันกับเอาต์พุตสตรีม เราจำเป็นต้องมีสคริปต์ใหม่ พิมพ์ข้อมูลต่อไปนี้ในเอดิเตอร์และบันทึกเป็น output.sh
#!/bin/bash ถ้า [ -t 1 ]; แล้ว echo stdout กำลังไปที่หน้าต่างเทอร์มินัล อื่น echo stdout กำลังถูกเปลี่ยนเส้นทางหรือวางท่อ fi
ใช้คำสั่งต่อไปนี้เพื่อให้ปฏิบัติการได้:
chmod +x อินพุต.sh
การเปลี่ยนแปลงที่สำคัญเพียงอย่างเดียวของสคริปต์นี้คือการทดสอบในวงเล็บเหลี่ยม เรากำลังใช้ตัวเลข 1 เพื่อแสดง file descriptor สำหรับ stdout
มาลองดูกัน เราจะไพพ์เอาต์พุตผ่าน cat
./output | แมว
สคริปต์รับรู้ว่าเอาต์พุตไม่ส่งไปยังหน้าต่างเทอร์มินัลโดยตรง
เรายังทดสอบสคริปต์ได้โดยเปลี่ยนเส้นทางเอาต์พุตไปยังไฟล์
./output.sh > capture.txt
ไม่มีเอาต์พุตไปยังหน้าต่างเทอร์มินัล เราจะกลับไปที่พรอมต์คำสั่งอย่างเงียบ ๆ อย่างที่เราคาดหวัง
เราสามารถมองเข้าไปในไฟล์ capture.txt เพื่อดูว่ามีอะไรถูกดักไว้บ้าง ใช้คำสั่งต่อไปนี้เพื่อทำเช่นนั้น
แมวจับ.sh
อีกครั้ง การทดสอบอย่างง่ายในสคริปต์ของเราตรวจพบว่าสตรีม stdout
ไม่ได้ส่งไปยังหน้าต่างเทอร์มินัลโดยตรง
หากเราเรียกใช้สคริปต์โดยไม่มีไพพ์หรือการเปลี่ยนเส้นทาง สคริปต์ควรตรวจพบว่า stdout
ถูกส่งโดยตรงไปยังหน้าต่างเทอร์มินัล
./output.sh
และนั่นคือสิ่งที่เราเห็น
สายธารแห่งสติ
การรู้วิธีบอกว่าสคริปต์ของคุณเชื่อมต่อกับหน้าต่างเทอร์มินัล หรือไปป์ หรือกำลังถูกเปลี่ยนเส้นทาง ช่วยให้คุณปรับพฤติกรรมตามนั้นได้
การบันทึกและเอาต์พุตการวินิจฉัยอาจมีรายละเอียดมากหรือน้อย ขึ้นอยู่กับว่าจะไปที่หน้าจอหรือไปที่ไฟล์ ข้อความแสดงข้อผิดพลาดสามารถบันทึกลงในไฟล์อื่นที่ไม่ใช่เอาต์พุตของโปรแกรมปกติได้
ตามปกติแล้ว ความรู้ที่มากขึ้นทำให้เกิดทางเลือกมากขึ้น
คำสั่งลินุกซ์ | ||
ไฟล์ | tar · pv · cat · tac · chmod · grep · diff · sed · ar · man · pushd · popd · fsck · testdisk · seq · fd · pandoc · cd · $PATH · awk · เข้าร่วม · jq · fold · uniq · journalctl · tail · stat · ls · fstab · echo · less · chgrp · chown · rev · ดู · strings · พิมพ์ · เปลี่ยนชื่อ · zip · unzip · เมานต์ · umount · ติดตั้ง · fdisk · mkfs · rm · rmdir · rsync · df · gpg · vi · nano · mkdir · du · ln · แพทช์ · แปลง · rclone · ฉีก · srm | |
กระบวนการ | alias · screen · top · nice · renice · progress · strace · systemd · tmux · chsh · history · at · batch · free · which · dmesg · chfn · usermod · ps · chroot · xargs · tty · pinky · lsof · vmstat · หมดเวลา · ผนัง · ใช่ · ฆ่า · หลับ · sudo · su · เวลา · groupadd · usermod · กลุ่ม · lshw · ปิดระบบ · รีบูต · หยุด · poweroff · passwd · lscpu · crontab · วันที่ · bg · fg | |
ระบบเครือข่าย | netstat · ping · traceroute · ip · ss · whois · fail2ban · bmon · dig · finger · nmap · ftp · curl · wget · who · whoami · w · iptables · ssh-keygen · ufw |
ที่เกี่ยวข้อง: แล็ปท็อป Linux ที่ดีที่สุดสำหรับนักพัฒนาและผู้ที่ชื่นชอบ