Làm thế nào để biết đầu ra của một lệnh hoặc shell script là stdout hay stderr


32

Hãy để chúng tôi nói tôi chạy một lệnh hoặc shell script, và nó cho tôi đầu ra. Không biết nội bộ của lệnh này hoặc shell script, làm thế nào để xác định xem đầu ra là từ stderrhay stdout?

Ví dụ:

$ ls -ld /
drwxrwxr-t  35 root  admin  1258 Dec 11 19:16 /

đấu với

ls -ld /test
ls: /test: No such file or directory

Làm thế nào để tôi xác định rằng lệnh đầu tiên được in stdoutvà lệnh thứ hai stderr(đã thực hiện?)?


1
Vấn đề gì bạn đang cố gắng giải quyết ở đây?
Kenster

3
Đã sợ ai đó sẽ hỏi điều đó; không thực sự, chủ yếu là tò mò và hy vọng cải thiện sự hiểu biết của tôi về chuyển hướng.
KM.

7
Bạn có thể đặt stderredtrong môi trường vỏ của bạn LD_PRELOADđể có được stdoutvà có stderrmàu sắc khác nhau. Đây là một câu hỏi liên quan trong tĩnh mạch đó.
Anko

Câu trả lời:


18

Không có cách nào để biết một khi đầu ra đã được in. Trong trường hợp này, cả hai stdoutstderrđược kết nối với thiết bị đầu cuối, vì vậy thông tin về luồng được ghi đã bị mất theo thời gian văn bản xuất hiện trên thiết bị đầu cuối của bạn; họ đã được kết hợp bởi chương trình trước khi đưa nó đến thiết bị đầu cuối.

Những gì bạn có thể làm, trong trường hợp như trên, sẽ là chạy lệnh stdoutstderrchuyển hướng đến các vị trí khác nhau và xem điều gì sẽ xảy ra. Hoặc chạy nó hai lần, một lần với stdoutchuyển hướng đến /dev/nullvà một lần với stderrchuyển hướng đến /dev/null, và xem trường hợp nào trong số những trường hợp đó dẫn đến văn bản hiển thị.

Bạn có thể chuyển hướng stdoutđến /dev/nullbằng cách xử lý >/dev/nullở cuối dòng lệnh và bạn có thể chuyển hướng stderrđến /dev/nullbằng cách thêm 2>/dev/null.


9

Bạn có thể chuyển hướng thiết bị xuất chuẩn bằng cách sử dụng > filevà chuyển hướng thiết bị xuất chuẩn bằng cách sử dụng 2> file. Nhiều shell hiện đại hỗ trợ chuyển hướng đến các lệnh, vì vậy bạn có thể sử dụng sedđể làm nổi bật đầu ra nào đến từ luồng nào:

$ ls 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
1: unity_support_test.0
1: vmwareDnD

$ ls foo 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
2: ls: cannot access foo: No such file or directory

Rất đẹp! Sẽ thật tuyệt nếu người ta có thể làm nổi bật các dòng bằng màu chứ không phải tiền tố.
dotancohen

3
@dotancohen: Người ta có thể! Ví dụ:(echo "this is stdout"; echo "this is stderr" >&2) > >(sed 's/.*/\x1b[32m&\x1b[0m/') 2> >(sed 's/.*/\x1b[31m&\x1b[0m/')
PM 2Ring

Lưu ý rằng nếu có đầu ra hỗn hợp từ thiết bị xuất chuẩn và thiết bị xuất chuẩn, thiết bị xuất chuẩn đầu tiên sẽ được in, sau đó là thiết bị xuất chuẩn.
nyuszika7h

5

Các annotate-outputkịch bản từ của Debian devscriptscho phép bạn làm điều này một cách chọn lọc:

$ annotate-output ls -ld /test
14:54:22 -: Started ls -ld /test
14:54:22 E: ls: cannot access /test: No such file or directory
14:54:22 -: Finished with exitcode 2

Cột thứ hai cho biết thiết bị xuất chuẩn và thiết bị xuất chuẩn với OEtương ứng.

Có một số lưu ý, vấn đề chính được lưu ý trong các câu trả lời khác: bạn không thể làm điều này sau khi thực tế. Cả shell và terminal đều không biết cách chương trình tùy ý sử dụng các bộ mô tả tệp của nó, mặc dù shell có trách nhiệm thiết lập chúng ban đầu.

Phương pháp này sử dụng fifos, viết cho fifo có thể hành xử khác với viết cho tty và viết cho hai fifos khác nhau chắc chắn là khác nhau (vấn đề thời gian / xen kẽ tiềm năng). Ngoài ra, nó không phù hợp để sử dụng tương tác, ví dụ annotate-output bashkhông phải là một kế hoạch tuyệt vời, nhưng nó hữu ích cho nhiều mục đích khác. Có rất nhiều ví dụ về tập lệnh và hàm shell trong câu trả lời cho các câu hỏi liên quan về tô màu stdin / stdout / stderr, mạnh nhất là stderrd sử dụng sửa đổi thời gian chạy của hầu hết các chương trình để sửa đổi dữ liệu được ghi thành stderr.

Câu hỏi này mà Anko liên kết để có câu trả lời hay về chủ đề liên quan đó: tô màu đầu ra stdout / stderr: Tôi có thể định cấu hình trình bao của mình để in STDERR và STDOUT bằng các màu khác nhau không?


1
Lưu ý rằng đó là bashtập lệnh sử dụng while readcác vòng lặp và chạy một datelệnh cho mỗi dòng thiết bị xuất chuẩn hoặc thiết bị xuất chuẩn, do đó, nó sẽ kém hiệu quả hơn nhiều so với cmd > >(ts '%T O:') 2> >(ts '%T E:')tương đương.
Stéphane Chazelas

1

Ngoài các câu trả lời khác, nó còn được chỉ ra /proc/$PID/fd(mặc dù nó không trả lời câu hỏi):

$ cat > /dev/null 2> /tmp/blablah &
[1] 3073

[1]+  Stopped                 cat > /dev/null 2> /tmp/blablah
$ ls -l /proc/3073/fd
total 0
lrwx------ 1 kampde kampde 64 Feb 24 11:43 0 -> /dev/pts/33
l-wx------ 1 kampde kampde 64 Feb 24 11:43 1 -> /dev/null
l-wx------ 1 kampde kampde 64 Feb 24 11:43 2 -> /tmp/blablah

Như bạn thấy, ở đây bạn có thể thấy các mô tả tập tin được mở cho một quá trình. 0STDIN, 1STDOUT2STDERR. Nếu bạn không chuyển hướng STDOUT hoặc STDERR, bạn sẽ thấy /dev/pts/33(ít nhất là trong ví dụ này) vì chúng sẽ trỏ đến thiết bị đầu cuối.

ghi chú : /proc/$PIDchỉ tồn tại cho các quy trình đang chạy. Trong trường hợp này, tôi đã sử dụng catmà không có đối số nên nó không kết thúc cho đến khi tôi đóng STDIN. Tôi cũng đã thực hiện nó trong nền vì vậy tôi có PID ngay lập tức vì ví dụ này.


0

Nó không hoàn toàn rõ ràng những gì bạn đang hỏi nhưng điều này có thể giúp

ls -ld /
echo $?    # Exit status 0 returned because command executed successfully.

ls -ld /test
echo $?    # Non-zero exit status returned -- command failed to execute

Nguồn

Nếu mã thoát là 0, điều đó chỉ có nghĩa là lệnh được thực thi chính xác (stdout), ở đây bạn có thể tìm thấy ý nghĩa nếu mã thoát khác 0 (stderr)


Rất thú vị! Tôi sẽ không bao giờ kết nối các trạng thái thoát với chuyển hướng. Có ngụ ý stdoutkhông và ngụ ý khác stderrkhông?
KM.

7
@KM., Không. Tôi muốn nói rằng nó tương quan mạnh mẽ, nhưng không có gì ngăn chương trình viết stderrvà trả lại mã lỗi tốt, hoặc viết stdoutvà trả lại mã lỗi xấu. Trên thực tế, hãy thử find /root- giả sử bạn không chạy bằng root, bạn sẽ nhận được 2 dòng được in ra - "/ root" được in ra stdoutvà "find: / root: Quyền bị từ chối" được in ra stderr. Và tìm trả về một mã trả lại xấu.
godlygeek

Vấn đề của op là rõ ràng làm thế nào để biết đó là thiết bị xuất chuẩn hay thiết bị xuất chuẩn.
it_is_a_literature

0

Thông thường STDERR sẽ có tên chương trình được thêm vào tin nhắn bằng dấu hai chấm.

Thí dụ:

rpm -zq some_utils 
rpm: -zq: unknown option

Vs

rpm -ql some_utils 
package some_utils is not installed

-1

Để chụp và kiểm tra đầu ra lỗi:

ls -l test 2>errors
if [ -s errors ]; then echo "There were errors:" && cat errors; fi
rm errors
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.