Bagaimana cara mengirim semua output ke `logger` di shell POSIX?


10

Saya ingin mencatat keluaran standar dan kesalahan standar secara terpisah dalam .xprofilemenggunakan logger. Di Bash saya pikir itu akan terlihat seperti ini:

exec 1> >(logger --priority user.notice --tag $(basename $0)) \
     2> >(logger --priority user.error --tag $(basename $0))

Bagaimana saya melakukannya dengan cara yang kompatibel dengan POSIX /bin/sh ?

Jawaban:


10

Tidak ada yang setara dengan POSIX. Anda hanya dapat melakukan pengalihan dengan exec, bukan garpu. Sebuah pipa membutuhkan garpu, dan cangkangnya menunggu anak selesai.

Salah satu solusinya adalah dengan meletakkan semua kode Anda dalam suatu fungsi.

all_my_code () {
  
}
{ all_my_code |
  logger --priority user.notice --tag "$(basename "$0")"; } 2>&1 | 
  logger --priority user.error --tag "$(basename "$0")"

(Ini juga mencatat kesalahan apa pun dari instance stdout dari logger ke instance stderr. Anda dapat menghindari ini dengan mengacak file deskriptor yang lebih banyak.)

Jika Anda ingin induk shell keluar bahkan jika loggerprosesnya masih berjalan, letakkan &di akhir loggerdoa.

{ all_my_code |
  logger --priority user.notice --tag "$(basename "$0")" & } 2>&1 | 
  logger --priority user.error --tag "$(basename "$0")" &

Atau, Anda dapat menggunakan pipa bernama.

pipe_dir=$(mktemp -d)
mkfifo "$pipe_dir/out" "$pipe_dir/err"
<"$pipe_dir/out" logger --priority user.notice --tag "$(basename "$0")" &
<"$pipe_dir/err" logger --priority user.error --tag "$(basename "$0")" &
exec >"$pipe_dir/out" 2>"$pipe_dir/err" 

rm -r "$pipe_dir"

Itu akan muncul di syslog sebagai dua entri (keluar & err) untuk keseluruhan skrip. Contoh dalam pertanyaan akan memiliki satu (atau dua) entri per perintah.
DarkHeart

@DarkHeart Saya tidak mengerti komentar Anda. Kode dalam pertanyaan dan kedua solusi yang saya usulkan menjalankan jumlah instance loggeryang sama dan memberikan input yang sama untuk masing-masingnya.
Gilles 'SANGAT berhenti menjadi jahat'

maaf, kesalahan saya
DarkHeart

1
Ini tampaknya lebih sederhana , jadi saya akan menggunakan solusi pipa bernama Anda.
l0b0

9

Substitusi perintah / proses POSIX


_log()( x=0
    while  [ -e "${TMPDIR:=/tmp}/$$.$((x+=1))" ]
    do     continue; done        &&
    mkfifo -- "$TMPDIR/$$.$x"    &&
    printf %s\\n "$TMPDIR/$$.$x" || exit
    exec >&- >/dev/null
    {  rm -- "$TMPDIR/$$.$x"
       logger --priority user."$1" --tag "${0##*/}"
    }  <"$TMPDIR/$$.$x" &
)   <&- </dev/null

Anda harus dapat menggunakannya seperti:

exec >"$(_log notice)" 2>"$(_log error)"

Berikut adalah versi yang menggunakan mktempperintah:

_log()( p=
    mkfifo "${p:=$(mktemp -u)}"    &&
    printf %s "$p"                 &&
    exec  <&- >&- <>/dev/null >&0  &&
    {   rm "$p"
        logger --priority user."$1" --tag "${0##*/}"
    }   <"$p" &
)

... yang tidak jauh berbeda, kecuali memungkinkan mktempuntuk memilih nama file untuk Anda. Ini bekerja karena proses substitusi sama sekali tidak ajaib dan bekerja dengan cara yang sangat mirip dengan perintah substitusi . Alih-alih mengganti ekspansi dengan nilai perintah yang dijalankan di dalamnya seperti yang dilakukan penggantian substitusi , substitusi proses menggantinya dengan nama tautan filesystem di mana output dapat ditemukan.

Sementara shell POSIX tidak memberikan akibat langsung pada hal seperti itu, meniru itu sangat mudah dilakukan. Yang perlu Anda lakukan adalah membuat file, mencetak namanya ke standar dari substitusi perintah, dan di latar belakang jalankan perintah Anda yang akan menghasilkan file itu. Sekarang Anda bisa mengarahkan kembali ke nilai ekspansi itu - persis seperti yang Anda lakukan dengan substitusi proses. Jadi shell POSIX menyediakan semua alat yang Anda butuhkan tentu saja - yang diperlukan hanyalah Anda menempatkannya untuk digunakan dengan cara yang sesuai untuk Anda.

Kedua versi di atas memastikan bahwa mereka menghancurkan tautan sistem file ke pipa yang mereka buat / gunakan sebelum menggunakannya. Ini berarti tidak ada pembersihan yang diperlukan setelah fakta, dan, yang lebih penting, aliran mereka hanya tersedia untuk proses yang awalnya membukanya - dan karenanya tautan sistem file mereka tidak dapat digunakan sebagai sarana untuk mengintai / membajak aktivitas logging Anda. Untuk meninggalkan fs-link mereka di sistem file adalah lubang keamanan potensial.


Cara lain adalah membungkusnya. Itu bisa dilakukan dari dalam skrip.

x=${x##*[!0-9]*}
_log(){ 
    logger --priority user."$1" --tag "${0##*/}"
}   2>/dev/null >&2

cd ../"$PPID.$x" 2>/dev/null &&
trap 'rm -rf -- "${TMPDIR:-/tmp}/$PPID.$x"' 0 || 
{   until cd -- "${TMPDIR:=/tmp}/$$.$x"
    do    mkdir -- "$TMPDIR/$$.$((x+=1))"
    done  && 
    x=$x "$0" "$@" | _log notice
    exit
}   2>&1 | _log error

Itu pada dasarnya akan memungkinkan skrip Anda untuk memanggil dirinya sendiri jika belum dan membuat Anda direktori kerja di temp untuk boot.


1
Selesai , terima kasih!
l0b0

@ l0b0 - Saya baru saja akan memperbarui jenis lain seperti ini ... Ini lebih umum, dan saya akhirnya memberikannya kemampuan untuk menangani beberapa opsi seperti yang terkait dengan i / o deskriptor / file.
mikeserv

@ l0b0 - jika Anda ingin menggunakan mktempdan perintah non-standar lainnya, bisa jadi: _log()( p=; mkfifo "${p:=$(mktemp -u)}"; printf %s "$p"; exec <&- >&- <>/dev/null >&0; { rm "$p"; logger --priority user."$1" --tag "${0##*/}"; } <"$p" &). Saya menulisnya menggunakan bahasa perintah sepenuhnya portabel dalam semua cara - dengan pengecualian Anda sendiri. Juga, basenamebukan utilitas yang sangat berguna. "${0##*/}"keduanya lebih kuat dan lebih cepat.
mikeserv

Saya mengubahnya karena saya hanya membutuhkannya untuk bekerja pada platform modern; masalah utama adalah bahwa .xprofile memiliki akan dieksekusi dengan sh.
l0b0

1
@ Kartu Memori - hanya satu menit dan saya akan mencoba untuk memilah bagian pertama dari pertanyaan, tetapi jawaban untuk yang kedua adalah ya: kasus tepi zshw / multios diaktifkan. Adapun bagian pertama: { this; can\'t; happen; before; } < this. Apakah itu membantu?
mikeserv
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.