Reindirizza l'output a less dall'interno dello script

Sep 24 2020

Posso reindirizzare l'output di uno script a un file di registro dall'interno dello script con exec:

#!/bin/bash
exec > stdout.log 2>&1
echo hello world

È possibile reindirizzare l'output a lessinvece che a un file? Provai

#!/bin/bash
exec > >(less) 2>&1

# output some text
for (( i=1; i <= 500; i++ )); do echo "hello world $i"; done

ma questo fallisce in modo strano ... il prompt meno è visibile ma si finisce di nuovo al terminale.

Mi piacerebbe impostarlo all'inizio dello script (quindi può essere condizionale, a seconda degli argomenti, tty, ecc.).

Risposte

1 zevzek Sep 25 2020 at 01:53

Dovresti fare in modo che il tuo script attenda il lessprocesso figlio, altrimenti il ​​tuo script terminerà prima di esso e lesssi ritroverà improvvisamente fuori dal gruppo di processi in primo piano, non in grado di leggere i comandi dal terminale o ripristinare le impostazioni del terminale più.

Inoltre, per evitare lessdi aspettare per sempre la fine del suo input, lo script dovrebbe chiudere il pipe ad esso.

Mettendo tutto insieme:

exec > >(less) 2>&1
trap 'exec >&- 2>&-; wait' EXIT
# >&- 2>&- => close stdout and stderr => cause EOF on less' stdin

seq 1 50000
# the rest of your script

Ma questo non è molto bello, non portabile alla maggior parte delle altre shell e fa affidamento su un comportamento non documentato (e inaffidabile) di bash: waitnon funzionerà bene se ne hai più di una exec > >(...)nel tuo script e aspetterà anche su un altro sfondo processi iniziati con &.


Un'idea migliore sarebbe quella di far chiamare lo script da solo, utilizzando una variabile di ambiente per evitare la ricorsione infinita:

if [ ! "$CALLED_MYSELF" ]; then set -o pipefail # supported in bash, but not in all the shells CALLED_MYSELF=1 "$0" "$@" 2>&1 | less
    exit
fi

seq 1 50000
# the rest of your script
1 SimonS Sep 24 2020 at 22:05

Prova solo questo (senza la execlinea):

for (( i=1; i <= 500; i++ )); do echo "hello world $i"; done | less

(aggiornare)

Se vuoi includere l'intero script, puoi avvolgere lo script con { ... }

#!/bin/bash
{
# output some text
for (( i=1; i <= 500; i++)) do echo "hello world $i"; done

# whatever output you want...

} | less