Đường ống STDERR so với STDOUT


24

Theo " Linux: The Complete Reference 6 bản " (. Pg 44), bạn có thể ống chỉ STDERR bằng cách sử dụng |&những biểu tượng chuyển hướng.

Tôi đã viết một kịch bản khá đơn giản để kiểm tra điều này:

#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2

Tôi chạy tập lệnh này như thế này:

./script.sh |& sed 's:^:\t:'

Có lẽ, chỉ các dòng được in ra STDERR sẽ được thụt lề. Tuy nhiên, nó không thực sự hoạt động như thế này, như tôi thấy:

    Normal Text.
    Error Text. 

Tôi làm gì sai ở đây?

Câu trả lời:


26

Tôi không biết sách của bạn sử dụng văn bản nào, nhưng hướng dẫn sử dụng bash rất rõ ràng (nếu bạn đã quen với việc chuyển hướng):

Nếu |&được sử dụng, lỗi tiêu chuẩn của lệnh1, ngoài đầu ra tiêu chuẩn của nó, được kết nối với đầu vào tiêu chuẩn của lệnh2 thông qua đường ống; nó là tốc ký cho 2>&1 |. Chuyển hướng ngầm định này của lỗi tiêu chuẩn đến đầu ra tiêu chuẩn được thực hiện sau khi bất kỳ chuyển hướng nào được chỉ định bởi lệnh.

Vì vậy, nếu bạn không muốn trộn lẫn đầu ra tiêu chuẩn và lỗi tiêu chuẩn, bạn sẽ phải chuyển hướng đầu ra tiêu chuẩn ở một nơi khác. Xem Làm thế nào để grep luồng lỗi tiêu chuẩn (stderr)?

{ ./script.sh 2>&1 >&3 | sed 's:^:\t:'; } 3>&1

Cả fd 1 và 3 của script.shsedsẽ chỉ đến đích đầu ra ban đầu. Nếu bạn muốn trở thành một công dân tốt, bạn có thể đóng những fd 3 mà những lệnh đó không cần:

{ ./script.sh 2>&1 >&3 3>&- | sed 's:^:\t:' 3>&-; } 3>&1

bashksh93có thể cô đọng >&3 3>&-đến >&3-(di chuyển fd).


Hướng dẫn bash không hoàn toàn rõ ràng với tôi. Tôi hoàn toàn không hiểu tại sao smth như ./script.sh > /tmp/stdout_goes_here |& grep 'grepping_script_stderr'không làm việc như mong muốn, ví dụ: chuyển hướng script.sh's stdout(trong đó, theo đoạn thủ công nên xảy ra đầu tiên), sau đó cho phép grepđể xử lý kịch bản của stderr. Thay vào đó, stderrvà cả hai đều kết thúc trongstdout_goes_here
sxc731

1
@ sxc731 |&là tốc ký cho 2>&1 |. Vì vậy, >/tmp/stdout_goes_here |&chuyển hướng stdout đến /tmp/stdout_goes_here, sau đó 2>&1chuyển hướng stderr đến bất cứ nơi nào stdout đang diễn ra /tmp/stdout_goes_here, và cuối cùng |không nhận được bất kỳ đầu vào nào vì đầu ra của lệnh đã được chuyển hướng. Hãy nhớ rằng >&1chuyển hướng đến bất cứ nơi nào mô tả tệp 1 hiện đang diễn ra , không phải bất cứ nơi nào mô tả tệp 1 sẽ kết thúc . Để ống stderr chỉ và chuyển hướng thiết bị xuất chuẩn vào một tệp, một cách là 2>&1 >/tmp/stdout_goes_here |.
Gilles 'SO- ngừng trở nên xấu xa'

6

|&ống stderr để stdin, như thế 2>&1 |, vì vậy chương trình tiếp theo sẽ có được cả trên stdin.

$cat test.sh
#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2
$./test.sh | sed 's:^:\t:'
Error Text.
        Normal Text.
$ ./test.sh |& sed 's:^:\t:'
        Normal Text.
        Error Text.

Oh, vậy về cơ bản nó tương đương với biểu thức dài hơn runcommand 2>&1 | tee? tức là runcommand |& tee?
Naftuli Kay

vâng, chúng giống nhau
Kevin

1

|&trong bash chỉ là một phím tắt (không di động khủng khiếp) 2>&1 |, vì vậy bạn sẽ thấy mọi dòng được thụt vào.

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.