Tại sao không '>' chuyển hướng thông báo lỗi từ gcc?


9

Tôi đã lưu trữ chương trình sau đây trong new.c

int main() 
{ 
    a;
    return 0; 
}

Nó trả về một thông báo lỗi. Tôi muốn gửi tin nhắn này đến một tập tin. Vì vậy, tôi đã sử dụng lệnh sau đây

gcc new.c > temp.txt

Nhưng tôi vẫn nhận được đầu ra trên thiết bị đầu cuối. Tôi đang sử dụng Ubuntu 13.04. Làm thế nào tôi có thể làm cho nó hoạt động?


Câu trả lời:


16

Khi bạn biên dịch một chương trình với gcc, có các loại đầu ra khác nhau: đến stdoutstderr. Thông thường, luồng >trực tiếp sẽ stdoutđến một tệp (ví dụ: kết quả của a printf("hello world\n");được gửi đến stdout). Tuy nhiên, việc stderrtiếp tục được gửi đến màn hình, vì nó được coi là "điều gì đó đặc biệt mà bạn cần phải nói về".

Có một cách để chuyển hướng stderr sang một tệp - bạn thực hiện việc này bằng lệnh sau (không trực quan lắm):

gcc new.c &> myFile

trong đó &>"bash shorthand" cho "chuyển hướng mọi thứ". Như được chỉ ra bởi @CharlesDuffy, biểu mẫu tuân thủ POSIX là

gcc new.c > myFile 2>&1

Điều này có nghĩa là "biên dịch 'new.c' và gửi stdoutđến myFile. Và gửi stderr(2) đến cùng một nơi với stdout( &1=" cùng địa điểm với thiết bị xuất chuẩn ").

Bạn sẽ tìm thấy thêm chi tiết về các chuyển hướng khác nhau tại http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.htmlhttp://mywiki.wooledge.org/BashFAQ/055

Nhân tiện, nếu bạn muốn gửi một cái gì đó từ trong chương trình của bạn cụ thể đến stderr, bạn có thể làm như vậy với những điều sau đây

fprintf(stderr, "hello world - this is urgent.\n");

Nếu bạn bao gồm điều đó trong một chương trình, hãy chạy chương trình và gửi đầu ra "bình thường" đến một tệp, điều này sẽ vẫn xuất hiện trên bàn điều khiển. Vì vậy, nếu bạn biên dịch phần trên thành tệp thực thi urgent, hãy gõ

./urgent > /dev/null

tại bàn điều khiển, đầu ra của bạn sẽ xuất hiện trên màn hình.


2
mywiki.wooledge.org/BashFAQ/055 có lẽ là một giới thiệu tốt hơn về chuyển hướng. Ngoài ra, người ta thực sự nên giới thiệu biểu mẫu tuân thủ POSIX ( >myFile 2>&1) cũng như phần mở rộng bash ( &>).
Charles Duffy

@CharlesDuffy - cả hai điểm rất tốt. Tôi sẽ bao gồm chúng trong câu trả lời của tôi cho đầy đủ.
Floris

11

>chỉ chuyển hướng thiết bị xuất chuẩn và lỗi được ghi vào stderr, nên bạn cần sử dụng một trong các cách sau:

gcc new.c &> temp.txt ## redirect both stdout and stderr using bash or zsh only

...hoặc là...

gcc new.c >temp.txt 2>&1 ## redirect both stdout and stderr in any POSIX shell

&>là một phần mở rộng BASH chuyển hướng cả hai stdoutstderrđến một tệp; mặt khác, cách tiếp cận đơn giản nhất là đầu tiên chuyển hướng stdout ( >temp.txt), sau đó biến stderr (FD 2) thành bản sao của tệp xử lý đã được chuyển hướng trên thiết bị xuất chuẩn (FD 1), như vậy : 2>&1.


4

Như những người khác đã nói, linux cung cấp hai luồng đầu ra khác nhau:

stdout , hay "đầu ra tiêu chuẩn" là nơi tất cả đầu ra thông thường đi.
              Bạn có thể tham khảo nó bằng cách sử dụng mô tả tập tin 1.

stderr , hoặc "lỗi tiêu chuẩn" là một luồng riêng cho thông tin ngoài băng.
              Bạn có thể tham khảo nó bằng cách sử dụng mô tả tập tin 2.

Tại sao hai luồng đầu ra khác nhau? Hãy xem xét một đường dẫn của các lệnh tưởng tượng:

 decrypt $MY_FILE | grep "secret" | sort > secrets.txt

Bây giờ hãy tưởng tượng decryptlệnh thất bại và tạo ra một thông báo lỗi. Nếu nó gửi tin nhắn đó đến stdout, nó sẽ gửi vào đường ống, và trừ khi nó có từ "bí mật", bạn sẽ không bao giờ nhìn thấy nó. Vì vậy, bạn kết thúc với một tập tin đầu ra trống rỗng, không biết điều gì đã xảy ra.

Tuy nhiên, do đường ống chỉ chụp stdout, nên decryptlệnh có thể gửi lỗi đến stderr, nơi chúng sẽ được hiển thị trên bàn điều khiển.

Bạn có thể chuyển hướng stdoutstderr, cùng nhau hoặc độc lập:

# Send errors to "errors.txt" and output to "secrets.txt"
# The following two lines are equivalent, as ">" means "1>"
decrypt $MY_FILE 2> errors.txt > secrets.txt
decrypt $MY_FILE 2> errors.txt 1> secrets.txt

Bạn có thể chuyển hướng các lỗi đến stdoutvà xử lý chúng như thể chúng là đầu ra bình thường:

# The operation "2>&1" means "redirect file descriptor 2 to file
# descriptor 1. So this sends all output from stderr to stdout.
# Note that the order of redirection is important.
decrypt $MY_FILE > errors.txt 2>&1 

# This may be confusing.  It will store the normal output in a file
# and send error messages to stdout, where they'll be captured by 
# the pipe and then sorted.
decrypt $MY_FILE 2>&1 > output.txt | sort

Bạn cũng có thể sử dụng ký hiệu "tốc ký" để chuyển hướng cả thiết bị xuất chuẩn và thiết bị xuất chuẩn vào cùng một tệp:

decrypt $MY_FILE &> output.txt

Và cuối cùng, >toán tử trước tiên sẽ cắt bớt tệp đầu ra của nó trước khi ghi vào nó. Thay vào đó, nếu bạn muốn nối thêm dữ liệu vào một tệp hiện có, hãy sử dụng >>toán tử:

decrypt $MY_FILE 2>> more_errors.txt >> more_secrets.txt
decrypt $MY_FILE >> more_output.txt 2>&1

1
Hai điểm yếu: (1) Sử dụng các mở rộng tham số không được trích dẫn ( $FOO) là một nguồn lỗi phổ biến và việc chứng minh nó trong các ví dụ là không quá lớn. (2) Sử dụng tên biến toàn chữ hoa là lý do chính cho xung đột không gian tên giữa môi trường và biến tích hợp (chữ hoa theo quy ước) và biến cục bộ (chữ thường theo quy ước). (3) Khuyến khích mọi người sử dụng nhiều lần >>(mở lại tệp mỗi lần sử dụng trong lệnh) thay vì mở tệp một lần và để bộ mô tả tệp mở để sử dụng bởi nhiều lệnh dẫn đến mã không hiệu quả.
Charles Duffy

... về điểm cuối cùng, so sánh với: exec 4>secrets; echo "this is a secret" >&4; echo "this is another secret" >&4
Charles Duffy

+1 Cảm ơn vì đã giữ cho tôi trung thực, @CharlesDuffy. Tất cả những điểm tốt. Tôi cố tình bỏ qua execvì đơn giản, mặc dù trong thực tế, đó thường là một chiến lược tốt hơn.

Ngoài ra, có thể được thu gọn đến hoặc (nơi phải có khoảng trắng trước và sau và a trước ). command₁ > output_file ; command₂ >> the_same_output_file( command₁ ; command₂ )  > output_file{ command₁ ; command₂ ;  }  > output_file{;}
G-Man nói 'Tái lập Monica'
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.