Bash script - хранить stderr в переменной

Я пишу скрипт для резервного копирования базы данных. У меня есть следующая строка:

mysqldump --user=$dbuser --password=$dbpswd  \
   --host=$host $mysqldb | gzip > $filename

Я хочу присвоить stderr переменной, чтобы он отправлял мне электронное письмо, сообщающее мне, что произошло, если что-то пойдет не так. Я нашел решения для перенаправления stderr в stdout, но я не могу этого сделать, так как stdout уже отправляется (через gzip) в файл. Как я могу отдельно хранить stderr в переменной $result?

4 ответа

Решение

Попробуйте перенаправить stderr на стандартный вывод и использовать $() чтобы захватить это. Другими словами:

VAR=$((your-command-including-redirect) 2>&1)

Поскольку ваша команда куда-то перенаправляет stdout, она не должна мешать stderr. Там может быть более чистый способ написать это, но это должно сработать.

Редактировать:

Это действительно работает. Я проверил это:

#!/bin/bash                                                                                                                                                                         
BLAH=$((
(
echo out >&1
echo err >&2
) 1>log
) 2>&1)

echo "BLAH=$BLAH"

распечатает BLAH=err и файл log содержит out,

Для любой общей команды в Bash вы можете сделать что-то вроде этого:

{ error=$(command 2>&1 1>&$out); } {out}>&1

Обычный вывод выглядит нормально, все, что нужно stderr, записывается в $error (заключите его в кавычки как "$error" при использовании для сохранения новых строк). Чтобы захватить стандартный вывод в файл, просто добавьте перенаправление в конце, например:

{ error=$(ls /etc/passwd /etc/bad 2>&1 1>&$out); } {out}>&1 >output

Разбивая его, читая извне, это:

  • создает описание файла $out для всего блока, дублируя стандартный вывод
  • захватывает стандартный вывод всей команды в $error (но см. ниже)
  • сама команда перенаправляет stderr на стандартный вывод (который захватывается выше), а затем стандартный вывод на исходный стандартный вывод извне блока, поэтому захватывается только стандартный вывод stderr.

Вы можете сохранить ссылку stdout до того, как она будет перенаправлена ​​в другой номер файла (например, 3), а затем перенаправить stderr на это:

result=$(mysqldump --user=$dbuser --password=$dbpswd  \
   --host=$host $mysqldb 3>&1 2>&3 | gzip > $filename)

Так 3>&1 перенаправит файл с номером 3 на стандартный вывод (обратите внимание, что это происходит до того, как стандартный вывод будет перенаправлен с конвейера). затем 2>&3 перенаправляет stderr в файл номер 3, который теперь совпадает с stdout. Наконец, stdout перенаправляется путем подачи в канал, но это не влияет на номера файлов 2 и 3 (обратите внимание, что перенаправление stdout из gzip не связано с выходными данными команды mysqldump).

Изменить: Обновлена ​​команда для перенаправления stderr из mysqldump командовать, а не gzipЯ был слишком быстр в своем первом ответе.

dd пишет как stdout и stderr:

$ dd if=/dev/zero count=50 > /dev/null 
50+0 records in
50+0 records out

два потока независимы и перенаправляются по отдельности:

$ dd if=/dev/zero count=50 2> countfile | wc -c
25600
$ cat countfile 
50+0 records in
50+0 records out
$ mail -s "countfile for you" thornate < countfile

если вам действительно нужна переменная:

$ variable=`cat countfile`
Другие вопросы по тегам