Neden çıktıyı 2> & 1 ve 1> & 2 olarak yönlendirelim?


36

Kullandığım birkaç komutları rastlamak 2>&1ve 1>&2ama bunu kullanarak gerekirken oldukça kullanmaktan amacı etrafında başımı almak ve olamaz.

Anladığım şey

Bunun 1standart çıkışı temsil ettiğini ve 2standart hatayı temsil ettiğini biliyorum . Anlıyorum 2>&1çıktısını birleştirir 2için 1ve tersi.

Ne alamadım

  1. Ne zaman kullanmalıyım?
  2. Hangi amaca hizmet ediyor?

Yanıtlar:


39

Bazen stdout ve stderr komutlarını aynı konuma yönlendirmek istiyorsunuz , Bu ne zaman >&kullanılıyor - bir dosya tanımlayıcısını diğerine işaret ediyor.


Örneğin, aynı stdout ve stderr'yi aynı dosyaya yazmak istiyorsanız ( /dev/nullya da olsun output.txt), bunları ayrı ayrı yönlendirebilirsiniz.

app 1>/dev/null 2>/dev/null

veya bir dosya tanımlayıcısını dosyaya, diğer dosya tanımlayıcısını da bir tanesine yönlendirebilirsiniz:

app 1>/dev/null 2>&1

app 2>/dev/null 1>&2

İlk örnekte, 2>&1dosya tanımlayıcısını # 2, # 1'in zaten işaret ettiği yere yönlendirir. İkinci örnek, sadece stderr ile başlayarak aynı şeyi başarır.

Başka bir örnek olarak, stdout'un (dosya tanıtıcısı # 1) istenen yere işaret ettiği durumlar vardır, ancak ada göre (bir boru, soket veya benzeri ile ilişkili olabilir) ismine başvuramazsınız. Bu genellikle normalde yalnızca stdout'u yakalayan işlem genişletme ( ` `veya $( )işleçler) kullanıldığında olur , ancak içine stderr eklemek isteyebilirsiniz. Bu durumda, >&stderr'i stdout'a yönlendirmek için de kullanabilirsiniz :

out=$(app 2>&1)

Yaygın olarak kullanılan başka bir örnek, bir çağrı cihazı grepveya benzeri bir yardımcı programdır, çünkü boru |normalde yalnızca stdout üzerinde çalışır , çünkü stderr'i boruyu kullanmadan önce stdout'a yönlendirirsiniz:

app 2>&1 | grep hello

Nasıl hangisinin bilmek 2>&1ya 1>&2doğrudur? Zaten kurulmuş dosya tanıtıcı sağındaki gider >&ve yeniden yönlendirmek istediğiniz dosya tanıtıcı sola gider. ( 2>&1"nokta tanımlayıcı # 2'ye dosya tanımlayıcı # 1" anlamına gelir.)


Bazı kabuklarda ortak yönlendirmeler için kısayollar bulunur; İşte Bash'ten örnekler:

  • 1> sadece kısaltılabilir >

  • 1>foo 2>&1için >&fooveya&>foo

  • 2>&1 | program için |& program


app 1>/dev/null 2>&1Yapmanın, 2> & 1'in 1'in zaten yönlendirdiği dosyayı göstereceği anlamına geleceğini bilmiyordum . Anlayabildiğim kadar kolay yapabildim app > /dev/null &>mi?
FıstıkMonkey

Anlamakta zorlanıyorum the already set up fd goes to the right of >&, and the fd you want to redirect goes to the left. Önceden ayarlanmış dosya tanımlayıcısı ile ne demek istiyorsunuz? Bu ne anlama geliyor?
FıstıkMonkey


Bana talimat vermek niyetinde olmadığınız sürece üzgünüm, daha önce belirtildiği gibi yaptığınız ifadeye uymam.
FıstıkMonkey

1
Her dosya tanımlayıcısını tek tek, soldan sağa yönlendirin ve bu kuralları bu sırayla uygulayın. Eğer varsa öncelikle bir dosyaya doğrudan stdout sonra şimdi işaret bizi stdout'a yere stderr'yi yönlendirmek, daha sonra Stderr ve stdout'u aynı dosyaya gidecek. Eğer bu iki yönlendirmeyi değiştirirseniz, o zaman farklı sonuçlar elde edersiniz (stderr'i şimdi stdout'un bulunduğu yere yönlendirin , sonra stderr'ı işaret ettiği yere devam ederken stdout'u başka bir dosyaya yönlendirin).
Jason,

2

İhtiyacınız olduğunda bir durum straceçıktıyı bir çağrı cihazında görüntülemek istediğiniz zamandır. straceçıktısını standart hataya yazdırır ve borular genellikle standart çıktıyı standart girdiye bağlar , bu nedenle yönlendirmeyi kullanmanız gerekir:

strace -p $pid 2>&1 | less

Ne demek istiyorsun pipes generally connect standard output to standard input?
FıstıkMonkey

2
Yani, pipe ( |) ilk komutun standart çıktısını alır ve ikinci komutun standart girişine bağlar.
jpalecek

2

Bazen her iki yönlendirmek istiyorum stdout( 1) ve stderr( 2(aynı konuma) /dev/nullörneğin). Bunu başarmanın bir yolu şudur:

$ program 1>/dev/null 2>/dev/null

Ancak çoğu kişi stderr, stdoutile yönlendirerek bunu kısaltır 2>&1:

$ program 1>/dev/null 2>&1

Daha da kısa bir sürüm:

$ program >&- 2>&-

1

2: Hem standart hatadan hem de standart çıkıştan çıkan çıktılara sahip olacağınız ve onları tek bir dizgeye dönüştürmek istediğiniz zaman içindir.

1: Hem standart hatanın hem de standartların çıktısını değiştirmek istediğinizde.


Manipülasyonla ne demek istiyorsunuz? Anladığım kadarıyla yönlendirilen herhangi bir şey >2/ dev / null'a gönderilir. Yoksa tamamen yanlış mı anladım?
FıstıkMonkey

Bu doğru değil. Manipülasyon ile grep veya benzeri bir şey için onu boru anlamına gelir. Örnek için buraya bakınız .
soandos

0

Ayrılmış bir işe başlamak için kullanıyorum:

someProgram 2>&1 >& my.log &

sonra çıkış yapabilirim ve bazı program hala çalışıyor olacak. İşlevsellik GNU Screen, tmux ve diğer bazı programlar tarafından sağlanır - fakat burada dışsal bağımlılıkların hiçbiri olmadan elde edilir.


1
Bu sadece programa gönderilen bir SIGHUP gönderilmediği sürece çalışır. Daha iyi kullanım nohupya disownda böyle durumlarda.
slhck

@slhck: tamam. Fakat eğer programa SIGHUP'ı göndermezsem - kimse olmaz, değil mi?
Adobe,

Hayır, kontrol terminali SIGHUP ile çıkış işlemlerini uyarır. Uygulamada, SSH üzerinden uzak bir kabuk koyarsanız ve çıkarsanız, işleminiz de örneğin ölür.
slhck

@slhck: Doğru olamaz: Birkaç yıl kullanıyorum - ssh'den çıkış yapıyorum ve işlem hala devam ediyor.
Adobe,

Bunu daha ayrıntılı olarak incelemem gerekecek, ancak programları arka plana eklemek sadece her durumda benim için işe yaramadı ve kesinlikle yerel makinemde bile çalışmıyor. Zsh ve Bash burada da farklı davranıyorlar, öyle görünüyor.
slhck

0

tryBu üç dosyaya sahip bir dizin olduğunu hayal edin :file file1 and file2.

Şimdi bu komutu çalıştırın:

cat file file1 file2 file3

İlk üç dosya açılır, ancak catdördüncü dosyayı açarken bir hata atmaz.

Şimdi koş:

cat file file1 file2 file3 1>outfile 2>&1

Ekranda herhangi bir çıktı görmezsiniz: Öncelikle 1>outfilekomuta çıktısını yönlendirir outfileve sonra (yönlendirir 2>&1açmaya çalışırken hata atılır) file3için outfile.

1>&2 benzer şekilde çalışır ve hata akışını standart çıktıya yönlendirir.

Bu yardımcı olur umarım!


0

Alternatif senaryo: terminal komutları çıktıyı başka bir terminale gösterir.

ttyTanımlamak için her terminaldeki komutu kullanın :

$ tty
/dev/pts/0

$ tty
/dev/pts/1

Bu TTY'lerin varsayıldığı gibi, ilkin stdout'unu ikinciye yönlendirmek için, bunu ilk terminalde çalıştırın:

exec 1>/dev/pts/1

Not: Şimdi her komut çıkışı pts / 1 ile gösterilecektir.

Pts / 0'ın varsayılan davranışını geri yüklemek için:

exec 1>/dev/pts/0

Bir gösteri için bu videoya bakın .


0

Stderr'i tekrar stdout'a yönlendirirken ortaya çıkan durum zaten burada ele alınmıştır (örn. Hata mesajlarını filtrelemek için kullanın).

Diğer durum ise stdout'u stderr'e yönlendiriyor. Yaygın bir kullanım temeli (en azından benim için), "echo" (kabuk komut dosyalarımda) ile basılan uyarıları / hata mesajlarını stderr'e göndermektir (böylece kullanıcının dikkatini daha kolay yakalarlar).

Örneğin,

echo "file \"${file\" does not exist..." 1>&2
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.