Sembunyikan output perintah shell hanya jika berhasil?


12

Menyembunyikan output dari perintah shell biasanya melibatkan redirect stderr dan stdout. Apakah ada fasilitas atau perintah builtin yang secara default menyembunyikan output tetapi pada kesalahan dumps semua akumulasi output? Saya ingin menjalankan ini sebagai pembungkus untuk sshperintah jarak jauh . Sekarang saya memiliki mereka menggunakan pengalihan tetapi saya tidak mendapatkan petunjuk tentang apa yang membuat mereka gagal, dan mereka terlalu bertele-tele.

EDIT: Pada akhirnya saya membuat template berikut berdasarkan jawaban oleh @Belmin yang saya tweak sedikit untuk mengakumulasi semua perintah sebelumnya dari skrip, gunakan pengenal proses saat ini, secara otomatis menghapus log, dan menambahkan kegagalan kesalahan merah pesan saat terjadi kesalahan. Dalam templat ini silentpembungkus awal akan berhasil, kemudian gagal perintah ketiga karena direktori sudah ada:

#!/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
Jika Anda hanya mengarahkan stdout, stderr akan tetap muncul; apakah ini cukup untuk Anda, atau apakah Anda ingin melihat stdout juga jika ada kesalahan?
Kromey

Saya ingin melihat keduanya tetapi hanya jika ada yang salah, kalau tidak saya tidak ingin melihat apa pun.
Grzegorz Adam Hankiewicz

2
Apa yang saya lakukan adalah mencetak stdout & stderr ke file log sehingga tidak mengacaukan layar. Saya juga mencetak stderr ke layar, sehingga jika ada yang dan kesalahan saya bisa melihatnya. Jika saya perlu detail, saya dapat memeriksa file log, yang berisi output program dan kesalahan program dalam konteks. Dengan cara ini, saya bisa 'melihat keduanya tetapi hanya jika ada yang salah'. Apakah ini membantu? Lihat stackoverflow.com/questions/2871233/...
Stefan Lasiewski

1
Apakah aman untuk mengarahkan ulang stderr dan stdout ke file yang sama dengan dua pengalihan terpisah? Saya pikir kita harus selalu menggunakan 2>&1, seperti:$* >>"${SILENT_LOG}" 2>&1" || report_and_exit
psmith

Jawaban:


3

Saya akan menyiapkan fungsi bash seperti ini:

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; }

Kemudian, Anda bisa menjalankan perintah:

suppress foo -a bar

Seorang penyerang yang memiliki akses non-root pada sistem Anda, bisa mencoba membuat symlink antara rm dan perintah panggilan, yang akan menunjuk ke /etc/passswdatau beberapa file penting lainnya dan mendapatkan konten ditimpa.
Mitar

1
BTW, urutan pengalihan di atas harus: $* > /tmp/surpress.out 2>&1Ini benar-benar menangkap stderr.
Mitar

2
$*bukan yang terbaik untuk menangani input sewenang-wenang. Terutama ketika itu berisi spasi atau bendera. Paling portabel ${1+"$@"}menurut stackoverflow.com/questions/743454/…
balrok

Dimodifikasi per kedua komentar. Terima kasih --- info bagus.
Belmin Fernandez


7

Seharusnya cukup mudah untuk menulis skrip untuk tujuan ini.

Sesuatu seperti skrip yang sama sekali belum teruji.

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

Di sisi lain untuk perintah saya jalankan sebagai bagian dari skrip saya biasanya menginginkan sesuatu yang lebih baik daripada hanya mencetak semua output. Saya sering membatasi apa yang saya lihat untuk yang tidak dikenal. Ini adalah skrip yang saya adaptasi dari sesuatu yang saya baca lebih dari satu dekade yang lalu.

#!/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

Saya tidak berpikir ada cara yang bersih untuk melakukan ini, satu-satunya hal yang dapat saya pikirkan adalah

  • Tangkap output dari perintah.
  • Periksa nilai pengembalian perintah dan jika gagal
    • tampilkan hasil tangkapan.

Menerapkan ini mungkin merupakan proyek yang menarik tetapi mungkin melampaui T&J.


Seharusnya bisa dilakukan dengan fungsi. Hm, coba saya coba.
Belmin Fernandez

1

akan kekurangan dengan sesuatu seperti tehcommand &>/tmp/$$ || cat /tmp/$$

tergantung seberapa banyak kegunaan / pengetikan yang Anda inginkan / butuhkan. (misalnya menggunakannya sebagai pipa atau melewati perintah dengan argumen)

Skrip pendek @zoredache pada dasarnya adalah proto-wrapper untuk ini, yang akan memberikan lebih banyak kekuatan, menangani konkurensi, dll


1

Cobalah demikian:

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

2
Saya akan menulisnya sebagaiout="$(command args...)" || echo "$out"
kasperd
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.