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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3130375/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 19:24:23  来源:igfitidea点击:

Bash script - store stderr in a variable

bashscriptingredirectstdoutstderr

提问by thornate

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 ?

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

回答by Adam Crume

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

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

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.

由于您的命令将 stdout 重定向到某处,因此它不应干扰 stderr。可能有一种更简洁的方式来编写它,但这应该可行。

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=errand the file logcontains out.

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

回答by Joat

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

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

{ 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:

常规输出正常出现,任何 stderr 都会在 $error 中捕获(使用它来保留换行符时将其引用为“$error”)。要将标准输出捕获到文件,只需在末尾添加重定向,例如:

{ 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
  • 为整个块创建文件描述 $out,复制标准输出
  • 在 $error 中捕获整个命令的标准输出(但见下文)
  • 命令本身将stderr重定向到stdout(在上面被捕获)然后stdout从块外部重定向到原始stdout,所以只有stderr被捕获

回答by hlovdal

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

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

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

So 3>&1will redirect file number 3 to stdout (notice this is before stdout is redirected with the pipe). Then 2>&3redirects 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).

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

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

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

回答by msw

ddwrites both stdout and stderr:

dd写入标准输出和标准错误:

$ 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`