หากคุณเคยใช้ pipes และ redirection ภายใต้ Linux shell ของคุณ โอกาสคือคุณจะต้องใช้ยูทิลิตี้ tee บ้าง
Tee ทำอะไร?
คำสั่งอย่าง
ls
จะแสดงเนื้อหาของไดเรกทอรีปัจจุบัน นั่นคือ มันแสดงเนื้อหาเหล่านี้ไปที่ stdout (standard output) ซึ่งโดยปกติคือหน้าจอของคุณ หรือแม่นยำกว่านั้น คือ virtual terminal display ของคุณ
คำสั่งอย่าง
ls > file123
จะไม่แสดงอะไรบนหน้าจอของคุณเลย นั่นเพราะเครื่องหมาย > เปลี่ยนทิศทางเอาต์พุตทั้งหมดไปที่ไฟล์แทนการแสดงไปที่ stdout file123 จะถูกเติมด้วยเนื้อหาที่แสดงบนหน้าจอก่อนหน้านี้
เพื่อแสดงเนื้อหาไดเรกทอรีบนหน้าจอ และเขียนลงไฟล์พร้อมกัน คุณต้องใช้สองคำสั่ง ด้วย tee คุณสามารถทำทั้งสองอย่างพร้อมกันได้
ls | tee file123
ทำไมต้องใช้ Tee หากคุณสามารถรันคำสั่งคล้ายกันสองครั้งได้?
ในตัวอย่างข้างต้น คุณชัดเจนว่าไม่ต้องใช้ tee หากคุณสามารถรัน ls ปกติแล้วจากนั้นรันอีกครั้งและเปลี่ยนทิศทางเอาต์พุตไปไฟล์ อย่างไรก็ตาม คุณจะพบสถานการณ์ที่เอาต์พุตจะเป็นเอกลักษณ์ (unique) 想像สถานการณ์ที่คุณพยายามวินิจฉัยปัญหา คุณรัน diagnose | tee error.log ข้อผิดพลาดที่คุณได้อาจเป็นเอกลักษณ์ คุณต้องการให้แสดงบนหน้าจอเพื่อดูว่ากำลังเกิดอะไรขณะทดสอบ แต่คุณยังต้องการบันทึกข้อผิดพลาดเหล่านั้นลงไฟล์ เพื่อทบทวนภายหลังหรือวางเอาต์พุตบนฟอรัมถามคนอื่น
สถานการณ์อีกอย่างที่พบบ่อย เมื่อคุณอาจต้องการ tee คือ: คุณต้องการเขียนเอาต์พุตของคำสั่งไปยังตำแหน่งที่เฉพาะ root user เท่านั้นที่อ่านหรือเขียนได้ นี่จะไม่ทำงาน
/sbin/blkid > /root/somefile
จากนั้น คุณอาจคิดว่า "โอเค ใช้ sudo ซิ!" และคุณจะประหลาดใจที่มันไม่ทำงานเช่นกัน:
sudo blkid > /root/somefile
นั่นเพราะหลังจาก sudo blkid รันเสร็จ คุณยังคงล็อกอินเป็นผู้ใช้ทั่วไป non-root และ shell ของคุณ (ปกติคือ bash) พยายามเขียนไป /root/somefile ด้วยข้อมูลประจำตัวผู้ใช้ทั่วไป เพื่อแก้ไข คุณสามารถใช้ tee:
/sbin/blkid | sudo tee /root/somefile
การต่อข้อความ (Appending) และการเปลี่ยนทิศทางข้อผิดพลาด
tee เป็นคำสั่งที่มีประโยแแตกแต่อย่างง่าย คำสั่งพื้นฐาน command | tee somefile จะเพียงพอในส่วนใหญ่ อย่างไรก็ตาม มีสองสถานการณ์ที่คุณอาจพบที่จะต้องใช้เคล็ดลับเหล่านี้
สิ่งแรกที่ต้องรู้คือ tee โดยค่าเริ่มต้นจะเขียนทับไฟล์เสมอ หากคุณรัน
ls | tee somefile
และจากนั้น
ls /tmp | tee somefile
คำสั่งที่สองจะเขียนทับเนื้อหาของ somefile และคุณจะเห็นเนื้อหาของคำสั่งสุดท้ายที่รันเท่านั้น เพื่อเปลี่ยนพฤติกรรมนี้ คุณสามารถทำให้ tee per ข้อความแทนการเขียนทับ ได้โดยใช้สวิตช์คำสั่ง -a
ls | tee -a somefile
สิ่งที่สองที่ต้องรู้คือ ไม่ใช่ทุกเอาต์พุตเหมือนกัน ข้อความข้อผิดพลาดถูกจัดการแตกต่าง และแม้จะปรากฏบนหน้าจอ พวกมันไม่ถือเป็น stdout ดังนั้นจึงไม่ถูกจับโดย tee (พวกมันถือเป็น stderr) นี่คือตัวอย่างบน grep
grep -r L2TP /etc | tee somefile
จะแสดงบางอย่างเหมือนภาพต่อไปนี้
ข้อความ "Permission denied" ถูกเขียนไปที่ stderr เพียงแค่ข้อความที่ไฮไลท์เท่านั้นที่ถูกเขียนไป stdout นั่นคือเหตุผลที่คุณจะสังเกตว่าเนื้อหาของ "somefile" คือสิ่งที่แสดงในภาพด้านล่าง
ในกรณีนี้ ที่ grep ใช้ค้นหาข้อความ มันมีประโยชน์ที่ข้อความข้อผิดพลาดไม่ถูกเปลี่ยนทิศทางไปไฟล์ พวกมันจะแค่เติมไฟล์ด้วยขยะที่ไม่จำเป็น คุณแค่อยากเห็นผลลัพธ์ที่เจอ แต่เมื่อคุณต้องการข้อความข้อผิดพลาด ใช้ 2>&1 ซึ่งเปลี่ยนทิศทาง stderr ไป stdout
grep -r L2TP /etc 2>&1 | tee somefile
ด้วยคำสั่งนี้ คุณจะสังเกตว่า somefile ตอนนี้ก็มีข้อความข้อผิดพลาดด้วย
สรุป
หวังว่าบทช่วยสอนนี้ครอบคลุมทุกสิ่งที่คุณต้องการเพื่อใช้ประโยชน์สูงสุดจากคำสั่ง tee แต่หากคุณพบสถานการณ์ที่คุณติดกับ tee ให้ความคิดเห็นด้านล่าง เราอาจช่วยได้