บังคับให้สคริปต์ทุบตีใช้ทีโดยไม่ต้องไพพ์จากบรรทัดคำสั่ง


20

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

ฉันมีไฟล์script.sh :

#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT
launch_applications_that_output_to_STDOUT
fini

และฉันต้องการทำสำเนา STDOUT ไปยังไฟล์script.logโดยไม่ต้องพิมพ์./script.sh | tee script.logทุกครั้ง

ขอบคุณทอม


ฉันขอโทษที่ไม่ได้พูดเรื่องนี้ก่อนหน้านี้ แต่สคริปต์ค่อนข้างยาวซึ่งเป็นสาเหตุที่ฉันกำลังมองหาวิธีแก้ปัญหาง่ายๆ ต่อท้าย | ทีออฟในแต่ละบรรทัดนั้นมากเกินไป
Tom

คำตอบ:


15

ฉันไม่สามารถใช้งานสายการบินเดียวที่ง่ายมากของ Dennis ดังนั้นนี่เป็นวิธีที่ซับซ้อนกว่านี้มาก ฉันจะลองก่อน

ตามที่กล่าวไว้คุณสามารถใช้ exec เพื่อเปลี่ยนเส้นทางข้อผิดพลาดมาตรฐาน & มาตรฐานสำหรับสคริปต์ทั้งหมด เช่น
exec > $LOGFILE 2>&1 นี้จะส่งออก stderr และ stdout ทั้งหมดไปที่ $ LOGFILE

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

# เริ่มทีการเขียนไปยังล็อกไฟล์ แต่ดึงอินพุตจากไพพ์ที่มีชื่อของเรา
tee $ LOGFILE <$ PIPEFILE &

# ประมวลผล ID กระบวนการของ tee สำหรับคำสั่ง wait
TEEPID = $!

# เปลี่ยนเส้นทางส่วนที่เหลือของ stderr และ stdout ไปยัง pipe ที่มีชื่อของเรา
exec> $ PIPEFILE 2> & 1

echo "สร้างคำสั่งของคุณที่นี่"
echo "มาตรฐานทั้งหมดของพวกเขาจะได้รับ teed"
echo "ข้อผิดพลาดมาตรฐานของพวกเขาจะ"> & 2

# ปิดคำอธิบายไฟล์ stderr และ stdout
exec 1> & - 2> & -

# รอให้ทีจบตั้งแต่ตอนนี้ปลายอีกด้านของท่อปิดแล้ว
รอ $ TEEPID

หากคุณต้องการที่จะละเอียดคุณสามารถสร้างและทำลายไฟล์ไปป์ที่มีชื่อที่จุดเริ่มต้นและจุดสิ้นสุดของสคริปต์ของคุณ

สำหรับเร็กคอร์ดนี้ฉันได้รวบรวมสิ่งเหล่านี้ส่วนใหญ่จากโพสต์บล็อกที่ให้ข้อมูลอย่างมากของคนที่แต่งตัวประหลาด: ( เวอร์ชันที่เก็บถาวร )


ดูเหมือนจะไม่ทำงานใน cygwin :-(
docwhat

โพสต์นี้ทำงานได้ดีในการให้ความรู้ ขอบคุณมาก.
เฟลิเป้อัลวาเรซ

27

เพียงเพิ่มส่วนนี้ลงในส่วนเริ่มต้นของสคริปต์ของคุณ:

exec > >(tee -ia script.log)

ที่จะผนวกเอาท์พุททั้งหมดที่ส่งไปยัง stdout ต่อท้ายไฟล์script.logโดยปล่อยให้เนื้อหาก่อนหน้านี้เข้าแทนที่ หากคุณต้องการเริ่มใหม่ทุกครั้งที่สคริปต์รันเพียงเพิ่มrm script.logก่อนหน้าexecคำสั่งนั้นหรือลบออก-aจากteeคำสั่ง

-iตัวเลือกที่เป็นสาเหตุteeที่จะไม่สนใจสัญญาณขัดจังหวะและอาจช่วยให้teeการจับเอาท์พุทชุดที่สมบูรณ์มากขึ้น

เพิ่มบรรทัดนี้เพื่อดักจับข้อผิดพลาดทั้งหมด (ในไฟล์แยกต่างหาก):

exec 2> >(tee -ia scripterr.out)

ช่องว่างระหว่าง>สัญลักษณ์หลายรายการมีความสำคัญ


ทางออกที่น่าสนใจมาก
ℝaphink

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


GNU bash รุ่น 3.2.25 (1) เป็นส่วนหนึ่งของการติดตั้ง RHEL5.3 ดูเหมือนว่านี่เป็นเวอร์ชั่นล่าสุดจากที่เก็บอย่างเป็นทางการ
Christopher Karel

ฉันเพิ่งลองภายใต้ cygwin ใน Bash 3.2.49 (23) - ปล่อยและมีข้อผิดพลาดอธิบายไฟล์ ฉันทำงานใน Bash 4.0.33 (1) - ปล่อยใน Ubuntu 9.10 แต่อาจเป็น Bash 4
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

6

นี่เป็นรุ่นที่รวมคำตอบที่โพสต์โดย Dennis Williamson ไว้ก่อนหน้านี้ ผนวกทั้ง err และ std out เข้ากับ script.log ในลำดับที่ถูกต้อง

เพิ่มบรรทัดนี้ไปยังจุดเริ่มต้นของสคริปต์ของคุณ:

exec > >(tee -a script.log) 2>&1

สังเกตช่องว่างระหว่าง>สัญญาณ ใช้งานได้สำหรับฉันใน GNU bash รุ่น 3.2.25 (1) - ปล่อย (x86_64-redhat-linux-gnu)


5

ฉันคิดว่าวิธีการอื่นเป็นดังนี้:

#!/bin/bash

# start grouping at the top
{ 
    # your script goes here
    do_something_that_outputs_stuff_to_STDOUT
    launch_applications_that_output_to_STDOUT

# and at the bottom, redirect everything from the grouped commands
} 2>&1 | tee script.log 

3

หากคุณต้องการสำเนาของเอาต์พุตคุณสามารถใช้teeวิธีนี้:

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT | tee script.log
  launch_applications_that_output_to_STDOUT | tee -a script.log
  fini

นี่จะเป็นการบันทึก stdout ไปยัง script.log เท่านั้น หากคุณต้องการแน่ใจว่าทั้ง stderr และ stdout ถูกเปลี่ยนเส้นทางใช้:

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT 2>&1 | tee script.log
  launch_applications_that_output_to_STDOUT 2>&1 | tee -a script.log
  fini

คุณสามารถทำให้มันดีขึ้นด้วยฟังก์ชันเล็กน้อย:

  #!/bin/bash

  LOGFILE="script.log"
  # Wipe LOGFILE if you don't want to add to it at each run
  rm -f "$LOGFILE"

  function logcmd() {
        local cmd="$1" logfile=${LOGFILE:-script.log} # Use default value if unset earlier

        # Launch command, redirect stderr to stdout and append to $logfile
        eval '$cmd' 2>&1 | tee -a "$logfile"
  }

  init
  logcmd "do_something_that_outputs_stuff_to_STDOUT"
  logcmd "launch_applications_that_output_to_STDOUT"
  fini

คำตอบที่ดี. ถ้าเขาสนใจ stdout จริงๆฉันจะปล่อยให้2>&1มันออกไป
DaveParillo

นั่นเป็นความจริงฉันรวม stderr เท่านั้นเพราะคำตอบก่อนหน้านี้จาก Igor ใส่ใจที่จะเปลี่ยนมันและฉันคิดว่ามันเป็นความคิดที่ดี
ℝaphink

1

คุณเพียงแค่ใช้สิ่งนี้:

script logfile.txt
your script or command here

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

และคุณสามารถเล่นสคริปต์ซ้ำถ้าคุณขี้เกียจ


อาจจะดีที่จะทราบว่าscriptเป็นแพคเกจเช่น sudo apt-get install scriptติดตั้งบนเดรส distros นอกจากนี้script -ac 'command opts' ~/Documents/some_log.scriptอาจจะมีการตรวจสอบภายในสถานีผ่านสิ่งที่ต้องการstrings ~/Documents/some_log.script | more; stringsเป็นวิธีง่าย ๆ ในการทำให้บริสุทธิ์บางอย่างของสิ่งที่script ฉีดเพื่ออนุญาตให้วิธีการที่นักเล่นของการเล่นใหม่ / ดู มิฉะนั้นคำตอบที่มั่นคง @ ฟิชชี่เพราะscriptยังเก็บสิ่งโต้ตอบเช่นกัน
S0AndS0

0
#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT > script.log 2>&1
launch_applications_that_output_to_STDOUT >> script.log 2>&1
fini

คุณสามารถดูเพิ่มเติมเกี่ยวกับวิธีการใช้งานได้ที่นี่: http://www.xaprb.com/blog/2006/06/06/what-does-devnull-21-mean/


1
ฉันเพิ่มวินาที> ในบรรทัดที่สองในคำตอบของ Igor เพื่อไม่ให้ลบบันทึกที่เขียนในบรรทัดแรก
Doug Harris

1
teeเขาต้องการสำเนาแม้ว่าดังนั้นเขาต้องการที่จะใช้
ℝaphink

@Raphink: นั่น :) ขวา
ทอม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.