Neden '>' hata mesajlarını gcc'den yönlendirmiyor?


9

Aşağıdaki programı new.c'de sakladım.

int main() 
{ 
    a;
    return 0; 
}

Bir hata mesajı döndürür. Bu mesajı bir dosyaya göndermek istiyorum. Bu yüzden aşağıdaki komutu kullandım

gcc new.c > temp.txt

Ama yine de terminalden çıktı alıyordum. Ubuntu 13.04 kullanıyorum. Nasıl çalıştırabilirim?


Yanıtlar:


16

Bir programı derlediğinizde gcc, farklı çıktı türleri vardır: stdoutve stderr. Normal olarak, >yönlendirir stdout(örneğin, bir sonucu, bir dosyaya akımı printf("hello world\n");gönderilir stdout). Ancak, stderr"size söylenmesi gereken olağanüstü bir şey" olduğu varsayıldığı için ekrana gönderilmeye devam ediyor.

Stderr dosyasını bir dosyaya yönlendirmenin bir yolu vardır - bunu aşağıdaki (çok sezgisel değil) komutuyla yaparsınız:

gcc new.c &> myFile

&>"her şeyi yeniden yönlendir" için "bash steno" nerede . @CharlesDuffy tarafından işaret edildiği gibi, POSIX uyumlu form

gcc new.c > myFile 2>&1

"Bu araçlar derleme 'new.c' ve gönder stdoutiçin myFile. Ve gönderme stderraynı yere (2) stdout( &1stdout'ta aynı yerde '=)'.

Farklı yönlendirmeler hakkında daha fazla bilgiyi http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html ve http://mywiki.wooledge.org/BashFAQ/055 adresinde bulabilirsiniz.

Bu arada, programınızdan özel olarak bir şey göndermek stderristiyorsanız, bunu aşağıdakilerle yapabilirsiniz

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

Bunu bir programa dahil ederseniz, programı çalıştırın ve "normal" çıktıyı bir dosyaya gönderin, bu konsolda görünmeye devam edecektir. Bu yüzden, yukarıdaki dosyayı yürütülebilir dosyaya derlerseniz urgent,

./urgent > /dev/null

konsolda, çıktınız ekranda görünecektir.


2
mywiki.wooledge.org/BashFAQ/055 muhtemelen yeniden yönlendirmeye daha iyi bir giriş niteliğindedir. Ayrıca, gerçekten POSIX uyumlu formu ( >myFile 2>&1) ve bash uzantısını ( &>) tanıtmalıdır .
Charles Duffy

@CharlesDuffy - her ikisi de çok iyi puan. Bunları eksiksiz olma cevabına ekleyeceğim.
Floris

11

Çünkü >yönlendirmeleri sadece stdout ve hatalar için yazılmıştır stderr, bunun yerine aşağıdakilerden birini kullanmanız gerekir:

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

...veya...

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

&>Her iki yönlendirme bir Bash uzantısıdır stdoutve stderrbir dosyaya; aksi takdirde kolay yaklaşım, ilk yönlendirme stdout'ta (etmektir >temp.txtşöyle (FD 2) stdout'ta zaten yönlendirildi dosya sapın bir kopyası (FD 1),) ve sonra stderr'yi olun: 2>&1.


4

Diğerlerinin söylediği gibi, linux iki farklı çıkış akışı sağlar:

stdout veya "standart çıktı" tüm normal çıkışın olduğu yerdir.
              Dosya tanımlayıcıyı kullanarak referans verebilirsiniz 1.

stderr veya "standart hata" bant dışı bilgi için ayrı bir akıştır.
              Dosya tanımlayıcıyı kullanarak referans verebilirsiniz 2.

Neden iki farklı çıkış akışı? Hayali komutların bir ardışık düzenini düşünün:

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

Şimdi decryptkomutun başarısız olduğunu ve bir hata mesajı oluşturduğunu düşünün . Bu mesajı stdoutgönderirse, boruya gönderir ve "gizli" kelimesi olmadıkça asla göremezsiniz. Böylece, neyin yanlış gittiğine dair bir fikriniz olmadan boş bir çıktı dosyası elde edersiniz.

Ancak, boru yalnızca yakaladığından stdout, decryptkomut hatalarını stderrkonsolda görüntülenecekleri yere gönderebilir .

Yönlendirebilir stdoutve stderrbirlikte veya bağımsız olarak şunları yapabilirsiniz:

# 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

Hataları stdoutnormal çıktıdaymış gibi yönlendirebilir ve işleyebilirsiniz:

# 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

Ayrıca yönlendirmek için bir "steno" notasyonu kullanabilirsiniz hem aynı dosyaya stdout ve stderr:

decrypt $MY_FILE &> output.txt

Ve son olarak, >operatör ilk olacak kesmek yazmadan önce çıkış dosyası. Bunun yerine, mevcut bir dosyaya veri eklemek istiyorsanız , >>işleci kullanın :

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

1
İki kelime oyunu: (1) Alıntılanmamış parametre genişletmelerinin ( $FOO) kullanımı yaygın bir hata kaynağıdır ve örneklerde gösterilmesi o kadar da büyük değildir. (2) Tüm büyük harfli değişken adlarının kullanılması, ortam ile yerleşik değişkenler (büyük harf konvansiyona göre) ve yerel değişkenler (küçük harf konvansiyonu) arasındaki ad alanı çakışmalarının birincil nedenidir. (3) >>Bir dosyayı bir kez açmak ve dosya tanımlayıcısını birden çok komut tarafından kullanılmak üzere açık bırakmak yerine, insanları tekrar tekrar kullanmaya teşvik etmek (her seferinde bir komutta dosyayı yeniden açmak ) etkin olmayan kodla sonuçlanır.
Charles Duffy

... son noktada, karşılaştırın: exec 4>secrets; echo "this is a secret" >&4; echo "this is another secret" >&4
Charles Duffy

+1 Beni dürüst tuttuğun için teşekkürler, @CharlesDuffy. Tüm iyi puan. execPratikte genellikle daha iyi bir strateji olsa da, basitlik için kasıtlı olarak atladım .

Ayrıca, daraltılmış olabilir ya da (boşluk önce ve sonra orada olması gereken ve önce ). command₁ > output_file ; command₂ >> the_same_output_file( command₁ ; command₂ )  > output_file{ command₁ ; command₂ ;  }  > output_file{;}
G-Man
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.