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

发布于 2024-09-07 10:19:27 字数 307 浏览 6 评论 0原文

我正在编写一个脚本来备份数据库。我有以下行:

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

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

I'm writing a script to backup a database. I have the following line:

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

I want to assign the stderr to a variable, so that it will send an email to myself letting me know what happened if something goes wrong. I've found solutions to redirect stderr to stdout, but I can't do that as the stdout is already being sent (via gzip) to a file. How can I separately store stderr in a variable $result ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

野侃 2024-09-14 10:19:27

尝试将 stderr 重定向到 stdout 并使用 $() 捕获它。换句话说:

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

Try redirecting stderr to stdout and using $() to capture that. In other words:

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

Since your command redirects stdout somewhere, it shouldn't interfere with stderr. There might be a cleaner way to write it, but that should work.

Edit:

This really does work. I've tested it:

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

echo "BLAH=$BLAH"

will print BLAH=err and the file log contains out.

℉服软 2024-09-14 10:19:27

对于 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 被捕获

For any generic command in Bash, you can do something like this:

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

Regular output appears normally, anything to stderr is captured in $error (quote it as "$error" when using it to preserve newlines). To capture stdout to a file, just add a redirection at the end, for example:

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

Breaking it down, reading from the outside in, it:

  • creates a file description $out for the whole block, duplicating stdout
  • captures the stdout of the whole command in $error (but see below)
  • the command itself redirects stderr to stdout (which gets captured above) then stdout to the original stdout from outside the block, so only the stderr gets captured
累赘 2024-09-14 10:19:27

您可以在重定向到另一个文件号(例如 3)之前保存 stdout 引用,然后将 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(请注意,从 gzip 重定向 stdout 与 mysqldump 命令的输出无关)。

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

You can save the stdout reference from before it is redirected in another file number (e.g. 3) and then redirect stderr to that:

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

So 3>&1 will redirect file number 3 to stdout (notice this is before stdout is redirected with the pipe). Then 2>&3 redirects stderr to file number 3, which now is the same as stdout. Finally stdout is redirected by being fed into a pipe, but this is not affecting file numbers 2 and 3 (notice that redirecting stdout from gzip is unrelated to the outputs from the mysqldump command).

Edit: Updated the command to redirect stderr from the mysqldump command and not gzip, I was too quick in my first answer.

惯饮孤独 2024-09-14 10:19:27

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`

dd writes both stdout and stderr:

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

the two streams are independent and separately redirectable:

$ 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

if you really needed a variable:

$ variable=`cat countfile`
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文