Отправить stdout и stderr в файл, системный журнал и терминал

8

Для некоторых облачных машин, которые я запускаю, я пытаюсь войти в определенный файл, системный журнал и терминал / консоль.

В верхней части сценариев настройки моего компьютера / cloud-init у меня есть следующее:

#!/bin/bash
exec &> >(tee "/tmp/box-setup.log" | logger -t box-setup)
apt-get install -y some-package

Это прекрасно работает при отправке вывода в файл и системный журнал, но не направляет вывод на терминал.

Вообще говоря, отсутствие вывода на терминал не является большой проблемой, за исключением случаев, когда я отлаживаю с удаленной консоли. Когда это происходит, я полностью ослеп, потому что консоль пуста, когда выполняется скрипт bash.

Существует ли простой способ с помощью bashперенаправления или чего-либо еще, чтобы передать весь вывод (стандартный вывод вместе со стандартной ошибкой) в файл, системный журнал и терминал одновременно?

Я использую Ubuntu 16.04.

Джонатан Оливер
источник

Ответы:

8

Добавьте подстановку вложенного процесса и еще одну, teeнапример:

exec &> >(tee >(tee "/tmp/box-setup.log" | logger -t box-setup))

Первый teeв рамках подстановки основного процесса отправляет STDOUT / STDERR на терминал, а также на подстановку вложенного процесса, teeвнутренняя часть, которая сохраняет содержимое в файл, /tmp/box-setup.logи канал используется для отправки вывода также на loggerSTDIN.

heemayl
источник
я запутался в нескольких вызовах тройника, он будет разветвляться на n потоков, разве это не должно быть эквивалентно? exec &> >(tee /tmp/box-setup.log >(logger -t box-setup))
ThorSummoner
3

Я полностью ослеп, потому что консоль пуста, когда выполняется скрипт bash.

Возможно, вы захотите решить эту проблему другим способом: запустите ваш bash-скрипт в фоновом режиме, запустите less /tmp/box-setup.logи нажмите F, чтобы продолжать обновлять экран по мере добавления строк в файл, который он просматривает (например tail -f).

Если запуск сценария в фоновом режиме является проблемой, используйте tmuxили, screenчтобы объединить несколько сеансов в одно соединение ssh. Используйте ту же lessкоманду в другой оболочке.


Оригинальная проблема:

teeможно копировать в несколько мест назначения. Сделайте один из них терминалом, используя /dev/ttyспециальный файл. Я думаю, что это всегда относится к контролю tty текущего процесса. Или, может быть, лучше, /dev/stderrпотому teeчто stderr все еще подключен к stderr оболочки. (Это позволяет отключить скрипт с помощью &> / dev / null).

exec &> >(tee /dev/stderr "/tmp/box-setup.log" | logger -t box-setup)

Кстати, это эквивалентно, но более эффективно, чем (tee /dev/stderr | tee "/tmp/box-setup.log" | logger ...).

Можно было бы использовать некоторое клонирование дескриптора файла, чтобы получить teeстандартный вывод исходного сценария, а не stderr.

Питер Кордес
источник
1

Просто добавьте /dev/stderr(ваш выбор) в качестве вывода на tee.

exec &> >(tee /dev/stderr "/tmp/box-setup.log" | logger -t box-setup)

Стандартный вывод и стандартная ошибка будут объединены. Невозможно разделить их, если вы хотите сохранить их порядок, что обычно желательно. Неважно, если они оба собираются в одно и то же место (например, терминал) в любом случае.

Жиль "ТАК - перестань быть злым"
источник
teeStdout - это канал к логгеру, а не к терминалу. Это stderrна тот момент все еще терминал, основанный на exec &> >(tee /dev/stderr > /dev/null)работе, как и ожидалось, в интерактивной оболочке. stderrкажется лучшей идеей, чем моя /dev/ttyидея, поскольку она позволяет легко закрыть скрипт перенаправлением, если хотите.
Питер Кордес