假设我有一个像下面这样的脚本:
useless.sh
echo "This Is Error" 1>&2
echo "This Is Output"
我有另一个shell脚本:
alsoUseless.sh
./useless.sh | sed 's/Output/Useless/'
我想捕捉“这是错误”,或任何其他stderr从无用的。sh,到一个变量。
我们称它为ERROR。
注意,我使用了stdout。我想继续使用stdout,所以在这种情况下,将stderr重定向到stdout没有帮助。
所以,基本上,我想做
./useless.sh 2> $ERROR | ...
但这显然行不通。
我也知道我能做到
./useless.sh 2> /tmp/Error
ERROR=`cat /tmp/Error`
但这是丑陋和不必要的。
不幸的是,如果这里没有答案,这就是我要做的。
我希望还有别的办法。
有人有更好的主意吗?
如果您想绕过临时文件的使用,可以使用进程替换。我还没把它弄好。这是我的第一次尝试:
$ .useless.sh 2> >( ERROR=$(<) )
-bash: command substitution: line 42: syntax error near unexpected token `)'
-bash: command substitution: line 42: `<)'
然后我尝试了
$ ./useless.sh 2> >( ERROR=$( cat <() ) )
This Is Output
$ echo $ERROR # $ERROR is empty
然而
$ ./useless.sh 2> >( cat <() > asdf.txt )
This Is Output
$ cat asdf.txt
This Is Error
所以过程替代通常是正确的…不幸的是,每当我在>()内用$()中的东西包装STDIN以试图将其捕获到一个变量时,我就会丢失$()的内容。我认为这是因为$()启动了一个子进程,该子进程不再访问父进程所拥有的/dev/fd中的文件描述符。
进程替换为我购买了与不再在STDERR中的数据流工作的能力,不幸的是,我似乎无法以我想要的方式操纵它。
我将使用find命令
find / -maxdepth 2 -iname 'tmp' -type d
作为非超级用户的演示。当访问/ dir时,它应该抱怨“权限被拒绝”。
#!/bin/bash
echo "terminal:"
{ err="$(find / -maxdepth 2 -iname 'tmp' -type d 2>&1 1>&3 3>&- | tee /dev/stderr)"; } 3>&1 | tee /dev/fd/4 2>&1; out=$(cat /dev/fd/4)
echo "stdout:" && echo "$out"
echo "stderr:" && echo "$err"
给出输出:
terminal:
find: ‘/root’: Permission denied
/tmp
/var/tmp
find: ‘/lost+found’: Permission denied
stdout:
/tmp
/var/tmp
stderr:
find: ‘/root’: Permission denied
find: ‘/lost+found’: Permission denied
终端输出也包含/dev/stderr内容,就像不带任何脚本地运行find命令一样。$out有/dev/stdout, $err有/dev/stderr内容。
use:
#!/bin/bash
echo "terminal:"
{ err="$(find / -maxdepth 2 -iname 'tmp' -type d 2>&1 1>&3 3>&-)"; } 3>&1 | tee /dev/fd/4; out=$(cat /dev/fd/4)
echo "stdout:" && echo "$out"
echo "stderr:" && echo "$err"
如果您不想在终端输出中看到/dev/stderr。
terminal:
/tmp
/var/tmp
stdout:
/tmp
/var/tmp
stderr:
find: ‘/root’: Permission denied
find: ‘/lost+found’: Permission denied