将我的bash的输出重定向到日志文件
我现在正在执行一系列bash脚本,并希望捕获在输出文件中运行的命令的值 我认为通过将我的命令与将我的bash的输出重定向到日志文件,bash,Bash,我现在正在执行一系列bash脚本,并希望捕获在输出文件中运行的命令的值 我认为通过将我的命令与|tee-a outputfile.txt相结合,这是可能的,但这只在脚本1中捕获 脚本2..4等未将输出附加到文件 环顾四周,输出也可以这样重定向-1>&1——但我有点困惑,因为有时我会看到数字1被2取代。我想这与信息的类型有关。然而,由于我不知道这个输出重定向是如何调用的,所以我陷入了查找信息的困境 有什么帮助吗? 谢谢 安德里亚试试看 command >> file 附加到文件 co
|tee-a outputfile.txt
相结合,这是可能的,但这只在脚本1中捕获
脚本2..4等未将输出附加到文件
环顾四周,输出也可以这样重定向-1>&1
——但我有点困惑,因为有时我会看到数字1被2取代。我想这与信息的类型有关。然而,由于我不知道这个输出重定向是如何调用的,所以我陷入了查找信息的困境
有什么帮助吗?
谢谢
安德里亚试试看
command >> file
附加到文件
command > file
每次从位置1写入时都清除文件。假设您在文件sc1.sh、sc2.sh和sc3.sh中有脚本,并且希望将输出写入名为log.txt的文件,则可以执行以下操作:
./sc1.sh >> log.txt
./sc2.sh >> log.txt
./sc3.sh >> log.txt
或者,如果您希望通过编写另一个bash脚本来循环其他bash脚本,从而自动化该过程:
#!/bin/bash
n=1
num_scripts=3
while test $n -le $num_scripts
do
script$n.sh >> log.txt
n=$[n+1]
done
在中运行命令(通过将所有命令嵌入一组括号),然后将该子shell的输出通过管道传输到tee
:
(command1;command2;command3)| tee outputfile.txt
基本技术
实现这一目标有多种方法:
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
也可以工作(但是使用大括号这样做,shell将无法找到命令{command1
(除非您碰巧有一个可执行的文件和…)。这会创建一个子外壳。在括号内完成的任何变量赋值在括号外都不会被看到/访问。有时(但并非总是)这会成为一个阻碍。子外壳的增量成本几乎可以忽略不计;它是存在的,但您可能很难衡量它
还有一个长期的方法:
command1 >>outputfile.txt
command2 >>outputfile.txt
command3 >>outputfile.txt
command4 >>outputfile.txt
如果你想证明你是一个新手,一定要使用这个技巧。如果你想被认为是一个更高级的shell程序员,不要这样做
请注意,上面的所有命令仅将标准输出重定向到指定的文件,将标准错误保留到原始目标(通常是终端)。如果要使标准错误转到同一文件,只需添加2>&1
(也就是说,在标准输出重定向之后,将文件描述符2,标准错误,发送到与文件描述符1,标准输出相同的位置)
应用技术 回答评论中提出的问题 通过使用
2>&1>$\u日志文件
(根据我下面的回答),我得到了我需要的东西,但现在我的输出文件中也有我的echo…。是否有办法同时在屏幕上和文件上打印它们
啊,所以您不希望所有内容都指向文件…这会使事情变得有点复杂。当然,也有一些方法;不一定是直接的。我可能会使用
exec 3>&1;
将文件描述符3设置为与1相同的位置(标准输出-或者如果我希望回显到标准错误,则使用3>&2
)在主重定向之前。然后我将创建一个函数echocho(){echo“$*”echo“$*”>&3;}
,我将使用echocho 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
$
现在,从我们发布的
我不喜欢变量名开头的。
;我看不到它的必要性。这会将错误重定向到标准输出(当前)的位置,然后将标准输出重定向到日志文件。因此,如果子目录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重定向通常从左到右进行处理,但管道控制标准输出(如果使用|&
,则为标准错误)的位置除外
2>>$_logfile >>$_logfile
>>$_logfile 2>&1
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
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>&-
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
$
#!/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