Làm thế nào để các chương trình xuất ra nơi khác ngoài STDOUT / STDERR? Làm thế nào để tránh nó?


15

Rõ ràng tôi không biết tất cả các điểm đến đầu ra có sẵn để sử dụng. Tôi biết về stdout( &1) và stderr( &2). Tuy nhiên, sau khi chuyển hướng cả hai mô tả, đôi khi tôi vẫn nhận được một số đầu ra trong bảng điều khiển của mình!

Ví dụ đơn giản nhất tôi có thể nghĩ đến là GNU Parallel; Mỗi lần tôi sử dụng, tôi thấy một thông báo trích dẫn. Ngay cả khi tôi làm &2>1 > file, tôi vẫn thấy thông báo.

Và cùng áp dụng cho emerge: Khi tôi chạy emerge và có một số vấn đề, một số thông tin không được in để stdouthay stdin, kể từ khi tôi chuyển hướng họ và họ vẫn vượt qua.

Tôi chủ yếu giải quyết những vấn đề này bằng cách sử dụng script, nhưng tôi vẫn đang tự hỏi điều gì gây ra vấn đề này.


1
Vui lòng cung cấp một ví dụ đầy đủ .
Kusalananda


8
Bạn sẽ không nhận được tất cả . Một kịch bản luôn có thể viết cho /dev/tty.
Satō Katsura

1
Đối với GNU parallel: mkdir ~/.parallel; touch ~/.parallel/will-citesẽ vô hiệu hóa thông báo gây phiền nhiễu. Ngoài ra, nhìn xung quanh để thực hiện khác parallel.
Satō Katsura

2
@OleTange Bởi vì đó không phải là vấn đề - Tôi đang hỏi tại sao điều gì đó đang xảy ra và tôi đang sử dụng parallellàm ví dụ.
MatthewRock

Câu trả lời:


40

Cú pháp bạn sử dụng là sai.

cmd &2>1 >file

sẽ được chia thành

cmd &
2>1 >file

Điều này sẽ:

  1. Chạy cmdnhư một công việc nền không có chuyển hướng
  2. Trong một quy trình riêng biệt (không có lệnh!) Sẽ chuyển hướng stderrđến một tệp được gọi theo nghĩa đen 1và chuyển hướng stdoutđếnfile

Cú pháp bạn muốn là:

cmd >file 2>&1

Thứ tự của các hoạt động là quan trọng. Điều này sẽ:

  1. Chuyển hướng stdoutđếnfile
  2. Chuyển hướng stderrđến &1- tức là cùng một tập tin nhưstdout

Kết quả là cả hai stderrstdoutsẽ được chuyển hướng đến file.

Trong bash, một cú pháp không chuẩn đơn giản hơn (và vì vậy tôi không khuyến nghị nó, trên cơ sở tính di động) cmd &> filethực hiện điều tương tự.


Tốt đẹp, cảm ơn. Vấn đề khác có thể là /dev/tty, nhưng hy vọng điều này không xảy ra quá thường xuyên (nếu có).
MatthewRock

5
Nếu bạn có atlệnh trên máy và có đặc quyền sử dụng nó, thì bạn có thể chạy lệnh qua at now. Xem trang hướng dẫn để biết chi tiết. Điều này sẽ chạy lệnh thông qua một cơ chế xử lý hàng loạt và quá trình sẽ không bao giờ có một tty để ghi vào. Nhưng, nói chung, tôi sẽ không lo lắng về trường hợp cạnh này. Thông thường chỉ có các quy trình yêu cầu tương tác và cần cố tình hiển thị mọi thứ cho người dùng mặc dù chuyển hướng sẽ sử dụng /dev/tty.
Stephen Harris

đã ở đó, thực hiện điều đó
davidbak

10

Có hai vấn đề.

Cái đầu tiên là thứ tự quan trọng, cái thứ hai là /dev/tty.

Hãy sử dụng tập lệnh này làm tập lệnh mẫu mà chúng tôi muốn thu được kết quả từ:

test.sh:

#!/bin/bash

echo dada
echo edada 1>&2
echo ttdada >/dev/tty

Bây giờ hãy xem kết quả đầu ra của các lệnh:

./testmyscript.sh 2>&1 >/dev/null:

edada
ttdada

Vì thứ tự đánh giá là từ trái sang phải, trước tiên chúng tôi nhận được "chuyển hướng stderrđến bất cứ nơi nào stdoutxuất ra (vì vậy, đầu ra giao diện điều khiển)". Sau đó, chúng tôi nhận được "chuyển hướng stdoutđến /dev/null. Chúng tôi kết thúc với tình huống như thế này:

stdout-> /dev/null stderr-> bảng điều khiển

Vì vậy, chúng tôi hiểu đúng:

./testmyscript.sh >/dev/null 2>&1

Và chúng tôi nhận được:

ttdada.

Bây giờ chúng ta thực hiện "Chuyển hướng stdoutđến /dev/null" và sau đó "Chuyển hướng stderr đến nơi thiết bị xuất chuẩn đang trỏ" (vì vậy, /dev/null). Tiếng hoan hô!

Tuy nhiên, chúng tôi vẫn có một vấn đề; chương trình in tới /dev/tty. Bây giờ tôi không biết cách khắc phục loại hành vi này, vì vậy rất có thể bạn sẽ cần script, nhưng hy vọng hành vi này sẽ không xảy ra quá thường xuyên.

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.