redirect dan output skrip log

8

Saya mencoba merapikan cuplikan berikut, tujuan desain adalah mencatat semua hasil dari skrip, dan tidak boleh menjadi pembungkus. Garis yang lebih sedikit lebih baik.

Saya tidak peduli dengan input pengguna (pada tahap ini), skrip target dijalankan secara non-interaktif.

Cuplikan perlu

  • stdout output untuk login, dan selalu echo ke konsol
  • output stderr untuk login, dan echo to console iff debugging diaktifkan
  • pesan stderr harus diawali dengan prangko waktu dan kegunaan lainnya

Saat ini saya memiliki yang berikut ini yang hanya menguji di bawah versi terbaru dari bash (4.2+?) Seperti di Ubuntu yang tepat, tetapi melakukan kesalahan pada CentOS6.

DEBUG_LOG="${0##*/}.log"

# copy stdout to log always and echo to console
exec >  >(tee -a ${DEBUG_LOG})           

# copy stderr to log only, unless debugging is enabled
[ $DEBUG_TEST = "true" ] \
  && exec 2> >(tee -a ${DEBUG_LOG} >&2) \
  || exec 2>> ${DEBUG_LOG}

Lalu ini...

# Expand escaped characters, wrap at 70 chars on spaces, 
# and indent wrapped lines
msg_log() { 
  echo -e "$(date +%T) ${0##*/}: $1" \
    | fold -w70 -s | sed '2~1s/^/  /' >&2; 
}
msg_con() { 
  if [ "${DEBUG_TEST}" = "true" ]; then 
    msg_log "$1"
  else
    echo -e "$1" | fold -w70 -s | sed '2~1s/^/  /'; 
  fi
}

Alih-alih, echosaya dapat memanggil salah satu prosedur pesan tersebut, misalnya msg_con "hello world",.
Output skrip kemudian akan pergi ke stderr dengan menetapkan sebagai variabel lingkungan pada waktu panggilan, misalnya  DEBUG_TEST=true myscript,.

Saya telah membaca bahwa exec mungkin tidak berfungsi di beberapa shell seperti busybox. Ada kombinasi mkfifo dan fork di https://stackoverflow.com/a/5200754 yang melakukan hal serupa tetapi saya lebih suka tidak menggunakan garpu kecuali benar-benar diperlukan.

Lebih suka contoh bash, tapi sesuatu yang bekerja di bawah sh atau lebih portabel akan menyenangkan. Ada ide?

Glenn
sumber

Jawaban:

1
function startLogging {
    exec > >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' | tee -a $logfile)
    [ ! -z "$DEBUG" ] && exec 2>&1 || exec 2> >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' >>$logfile)
    echo "=== Log started for $$ at $(date +%F-%T) ==="
}

Anda perlu mengatur $ logfile ke sesuatu

Angelo
sumber
Ini agak keren, cara saya membacanya Anda menggunakan gawk untuk menambahkan header pesan. Itu akan memiliki efek samping tambahan menambahkan mereka ke perintah output juga.
Glenn
Alasan untuk menggunakan gawk untuk menambahkan timestamp (dan memproses id) untuk setiap baris log adalah karena itu akan dieksekusi setiap kali output ditulis dan karenanya memperbarui timestamp. Juga penting untuk menggunakan gawk dan tidak awk karena saya pikir fungsi strftime adalah ekstensi GNU.
Angelo
0

exec > filenameharus bekerja di sh, dan itu benar-benar berfungsi di busybox v1.15.3 (Nov 2011). Tetapi proses substitusi tidak >(command)dapat dilakukan karena ekstensi bash. Hindari menggunakannya dalam skrip. Kenapa >>tidak cukup untukmu?

exec 1>>${DEBUG_LOG}
exec 2>>${DEBUG_LOG}

Solusi lain adalah dengan menentukan pengalihan di luar skrip Anda. Ketika skrip Anda dipanggil di latar belakang (dengan cron, atau skrip sistem, dll.), Mereka harus dipanggil seperti ini

./my_script 1>>${DEBUG_LOG} 2>>${DEBUG_LOG}

Saat Anda menjalankan skrip secara manual dan Anda ingin melihat hasilnya, panggil saja tanpa pengalihan.

Kirikaza
sumber
1
Penanya pertanyaan menginginkan output dari skrip untuk pergi ke konsol dan file log.
0

Dua contoh ini akan melakukan apa yang menjadi tujuan Anda

echo -n $(date) >> $DEBUG_LOG
command 2>&1 | tee -a $DEBUG_LOG

atau

echo -n $(date) >> $DEBUG_LOG
command >> $DEBUG_LOG 2>&1
Luke
sumber
0

Anda bisa menggunakan teeperintah atau scriptperintah keduanya benar-benar bermanfaat.

Falk
sumber
skrip terlihat keren, tetapi tidak benar-benar melakukan apa yang saya butuhkan, perilaku harus dimodifikasi selama runtime.
Glenn