วิธีรันไทม์บนหลายคำสั่งและเขียนเอาต์พุตเวลาไปยังไฟล์?


66

ฉันต้องการเรียกใช้timeคำสั่งเพื่อวัดเวลาของคำสั่งต่างๆ

สิ่งที่ฉันต้องการจะทำคือ:

  • วัดเวลาในการทำงานของพวกเขาทั้งหมดเข้าด้วยกัน
  • เขียนtimeเอาต์พุตไปยังไฟล์
  • เขียนSTDERRจากคำสั่งที่ฉันวัดSTDERR

สิ่งที่ฉันไม่ต้องการทำคือ

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

สิ่งที่ฉันพยายาม:

/usr/bin/time --output=outtime -p echo "a"; echo "b";

ใช้งานไม่ได้ทำงานtimeเฉพาะกับเครื่องแรกเท่านั้น

/usr/bin/time --output=outtime -p ( echo "a"; echo "b"; )

ไม่ทำงาน(เป็นโทเค็นที่ไม่คาดคิด

/usr/bin/time --output=outtime -p { echo "a"; echo "b"; }

ไม่ทำงาน "ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว"

/usr/bin/time --output=outtime -p ' echo "a"; echo "b";'

ไม่ทำงาน "ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว"

time ( echo "a"; echo "b"; ) 2>outtime

ไม่ทำงานเพราะมันเปลี่ยนเส้นทางทั้งหมดSTDERRเข้าouttime; ฉันต้องการเฉพาะtimeผลลัพธ์ที่นั่น

และแน่นอนว่า,

time --output=outime echo "a";

--output=outime: command not foundไม่ทำงานตั้งแต่

ฉันจะทำมันได้อย่างไร

คำตอบ:



8

ลองสิ่งนี้:

% (time ( { echas z; echo 2 } 2>&3 ) ) 3>&2 2>timeoutput
zsh: command not found: echas
2
% cat timeoutput                                
( { echas z; echo 2; } 2>&3; )  0.00s user 0.00s system 0% cpu 0.004 total

คำอธิบาย:

timeอันดับแรกเราต้องไปหาวิธีที่จะเปลี่ยนเส้นทางการส่งออกของที่ เนื่องจากtimeเป็น shell builtin จึงใช้บรรทัดคำสั่งแบบเต็มเป็นคำสั่งในการวัดรวมถึงการเปลี่ยนเส้นทาง ดังนั้น,

% time whatever 2>timeoutput
whatever 2> timeoutput  0.00s user 0.00s system 0% cpu 0.018 total
% cat timeoutput 
zsh: command not found: whatever

[หมายเหตุ: ความคิดเห็นของ janos บอกเป็นนัยว่านี่ไม่ใช่กรณีbashนี้] เราสามารถบรรลุการเปลี่ยนเส้นทางของtimeเอาต์พุตโดยเรียกใช้timeใน subshell แล้วเปลี่ยนเส้นทางเอาต์พุตของ subshell นั้น

% (time whatever) 2> timeoutput
% cat timeoutput 
zsh: command not found: whatever
whatever  0.00s user 0.00s system 0% cpu 0.018 total

ตอนนี้เราได้เปลี่ยนเส้นทางผลลัพธ์เรียบร้อยtimeแล้ว แต่เอาต์พุตนั้นผสมกับเอาต์พุตข้อผิดพลาดของคำสั่งที่เราวัด ในการแยกทั้งสองเราใช้ file descriptor เพิ่มเติม

ใน "นอก" เรามี

% (time ... ) 3>&2 2>timeout

ซึ่งหมายความว่า: สิ่งใดก็ตามที่ถูกเขียนไปยัง file descriptor 3 จะถูกส่งออกไปยัง file descriptor 2 ที่เดียวกัน (ข้อผิดพลาดมาตรฐาน) ที่กำลังส่งออกตอนนี้ (เทอร์มินัล) timeoutและจากนั้นเราเปลี่ยนเส้นทางข้อผิดพลาดมาตรฐานไปยังแฟ้ม

ตอนนี้เรามี: ทุกอย่างที่เขียนไปยัง stdout และ fd 3 จะไปที่เทอร์มินัลและทุกอย่างที่เขียนไปยัง stderr จะไปที่ไฟล์ สิ่งที่เหลือคือการเปลี่ยนเส้นทางของคำสั่ง stderr ไปยัง fd 3

% (time whatever 2>&3) 3>&2 2>timeout

ตอนนี้เพื่อให้เวลาในการวัดมากกว่าหนึ่งคำสั่งเราจำเป็นต้องเรียกใช้พวกเขาใน subshell (อื่น ๆ !) (ภายในวงเล็บ) และเพื่อเปลี่ยนเส้นทางข้อผิดพลาดของพวกมันทั้งหมดไปยัง fd 3 เราต้องจัดกลุ่มพวกมันไว้ในวงเล็บปีกกา

ดังนั้นในที่สุดเรามาถึงที่:

% (time ( { whatever; ls } 2>&3 ) ) 3>&2 2>timeoutput

แค่นั้นแหละ.


นี่เป็นข้อผิดพลาดทางไวยากรณ์ในเปลือก POSIX น่าจะเป็น bashism หรือไม่?
josch

@josch เชลล์ที่ใช้ที่นี่คือ zsh
กัส

6

ไม่ใช่คำตอบที่ถูกต้อง แต่เกี่ยวข้องกับคำถามมาก
รับสถิติเวลาสำหรับหลาย ๆ โปรแกรมที่ต้องใช้วงเล็บรวม แยกคำสั่งด้วยเครื่องหมายอัฒภาค

time ( command1 ; command2 )

1
นี่เป็นสิ่งที่ดี ดีกว่าให้ใช้ && ระหว่างคำสั่งเช่นtime ( command1 && command2 )เพื่อที่ว่าหากคำสั่งแรกล้มเหลว มันจะไม่ดำเนินการอื่น ๆ
bikashg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.