สำหรับวิธีการเปลี่ยนเส้นทางคำสั่งจำนวนมากในครั้งเดียว:
#!/bin/bash
{
somecommand
somecommand2
somecommand3
} 2>&1 | tee -a $DEBUGLOG
สาเหตุที่โซลูชันดั้งเดิมของคุณใช้งานไม่ได้: exec 2> & 1 จะเปลี่ยนเส้นทางข้อผิดพลาดมาตรฐานไปยังเอาต์พุตมาตรฐานของเชลล์ซึ่งถ้าคุณเรียกใช้สคริปต์จากคอนโซลจะเป็นคอนโซลของคุณ การเปลี่ยนเส้นทางไปป์บนคำสั่งจะเปลี่ยนเส้นทางเอาต์พุตมาตรฐานของคำสั่งเท่านั้น
ในมุมมองของsomecommand
เอาต์พุตมาตรฐานจะเชื่อมต่อกับtee
ไพพ์ที่เชื่อมต่อและข้อผิดพลาดมาตรฐานไปที่ไฟล์ / pseudofile เดียวกับข้อผิดพลาดมาตรฐานของเชลล์ซึ่งคุณเปลี่ยนเส้นทางไปยังเอาต์พุตมาตรฐานของเชลล์ซึ่งจะเป็น คอนโซลถ้าคุณเรียกใช้โปรแกรมของคุณจากคอนโซล
วิธีหนึ่งที่จะอธิบายได้อย่างแท้จริงคือดูว่าเกิดอะไรขึ้นจริง:
สภาพแวดล้อมดั้งเดิมของเชลล์ของคุณอาจมีลักษณะเช่นนี้หากคุณเรียกใช้จากเทอร์มินัล:
stdin -> /dev/pts/42
stdout -> /dev/pts/42
stderr -> /dev/pts/42
หลังจากที่คุณเปลี่ยนเส้นทางข้อผิดพลาดมาตรฐานไปยังเอาต์พุตมาตรฐาน ( exec 2>&1
) คุณจะไม่เปลี่ยนแปลงอะไรเลย แต่ถ้าคุณเปลี่ยนเส้นทางการส่งออกมาตรฐานของสคริปต์ไปยังไฟล์คุณจะพบกับสภาพแวดล้อมเช่นนี้:
stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /dev/pts/42
จากนั้นการเปลี่ยนเส้นทางข้อผิดพลาดมาตรฐานของเชลล์ไปที่เอาต์พุตมาตรฐานจะเป็นดังนี้:
stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /your/file
การรันคำสั่งจะสืบทอดสภาพแวดล้อมนี้ หากคุณรันคำสั่งและไพพ์มันเพื่อทีสภาพแวดล้อมของคำสั่งจะเป็น:
stdin -> /dev/pts/42
stdout -> pipe:[4242]
stderr -> /your/file
ดังนั้นข้อผิดพลาดมาตรฐานของคำสั่งของคุณยังคงเป็นสิ่งที่เชลล์ใช้เป็นข้อผิดพลาดมาตรฐาน
คุณสามารถเห็นสภาพแวดล้อมของคำสั่งจริงโดยดูใน/proc/[pid]/fd
: ใช้ls -l
เพื่อแสดงรายการเนื้อหาของลิงก์สัญลักษณ์ 0
ไฟล์ที่นี่เป็นที่เข้ามาตรฐาน1
คือส่งออกมาตรฐานและ2
เป็นข้อผิดพลาดมาตรฐาน หากคำสั่งเปิดไฟล์เพิ่มเติม (และโปรแกรมส่วนใหญ่ทำ) คุณจะเห็นไฟล์เหล่านั้นด้วย โปรแกรมยังสามารถเลือกที่จะเปลี่ยนเส้นทางหรือปิดการป้อนข้อมูลมาตรฐาน / ส่งออกและนำมาใช้ใหม่0
, และ1
2
|&
ทำงานเป็นทางลัดเพราะ2>&1 |
อย่างน้อยก็สะดวกกว่าเล็กน้อย