Viết đầu ra của `time` trong một tệp, tại sao cần phải có dấu ngoặc đơn?


18

timeghi vào stderr, vì vậy người ta sẽ cho rằng việc thêm 2>&1vào dòng lệnh sẽ định tuyến đầu ra của nó tới stdout. Dường như không hiệu quả:

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

Chỉ với dấu ngoặc đơn, nó hoạt động:

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

Tại sao dấu ngoặc đơn cần thiết trong trường hợp này? Tại sao không được time wchiểu là một lệnh duy nhất ?


3
Lưu ý rằng kết quả sẽ khác nhau tùy thuộc vào việc timetừ khóa shell hay /usr/bin/time. Có thể có một số bộ mô tả liên quan ở đây (vỏ và những bộ được gắn vào một timequy trình). Và đừng quên những điều được ngụ ý bởi ()subshell. ( chờ đợi một chuyên gia bash : p)
John WH Smith

Câu trả lời:


24

Trong ksh, bashzsh, timekhông phải là một lệnh (dựng sẵn hay không), đó là một từ dành riêng trong ngôn ngữ như forhoặc while.

Nó được sử dụng để đặt thời gian cho một đường ống 1 .

Trong:

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

Bạn có cú pháp đặc biệt báo cho shell chạy đường ống đó:

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

Và báo cáo thống kê thời gian cho nó.

Trong:

time cmd > output 2> error

Tương tự như vậy, bạn đang định thời gian cho cmd > output 2> errorlệnh và số liệu thống kê thời gian vẫn tiếp tục trên stderr của shell.

Bạn cần:

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

Hoặc là:

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

Để stderr của shell được chuyển hướng đến timing-outputtrước khi cấu trúc thời gian (một lần nữa, không phải lệnh ) được sử dụng (ở đây theo thời gian cmd > output 2> error 3>&-).

Bạn cũng có thể chạy timecấu trúc đó trong một lớp con có chuyển hướng stderr của nó:

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

Nhưng subshell đó là không cần thiết ở đây, bạn chỉ cần stderr được chuyển hướng tại thời điểm mà timecấu trúc được gọi.

Hầu hết các hệ thống cũng có một timelệnh. Bạn có thể gọi cái đó bằng cách vô hiệu hóa timetừ khóa. Tất cả những gì bạn cần làm là trích dẫn từ khóa đó bằng cách nào đó vì từ khóa chỉ được công nhận như vậy khi nghĩa đen.

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

Nhưng hãy cẩn thận định dạng có thể khác nhau và tiêu chuẩn của cả hai timecmdsẽ được hợp nhất vào error-and-timing-output.

Ngoài ra, timelệnh, trái ngược với timecấu trúc không thể thời gian đường ống hoặc lệnh ghép hoặc hàm hoặc hàm dựng ...

Nếu nó là một lệnh dựng sẵn, nó có thể có thời gian gọi các hàm hoặc hàm dựng, nhưng nó không thể chuyển hướng thời gian hoặc đường ống hoặc lệnh ghép.


1 Lưu ý rằng bashcó (lỗi có thể được coi là) một lỗi theo đó time (cmd) 2> file(nhưng không phải là time cmd | (cmd2) 2> fileví dụ) chuyển hướng đầu ra thời gian tớifile


Chà, tôi thường nhấn mạnh vào đầu mình để nhớ rằng đó timelà một từ khóa, không phải là một shellin.
cuonglm

Cảm ơn các mẹo về việc sử dụng 'time'để có được thực thi-- dễ dàng hơn viết /usr/bin/time(hoặc thậm chí command time:-)).
alexis

@alexis cũng vậy \time.
ctrl-alt-delor

7

Không có lệnh đặt tên time wc, timewcđược tách ra từ trong vỏ.

Bây giờ, thường có hai chương trình riêng biệt được đặt tên time, một là từ khóa shell, một chương trình khác là lệnh bên ngoài . Trong shell timelà một từ khóa shell, khi bạn gõ time wc ..., shell đã sử dụng từ khóa của nó timethay vì tiện ích thời gian bên ngoài .

Khi shell sử dụng timetừ khóa, nó không cần rẽ nhánh () tiến trình mới, timetiêu chuẩn hiện tại và lỗi tiêu chuẩn không được thay đổi. Phần chuyển hướng trong:

time wc file > wc.out 2>&1

wcchỉ ảnh hưởng .

Khi bạn sử dụng lệnh ghép(list) :

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

Shell chạy time wc filebên trong một lớp con, (time wc file)được coi là một lệnh duy nhất và phần chuyển hướng ảnh hưởng đến đầu ra tiêu chuẩn và lỗi tiêu chuẩn của nó, hiện bao gồm cả hai timewc.


Bạn có thể tạo ra hiệu ứng tương tự, mà không phải trả chi phí cho quá trình mới bằng cách sử dụng một hình thức lệnh nhóm khác {list;}:

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

Nếu bạn sử dụng bên ngoài time, thì bạn không gặp phải vấn đề này, vì nó đã được chạy trong quy trình mới:

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

Có sự khác biệt thực tế giữa việc sử dụng time/usr/bin/time? Là các thực thi được gọi là chức năng giống nhau?
Hashim

2

Bởi vì timebạn đang thực hiện là bash dựng sẵn. Bash xử lý nó theo cách đặc biệt như vậy.

Nếu bạn sẽ sử dụng timenhị phân thực , nó sẽ hoạt động chính xác theo cách bạn mong đợi:

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

Mặc dù đầu ra của lần này hơi khác một chút:

 $ /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
Nếu nó là một nội trang, nó sẽ không thành vấn đề. Vấn đề là đó là một từ khóa trong ngôn ngữ. time cmd > outputlần cmd > outputlệnh, và time foo | barlần foo | bar.
Stéphane Chazelas

1

Nó không phải timelà viết thông tin thời gian. Nội dung timelàm cho shell viết điều này sau khi lệnh đã hoàn thành. Nhưng chuyển hướng chỉ ảnh hưởng đến lệnh.

Trong (time ...)trường hợp chuyển hướng được áp dụng cho toàn bộ khung con.


0

Bởi vì thời gian là một vỏ được tích hợp sẵn, nó ghi vào stderr của shell , chứ không phải là stderr của lệnh.

Sử dụng dấu ngoặc đơn buộc toàn bộ lệnh vào một vỏ con mà stderr có thể được chuyển hướng.

sử dụng dấu ngoặc nhọn tạo ra kết quả tương tự mà không thực sự bắt đầu một khung con

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

(vâng, bạn cần dấu chấm phẩy)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.