Bash script - хранить stderr в переменной
Я пишу script для резервного копирования базы данных. У меня есть следующая строка:
mysqldump --user=$dbuser --password=$dbpswd \
--host=$host $mysqldb | gzip > $filename
Я хочу назначить stderr переменной, чтобы он отправил мне электронное письмо, давая мне знать, что произошло, если что-то пойдет не так. Я нашел решения для перенаправления stderr на stdout, но я не могу этого сделать, поскольку stdout уже отправляется (через gzip) в файл. Как я могу отдельно хранить stderr в переменной $result?
Ответы
Ответ 1
Попробуйте перенаправить stderr в stdout и с помощью $()
, чтобы зафиксировать это. Другими словами:
VAR=$((your-command-including-redirect) 2>&1)
Поскольку ваша команда перенаправляет stdout где-то, она не должна мешать stderr. Там может быть более чистый способ написать его, но это должно работать.
Edit:
Это действительно работает. Я протестировал его:
#!/bin/bash
BLAH=$((
(
echo out >&1
echo err >&2
) 1>log
) 2>&1)
echo "BLAH=$BLAH"
напечатает BLAH=err
, а файл log
содержит out
.
Ответ 2
Для любой общей команды в Bash вы можете сделать что-то вроде этого:
{ error=$(command 2>&1 1>&$out); } {out}>&1
Обычный вывод появляется нормально, все, что stderr записывается в $error (цитируйте его как "$ error" при его использовании для сохранения новых строк). Чтобы записать stdout в файл, просто добавьте перенаправление в конце, например:
{ error=$(ls /etc/passwd /etc/bad 2>&1 1>&$out); } {out}>&1 >output
Разбивая его, читая снаружи, он:
- создает описание файла $out для всего блока, дублируя stdout
- захватывает команду stdout всей команды в $error (но см. ниже)
- сама команда перенаправляет stderr на stdout (который захватывается выше), а затем stdout на исходный stdout из-за пределов блока, поэтому только stderr получает захваченный
Ответ 3
Вы можете сохранить ссылку на stdout до того, как она будет перенаправлена в другой номер файла (например, 3), а затем перенаправить stderr на это:
result=$(mysqldump --user=$dbuser --password=$dbpswd \
--host=$host $mysqldb 3>&1 2>&3 | gzip > $filename)
Итак, 3>&1
перенаправит номер файла 3 в stdout (обратите внимание, что это происходит до того, как stdout перенаправляется с помощью этого канала). Затем 2>&3
перенаправляет stderr на номер файла 3, который теперь совпадает с stdout. Наконец, stdout перенаправляется путем подачи в канал, но это не влияет на номера файлов 2 и 3 (обратите внимание, что перенаправление stdout из gzip не связано с выводами команды mysqldump).
Изменить: обновлена команда перенаправления stderr из команды mysqldump
, а не gzip
, я был слишком быстр в своем первом ответе.
Ответ 4
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`