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`