Tại sao đầu ra của một số chương trình Linux không chuyển sang STDOUT hay STDERR?


21

Tại sao đầu ra của một số chương trình Linux không chuyển sang STDOUT hay STDERR?

Trên thực tế, tôi muốn biết làm thế nào để nắm bắt tất cả đầu ra chương trình một cách đáng tin cậy, bất kể nó sử dụng "luồng" nào. Vấn đề tôi gặp phải là một số chương trình dường như không để đầu ra của chúng bị bắt.

Một ví dụ là lệnh 'time':

time sleep 1 2>&1 > /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

hoặc là

time sleep 1 &> /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

Tại sao tôi thấy đầu ra cả hai lần? Tôi hy vọng tất cả sẽ được dẫn vào / dev / null .

Luồng đầu ra nào đang sử dụng thời gian và làm cách nào tôi có thể chuyển nó thành một tệp?

Một cách để giải quyết vấn đề là tạo tập lệnh Bash , ví dụ, combine.shcó chứa lệnh này:

$@ 2>&1

Sau đó, đầu ra của 'thời gian' có thể được nắm bắt theo cách chính xác:

combine.sh time sleep 1 &> /dev/null

(không thấy đầu ra - chính xác)

Có cách nào để đạt được những gì tôi muốn mà không cần sử dụng tập lệnh kết hợp riêng không?


3
trước tiên, bạn nên đảo ngược thứ tự: 2>&1 > /dev/nullcó nghĩa là "2 bây giờ đi đến nơi 1 đi (nghĩa là thiết bị đầu cuối, theo mặc định), và sau đó 1 bây giờ chuyển sang / dev / null (nhưng 2 vẫn đi đến thiết bị đầu cuối!). sử dụng >/dev/null 2>&1để nói "1 đi ngay bây giờ đến / dev / null, sau đó 2 đi đến nơi 1 đi (nghĩa là cũng đến / dev / null). Điều này vẫn không hoạt động ở đây vì thời gian tích hợp sẽ không được chuyển hướng, nhưng nói chung là chính xác hơn (ví dụ: nó sẽ hoạt động nếu bạn sử dụng / usr / bin / time). Hãy nghĩ về "2> & 1" khi sao chép "hướng" của 1 thành 2, chứ không phải là 2 đi 1
Olivier Dulac

Câu trả lời:


38

Câu hỏi này được giải quyết trong BashFAQ / 032 . Trong ví dụ của bạn, bạn sẽ:

{ time sleep 1; } 2> /dev/null

Lý do tại sao

time sleep 1 2>/dev/null

không hành xử theo cách bạn mong đợi là vì với cú pháp đó, bạn sẽ muốn sử timedụng lệnh sleep 1 2>/dev/null(vâng, lệnh sleep 1với stderr được chuyển hướng đến /dev/null). Nội dung timehoạt động theo cách đó để làm cho điều này thực sự có thể.

Các bash BUILTIN thực sự có thể làm được điều này bởi vì ... tốt, đó là một dựng sẵn. Một hành vi như vậy sẽ là không thể với lệnh bên ngoài timethường được đặt trong /usr/bin. Thật:

$ /usr/bin/time sleep 1 2>/dev/null
$

Bây giờ, câu trả lời cho câu hỏi của bạn

Tại sao đầu ra của một số chương trình linux không chuyển sang STDOUT hay STDERR?

là: nó, đầu ra đi đến thiết bị xuất chuẩn hoặc thiết bị xuất chuẩn .

Hi vọng điêu nay co ich!


2
bạn có thể tạo các fd khác và có các lệnh rõ ràng đi đến các lệnh đó (ví dụ: trong tập lệnh bash exec 3>/some/file ; ls >&3 ;:)
Olivier Dulac

@OlivierDulac Chắc chắn, hoặc thậm chí đơn giản hơn với coprocnội dung. Nhưng đó không phải là trường hợp của timenội dung.
gniourf_gniourf

@ gniourf-gniourf: Tôi đã bình luận vì câu của bạn "đầu ra chuyển sang stdout hoặc stderr" ^^
Olivier Dulac

14

Câu hỏi cụ thể của bạn về timeBUILTIN đã được trả lời, nhưng có được một số lệnh mà không viết hoặc để stdouthoặc stderr. Một ví dụ kinh điển là lệnh Unix crypt. cryptkhông có đối số mã hóa đầu vào tiêu chuẩn stdinvà ghi nó vào đầu ra tiêu chuẩn stdout. Nó nhắc người dùng nhập mật khẩu bằng cách sử dụng getpass()mặc định sẽ đưa ra lời nhắc /dev/tty. /dev/ttylà thiết bị đầu cuối hiện tại. Viết để /dev/ttycó tác dụng viết vào thiết bị đầu cuối hiện tại (nếu có, xem isatty()).

Lý do cryptkhông thể ghi stdoutlà vì nó ghi đầu ra được mã hóa stdout. Ngoài ra, tốt hơn là nhắc nhở /dev/ttythay vì viết thư để stderrnếu người dùng chuyển hướng stdoutstderr, dấu nhắc vẫn được nhìn thấy. (Vì lý do tương tự, cryptkhông thể đọc mật khẩu từ đó stdin, vì nó được sử dụng để đọc dữ liệu cần mã hóa.)


2
+1. Ít liên quan hơn với OP, nhưng phù hợp hơn với mọi người đi qua "Tại sao đầu ra của một số chương trình linux không chuyển sang STDOUT hay STDERR?" thông qua Google. :-)
ruakh

0

time sleep 1 > /dev/null 2>&1# chuyển hướng đầu ra "ngủ" làm null. Sau đó, "thời gian" ghi đầu ra của chính nó, không có chuyển hướng. Nó giống như " time (sleep 1 > /dev/null 2>&1)".

(time sleep 1) > /dev/null 2>&1 # chạy "thời gian ngủ 1", sau đó chuyển hướng đầu ra của nó thành null.

[]S


-1

Vấn đề trong trường hợp của bạn là chuyển hướng hoạt động theo cách khác. Bạn đã viết

time sleep 1 2>&1 > /dev/null

Điều này chuyển hướng đầu ra tiêu chuẩn đến /dev/nullvà sau đó chuyển hướng lỗi tiêu chuẩn sang đầu ra tiêu chuẩn.

Để chuyển hướng tất cả đầu ra, bạn phải viết

time sleep 1 > /dev/null 2>&1 

Sau đó, lỗi tiêu chuẩn sẽ được chuyển hướng đến đầu ra tiêu chuẩn và sau đó tất cả đầu ra tiêu chuẩn (chứa lỗi tiêu chuẩn) sẽ được chuyển hướng đến /dev/null.


Điều này không hoạt động với bash dựng sẵn time . Xem câu trả lời của tôi cho một số giải thích.
gniourf_gniourf

+1 vì đây là câu trả lời hữu ích cho một câu hỏi tương tự. Mặc dù @Olivier giải thích nó tốt hơn trong phần bình luận cho câu hỏi trên.
Will Sheppard
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.