Bash脚本 - 将stderr存储在变量中

tho*_*ate 48 bash scripting redirect stdout stderr

我正在编写一个备份数据库的脚本.我有以下几行:

mysqldump --user=$dbuser --password=$dbpswd  \
   --host=$host $mysqldb | gzip > $filename
Run Code Online (Sandbox Code Playgroud)

我想将stderr分配给一个变量,这样它就会向我发送一封电子邮件,让我知道如果出现问题会发生什么.我找到了将stderr重定向到stdout的解决方案,但我不能这样做,因为stdout已经被发送(通过gzip)到一个文件.如何在变量$ result中单独存储stderr?

Ada*_*ume 84

尝试将stderr重定向到stdout并使用$()捕获它.换一种说法:

VAR=$((your-command-including-redirect) 2>&1)
Run Code Online (Sandbox Code Playgroud)

由于您的命令将stdout重定向到某个地方,因此它不应该干扰stderr.可能有一种更清晰的方式来编写它,但这应该有效.

编辑:

这确实有效.我测试过了:

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

echo "BLAH=$BLAH"
Run Code Online (Sandbox Code Playgroud)

将打印BLAH=err,文件log包含out.


小智 17

对于Bash中的任何通用命令,您可以执行以下操作:

{ error=$(command 2>&1 1>&$out); } {out}>&1
Run Code Online (Sandbox Code Playgroud)

正常输出正常显示,stderr的任何内容都在$ error中捕获(在使用它来保留换行符时将其引用为"$ error").要将stdout捕获到文件,只需在末尾添加重定向,例如:

{ error=$(ls /etc/passwd /etc/bad 2>&1 1>&$out); } {out}>&1 >output
Run Code Online (Sandbox Code Playgroud)

打破它,从外面读取,它:

  • 为整个块创建一个文件描述$ out,复制stdout
  • 在$ error中捕获整个命令的stdout(但见下文)
  • 命令本身将stderr重定向到stdout(上面被捕获)然后stdout从块外部转移到原始stdout,因此只有stderr被捕获

  • 在 bash v3.2 中不起作用:“意外的标记‘{out}’”。这个语法需要 Bash 4 吗? (2认同)

hlo*_*dal 5

您可以将stdout引用从重定向之前保存到另一个文件号(例如3)中,然后将stderr重定向到该文件:

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

因此3>&1会将文件编号3重定向到stdout(注意,这是在使用管道将stdout重定向之前)。然后2>&3将stderr重定向到3号文件,该文件现在与stdout相同。最后,将stdout通过送入管道进行重定向,但这不会影响文件编号2和3(请注意,从gzip重定向stdout与mysqldump命令的输出无关)。

编辑:更新了命令以从命令重定向stderr mysqldump而不是gzip,我的第一个答案太快了。