Rediriger la sortie vers less à partir du script interne

Sep 24 2020

Je peux rediriger la sortie d'un script vers un fichier journal depuis l'intérieur du script avec exec:

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

Est-il possible de rediriger la sortie vers lessau lieu d'un fichier? j'ai essayé

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

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

mais cela échoue d'une manière étrange ... la moins invite est visible mais vous vous retrouvez au terminal.

Je voudrais configurer cela au début du script (afin qu'il puisse être conditionnel, en fonction des arguments, tty, etc.).

Réponses

1 zevzek Sep 25 2020 at 01:53

Votre script devrait attendre le lessprocessus enfant, sinon votre script se terminera avant lui et lessse retrouvera soudainement en dehors du groupe de processus de premier plan, incapable de lire les commandes du terminal ou de restaurer les paramètres du terminal.

De plus, pour éviter lessd'attendre indéfiniment la fin de son entrée, votre script doit fermer le tube.

Mettre tout cela ensemble:

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

Mais ce n'est pas très agréable, pas portable pour la plupart des autres shells, et s'appuyant sur un comportement non documenté (et peu fiable) de bash: waitcela ne fonctionnera pas bien si vous en avez plus d'un exec > >(...)dans votre script, et il attendra également sur un autre arrière-plan les processus ont commencé avec &.


Une meilleure idée serait de faire appeler votre script lui-même, en utilisant une variable d'environnement pour éviter une récursion infinie:

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

Essayez juste ceci (sans la execligne):

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

(mettre à jour)

Si vous souhaitez inclure tout le script, vous pouvez envelopper le script avec { ... }

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

# whatever output you want...

} | less