Redirigir la salida a menos desde el script interno

Redirigir la salida a menos desde el script interno

Puedo redirigir la salida de un script a un archivo de registro desde dentro del script con exec:

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

¿Es posible redirigir la salida a lessun archivo en lugar de hacerlo? Lo intenté

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

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

pero esto falla de una manera extraña... cuanto menos mensaje es visible, terminas de regreso en la terminal.

Me gustaría configurar esto al inicio del script (para que pueda ser condicional, dependiendo de los argumentos, tty, etc.).

Respuesta1

Debe hacer que su secuencia de comandos espere al lessproceso hijo; de lo contrario, su secuencia de comandos terminará antes que él y lessde repente se encontrará fuera del grupo de procesos de primer plano, sin poder leer comandos desde la terminal ni restaurar la configuración de la terminal.

Además, para evitar lessesperar eternamente hasta el final de su entrada, su script debe cerrar la tubería.

Juntando todo eso:

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

Pero esto no es muy agradable, no es portátil para la mayoría de los otros shells y depende del comportamiento no documentado (y poco confiable) de bash: waitno funcionará bien si tiene más de uno exec > >(...)en su script y también esperará en otros antecedentes. procesos iniciados con &.


Una mejor idea sería hacer que su script se llame a sí mismo, usando una variable de entorno para evitar la recursividad 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

Respuesta2

Pruebe solo esto (sin la execlínea):

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

(actualizar)

Si desea incluir el script completo, puede envolver el script con{ ... }

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

# whatever output you want...

} | less

información relacionada