Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将我的bash的输出重定向到日志文件_Bash - Fatal编程技术网

将我的bash的输出重定向到日志文件

将我的bash的输出重定向到日志文件,bash,Bash,我现在正在执行一系列bash脚本,并希望捕获在输出文件中运行的命令的值 我认为通过将我的命令与|tee-a outputfile.txt相结合,这是可能的,但这只在脚本1中捕获 脚本2..4等未将输出附加到文件 环顾四周,输出也可以这样重定向-1>&1——但我有点困惑,因为有时我会看到数字1被2取代。我想这与信息的类型有关。然而,由于我不知道这个输出重定向是如何调用的,所以我陷入了查找信息的困境 有什么帮助吗? 谢谢 安德里亚试试看 command >> file 附加到文件 co

我现在正在执行一系列bash脚本,并希望捕获在输出文件中运行的命令的值

我认为通过将我的命令与
|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