Bagaimana saya bisa menekan output hanya jika perintah berhasil?

22

Saya ingin menyederhanakan output skrip dengan menekan output dari perintah sekunder yang biasanya berhasil.

Namun, menggunakan -qmereka menyembunyikan output ketika mereka kadang-kadang gagal, jadi saya tidak punya cara untuk memahami kesalahan. Selain itu, perintah ini mencatat outputnya stderr.

Apakah ada cara untuk menekan output perintah hanya jika berhasil ?

Misalnya (tetapi tidak terbatas pada) sesuatu seperti ini:

mycommand | fingerscrossed

Jika semuanya berjalan dengan baik, fingerscrossedtangkap hasilnya dan buang. Jika tidak, gema ke standar atau output kesalahan (apa pun).

Matthieu Napoli
sumber

Jawaban:

36

moreutils' chronicPerintah tidak hanya itu:

chronic mycommand

akan menelan mycommandoutput, kecuali jika gagal, dalam hal ini output ditampilkan.

Stephen Kitt
sumber
1
Terima kasih. Saya pikir itu tidak diinstal secara default pada sebagian besar OS Unix?
Matthieu Napoli
1
Mungkin tidak, meskipun sudah banyak dikemas sehingga harus mudah dipasang.
Stephen Kitt
1
Debian memilikinya dalam paket moreutils. Baik untuk saya, tetap :)
Tom Zych
6
Perhatikan bahwa ia menyimpan seluruh output dalam memori.
Stéphane Chazelas
1
@ StéphaneChazelas itu kemungkinan satu-satunya cara untuk mengimplementasikan sesuatu seperti ini, output perlu disimpan saat perintah dijalankan jika diperlukan.
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))"

Itu mungkin harus melakukan trik. Ini akan buffer output masing-masing commandke dalam file sementara yang dihapus, dan kemudian menyedot outputnya ke salah satu /dev/nullatau stderr tergantung pada apakah atau tidaknya status pengembaliannya tidak nol. Karena file temp dihapus sebelumnya tidak dapat dibaca oleh proses apa pun kecuali shell saat ini dan anak-anaknya di deskriptor file-nya (kecuali /proc/$pid/fdsnoop licik dengan izin yang sesuai) , dan tidak perlu dibersihkan saat Anda selesai.

Mungkin solusi yang lebih nyaman pada sistem linux:

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

... yang, di sebagian besar kerang, bekerja seperti yang lain, kecuali bahwa Anda dapat menyebutnya seperti: divert some simple-command with args. Waspadalah terhadap perintah output tinggi di "$@", meskipun untuk dash,, yashatau beberapa shell lain yang dilakukan di sini-dokumen dengan pipa - Saya pikir itu mungkin dalam shell untuk mengisi buffer pipa (pada default sekitar 128kb di linux) dan kebuntuan . Itu seharusnya tidak menjadi khawatir untuk ksh, mksh, bash, zsh, atau Bourne shell, meskipun - semua orang pada dasarnya melakukan hal yang sama seperti yang saya lakukan secara eksplisit di atas dengan exec.

mikeserv
sumber
9

Biasanya jika terjadi kesalahan, perintah menampilkan pesan stderrsehingga untuk tugas Anda, Anda bisa menekanstdout

mycommand > /dev/null
Costas
sumber
9
Hati-hati
PyRulez
Terima kasih, tetapi seperti yang saya katakan dalam pertanyaan, perintah saya mencatat semua output stderr(jadi tidak berpengaruh).
Matthieu Napoli
4

Untuk membuat Anda sendiri kronis

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
}
Yakub Minshall
sumber
3

Saya melakukan sesuatu seperti ini di makefiles saya:

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

Menyesuaikan itu dengan situasi Anda, Anda bisa melakukan sesuatu seperti ini:

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

Jadi, "jika" menjalankan perintah dan menyalurkan output ke mycommand.log. Jika Anda perlu menangkap stdout vs stdout vs apa pun, Anda mungkin perlu mengubah perintah pipa '&>' ke '>'. Jika perintah gagal maka tangkap kode kesalahan, cetak konten mycommand.log, hapus mycommand.log, dan akhirnya kembali dengan kode kesalahan asli.

Tanpa (keluar $ c) Anda akan kembali dengan kode keluar yang cocok dengan apa yang dikembalikan oleh perintah 'rm'.

Akhirnya, jika Anda ingin liner satu, sesuatu seperti ini akan berhasil.

mycommand &> mycommand.log || cat mycommand.log; rm mycommand.log
Jordan
sumber
2
Apakah Anda benar-benar membungkus perintah Anda / etc. di (...)seperti itu? Karena itu tidak melakukan apa pun yang berguna untuk Anda tetapi menelurkan sub-shell ekstra.
Etan Reisner
@EtanReisner (exit $c)sedang mengatur $?, sesuatu yang tidak bisa Anda lakukan sebaliknya. if ! (mycommand) &>xberarti dengan pengalihan jika perintah menggunakan eg timeatau akan memberikan kesalahan shell.
Michael Homer
@MichaelHomer - untuk hal-hal itu ada { ; }ikal ... meskipun exitada sedikit rumit, harus diakui.
mikeserv
Dalam potongan makefile jika Anda mencoba untuk keluar dengan yang sebelumnya disimpan $?maka Anda bisa menggunakan exit $ctetapi ya, dalam kasus lain (exit $?)memiliki nilai (meskipun fungsi shell rret() { return $1; }akan lebih baik secara umum saya berpendapat). Subshell untuk perintah masih tidak benar-benar seperti yang ditunjukkan mikeserv.
Etan Reisner
3

Saya baru saja menemukan jawaban yang jauh lebih sederhana pada pertanyaan lain ini :

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

Bekerja seperti pesona!

Matthieu Napoli
sumber
Catatan: untuk kasus penggunaan saya, ini adalah solusi yang jauh lebih sederhana (hindari memasang hal-hal tambahan pada semua server CI) jadi saya memilih untuk menandai yang ini sebagai diterima. YMMV.
Matthieu Napoli
Perhatikan bahwa jika Anda menggunakan set -o xtrace dalam skrip shell Anda maka semua output akan ada lagi sebagai bagian dari pendataan detail dari tugas keluaran = ... :-). Dalam hal ini mungkin lebih baik menggunakan kronis.
Jan-Philip Gehrcke