เขียนเอาต์พุตของ "time" ในไฟล์ทำไมต้องใช้วงเล็บ?


18

timeเขียนไปstderrดังนั้นใครจะคิดว่าการเพิ่มบรรทัดคำสั่งควรเส้นทางการส่งออกไปยัง2>&1 stdoutแต่นี่ไม่ได้ผล:

test@debian:~$ cat file 
one two three four
test@debian:~$ time wc file > wc.out 2>&1

real    0m0.022s
user    0m0.000s
sys     0m0.000s
test@debian:~$ cat wc.out 
 1  4 19 file

ใช้งานได้กับวงเล็บเท่านั้น:

test@debian:~$ (time wc file) > wc.out 2>&1
test@debian:~$ cat wc.out 
 1  4 19 file

real    0m0.005s
user    0m0.000s
sys     0m0.000s

เหตุใดจึงต้องใช้วงเล็บในกรณีนี้ เหตุใดจึงไม่time wcตีความว่าเป็นคำสั่งเดียว ?


3
หมายเหตุว่าผลที่ได้จะแตกต่างกันขึ้นอยู่กับว่าเป็นคำสำคัญเปลือกหรือtime /usr/bin/timeอาจมีชุดคำอธิบายหลายชุดที่เกี่ยวข้องที่นี่ (เปลือกของและชุดที่แนบกับtimeกระบวนการ) และอย่าลืมเกี่ยวกับสิ่งที่แสดงโดย()subshell ( กำลังรอผู้เชี่ยวชาญด้านทุบตี : p)
John WH Smith

คำตอบ:


24

ในksh, bashและzsh, timeไม่ได้เป็นคำสั่ง (ในตัวหรือไม่) มันเป็นคำสงวนในภาษาที่เหมือนหรือforwhile

โดยจะใช้เวลาในการท่อ1

ใน:

time for i in 1 2; do cmd1 "$i"; done | cmd2 > redir

คุณมีไวยากรณ์พิเศษที่บอกให้เชลล์เรียกใช้ไพพ์ไลน์นั้น:

for i in 1 2; do cmd1 "$i"; done | cmd2 > redir

และรายงานสถิติเวลาของมัน

ใน:

time cmd > output 2> error

ก็เหมือนกันคุณเวลาcmd > output 2> errorคำสั่งและสถิติเวลายังคงไปบน stderr เปลือก

คุณต้องการ:

{ time cmd > output 2> error; } 2> timing-output

หรือ:

exec 3>&2 2> timing-output
time cmd > output 2> error 3>&-
exec 2>&3 3>&-

สำหรับ stderr ของเชลล์ที่จะถูกเปลี่ยนทิศทางไปtiming-outputก่อนการสร้างเวลา (อีกครั้งไม่ใช่คำสั่ง ) จะถูกใช้ (ที่นี่เป็นครั้งคราวcmd > output 2> error 3>&-)

คุณยังสามารถเรียกใช้timeงานโครงสร้างนั้นในsubshellที่เปลี่ยนเส้นทาง stderr ได้:

(time cmd > output 2> error) 2> timing-output

แต่ไม่จำเป็นต้องใช้ subshell ที่นี่คุณจะต้องเปลี่ยนเส้นทาง stderr ในเวลาที่การtimeสร้างถูกเรียกใช้

ระบบส่วนใหญ่ก็มีtimeคำสั่ง คุณสามารถเรียกใช้อันนั้นโดยปิดการใช้งานtimeคำหลัก สิ่งที่คุณต้องทำคืออ้างว่าคำหลักใดก็ตามที่เป็นคำหลักที่ได้รับการยอมรับเช่นเมื่อตัวอักษร

'time' cmd > output 2> error-and-timing-output

แต่ระวังรูปแบบอาจแตกต่างกันและ stderr ของทั้งสองtimeและcmdจะถูกรวมเข้าerror-and-timing-outputด้วยกัน

นอกจากนี้timeคำสั่งซึ่งตรงข้ามกับการtimeสร้างไม่สามารถกำหนดเวลาไปป์ไลน์หรือคำสั่งผสมหรือฟังก์ชันหรือเชลล์บิลด์อิน ...

หากเป็นคำสั่ง builtin มันอาจสามารถกำหนดเวลาการเรียกใช้ฟังก์ชันหรือบิลด์อินได้ แต่ไม่สามารถเปลี่ยนเส้นทางหรือไพพ์ไลน์หรือคำสั่งผสมได้


1ทราบว่าbashได้ (สิ่งที่ถือได้ว่าเป็น) ข้อผิดพลาดโดยtime (cmd) 2> file( แต่ไม่ได้time cmd | (cmd2) 2> fileเป็นต้น) การเปลี่ยนเส้นทางการส่งออกระยะเวลาในการfile


ฉันมักจะเน้นหัวของฉันให้จำว่าtimeเป็นคำหลักไม่ใช่ตัวเชลล์ในตัว
cuonglm

ขอบคุณสำหรับเคล็ดลับเกี่ยวกับการใช้งาน'time'เพื่อให้สามารถเรียกใช้งาน - handier ได้ดีกว่าการเขียน/usr/bin/time(หรือแม้แต่command time:-))
alexis

@alexis \timeยัง
ctrl-alt-delor

7

มีคำสั่งไม่มีชื่อtime wc, timeและwcจะแยกคำในเปลือก

ขณะนี้มีอยู่บ่อยครั้งที่สองแยกโปรแกรมชื่อtimeหนึ่งที่มีคำหลักเปลือกอีกคนหนึ่งเป็นคำสั่งภายนอก ในเปลือกหอยซึ่งtimeเป็นคำหลักเปลือกเมื่อคุณพิมพ์time wc ...เปลือกใช้คำหลักtimeแทนภายนอกยูทิลิตี้เวลา

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

time wc file > wc.out 2>&1

ส่งผลกระทบต่อwcเท่านั้น

เมื่อคุณใช้คำสั่งผสม(list) :

(time wc file) > wc.out 2>&1

วิ่งเปลือกtime wc fileภายใน subshell ที่(time wc file)ได้รับการพิจารณาเดียวคำสั่งและเป็นส่วนหนึ่งการเปลี่ยนเส้นทางส่งผลกระทบต่อการส่งออกมาตรฐานและข้อผิดพลาดมาตรฐานซึ่งขณะนี้รวมทั้งและtimewc


คุณสามารถสร้างเอฟเฟกต์เดียวกันได้โดยไม่ต้องเสียค่าใช้จ่ายในการฟอร์กกระบวนการใหม่โดยใช้คำสั่งการจัดกลุ่มรูปแบบอื่น{list;}:

{time wc file;} > wc.out 2>&1

หากคุณใช้ภายนอกtimeคุณจะไม่ประสบปัญหานี้เพราะทำงานในกระบวนการใหม่:

/usr/bin/time wc file > wc.out 2>&1

มีความแตกต่างในทางปฏิบัติระหว่างการใช้timeและ/usr/bin/time? ไฟล์เอ็กซีคิ้วท์จะถูกเรียกใช้เหมือนกันหรือไม่?
Hashim

2

เพราะtimeคุณกำลังดำเนินการคือทุบตี builtin Bash ประมวลผลด้วยวิธีพิเศษดังกล่าว

หากคุณจะใช้timeไบนารี่จริงมันจะทำงานตามที่คุณคาดหวัง:

/usr/bin/time wc file > wc.out 2>&1

แม้ว่าผลลัพธ์ของเวลานี้จะแตกต่างกันเล็กน้อย:

 $ /usr/bin/time wc file > wc.out 
0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata1900maxresident)k
0inputs+8outputs (0major+82minor)pagefaults 0swaps

9
ถ้ามันเป็นแบบ builtin มันจะไม่เป็นปัญหา ปัญหาคือว่ามันเป็นคำหลักในภาษา time cmd > outputครั้งcmd > outputคำสั่งครั้งtime foo | bar foo | bar
Stéphane Chazelas

1

ไม่ใช่timeว่าจะเขียนข้อมูลเวลา builtin timeทำให้เชลล์เขียนสิ่งนี้หลังจากคำสั่งเสร็จสิ้น แต่การเปลี่ยนเส้นทางมีผลกับคำสั่งเท่านั้น

ใน(time ...)กรณีที่การเปลี่ยนเส้นทางถูกนำไปใช้กับ subshell ทั้งหมด


0

เพราะเวลาคือเชลล์บิวด์อินมันจึงเขียนไปยังstderr ของเชลล์มากกว่า stderr ของคำสั่ง

การใช้วงเล็บจะบังคับให้คำสั่งทั้งหมดลงในเปลือกลูกซึ่ง stderr สามารถเปลี่ยนเส้นทางได้

การใช้วงเล็บปีกกาให้ผลลัพธ์ที่คล้ายกันโดยไม่ต้องเริ่ม subshell

  { time who ; } > /tmp/timwho >& /tmp/xx 

(ใช่คุณต้องใช้เครื่องหมายอัฒภาค)

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