stderr çıktısı yankı


1115

Eko gibi davranan ancak stdout'tan ziyade stderr'a çıktı veren standart bir Bash aracı var mı?

Yapabileceğimi biliyorum echo foo 1>&2ama biraz çirkin ve şüpheli, hata eğilimli (örneğin işler değiştiğinde yanlış düzenleme olasılığı daha yüksek).


Yanıtlar:


1453

Bunu, okumayı kolaylaştırarak yapabilirsiniz:

>&2 echo "error"

>&2# 2 dosya tanımlayıcısını 1 numaralı dosya tanımlayıcısına kopyalar. Bu nedenle, bu yeniden yönlendirme gerçekleştirildikten sonra, her iki dosya tanıtıcısı da aynı dosyaya başvurur: bir dosya tanıtıcısı # 2 başlangıçta atıfta bulundu. Daha fazla bilgi için Bash Hackerları Resimli Yeniden Yönlendirme Eğiticisine bakın .


2
Bu numarayı bir süre önce öğrendim. Bu sayfada bazı iyi bilgiler var. tldp.org/LDP/abs/html/io-redirection.html
Marco Aurelio

46
@BCS aliasBir kabuk komut dosyasında bir kullanmak bilmiyorum . Muhtemelen kullanımı daha güvenli olurerrcho(){ >&2 echo $@; }
Braden Best

3
> & 2 normalde sonuna konur. Bu işe yarayacak, ancak daha az kullanılır
Iskren Ivov Chernev

159
Unix benzeri sistemleri kullandığım yaklaşık 40 yıl içinde, yönlendirmeyi herhangi bir yere koyabiliyordun ama sonunda hiç aklıma gelmedi. Bu şekilde öne koymak, çok daha belirgin hale getirir (veya @MarcoAurelio'nun dediği gibi "okumayı kolaylaştırır"). Bana yeni bir şey öğrettiğin için +1.
Hephaestus

Bilginize: dizgiyi biçimlendirmek ya da başka bir şey yapmak istiyorsanız, yönlendirmeyi sonuna kadar taşımanız gerekir. Örneğin errcho(){ >&2 echo $@|pr -To5;}işe yaramaz. Böyle bir şey yapmak için, yönlendirmeyi son borudan sonra bir yere koymak zorunda kalacaksınız:errcho(){ echo $@|>&2 pr -To5;}
Jon Red

423

Bir işlev tanımlayabilirsiniz:

echoerr() { echo "$@" 1>&2; }
echoerr hello world

Bu bir komut dosyasından daha hızlı olacaktır ve bağımlılıkları olmayacaktır.

Camilo Martin'in bash özel önerisi bir "burada dize" kullanır ve yankının normalde yutacağı argümanlar (-n) da dahil olmak üzere ilettiğiniz her şeyi yazdırır:

echoerr() { cat <<< "$@" 1>&2; }

Glenn Jackman'ın çözümü aynı zamanda yutma problemini de önler:

echoerr() { printf "%s\n" "$*" >&2; }

7
Yankının biraz güvenilmez olduğunu söylemeliyim. echoerr -ne xt"-ne xt" yazdırmayacak. Bunun için daha iyi kullanın printf.
Camilo Martin

10
Oh, aslında kediyi de kullanabilirsiniz:echoerr() { cat <<< "$@" 1>&2; }
Camilo Martin

2
Bunun farkında değildim. Katma.
James Roth

4
Veya,printf "%s\n" "$*" >&2
glenn jackman

4
@GKFX Tabii ki sadece alıntı yaparken doğru çalışıyor. İnsanlar neden iplerini teklif etmiyorlar? (Eğer alıntı olmadığında, her şey birer ayrılmış veya daha $IFShalinde ayrı bir argüman olarak gönderilir boşluk echoile bitiştirmek araçlarla 0x20s, ancak tip 2 daha az karakterden oluşan çok outweight kolaylık alıntı değil tehlikeleri) .
Camilo Martin

252

Yana 1standart çıkışı, açıkça gibi bir çıkış yönlendirme önünde adlandırın gerekmez >ancak bunun yerine basitçe yazabilirsiniz:

echo Bu mesaj stderr> & 2'ye gider

1>&2Güvenilir bir şekilde yazmanızın zor olacağından endişe duyduğunuzdan , gereksizliğin ortadan kaldırılması sizin için 1hafif bir teşvik olabilir!


59

Başka seçenek

echo foo >>/dev/stderr

4
Bu seçenek taşınabilir mi? Birisi bunun unix lezzeti için işe yarayıp yaramadığını biliyor mu?
Dacav

7
/ Dev / stderr'ye erişemeyen belirli krootlarda çalışmaz.
Zachary Vance

12
Bu çizgiyi yürütür komut ise - diyelim foo- örneğin - kendi Stderr yönlendirildi vardır foo >foo.log 2>&1- o zaman echo foo >/dev/stderrbundan önceki bütün çıktıyı pataklayacak. >>yerine kullanılmalıdır:echo foo >>/dev/stderr
doshea

Benzer şekilde, var /dev/fd/2.
jbruni

@Dacav bu kesin taşınabilir içindir: /proc/self/fd/2. Aşağıdaki cevabımı gör :)
Sebastian

31

Hayır, bunu yapmanın standart yolu bu. Hatalara neden olmamalıdır.


9
Hatalara neden olmamalı, ancak daha olası olabilir. OTOH o kadar büyük bir anlaşma değil.
BCS

6
@Mike DeSimone: Birisi kodla uğraşırsa, çıktıyı karıştırırsa ve aslında bash'ı bilmiyorsa, kolayca bırakabilir (veya yanlış yazabilir) 1>&2. Hepimiz bunun gerçekleşmemesini dileriz, ancak eminim hepimiz olduğu yerler olmuştur.
Cascabel

2
( echo something 1>&2 ; something else ) > log-> (echo something; cp some junk 1>&2 ; something else) > logHata.
BCS

29
IMHO, birisi kodla uğraşır ve bash'ı bilmiyorsa, sorunlarınızın en azı bu olabilir.
Mike DeSimone

7
Bence bu bir sorun olacaksa, farklı bir dil kullanmaya başlamalısınız: bash kusursuz yapmaya çalışmak aptalın girişimidir.
intuited

17

İletiyi syslog dosyasına da kaydetmeyi önemsemiyorsanız, not_so_ugly yolu:

logger -s $msg

-S seçeneği şu anlama gelir: "İletiyi standart hataya ve sistem günlüğüne gönder."


1
bu harika! ne kadar taşınabilir?
code_monk

@code_monk: logger komut IEEE Std, logger komutu ( "POSIX.2") uyumlu util-linux paketinin bir parçasıdır ve Linux Kernel Archive ⟨edinilebilir 1003,2 olması bekleniyor kernel.org/pub/linux/utils / util- linux⟩.
miku

12

Bu, boru girişini STDERR'a yönlendiren basit bir STDERR işlevidir.

#!/bin/bash
# *************************************************************
# This function redirect the pipe input to STDERR.
#
# @param stream
# @return string
#
function STDERR () {

cat - 1>&2

}

# remove the directory /bubu
if rm /bubu 2>/dev/null; then
    echo "Bubu is gone."
else
    echo "Has anyone seen Bubu?" | STDERR
fi


# run the bubu.sh and redirect you output
tux@earth:~$ ./bubu.sh >/tmp/bubu.log 2>/tmp/bubu.err

2
Aynı şeyi takma adla da yapabileceğinizi ve çok daha kompakt olabileceğinizi düşünüyorum
BCS

ya da sadece cihaz dosyasına doğrudan boru echo what | /dev/stderr...
ardnew

11

Not: Ben post-cevap stderr çıktı yanıltıcı / belirsiz "yankı" değil soru (zaten OP tarafından cevaplandı).

Niyeti göstermek ve istediğiniz uygulamayı kaynaklamak için bir işlev kullanın . Örneğin

#!/bin/bash

[ -x error_handling ] && . error_handling

filename="foobar.txt"
config_error $filename "invalid value!"

output_xml_error "No such account"

debug_output "Skipping cache"

log_error "Timeout downloading archive"

notify_admin "Out of disk space!"

fatal "failed to open logger!"

Ve error_handlingolmak:

ADMIN_EMAIL=root@localhost

config_error() { filename="$1"; shift; echo "Config error in $filename: $*" 2>&1; }

output_xml_error() { echo "<error>$*</error>" 2>&1; }

debug_output() { [ "$DEBUG"=="1" ] && echo "DEBUG: $*"; }

log_error() { logger -s "$*"; }

fatal() { which logger >/dev/null && logger -s "FATAL: $*" || echo "FATAL: $*"; exit 100; }

notify_admin() { echo "$*" | mail -s "Error from script" "$ADMIN_EMAIL"; }

OP'deki endişeleri ele alan nedenler:

  • mümkün olan en güzel sözdizimi (çirkin semboller yerine anlamlı kelimeler)
  • hata yapmak daha zor (özellikle betiği yeniden kullanırsanız)
  • standart bir Bash aracı değildir, ancak sizin veya şirketiniz / kuruluşunuz için standart bir kabuk kütüphanesi olabilir

Diğer sebepler:

  • netlik - diğer koruyuculara niyeti gösterir
  • hız - işlevler kabuk komut dosyalarından daha hızlıdır
  • yeniden kullanılabilirlik - bir işlev başka bir işlevi çağırabilir
  • yapılandırılabilirlik - orijinal komut dosyasını düzenlemenize gerek yoktur
  • hata ayıklama - bir hatadan sorumlu satırı bulmak daha kolaydır (özellikle bir ton yönlendirme / filtreleme çıktısı ile ölüyorsanız)
  • sağlamlık - bir işlev eksikse ve komut dosyasını düzenleyemiyorsanız, aynı ada sahip harici bir aracı kullanmaya geri dönebilirsiniz (örneğin, log_error Linux'ta günlükçü için diğer adla değiştirilebilir)
  • uygulamaları değiştirme - kütüphanenin "x" özelliğini kaldırarak harici araçlara geçebilirsiniz
  • agnostik çıktı - artık STDERR'a mı yoksa başka bir yere mi gittiğinize bakmanıza gerek yok
  • kişiselleştirme - davranışları ortam değişkenleriyle yapılandırabilirsiniz

10

Benim önerim:

echo "my errz" >> /proc/self/fd/2

veya

echo "my errz" >> /dev/stderr

echo "my errz" > /proc/self/fd/2olacak etkili bir çıkış stderrnedeniyle /proc/selfcari sürecine bir bağlantıdır ve /proc/self/fdsüreç açılan dosya tanımlayıcıları tutan ve daha sonra 0, 1ve 2ayakta stdin, stdoutve stderrsırasıyla.

/proc/selfBağlantı MacOS çalışmıyor, ancak, /proc/self/fd/*Android'de Termux geçerli değil /dev/stderr. Bash betiğinden işletim sistemi nasıl algılanır? hangi varyantı kullanacağınızı belirleyerek komut dosyanızı daha taşınabilir hale getirmeniz gerekiyorsa yardımcı olabilir.


5
Bağlantı /proc/selfMacOS'ta çalışmıyor, bu yüzden daha basit bir /dev/stderryöntemle devam edeceğim . Ayrıca, diğer cevaplarda / yorumlarda belirtildiği gibi, >>eklemek için kullanmak daha iyidir .
MarkHu

4
/proc/self/fd/*Android'de Termux'da kullanılabilir, ancak mevcut değildir /dev/stderr.
go2null

9

catBurada bahsedildiği gibi kullanmayın . cata, programı sırasında echove printf(kabuk) yerleşiklere deneme vardır. Bir programın veya başka bir komut dosyasının (yukarıda da belirtildiği gibi) başlatılması, tüm maliyetleri ile yeni bir süreç oluşturmak anlamına gelir. Yerleşikleri kullanarak yazma işlevleri oldukça ucuzdur, çünkü bir işlem (-evre) oluşturmaya (yürütmeye) gerek yoktur.

Opner "çıkışı (herhangi standart bir araç olduğunu sorar boru stderr)", schort cevap: HAYIR ... neden? ... rediredcting boruları bu kavramlar üzerine kurulmuş olan unix (Linux ...) ve bash (sh) gibi sistemlerde temel bir kavramdır.

Bunun gibi notasyonlarla yönlendirmenin açıcıya katılıyorum: &2>1modern programcılar için çok hoş değil, ama bu bash. Bash büyük ve sağlam programlar yazmak için tasarlanmamıştı, yöneticilerin daha az tuşa basmak için oraya ulaşmasına yardımcı olmak için tasarlandı ;-)

Ve en azından, yönlendirmeyi satırın herhangi bir yerine yerleştirebilirsiniz:

$ echo This message >&2 goes to stderr 
This message goes to stderr

1
Geliştiricilere programları yalnızca performans nedenlerinden dolayı kullanmamalarını söylemek erken optimizasyondur. Zarif, takip edilmesi kolay yaklaşımlar, daha iyi performans gösteren (milisaniye sırasına göre) anlaşılması zor kodlara göre tercih edilmelidir.
GuyPaddock

@GuyPaddock üzgünüm, bunu düzgün okumadınız. Firs; Onun bash tarafından iyi yönetilen yönlendirme boruları hakkında. Eğer bash'ın nasıl yönlendirdiği (çirkin) sözdizimini beğenmezse, bash komut dosyalarını uygulamayı bırakmalı veya bash yolunu öğrenmelidir. İkinci; bir bash yerleşik olarak adlandırılana kıyasla yeni bir süreç başlatmak ne kadar pahalı olduğunu bilmelisiniz.
return42

1
Bash yerleşiklerinin performans değiş tokuşlarına karşı catbirisini birisine bildirmek ile birine kedi kullanmamalarını bildirmek arasında bir fark var, çünkü bu yavaş. Kedinin doğru seçim olduğu sayısız kullanım durumu vardır, bu yüzden cevabınıza itiraz ediyorum.
GuyPaddock

@GuyPaddock Açıcı bir echodeğişiklik istedi . Kullansa bile cat, bir bash yönlendirmesi kullanması gerekir. neyse. Yani, burada kullanmak için hiçbir anlamı yoktur cat. BTW catGünde 100 kez kullanıyorum , ama asla açıcı istediğinde bağlamda ... anladınız mı?
return42

8

Son zamanlarda tökezlediğim başka bir seçenek şudur:

    {
        echo "First error line"
        echo "Second error line"
        echo "Third error line"
    } >&2

Bu, çok satırlı hata çıkışını daha az hataya eğilimli hale getirirken yalnızca Bash yerleşiklerini kullanır (çünkü &>2her satıra eklemeyi hatırlamanız gerekmez ).


1
İnanamıyorum, bash-redirect'i kullanmanızı önerdiğimde bana oy veriyorsunuz ve kendi cevabınızda bash-redirect'i kullanıyorsunuz.
return42

1
@ return42 Cevabınızı oyladım çünkü tek yaptığı OP'ye başladıkları şeyden daha iyi bir cevap olmadığını söylemekti .. bu gerçekten bir cevap değil. Ayrıca cevabınızda bir alt kabuk öneri görmüyorum ... Cevabınız gerçekten OP'ye catveya soru için konu dışı başka bir yardımcı programın kullanılmamasını tavsiye ediyor .
GuyPaddock


6

read stderr'e yazdırılan ve yeniden yönlendirme hileleri yapmadan yankı gibi kullanılabilen bir kabuk yerleşik komutudur:

read -t 0.1 -p "This will be sent to stderr"

Bu -t 0.1, bir stdin satırını bir değişkene depolayarak, okunan ana işlevselliğini devre dışı bırakan bir zaman aşımıdır.


5
OS X'teki Bash "0.1" e izin vermiyor
James Roth

2

Senaryo yap

#!/bin/sh
echo $* 1>&2

bu sizin aracınız olur.

Veya ayrı bir dosyada komut dosyası istemiyorsanız bir işlev yapın.


6
Bir işlev olması daha iyi (James Roth'un yanıtı gibi) ve sadece ilkini değil, tüm argümanları iletmek daha iyi.
Cascabel

2
Bir işlev neden daha iyi olsun ki? (Veya alternatif olarak: "Neden daha iyi olacağını açıklamak daha iyi ...")
Ogre Psalm33

3
@ OgrePsalm33 Bir işlevin daha iyi olmasının bir nedeni, bir komut dosyası çağrıldığında, komut dosyasının yürütüleceği bir ortam sağlamak için genellikle yeni bir kabuk örneğinin oluşturulmasıdır. Öte yandan, çalışmakta olan kabuğun ortamına bir işlev yerleştirilir. Bir işlevi çağırmak, bu durumda, başka bir kabuk örneğinin oluşturulmasından kaçınılacağı için çok daha verimli bir işlem olacaktır.
destenson

-10

Mac OS X: Kabul edilen yanıtı ve birkaç diğer yanıtı denedim ve hepsi Mac'imde STDERR değil STDOUT yazdı.

Perl kullanarak standart hataya yazmanın taşınabilir bir yolu:

echo WARNING! | perl -ne 'print STDERR'

lol istediğiniz tüm downvote ama bu aslında benim kod kullanmak çözümdür!
Noah Sussman
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.