POSIX kabuğundaki tüm çıktıları “logger” a nasıl gönderirim?


10

.xprofileKullanırken standart çıktı ve standart hatayı ayrı ayrı günlüğe kaydetmek istiyorum logger. Bash'de bunun şöyle görüneceğini düşünüyorum:

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

Bunu POSIX /bin/sh uyumlu bir şekilde nasıl yapabilirim ?

Yanıtlar:


10

POSIX eşdeğeri yok. Çatalla değil, yalnızca ile yeniden yönlendirme yapabilirsiniz exec. Bir boru çatal gerektirir ve kabuk çocuğun bitmesini bekler.

Bir çözüm, tüm kodunuzu bir fonksiyona koymaktır.

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

(Bu ayrıca günlükçünün stdout örneğinden stderr örneğine kadar olan herhangi bir hatayı günlüğe kaydeder. Daha fazla dosya tanımlayıcı karıştırmasıyla bunu önleyebilirsiniz.)

loggerİşlemler hala çalışıyor olsa bile üst kabuğun çıkmasını istiyorsanız &, loggerçağrıların sonuna koyun .

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

Alternatif olarak, adlandırılmış yöneltmeler kullanabilirsiniz.

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"

Bu, syslog içinde tüm komut dosyası için iki giriş (out & err) olarak görünür. Sorudaki örnekte komut başına bir (veya iki) giriş olacaktır.
DarkHeart

@DarkHeart Yorumunuzu anlamıyorum. Sorudaki kod ve önerdiğim her iki çözüm de aynı sayıda örneği çalıştırıyor ve loggerher birine aynı girişi geçiriyor.
Gilles 'SO- kötü olmayı bırak

üzgünüm, hatam
DarkHeart

1
Bu daha basit görünüyor , bu yüzden adlandırılmış boru çözümünüzle gidiyorum.
l0b0

9

POSIX komutu / işlem ikamesi


_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

Bunu şu şekilde kullanabilmelisiniz:

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

mktempKomutu kullanan bir sürüm :

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

... aynı şeyi yapar, ancak mktempsizin için dosya adını seçmenize izin verir . Bu, süreç ikamesi hiçbir şekilde büyülü olmadığı ve ikame komutuna çok benzer bir şekilde çalıştığı için çalışır . Genişletme yerine komut ikamesi gibi içinde çalıştırılan komutun değerini değiştirmek yerine , işlem ikamesi , çıktının bulunabileceği bir dosya sistemi bağlantısının adıyla değiştirilir.

POSIX kabuğu böyle bir şeye doğrudan bir sonuç vermese de, taklit etmek çok basit bir şekilde yapılır. Yapmanız gereken tek şey bir dosya yapmak, adını bir komut değiştirme dışında standart olarak yazdırmak ve aynı dosyanın arka planında o dosyaya verilecek komutunuzu çalıştırmaktır. Şimdi sadece bu genişlemenin değerine yönlendirebilirsiniz - tıpkı süreç ikamesi gibi. Ve böylece POSIX kabuğu, elbette ihtiyacınız olan tüm araçları sağlar - tek gereken, onları size uygun bir şekilde kullanmanızdır.

Yukarıdaki sürümlerin her ikisi de, hiç kullanmadan önce oluşturdukları / kullandıkları boruların dosya sistemi bağlantısını yok etmelerini sağlar. Bu, olaydan sonra herhangi bir temizleme gerekmediği anlamına gelir ve daha da önemlisi, akışları yalnızca başlangıçta açılan işlemler için kullanılabilir - ve bu nedenle dosya sistemi bağlantıları, günlük etkinliğinizi gizlemek / kaçırmak için bir araç olarak kullanılamaz. Fs-linklerini dosya sisteminde bırakmak potansiyel bir güvenlik açığıdır.


Başka bir yol onu sarmaktır. Senaryo içinden yapılabilir.

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

Bu, temel olarak henüz komut dosyanızın kendisini çağırmasına izin verir ve önyükleme için geçici bir çalışma dizini alır.


1
Tamam , teşekkürler!
l0b0

@ l0b0 - Bunun gibi başka bir tür güncellemek üzereyim ... Daha genel amaçlı ve nihayet i / o tanımlayıcıları / dosyaları ile ilgili bazı seçenekleri işleme yeteneği vermek için var.
mikeserv

@ l0b0 - Kullanmak isteseydiniz mktempve diğer standart dışı komutları, olabilir: _log()( p=; mkfifo "${p:=$(mktemp -u)}"; printf %s "$p"; exec <&- >&- <>/dev/null >&0; { rm "$p"; logger --priority user."$1" --tag "${0##*/}"; } <"$p" &). Tamamen taşınabilir komut dili kullanarak yazdım - kendiniz hariç. Ayrıca, basenameçok yararlı bir yardımcı program değildir. "${0##*/}"hem daha sağlam hem de daha hızlı.
mikeserv

Değiştirdim çünkü sadece modern platformlarda çalışmak için ihtiyacım var; ana konu oldu .xprofile sahiptir ile yürütülecek sh.
l0b0

1
@Wildcard - sadece bir dakika ve sorunun ilk kısmını sıralamaya çalışacağım, ancak ikincinin cevabı evet: kenar durumu zshw / multios etkin. İlk bölümde gelince: { this; can\'t; happen; before; } < this. Bu yardımcı olur mu?
mikeserv
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.