Mengapa '>' tidak mengalihkan pesan kesalahan dari gcc?


9

Saya menyimpan program berikut di new.c

int main() 
{ 
    a;
    return 0; 
}

Ini mengembalikan pesan kesalahan. Saya ingin mengirim pesan ini ke file. Jadi saya menggunakan perintah berikut

gcc new.c > temp.txt

Tapi saya masih mendapatkan output di terminal. Saya menggunakan Ubuntu 13.04. Bagaimana saya bisa membuatnya bekerja?


Jawaban:


16

Ketika Anda mengkompilasi program dengan gcc, ada berbagai jenis output: ke stdoutdan stderr. Biasanya, >akan mengarahkan stdoutaliran ke file (misalnya, hasil dari printf("hello world\n");dikirim ke stdout). Namun, stderrterus dikirim ke layar, karena itu dianggap "sesuatu yang luar biasa yang perlu Anda ketahui".

Ada cara untuk mengarahkan stderr ke file - Anda melakukan ini dengan perintah berikut (tidak sangat intuitif):

gcc new.c &> myFile

di mana &>"bash steno" untuk "redirect everything". Seperti yang ditunjukkan oleh @CharlesDuffy, formulir yang sesuai dengan POSIX adalah

gcc new.c > myFile 2>&1

Ini berarti "kompilasi 'new.c' dan kirim stdoutke myFile. Dan kirim stderr(2) ke tempat yang sama dengan stdout( &1=" tempat yang sama dengan stdout ").

Anda akan menemukan detail lebih lanjut tentang pengalihan yang berbeda di http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html dan http://mywiki.wooledge.org/BashFAQ/055

Omong-omong, jika Anda ingin mengirim sesuatu dari dalam program Anda khusus untuk stderr, Anda dapat melakukannya dengan berikut ini

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

Jika Anda memasukkannya ke dalam program, jalankan program dan kirim output "normal" ke file, ini masih akan muncul di konsol. Jadi, jika Anda mengkompilasi di atas ke dalam executable urgent, ketikkan

./urgent > /dev/null

di konsol, output Anda akan muncul di layar.


2
mywiki.wooledge.org/BashFAQ/055 mungkin merupakan pengantar yang lebih baik untuk pengalihan. Selain itu, orang benar-benar harus memperkenalkan formulir yang sesuai dengan POSIX ( >myFile 2>&1) dan juga ekstensi bash ( &>).
Charles Duffy

@CharlesDuffy - keduanya poin yang sangat bagus. Saya akan memasukkan mereka dalam jawaban saya untuk kelengkapan.
Floris

11

Karena >hanya mengarahkan ulang stdout, dan kesalahan ditulis stderr, Anda perlu menggunakan salah satu dari berikut ini sebagai gantinya:

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

...atau...

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

&>adalah ekstensi BASH yang mengarahkan baik stdoutdan stderrke file; sebaliknya, pendekatan termudah adalah dengan stdout redirect pertama ( >temp.txt), dan kemudian membuat stderr (FD 2) salinan file handle yang sudah diarahkan pada stdout (FD 1), seperti: 2>&1.


4

Seperti yang dikatakan orang lain, linux menyediakan dua aliran keluaran yang berbeda:

stdout , atau "output standar" adalah tempat semua output biasa berjalan.
              Anda dapat referensi menggunakan deskriptor file 1.

stderr , atau "standard error" adalah aliran terpisah untuk informasi out-of-band.
              Anda dapat referensi menggunakan deskriptor file 2.

Mengapa dua aliran output berbeda? Pertimbangkan pipa perintah imajiner:

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

Sekarang bayangkan decryptperintah gagal dan menghasilkan pesan kesalahan. Jika mengirim pesan stdoutitu, itu akan mengirim ke pipa, dan kecuali jika ada kata "rahasia" Anda tidak akan pernah melihatnya. Jadi, Anda akan berakhir dengan file output kosong, tanpa tahu apa yang salah.

Namun, karena pipa hanya menangkap stdout, decryptperintah dapat mengirim kesalahannya ke stderr, di mana mereka akan ditampilkan di konsol.

Anda dapat mengarahkan stdoutdan stderr, baik bersama-sama atau secara mandiri:

# 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

Anda dapat mengarahkan kesalahan ke stdoutdan memprosesnya seolah-olah itu adalah output normal:

# 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

Anda juga dapat menggunakan "singkatan" notasi untuk mengarahkan kedua stdout dan stderr ke file yang sama:

decrypt $MY_FILE &> output.txt

Dan, akhirnya, >operator akan terlebih dahulu memotong file outputnya sebelum menulis ke sana. Sebaliknya, jika Anda ingin menambahkan data ke file yang ada, gunakan >>operator:

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

1
Dua quibble: (1) Penggunaan ekspansi parameter yang tidak dikutip ( $FOO) adalah sumber bug yang umum, dan menunjukkannya dalam contoh tidak terlalu bagus. (2) Penggunaan nama variabel semua-huruf besar adalah alasan utama untuk konflik namespace antara variabel lingkungan dan bawaan (huruf besar dengan konvensi) dan variabel lokal (huruf kecil dengan konvensi). (3) Mendorong orang untuk berulang kali menggunakan >>(yang membuka kembali file setiap kali digunakan dalam perintah) daripada membuka file sekali dan membiarkan deskriptor file terbuka untuk digunakan oleh beberapa perintah menghasilkan kode yang tidak efisien.
Charles Duffy

... pada poin terakhir, bandingkan dengan: exec 4>secrets; echo "this is a secret" >&4; echo "this is another secret" >&4
Charles Duffy

+1 Terima kasih telah membuat saya jujur, @CharlesDuffy. Semua poin bagus. Saya sengaja dihilangkan execkarena kesederhanaan, meskipun dalam praktiknya itu umumnya strategi yang lebih baik.

Juga, dapat diciutkan ke atau (di mana harus ada spasi sebelum dan sesudah , dan sebelum ). command₁ > output_file ; command₂ >> the_same_output_file( command₁ ; command₂ )  > output_file{ command₁ ; command₂ ;  }  > output_file{;}
G-Man Mengatakan 'Reinstate Monica'
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.