
Я могу перенаправить вывод скрипта в файл журнала изнутри скрипта с помощью exec
:
#!/bin/bash
exec > stdout.log 2>&1
echo hello world
Можно ли перенаправить вывод less
вместо файла? Я пробовал
#!/bin/bash
exec > >(less) 2>&1
# output some text
for (( i=1; i <= 500; i++ )); do echo "hello world $i"; done
но это странным образом не срабатывает... меньше подсказок видно, но вы возвращаетесь к терминалу.
Я хотел бы установить это в начале скрипта (чтобы он мог быть условным, в зависимости от аргументов, tty и т. д.).
решение1
Ваш скрипт должен дождаться less
дочернего процесса, в противном случае он завершится раньше него и less
внезапно окажется вне группы процессов переднего плана, не имея возможности считывать команды с терминала или восстанавливать настройки терминала.
Кроме того, чтобы предотвратить less
вечное ожидание окончания ввода, ваш скрипт должен закрыть канал к нему.
Собираем все это вместе:
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
Но это не очень хорошо, непереносимо для большинства других оболочек и полагается на недокументированное (и ненадежное) поведение bash: wait
не будет работать нормально, если в вашем скрипте их больше одного exec > >(...)
, и он также будет ждать другие фоновые процессы, запущенные с помощью &
.
Лучшей идеей было бы заставить ваш скрипт вызывать сам себя, используя переменную окружения, чтобы избежать бесконечной рекурсии:
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
решение2
Попробуйте просто это (без строки exec
):
for (( i=1; i <= 500; i++ )); do echo "hello world $i"; done | less
(обновлять)
Если вы хотите включить весь скрипт, вы можете обернуть его в{ ... }
#!/bin/bash
{
# output some text
for (( i=1; i <= 500; i++)) do echo "hello world $i"; done
# whatever output you want...
} | less