Bir kabuk komutunun çıktısını sadece başarılı bir şekilde gizlemek ister misiniz?


12

Bir kabuk komutunun çıktısını gizlemek genellikle stderr ve stdout'un yönlendirilmesini içerir. Varsayılan olarak çıktıyı gizleyen ancak hata durumunda biriken tüm çıktıyı döken yerleşik bir tesis veya komut var mı? Bunu uzaktan sshkomutlar için bir sarıcı olarak çalıştırmak istiyorum . Şimdi onları yeniden yönlendirmeyi kullanıyorum ama onları neyin başarısız kıldığı konusunda bir fikrim yok ve bunlar çok ayrıntılı.

DÜZENLEME: Sonunda komuttan önceki tüm komutları biriktirmek, geçerli işlem tanımlayıcısını kullanmak, günlüğü otomatik olarak kaldırmak ve hata kırmızı hatası eklemek için biraz ince ayar yaptığım @Belmin'in cevabına dayalı olarak aşağıdaki şablonu oluşturdum. bir şeyler ters gittiğinde mesaj. Bu şablonda ilk silentsarmalayıcılar başarılı olur, ardından dizin zaten var olduğundan üçüncü komutu başarısız olur:

#!/bin/sh

set -e

SILENT_LOG=/tmp/silent_log_$$.txt
trap "/bin/rm -f $SILENT_LOG" EXIT

function report_and_exit {
    cat "${SILENT_LOG}";
    echo "\033[91mError running command.\033[39m"
    exit 1;
}

function silent {
    $* 2>>"${SILENT_LOG}" >> "${SILENT_LOG}" || report_and_exit;
}

silent mkdir -v pepe
silent mkdir -v pepe2
silent mkdir -v pepe
silent mkdir -v pepe2

2
Yalnızca stdout'u yeniden yönlendirirseniz, stderr yine de görünür; bu sizin için yeterli mi yoksa bir hata varsa stdout'u da görmek ister misiniz?
Kromey

İkisini de görmek istiyorum ama sadece bir şeyler ters giderse, aksi halde hiçbir şey görmek istemiyorum.
Grzegorz Adam Hankiewicz

2
Ne yapmak stdout & stderr bir günlük dosyasına yazdırmak, böylece ekran dağınık değildir. Ben de orada eğer öyleyse, ekrana stderr'yi yazdırmak olduğunu ve bunu görebiliyorum hata. Ayrıntılara ihtiyacım olursa, program çıktısını ve program hatalarını bağlamda içeren günlük dosyasını kontrol edebilirim. Bu şekilde, 'ikisini de görebiliyorum ama sadece bir şeyler ters giderse'. Bu yardımcı olur mu? Bkz. Stackoverflow.com/questions/2871233/…
Stefan Lasiewski

1
Stderr ve stdout'u aynı dosyaya iki ayrı yönlendirmeyle yönlendirmek güvenli midir? Her zaman kullanmamız gerektiğini düşündüm 2>&1:$* >>"${SILENT_LOG}" 2>&1" || report_and_exit
psmith

Yanıtlar:


3

Ben böyle bir bash işlevi kurmak istiyorum:

function suppress { /bin/rm --force /tmp/suppress.out 2> /dev/null; ${1+"$@"} > /tmp/suppress.out 2>&1 || cat /tmp/suppress.out; /bin/rm /tmp/suppress.out; }

Ardından, şu komutu çalıştırabilirsiniz:

suppress foo -a bar

Sisteminizde root olmayan erişime sahip bir saldırgan, rm ve komut çağrısı arasında bir /etc/passswdveya daha fazla kritik dosyaya işaret eden ve içeriğin üzerine yazılmasını sağlayacak bir sembolik bağlantı yapmaya çalışabilir .
Mitar

1
BTW, yukarıdaki yönlendirmelerin sırası şu olmalıdır: $* > /tmp/surpress.out 2>&1Bu gerçekten stderr'i yakalar.
Mitar

2
$*keyfi girişi işlemek için en iyisi değildir. Özellikle boşluklar veya bayraklar içerdiğinde. En taşınabilir stackoverflow.com/questions/743454/…${1+"$@"}
balrok

Her iki yoruma göre değiştirildi. Teşekkürler --- iyi bilgi.
Belmin Fernandez


7

Bu amaçla bir senaryo yazmak yeterince kolay olmalıdır.

Tamamen denenmemiş bu senaryo gibi bir şey.

OUTPUT=`tempfile`
program_we_want_to_capture &2>1 > $OUTPUT
[ $? -ne 0 ]; then
    cat $OUTPUT
    exit 1
fi
rm $OUTPUT

Öte yandan bir betiğin parçası olarak çalıştırdığım komutlar için genellikle tüm çıktıları yazdırmaktan daha iyi bir şey istiyorum. Sık sık gördüklerimi bilinmeyene sınırlarım. İşte on yıl önce okuduğum bir şeyden uyarladığım bir senaryo.

#!/bin/bash

the_command 2>&1 | awk '
BEGIN \
{
  # Initialize our error-detection flag.
  ErrorDetected = 0
}
# Following are regex that will simply skip all lines
# which are good and we never want to see
/ Added UserList source/ || \
/ Added User/ || \
/ init domainlist / || \
/ init iplist / || \
/ init urllist / || \
/ loading dbfile / || \
/^$/ {next} # Uninteresting message.  Skip it.

# Following are lines that we good and we always want to see
/ INFO: ready for requests / \
{
  print "  " $0 # Expected message we want to see.
  next
}

# any remaining lines are unexpected, and probably error messages.  These will be printed out and highlighted.
{
  print "->" $0 # Unexpected message.  Print it
  ErrorDetected=1
}

END \
{
  if (ErrorDetected == 1) {
    print "Unexpected messages (\"->\") detected in execution."
    exit 2
  }
}
'
exit $?

5

Bunu yapmanın temiz bir yolu olduğunu sanmıyorum, aklıma gelen tek şey

  • Komutun çıktısını yakalayın.
  • Komutun dönüş değerini ve başarısız olup olmadığını kontrol edin
    • yakalanan çıktıyı görüntüler.

Bunu uygulamak ilginç bir proje olabilir ama belki de Soru-Cevap ötesinde olabilir.


Bir işlev ile yapılabilir olmalıdır. Hm, bir deneyeyim.
Belmin Fernandez

1

gibi bir şeyle kısa sürmek tehcommand &>/tmp/$$ || cat /tmp/$$

ne kadar kullanılabilirlik / yazım istediğinize / ihtiyacınıza bağlıdır. (örneğin, kanal olarak kullanmak veya komutu bağımsız olarak iletmek)

@zoredache kısa senaryosu temelde bunun için daha fazla sağlamlık, eşzamanlılık vb.


1

Deneyin:

out=`command args...` || echo $out

2
Ben şöyle yazardımout="$(command args...)" || echo "$out"
kasperd
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.