เปลี่ยนเส้นทางการส่งออกของคำสั่งเวลาในยูนิกซ์เป็นตัวแปรในทุบตี?


13

ฉันแค่อยากจะจับเอาท์พุทของคำสั่งเวลาเช่น:

X=$(time ls)

หรือ

$(time ls) | grep real

ฟังก์ชั่นเวลาถ่มน้ำลายไปที่คอนโซลแม้ว่า ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


12

X = `(time ls) 2> & 1 | grep real`


คุณไม่ต้องการ subshell เพียงเพื่อtime; คำตอบของเดนนิสวิลเลียมสันนั้นดีกว่าในเรื่องนั้น
musiphil

11

ดูBashFAQ / 032

$ # captures output of command and time
$ time=$( TIMEFORMAT="%R"; { time ls; } 2>&1 )    # note the curly braces

$ # captures the time only, passes stdout through
$ exec 3>&1 4>&2
$ time=$(TIMEFORMAT="%R"; { time ls 1>&3 2>&4; } 2>&1)
bar baz
$ exec 3>&- 4>&-

เวลาจะมีลักษณะเหมือน "0.000" TIMEFORMAT="%R"ซึ่งใช้เป็นเวลา "ของจริง"


คุณช่วยอธิบายหน่อยได้ไหมว่ามันทำงานอย่างไร ฉันใช้ตัวอย่างข้อมูลสไตล์การขนส่งสินค้านี้มาหลายปีแล้ว สตรีม 3 และ 4 คืออะไร และ '-' ?
Sirex

1
@Sirex: สตรีม 3 และ 4 เป็นสตรีมที่สร้างขึ้นโดยexecคำสั่งในคำตอบของฉันโดยใช้ตัวอธิบายไฟล์ที่มีอยู่ ตัวอธิบายไฟล์ใด ๆ ที่มีอยู่สามารถใช้ได้ สตรีม 3 และ 4 เป็นสำเนา 1 ( stdout) และ 2 ( stderr) ตามลำดับ สิ่งนี้อนุญาตให้เอาต์พุตของlsการส่งผ่านเป็นปกติไปยังstdoutและstderrผ่าน 3 และ 4 ในขณะที่เอาต์พุตของtime(ซึ่งไปตามปกติstderr) ถูกเปลี่ยนเส้นทางไปยังต้นฉบับstdout(1) จากนั้นถูกดักจับในตัวแปรโดยใช้การแทนที่คำสั่ง อย่างที่คุณเห็นในตัวอย่างของฉันชื่อไฟล์barและbazเอาต์พุตไปยังเทอร์มินัล ...
หยุดชั่วคราวจนกว่าจะมีประกาศ

1
... -เมื่อเสร็จแล้วลำธารพิเศษถูกปิดใช้ต่อท้าย
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

4

เวลาเขียนเอาต์พุตไปยัง STDERR มากกว่า STDOUT การทำให้เรื่องแย่ลงโดยค่าเริ่มต้น 'time' เป็นคำสั่ง shell builtin ดังนั้นหากคุณลอง 'time ls 2> & 1' the '2> & 1' จะใช้กับ 'ls' เท่านั้น

วิธีแก้ปัญหาอาจเป็นดังนี้:

/usr/bin/time -f 'real %e' -o OUTPUT_FILE ls > /dev/null 2>&1<br>
REALTIME=$(cat OUTPUT_FILE | cut -f 2 -d ' ')

มีวิธีแฟนซีมากกว่าที่จะทำ แต่นั่นเป็นวิธีที่ชัดเจน / ง่าย


ฉันสนใจที่จะทำสิ่งนี้โดยไม่ใช้ -o คุณช่วยโพสต์หนึ่งในวิธีแฟนซีที่คุณนึกถึง :)
David Doria

0

@Dennis Williamson คำตอบนั้นยอดเยี่ยม แต่ก็ไม่ได้ช่วยให้คุณเก็บผลลัพธ์ของคำสั่งไว้ในตัวแปรเดียวและเอาท์พุทของtimeตัวแปรอื่น สิ่งนี้ไม่สามารถทำได้โดยใช้ file descriptors

หากคุณต้องการบันทึกระยะเวลาที่โปรแกรมใช้ในการทำงานคุณสามารถทำได้โดยเพียงแค่ลบเวลาเริ่มต้นจากเวลาสิ้นสุด นี่คือตัวอย่างง่ายๆที่แสดงจำนวนมิลลิวินาทีที่โปรแกรมใช้ในการทำงาน:

START_TIME=$(date +%s%3N)
OUTPUT=$(ls -l)
ELAPSED_TIME=$(expr $(date +%s%3N) - $START_TIME)
echo "Command finished in $ELAPSED_TIME milliseconds"

นี่ไม่ค่อยแม่นยำเท่าtimeคำสั่ง แต่ควรทำงานได้อย่างสมบูรณ์แบบสำหรับสคริปต์ทุบตีส่วนใหญ่

น่าเสียดายที่dateคำสั่งของ Mac ไม่รองรับ%Nรูปแบบ แต่คุณสามารถติดตั้งcoreutils( brew install coreutils) และใช้งานได้gdate:

START_TIME=$(gdate +%s%3N)
OUTPUT=$(ls -l)
ELAPSED_TIME=$(expr $(gdate +%s%3N) - $START_TIME)
echo "Command finished in $ELAPSED_TIME milliseconds"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.