我现在正在执行一系列的bash脚本,我想捕获在输出文件中运行的命令的值。
我以为可以通过将我的命令与合并来实现,| tee -a outputfile.txt
但这仅针对脚本1捕获。
脚本2..4等未将输出附加到文件中。
环顾四周,输出也可以通过这种方式重定向1>&1
--但我有些困惑,因为有时我看到数字1被2代替。我想这与消息传递的类型有关。但是,由于我不知道如何调用此输出重定向,因此我一直在寻找信息。
有什么帮助吗?谢谢安德里亚
有多种实现方法:
exec >outputfile.txt
command1
command2
command3
command4
这会将整个脚本的标准输出更改为日志文件。
我通常更喜欢的方法是:
{
command1
command2
command3
command4
} > outputfile.txt
这会对括号范围内的所有命令进行I / O重定向。小心,你必须同时治疗{
和}
,如果他们的命令; 它们不能出现在任何地方。这不会创建子外壳,这是我赞成它的主要原因。
您可以将括号替换为括号:
(
command1
command2
command3
command4
) > outputfile.txt
与括号相比,您可以更轻松地理解括号的位置,因此:
(command1
command2
command3
command4) > outputfile.txt
也可以工作(但是用花括号做到这一点,外壳将无法找到命令{command1
(除非您碰巧有一个可执行文件和...周围的文件)。这将创建一个子外壳。括号内的所有变量赋值将不会在括号外显示/访问。有时(但并非总是),这可能是个麻烦。子外壳的增量成本几乎可以忽略不计;它存在,但您可能很难承受测量它。
还有很长的路要走:
command1 >>outputfile.txt
command2 >>outputfile.txt
command3 >>outputfile.txt
command4 >>outputfile.txt
如果您想证明自己是一名新手Shell程序员,请务必使用此技术。如果您希望被视为更高级的Shell程序员,请不要这样做。
请注意,以上所有命令仅将标准输出重定向到命名文件,而将标准错误发送到原始目标位置(通常是终端)。如果要获取标准错误以转到同一文件,只需2>&1
在重定向标准输出之后添加(即,将文件描述符2,标准错误发送到与文件描述符1,标准输出相同的位置)。
解决评论中提出的问题。
通过使用
2>&1 >> $_logfile
(按照下面的回答),我得到了所需的东西,但是现在我确实在输出文件中有了echo...。有没有办法同时在屏幕和文件上打印它们?
啊,所以您不希望所有内容都进入文件...这会使事情变得有些复杂。当然有很多方法。不一定直接。在主重定向之前,我可能会使用exec 3>&1;
将文件描述符3设置为与文件描述符1相同的位置(标准输出-或3>&2
如果我想要回显标准错误)。然后,我将创建一个函数echoecho() { echo "$*"; echo "$*" >&3; }
并echoecho Whatever
用于执行回显。完成文件描述符3的操作后(如果您不打算退出,则系统将其关闭),您可以使用来关闭它exec 3>&-
。
当您提到
exec
那应该是我正在创建的单个脚本文件中执行的命令,并且我将在循环之间执行吗?(只需在下面查看我的答案,看看我如何演变了脚本)。对于其余的建议,我完全失去了你。
没有; 我指的是Bash(shell)内置命令exec
。它可以用于永久性地进行I / O重定向(针对脚本的其余部分),或者用新程序替换当前脚本,例如exec ls -l
—可能是一个不好的例子。
我想现在我比起初时更加困惑:)是否有可能创建一个小例子……以便我能更好地理解它?
评论的缺点是它们难以格式化且大小受限制。这些局限性也是有好处的,但有时必须扩大答案。说的时间到了。
为了便于讨论,我将自己限制为2个命令,而不是问题中的4个命令(但这不会失去任何通用性)。这些命令将是cmd1
和cmd2
,实际上,这是同一脚本的两个不同名称:
#!/bin/bash
for i in {01..10}
do
echo "$0: stdout $i - $*"
echo "$0: stderr $i - error message" >&2
done
如您所见,此脚本将消息写入标准输出和标准错误。例如:
$ ./cmd1 trying to work
./cmd1: stdout 1 - trying to work
./cmd1: stderr 1 - error message
./cmd1: stdout 2 - trying to work
./cmd1: stderr 2 - error message
…
./cmd1: stdout 9 - trying to work
./cmd1: stderr 9 - error message
./cmd1: stdout 10 - trying to work
./cmd1: stderr 10 - error message
$
现在,从Andrea Moro发布的答案中,我们发现:
#!/bin/bash
_logfile="output.txt"
# Delete output file if exist
if [ -f $_logfile ];
then
rm $_logfile
fi
for file in ./shell/*
do
$file 2>&1 >> $_logfile
done
我不喜欢变量名开头_
;我不需要看到它。这会将错误重定向到(当前)标准输出要去的地方,然后将标准输出重定向到日志文件。因此,如果子目录shell
包含cmd1
和cmd2
,则输出为:
$ bash ex1.sh
./shell/cmd1: stderr 1 - error message
./shell/cmd1: stderr 2 - error message
…
./shell/cmd1: stderr 9 - error message
./shell/cmd1: stderr 10 - error message
./shell/cmd2: stderr 1 - error message
./shell/cmd2: stderr 2 - error message
…
./shell/cmd2: stderr 9 - error message
./shell/cmd2: stderr 10 - error message
$
要同时获取文件的标准输出和标准错误,您可以使用以下之一:
2>>$_logfile >>$_logfile
>>$_logfile 2>&1
I / O重定向通常从左到右处理,除了管道控制在|&
处理I / O重定向之前将标准输出(如果使用,则为标准错误)控制在何处。
修改此脚本以生成信息到标准输出以及记录到日志文件,有多种工作方式。我假设shebang线路#!/bin/bash
从这里开始。
logfile="output.txt"
rm -f $logfile
for file in ./cmd1 ./cmd2
do
$file trying to work >> $logfile 2>&1
done
如果存在该日志文件,则会删除该日志文件(但比以前少了很多)。标准输出和标准错误中的所有内容均保存到日志文件中。我们也可以这样写:
logfile="output.txt"
{
for file in ./cmd1 ./cmd2
do
$file trying to work
done
} >$logfile 2>&1
或者代码可以使用括号代替大括号,而功能上的细微差别不会实质性地影响此脚本。或者,实际上,在这种情况下,我们可以使用:
logfile="output.txt"
for file in ./cmd1 ./cmd2
do
$file trying to work
done >$logfile 2>&1
尚不清楚该变量是否必要,但我们将其保留在原位。请注意,这两个都使用“临时” I / O重定向,因为它们仅创建一次日志文件,这反过来意味着无需删除它(尽管可能有这样做的理由,这与事先运行该命令的其他用户有关)并留下一个不可写的文件,但是无论如何您都应该有一个带日期戳的日志文件,这样毕竟不是问题。
显然,如果我们想在原始标准输出以及日志文件中回显某些内容,则我们必须做些不同的事情,因为标准错误和标准输出都将发送到日志文件中。
一种选择是:
logfile="output.txt"
rm -f $logfile
for file in ./cmd1 ./cmd2
do
echo $file $(date +'%Y-%m-%d %H:%M:%S')
$file trying to work >> $logfile 2>&1
done
另一个选择是:
exec 3>&1
logfile="output.txt"
for file in ./cmd1 ./cmd2
do
echo $file $(date +'%Y-%m-%d %H:%M:%S') >&3
$file trying to work
done >$logfile 2>&1
exec 3>&-
现在,文件描述符3与原始标准输出位于同一位置。在循环内部,标准输出和标准错误都发送到日志文件,但是echo … >&3
将标准输出发送echo
到文件描述符3。
如果要将相同的回显输出同时发送到重定向的标准输出和原始的标准输出,则可以使用:
exec 3>&1
echoecho()
{
echo "$*"
echo "$*" >&3
}
logfile="output.txt"
for file in ./cmd1 ./cmd2
do
echoecho $file $(date +'%Y-%m-%d %H:%M:%S')
$file trying to work
done >$logfile 2>&1
exec 3>&-
输出是:
$ bash ex3.sh
./cmd1 2014-01-07 14:57:13
./cmd2 2014-01-07 14:57:13
$ cat output.txt
./cmd1 2014-01-07 14:57:13
./cmd1: stdout 1 - trying to work
./cmd1: stderr 1 - error message
./cmd1: stdout 2 - trying to work
./cmd1: stderr 2 - error message
…
./cmd1: stdout 9 - trying to work
./cmd1: stderr 9 - error message
./cmd1: stdout 10 - trying to work
./cmd1: stderr 10 - error message
./cmd2 2014-01-07 14:57:13
./cmd2: stdout 1 - trying to work
./cmd2: stderr 1 - error message
./cmd2: stdout 2 - trying to work
./cmd2: stderr 2 - error message
…
./cmd2: stdout 9 - trying to work
./cmd2: stderr 9 - error message
./cmd2: stdout 10 - trying to work
./cmd2: stderr 10 - error message
$
这就是我在评论中说的全部内容。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句