Çıktıyı ancak komut başarılı olursa nasıl bastırabilirim?


22

Genellikle başarılı olan ikincil komutların çıktısını bastırarak bir betiğin çıktısını basitleştirmek istiyorum.

Ancak, -qbunları kullanmak zaman zaman başarısız olduklarında çıktısını gizler, bu yüzden hatayı anlama imkanım yoktur. Ek olarak, bu komutlar çıktılarını açarlar stderr.

Bir komutun çıktısını, sadece başarılı olursa bastırmanın bir yolu var mı ?

Örneğin (ancak bunlarla sınırlı olmamak üzere) şunun gibi bir şey:

mycommand | fingerscrossed

Her şey yolunda giderse fingerscrossed, çıkışı yakalar ve atar. Aksi takdirde, onu standart veya hata çıktısına ekler (ne olursa olsun).

Yanıtlar:


36

moreutils' chronickomutu sadece şunu yapar:

chronic mycommand

mycommandbaşarısız olduğu sürece çıktısını yutar , bu durumda çıktı görüntülenir.


1
Teşekkür ederim. Çoğu Unix işletim sisteminde varsayılan olarak kurulu olmadığını kabul ediyorum.
Matthieu Napoli

1
Muhtemelen hayır, yaygın olarak paketlenmiş olmasına rağmen kurulumu kolay olmalıdır.
Stephen Kitt

1
Debian paketinde var moreutils. Zaten benim için güzel, :)
Tom Zych

6
Tüm çıktının bellekte saklandığını unutmayın.
Stéphane Chazelas

1
@ StéphaneChazelas, bunun gibi bir şeyi uygulamanın tek yolu, çıkışın gerekli olması durumunda komut çalışırken kaydedilmesi gerekiyor.
Centimane

11
### do this bit once at the top of your script
divert=
exec 3<>"${divert:=$(mktmp)}" 4<>/dev/null
rm -- "$divert"; unset divert
### then do this bit as often as needed
command >&3 2>&3
cat <&3 >&"$(((RTN=$?)?2:4))"

Bu muhtemelen hile yapmalı. Her birinin çıktısını commandsilinmiş geçici bir dosyaya tamponlar ve daha sonra /dev/nullgeri dönüş durumunun sıfır olmamasına bağlı olarak çıktısını ya ya da stderr olarak siler . Temp dosyası önceden silindiğinden, mevcut kabuk ve alt dosyaları dosya tanımlayıcısında ( /proc/$pid/fduygun izinlere sahip sinsi sümükleri engellemek) dışında hiçbir işlem tarafından okunamaz ve işin bitince temizlenmesi gerekmez.

Belki Linux sistemlerinde daha uygun bir çözüm:

divert(){
    "$@" >&3 2>&3 ||
    eval "cat <&3
          return $?"
}   3<<"" 3<>/dev/fd/3

... En kabuklarda, diğerleri gibi çok çalışır, şöyle diyoruz ki hariç: divert some simple-command with args. Yüksek çıkış komutlarına dikkat edin."$@" olsa için dash, yashya da borularla buraya-belgeleri yapmak diğer bazı kabukları - Bence boru tampon doldurmak için bu kabuklarda mümkün olabilir düşünüyorum (linux'lar etrafında 128kb bir varsayılan olarak) ve çıkmaza böylece . Yani için bir endişe olmamalı ksh, mksh, bash, zshgerçi veya Bourne kabuğu, - bunların hepsi temelde aynı şeyi yapmak açıkça yukarıda yaptığımız gibi exec.


9

Genellikle hata durumunda komut stderrsize verilen mesajları gönderir , böylece görevinizi yerine getirebilirsinizstdout

mycommand > /dev/null


Teşekkürler, ama benim de söylediğim gibi, komutlarım bütün çıktıları açarlar stderr(yani etkisizdir).
Matthieu Napoli

4

Kendi kronik hale getirmek için

my_chronic() {
  tmp=$(mktemp) || return # this will be the temp file w/ the output
  "$@"  > "$tmp" 2>&1 # this should run the command, respecting all arguments
  ret=$?
  [ "$ret" -eq 0 ] || cat "$tmp"  # if $? (the return of the last run command) is not zero, cat the temp file
  rm -f "$tmp"
  return "$ret" # return the exit status of the command
}

3

Makefiles'de böyle bir şey yapıyorum:

if (mycommand) &> mycommand.log; then 
  echo success 
else 
  c=$?; 
  echo;echo -e "Bad result from previous command, see mycommand.log for more details";echo;
  command_to_run_on_fail
  (exit $c)
fi

Bunu kendi durumunuza uyarlayarak, şöyle bir şey yapabilirsiniz:

if ! (mycommand) &> mycommand.log; then 
  c=$?; 
  cat mycommand.log
  rm mycommand.log
  (exit $c)
fi

Bu nedenle, "if" komutu çalıştırır ve çıktıyı mycommand.log dosyasına aktarır. Stdout vs stdout vs herhangi birşeyi yakalamanız gerekirse, '&>' boru komutunu '>' olarak değiştirmeniz gerekebilir. Komut başarısız olursa, hata kodunu yakalayın, mycommand.log dosyasının içeriğini yazdırın, mycommand.log dosyasını kaldırın ve son olarak orijinal hata koduyla geri dönün.

($ C çıkışından) olmadan 'rm' komutunun döndürdüğü ile eşleşen çıkış koduyla geri dönersiniz.

Son olarak, bir astar istiyorsanız, bunun gibi bir şey işe yarar.

mycommand &> mycommand.log || cat mycommand.log; rm mycommand.log

2
Gerçekten komutlarınızı / etc. içinde (...)böyle? Çünkü sizin için faydalı bir şey yapmaz, ancak ekstra mermiler oluşturur.
Etan Reisner

@EtanReisner (exit $c)ayar yapıyor $?, aksi halde yapamayacağınız bir şey. if ! (mycommand) &>xeğer komut örneğin kullanıyorsa timeveya bir kabuk hatası verirse, yönlendirme ile anlamlıdır .
Michael Homer

@MichaelHomer - orada olanlar için o kıvrımlar var { ; }... yine exitde biraz zor olsa da, kuşkusuz.
mikeserv

Bir makefile snippet'inde, önceden kaydedilmiş olandan çıkmaya çalışıyorsanız $?, sadece kullanabilirsiniz, exit $cancak evet, diğer durumlarda (exit $?)değeri vardır ( rret() { return $1; }genel olarak bir kabuk işlevi daha iyi olacağını düşünürdüm). Komutlar için alt kabuk hala mikeserv in belirtildiği gibi olmuyor.
Etan Reisner,

3

Sadece bu kadar basit cevabı buldum bu diğer soru :

output=`mycommand 2>&1` || echo $output

ÇALIŞIYOR bir cazibe gibi!


Not: Kullanım durumum için bu çok daha basit bir çözümdü (tüm CI sunucularına fazladan şeyler yüklemekten kaçının), bu yüzden bunu kabul edildi olarak işaretlemeyi seçtim. YMMV.
Matthieu Napoli,

Kabuk betiğinizde set -o xtrace kullanırsanız, tüm çıktıların tekrar atama çıktısının ayrıntılarının günlüğe kaydedilmesinin bir parçası olacağını unutmayın = ... :-). Bu durumda muhtemelen kronik kullanmak daha iyidir.
Jan-Philip Gehrcke
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.