Come inviare tutto l'output a `logger` nella shell POSIX?


10

Vorrei registrare l'output standard e l'errore standard separatamente durante l' .xprofileutilizzo logger. In Bash penso che sarebbe simile a questo:

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

Come lo farei in modo compatibile con POSIX /bin/sh ?

Risposte:


10

Non esiste un equivalente POSIX. È possibile eseguire solo un reindirizzamento con exec, non un fork. Una pipa richiede una forchetta e il guscio attende che il bambino finisca.

Una soluzione è mettere tutto il codice in una funzione.

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

(Questo registra anche qualsiasi errore dall'istanza stdout del logger all'istanza stderr. Puoi evitarlo con più shuffle di descrittore di file.)

Se vuoi che la shell genitore esca anche se i loggerprocessi sono ancora in esecuzione, metti &alla fine delle loggerinvocazioni.

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

In alternativa, puoi usare le pipe con nome.

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"

Questo apparirà in syslog come due voci (out & err) per l'intero script. L'esempio nella domanda avrà una (o due) voci per comando.
DarkHeart,

@DarkHeart Non capisco il tuo commento. Il codice nella domanda e entrambe le soluzioni che propongo eseguono lo stesso numero di istanze loggere trasmettono lo stesso input a ciascuna di esse.
Gilles 'SO- smetti di essere cattivo' il

scusa, errore mio
DarkHeart,

1
Sembra più semplice , quindi vado con la tua soluzione di pipe denominata.
l0b0,

9

Sostituzione comando / processo 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

Dovresti essere in grado di usarlo come:

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

Ecco una versione che utilizza il mktempcomando:

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

... che fa più o meno la stessa cosa, tranne per il fatto che consente mktempdi selezionare il nome file per te. Questo funziona perché la sostituzione del processo non è affatto magica e funziona in un modo molto simile per comandare la sostituzione . Invece di sostituire l'espansione con il valore del comando eseguito al suo interno come fa la sostituzione dei comandi , la sostituzione del processo lo sostituisce con il nome di un collegamento al filesystem in cui è possibile trovare l'output.

Mentre la shell POSIX non fornisce un corollario diretto a una cosa del genere, emularla è molto semplice. Tutto quello che devi fare è creare un file, stampare il suo nome sullo standard da una sostituzione di comando e sullo sfondo dello stesso eseguire il tuo comando che verrà emesso su quel file. Ora puoi semplicemente reindirizzare al valore di tale espansione, esattamente come fai con la sostituzione del processo. E così la shell POSIX fornisce ovviamente tutti gli strumenti di cui hai bisogno - tutto ciò che serve è metterli in uso secondo le tue esigenze.

Entrambe le versioni precedenti assicurano di distruggere il collegamento del filesystem alle pipe che creano / usano prima di utilizzarle. Ciò significa che non è necessario alcun cleanup dopo il fatto e, cosa più importante, i loro flussi sono disponibili solo per i processi che li aprono inizialmente - e quindi i loro collegamenti al filesystem non possono essere usati come mezzo per snoop / dirottare la tua attività di registrazione. Lasciare i loro collegamenti fs nel filesystem è un potenziale buco nella sicurezza.


Un altro modo è avvolgerlo. Può essere fatto all'interno dello script.

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

Ciò consentirebbe fondamentalmente al tuo script di chiamarsi se non lo è ancora e di farti avviare una directory di lavoro in temp.


1
Fatto , grazie!
l0b0,

@ l0b0 - Sto per aggiornare un altro tipo di questo tipo ... È più generale e finalmente sono riuscito a dargli la possibilità di gestire alcune opzioni in relazione ai descrittori / file / i.
Mikeserv,

@ l0b0 - se si voleva utilizzare mktempe altri comandi non standard, potrebbe essere: _log()( p=; mkfifo "${p:=$(mktemp -u)}"; printf %s "$p"; exec <&- >&- <>/dev/null >&0; { rm "$p"; logger --priority user."$1" --tag "${0##*/}"; } <"$p" &). L'ho scritto usando un linguaggio di comando completamente portatile in tutti i modi, ad eccezione del tuo. Inoltre, basenamenon è un'utilità molto utile. "${0##*/}"è sia più robusto che più veloce.
Mikeserv,

L'ho cambiato perché ne ho solo bisogno per funzionare su piattaforme moderne; il problema principale è che .xprofile deve essere eseguito con sh.
l0b0,

1
@Wildcard - solo un minuto e cercherò di risolvere la prima parte della domanda, ma la risposta alla seconda è sì: il caso limite è zshabilitato con w / multios. Per quanto riguarda la prima parte: { this; can\'t; happen; before; } < this. Questo aiuta?
Mikeserv,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.