为什么使用tee命令进行重定向不能按预期工作?

4
我希望能够在脚本本身中记录所有输出到文件的内容,将屏幕上所见的一切保存在日志文件中。如果不将输出重定向到文件,则脚本按预期工作,继续循环直到我按下CTRL+C;当这种情况发生时,它会在屏幕上打印出几条消息并退出。如果我尝试重定向到文件,使用tee命令,它不仅不打印消息,而且日志不完整,只有循环行,没有其他内容。以下是脚本(精简版):
#!/bin/sh
EXIT=0
COUNT=0
{
while [ $EXIT -eq 0 ]
do
  COUNT=$((COUNT+1)) && echo "Eternal loop $COUNT" && sleep 1
  trap 'EXIT=1; echo "Loop interrupted by user, exiting."' 15 2 8 20
done
echo "Out of loop, eternity ends"
} | tee log.log 2>&1

我阅读了一些内容,无法确定我的问题是由于使用tee管道、标准错误和标准输出,还是由于我使用的陷阱trap的方式引起的。

我对shell脚本毫无经验,这让我很沮丧,感激任何帮助。

谢谢。

编辑1:在阅读chepner的答案后,我修改了脚本如下:

#!/bin/sh
EXIT=0
COUNT=0
rm log.log
while [ $EXIT -eq 0 ]
do
COUNT=$((COUNT+1)) && echo "Eternal loop $COUNT" | tee -a log.log && sleep 1
trap 'EXIT=1; echo "Loop interrupted by user, exiting." | tee -a log.log' 15 2 8 20
done
echo "Out of loop, eternity ends" | tee -a log.log

而且它能够正常工作,将输出记录到日志文件中,并且我仍然可以在屏幕上看到输出,完全符合我的要求。现在有一个问题:如果我有很多命令而不仅仅是3个,这个解决方案是否足够“干净”?我的意思是,所有我调用的tee会发生什么情况?有没有更好的方法来做到这一点,比如更加精细的方法?

3个回答

6

虽然不完全符合您的要求,但是当您想要记录过程中看到的所有内容时,使用脚本命令比处理重定向更容易。

如果您仍然想要使用tee,请将重定向放在管道前面。

somecommand 2>&1 | tee outfile

1
我并不一定要使用tee,我只需要将屏幕输出记录下来。你说“script命令比处理重定向更容易”,你是什么意思?能举几个例子吗?谢谢。 - VeryStrange
1
Unix命令脚本。您键入“script somefile.log”,它会说“脚本已启动,文件为somefile.log”,然后记录屏幕上出现的所有内容,直到您在该文件中键入exit。 - genisage
1
使用脚本命令可以记录屏幕上出现的所有内容,但我不能同时在屏幕上看到它。 - VeryStrange
这对我有用。在我的情况下,普通的管道和teetee -a命令没有起作用。谢谢! - Piotr Wittchen

3

使用管道时,前台作业由两个进程组成,每个管道两端各有一个进程。按下Control-C会向所有进程发送SIGINT信号,因此没有机会运行后循环的echo或者让tee输出左侧进程的最终输出。没有管道到teewhile循环完全在当前shell实例中运行,因此shell本身接收到SIGINT信号并且(我相信)只中断当前在循环中运行的shell命令。触发陷阱,然后循环因为对EXIT条件检查而自然退出。


哦,这是一些详细的信息,谢谢。我应该找另一种方法来记录脚本输出,因为使用重定向和tee会干扰陷阱。 - VeryStrange
仔细重新阅读您的答案后,我意识到如果我将tee用于我需要输出的每个命令,它将起作用,因此我稍微修改了脚本。 - VeryStrange

1
也许你想将 stderr 重定向到 stdout,然后再使用管道传递给 tee 命令:
...
} 2>&1 | tee log.log

我尝试了你建议的方法,但结果还是一样的;我认为这是因为Chepner的答案所述的原因。 - VeryStrange

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