如何将stderr捕获到一个变量中并通过管道将stdout输出

4
我正在尝试将curl响应的标准错误头存储在一个变量中,并将正文(来自标准输出)传输到grep。
这是我目前的尝试:
{
  HEADERS=$(curl -vs $URL 2>&1 1>&3-)
  echo "$HEADERS"
} 3>&1 | grep "regex" >> filename
echo "$HEADERS"

当我使用bash -x script.sh运行脚本时,我能看到预期输出的+ HEADERS='...',但是无论是内联组内部还是外部,我都无法通过$HEADERS"$HEADERS"访问它们。
正文按预期被管道传递。

你想让 grep 的输出在终端上还是其他地方? - anishsane
2
curl -vs -$URL 2>&1 1>&3- 翻译成中文为:curl -vs $URL 2>&1 1>&3- - han058
有什么理由不将标题设置为变量,然后搜索该变量,而不是使用这个复杂的管道呢? - 123
@anishsane,这种情况下grep的输出应该被附加到filename。这部分是有效的。 - André Rüdiger
@123 变量包含来自 stderr 的标头。grep 处理来自 stdout 的正文。 - André Rüdiger
"将标准输出和错误输出分别存储/捕获到不同的变量中,这个解答是否涵盖了你需要知道的内容?虽然它更复杂,因为它捕获了两个流到变量中,但它基本上涵盖了非常相似的领域。" - Jonathan Leffler
2个回答

2

由于使用管道,将您的管道命令分叉并在子 shell 中运行,父 shell 看不到在子 shell 中创建的变量,因此您失去了 HEADERS 变量。

您可以通过临时文件来解决这个问题:

{ f=$(mktemp /tmp/curl.XXXXXX); curl -vs "$URL" 2>"$f" |
grep 'regex' >> filename; HEADERS="$(<$f)"; trap 'rm -f "$f"' EXIT;}

现在,HEADERS 变量将通过读取使用 mktemp 创建的临时文件来在父 shell 中填充。


1
在将HEADERS赋值后显示rm -f“$f”是个好主意吗?中断、陷阱和文件的清理呢? - Jonathan Leffler
谢谢,我添加了trap来清理临时文件。 - anubhava
感谢这个版本,它也能够正常工作。我接受了 @JonathanLeffler 的方案,因为它避免了使用临时文件。 - André Rüdiger

2
正如anubhava正确诊断的那样,问题在于您正在子进程中设置HEADERS,而不是在shell的主进程中设置。
您可以使用Bash的进程替换来避免这个问题,而不必使用临时文件,在shell被中断的情况下需要清理它们:
HEADERS=""
{ HEADERS=$(curl -vs "$URL" 2>&1 1>&3-); } 3> >(grep "regex" > file)
echo "$HEADERS"

grep子进程被进程替换隐藏了。 3>>(…)之间的空格是必需的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接