Как перенаправить вывод всего сценария оболочки внутри самого сценария?
Можно ли перенаправить все выходные данные сценария оболочки Bourne куда-нибудь, но с помощью команд оболочки внутри самого сценария?
Перенаправить вывод одной команды легко, но я хочу что-то вроде этого:
#!/bin/sh
if [ ! -t 0 ]; then
# redirect all of my output to a file here
fi
# rest of script...
Значение: если скрипт запускается не в интерактивном режиме (например, cron), сохраните все данные в файле. Если вы запускаетесь в интерактивном режиме из оболочки, позвольте выводу перейти на стандартный вывод.
Я хочу сделать это для скрипта, обычно запускаемого периодической утилитой FreeBSD. Это часть ежедневной работы, которую я обычно не хочу видеть каждый день в электронной почте, поэтому я не отправляю ее. Однако, если что-то в этом конкретном скрипте дает сбой, это важно для меня, и я хотел бы иметь возможность получать и отправлять по электронной почте результаты этой части ежедневных заданий.
Обновление: ответ Джошуа точный, но я также хотел сохранить и восстановить stdout и stderr по всему сценарию, что делается так:
# save stdout and stderr to file descriptors 3 and 4, then redirect them to "foo"
exec 3>&1 4>&2 >foo 2>&1
# ...
# restore stdout and stderr
exec 1>&3 2>&4
6 ответов
Решение вопроса как обновлено.
#...part of script without redirection...
{
#...part of script with redirection...
} > file1 2>file2 # ...and others as appropriate...
#...residue of script without redirection...
Скобки '{ ... }' обеспечивают единицу перенаправления ввода / вывода. Скобки должны появляться там, где может появиться команда - упрощенно, в начале строки или после точки с запятой. (Да, это может быть уточнено; если вы хотите поспорить, дайте мне знать.)
Вы правы в том, что вы можете сохранить исходные stdout и stderr с указанными вами перенаправлениями, но людям, которым необходимо поддерживать скрипт позже, обычно проще понять, что происходит, если вы расширяете область действия перенаправленного кода, как показано выше.
Обычно мы помещаем один из них в верхнюю часть скрипта или около него. Скрипты, которые анализируют свои командные строки, будут выполнять перенаправление после анализа.
Отправить стандартный вывод в файл
exec > file
с stderr
exec > file
exec 2>&1
добавить как stdout, так и stderr в файл
exec >> file
exec 2>&1
Как отметил в своем комментарии Jonathan Leffler:
exec
имеет две отдельные работы. Первый - заменить текущую исполняемую оболочку (скрипт) новой программой. Другой - изменение перенаправлений ввода / вывода в текущей оболочке. Это отличается отсутствием аргументов exec
,
Вы можете сделать весь скрипт такой функцией:
main_function() {
do_things_here
}
тогда в конце скрипта есть это:
if [ -z $TERM ]; then
# if not run via terminal, log everything into a log file
main_function 2>&1 >> /var/log/my_uber_script.log
else
# run via terminal, only output to screen
main_function
fi
В качестве альтернативы, вы можете записывать все в файл журнала при каждом запуске и по-прежнему выводить его на стандартный вывод, просто выполнив:
# log everything, but also output to stdout
main_function 2>&1 | tee -a /var/log/my_uber_script.log
Для сохранения оригинальных stdout и stderr вы можете использовать:
exec [fd number]<&1
exec [fd number]<&2
Например, следующий код выведет "walla1" и "walla2" в файл журнала (a.txt
), "walla3" на стандартный вывод, "walla4" на стандартный вывод.
#!/bin/bash
exec 5<&1
exec 6<&2
exec 1> ~/a.txt 2>&1
echo "walla1"
echo "walla2" >&2
echo "walla3" >&5
echo "walla4" >&6
Наконец-то я понял, как это сделать. Я хотел не только сохранить вывод в файл, но и выяснить, успешно ли запустился скрипт bash!
Я обернул команды bash внутри функции, а затем вызвал функциюmain_function
с тройником вывода в файл. После этого я зафиксировал вывод, используяif [ $? -eq 0 ]
.
#! /bin/sh -
main_function() {
python command.py
}
main_function > >(tee -a "/var/www/logs/output.txt") 2>&1
if [ $? -eq 0 ]
then
echo 'Success!'
else
echo 'Failure!'
fi