ฉันจะประสบความสำเร็จได้อย่างไร
cmd >> file1 2>&1 1>>file2
นั่นคือ stdout และ stderr ควรเปลี่ยนเส้นทางไปที่หนึ่งไฟล์ (file1) และ stdout เท่านั้น (file2) ควรเปลี่ยนเส้นทางไปที่อื่น (ทั้งในโหมดต่อท้าย)?
ฉันจะประสบความสำเร็จได้อย่างไร
cmd >> file1 2>&1 1>>file2
นั่นคือ stdout และ stderr ควรเปลี่ยนเส้นทางไปที่หนึ่งไฟล์ (file1) และ stdout เท่านั้น (file2) ควรเปลี่ยนเส้นทางไปที่อื่น (ทั้งในโหมดต่อท้าย)?
คำตอบ:
ปัญหาคือเมื่อคุณเปลี่ยนเส้นทางเอาต์พุตของคุณจะไม่สามารถใช้งานได้อีกในการเปลี่ยนเส้นทางครั้งต่อไป คุณสามารถtee
ไพพ์ไปไว้ในเชลล์ย่อยเพื่อเก็บเอาท์พุทสำหรับการเปลี่ยนเส้นทางครั้งที่สอง:
( cmd | tee -a file2 ) >> file1 2>&1
หรือถ้าคุณต้องการที่จะเห็นผลลัพธ์ใน terminal:
( cmd | tee -a file2 ) 2>&1 | tee -a file1
เพื่อหลีกเลี่ยงการเพิ่ม stderr ของคำสั่งแรกtee
ไปfile1
คุณควรเปลี่ยน stderr ของคำสั่งของคุณไปยัง file descriptor (เช่น 3) และจากนั้นเพิ่มไฟล์นี้ใน stdout อีกครั้ง:
( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1
(ขอบคุณ @ fra-san)
ด้วยzsh
:
cmd >& out+err.log > out.log
ในโหมดต่อท้าย:
cmd >>& out+err.log >> out.log
ในzsh
และmult_ios
ตัวเลือกที่ให้ไว้ไม่ได้ถูกปิดใช้งานเมื่อตัวบ่งชี้ไฟล์ (ที่นี่ 1) ถูกเปลี่ยนเส้นทางหลายครั้งสำหรับการเขียนเชลล์จะใช้บิวด์อินtee
เพื่อคัดลอกเอาต์พุตไปยังเป้าหมายทั้งหมด
cmd >& file1 > file2
คุณสามารถ: tag stdout (โดยใช้ UNBUFFERED sed, เช่น:), sed -u ...
stderr ก็ไปที่ stdout (ไม่ได้ใส่แท็กเพราะมันไม่ได้ผ่าน sed การติดแท็กนั้น) และสามารถแยก 2 ในไฟล์บันทึกผลลัพธ์
ต่อไปนี้: ช้า (สามารถปรับให้เหมาะสมอย่างจริงจังโดยใช้สำหรับสคริปต์ exlple แทนที่จะเป็นขณะที่ ... ; do ... ; เสร็จสิ้นสำหรับตัวอย่างที่จะวางไข่ subshells & คำสั่งที่ทุกบรรทัด!) แปลก (ดูเหมือนว่าฉันต้องการสเตจ 2 {} ในการเปลี่ยนชื่อหนึ่ง stdout แล้วเพิ่มอีก "stedr ผ่าน" stderr ลงไปในนั้น) ฯลฯ แต่มันคือ: " หลักฐานของแนวคิด " ที่จะพยายามเก็บไว้ คำสั่งของเอาท์พุทมากที่สุดของ stdout & stderr มากที่สุด:
#basic principle (some un-necessary "{}" to visually help see the layers):
# { { complex command ;} | sed -e "s/^/TAGstdout/" ;} 2>&1 | read_stdin_and_redispatch
#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
# to see if the order of stdout&stderr is kept
#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
\rm out.file out_AND_err.file unknown unknown2
touch existing existing2 existing3
#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs...
# avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.
{
{ for f in existing unknown existing2 unknown2 existing3 ; do ls -l "$f" ; sleep 1; done ;
} | sed -u -e "s/^/${uniquetag}/" ;
} 2>&1 | while IFS="" read -r line ; do
case "$line" in
${uniquetag}*) printf "%s\n" "$line" | tee -a out_AND_err.file | sed -e "s/^${uniquetag}//" >> out.file ;;
*) printf "%s\n" "$line" >> out_AND_err.file ;;
esac;
done;
# see the results:
grep "^" out.file out_AND_err.file
ls unknown
) เพื่อพิมพ์บางอย่างบน stderr? >&2 echo "error"
จะดี (2) tee
สามารถผนวกหลายไฟล์พร้อมกันได้ (3) ทำไมไม่เพียง แต่cat
แทนที่จะเป็นgrep "^"
? (4) สคริปต์ของคุณจะล้มเหลวเมื่อเอาท์พุท stderr _stdout_
เริ่มต้นด้วย (5) ทำไม
ls loop
จะเอาท์พุททั้งบน stdout และ stderr, ผสม (หรือ), ในลำดับที่ควบคุม, เพื่อให้เราสามารถตรวจสอบได้ว่าเราเก็บ stderr / stdout ไว้แม้จะมีการติดแท็กของ stdout 2): gnu tail, อาจ แต่ไม่ หางปกติ (เช่นบน aix.) 3): grep "^" ยังแสดงชื่อไฟล์ทั้งสอง 4): ตัวแปรนี้สามารถเปลี่ยนแปลงได้ 5): ตัวอย่างที่ซับซ้อนที่ทำงานบน oses เก่า (เช่น aix เก่า) ที่ฉันทดสอบ (ไม่มี Perl)
uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
... )
ถ้าลำดับของเอาต์พุตต้องเป็น: stdout ดังนั้น stderr ; ไม่มีวิธีแก้ปัญหาด้วยการเปลี่ยนเส้นทางเท่านั้น
stderr ต้องถูกเก็บไว้ในไฟล์ชั่วคราว
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
รายละเอียด:
วิธีเดียวที่จะเปลี่ยนเส้นทางหนึ่งเอาต์พุต (fd เช่น stdout หรือ stderr) ไปยังสองไฟล์คือการทำซ้ำ คำสั่งtee
เป็นเครื่องมือที่ถูกต้องในการทำซ้ำเนื้อหาอธิบายไฟล์ ดังนั้นความคิดเริ่มต้นที่จะมีหนึ่งเอาต์พุตในสองไฟล์คือการใช้:
... | tee file1 file2
นั่นจะสร้าง stdin ของทีออฟให้กับไฟล์ทั้งสอง (1 & 2) โดยปล่อยเอาต์พุตของทียังคงไม่ได้ใช้ แต่เราต้องผนวก (ใช้-a
) และต้องการเพียงหนึ่งสำเนา วิธีนี้แก้ปัญหาทั้งสอง:
... | tee -a file1 >>file2
ในการจัดหาtee
stdout (สิ่งที่ต้องทำซ้ำ) เราจำเป็นต้องใช้ stderr โดยตรงจากคำสั่ง วิธีหนึ่งหากคำสั่งซื้อไม่สำคัญ (ลำดับของเอาต์พุตจะ (อาจเป็นไปได้) จะถูกรักษาไว้ตามที่สร้างขึ้นแล้วแต่ว่าสิ่งใดที่ได้รับการส่งออกมาก่อนจะถูกเก็บไว้ก่อน) ทั้ง:
cmd 2>>file1 | tee -a file2 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
ตัวเลือก 2 ใช้งานได้ในเปลือกหอยบางตัวเท่านั้น ตัวเลือก 3 ใช้ subshell เพิ่มเติม (ช้ากว่า) แต่ใช้ชื่อไฟล์เพียงครั้งเดียว
แต่ถ้าstdout จะต้องเป็นอันดับแรก (ไม่ว่าจะสร้างเอาต์พุตคำสั่งใด) เราต้องจัดเก็บ stderr เพื่อผนวกเข้ากับไฟล์ที่ส่วนท้าย (โพสต์โซลูชันแรก)
sponge
:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
ในความสนใจของความหลากหลาย:
หากระบบของคุณรองรับ/dev/stderr
แล้ว
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
จะทำงาน. เอาต์พุตมาตรฐานของ the cmd
ถูกส่งไปยัง stdout และ stderr ของไปป์ไลน์ ข้อผิดพลาดมาตรฐานของการcmd
ข้ามtee
และออก stderr ของไปป์ไลน์
ดังนั้น
cmd
และcmd
, ถูกผสมมันเป็นเรื่องง่าย ๆ ในการส่งกระแสข้อมูลเหล่านั้นไปยังไฟล์ที่ถูกต้อง
เช่นเดียวกับวิธีการเกือบทุกอย่างเช่นนี้ (รวมถึงคำตอบของStéphane )
file1
อาจได้รับบรรทัดที่ไม่เป็นระเบียบ
out+err
และout
หมายถึงที่นี่ ชื่อไฟล์? สตรีมที่จะถูกเปลี่ยนเส้นทาง?