我无法将标准错误发送到标准输出。我打算把它放在cron中,但现在我只是手动运行。将标准错误发送到标准输出不起作用
/home/backups/backup_scripts/backup.sh 2>&1 >> /var/log/backups/backup.log
我希望在日志文件将包含被印到标准输出的任何消息,但日志文件只显示标准输出和控制台输出显示错误。
我在这里做错了什么?
我无法将标准错误发送到标准输出。我打算把它放在cron中,但现在我只是手动运行。将标准错误发送到标准输出不起作用
/home/backups/backup_scripts/backup.sh 2>&1 >> /var/log/backups/backup.log
我希望在日志文件将包含被印到标准输出的任何消息,但日志文件只显示标准输出和控制台输出显示错误。
我在这里做错了什么?
发生这种情况,因为重定向的顺序。 2>&1
的意思是“将标准错误重定向到当前的标准输出的位置”。它们从左到右进行处理,以便将第一个标准错误重定向到当前标准输出(仍是终端),然后将标准输出重定向到文件。如果您将订单切换为读取
/home/backups/backup_scripts/backup.sh >> /var/log/backups/backup.log 2>&1
它应该做你想做的。如果你的shell是bash,它有一个快捷方式来同时重定向标准输出和标准错误:command &> file
将它们重定向到一个文件并且command &>> file
将两个文件都附加到一个文件中。此命令依赖关系也在bash手册中提到
请注意,重定向的顺序很重要。例如,命令
ls > dirlist 2>&1
指示标准输出和标准误差到文件dirlist,而命令
ls 2>&1 > dirlist
指示只有标准输出到文件dirlist,因为标准误差为 复制从标准输出之前的标准输出重定向到dlist的 。
我认为文件描述符和重定向的工作方式存在一些误解。内核有一个包含文件偏移量,状态标志和文件本身名称的系统上所有打开文件的大表。然后每个进程都有一个表,将文件描述符编号映射到此全局表中的条目。
之前的任何重定向发生全局表可能是这个样子
A: TERMINAL
和进程表看起来像
0: A
1: A
2: A
因为描述数字0,1,和2标准输入,标准输出,和stderr分别。
然后处理2>&1
重定向。这将更改进程表,以便2包含与1相同的全局条目。但是,它们已经相同,因此没有任何反应。
当>> /var/log/backups/backup.log
重定向被处理。首先,文件被打开并分配到文件描述符3在进程表使表看起来像
A: TERMINAL
B: /var/log/backups/backup.log
和
0: A
1: A
2: A
3: B
那么标准out变成指向新打开的文件(好像1>&3
被完成),从而进程表现在
0: A
1: B
2: A
3: B
注意,2(错误)仍然指向该终端。
当重定向以其他顺序完成时,>> /var/log/backups/backup.log
之后的表看起来相同。
0: A
1: B
2: A
3: B
然后2>&1
重定向改变什么2点给
0: A
1: B
2: B
3: B
所以现在输出和错误都去文件。
重定向的顺序很重要。你应该将其更改为:
/home/backups/backup_scripts/backup.sh >> /var/log/backups/backup.log 2>&1
这个标准输出重定向到/var/log/backups/backup.log
,然后重定向标准错误到标准输出(这是进入该文件)。
您还可以使用较短的形式:
/home/backups/backup_scripts/backup.sh &>> /var/log/backups/backup.log
&>>file
是语义上等同于>>file 2>&1
我真的不明白这一点。如果它从左向右读,那么你建议的命令是不是不起作用?不是>>将标准重定向到文件?如果是这样,那么我需要确保我第一次有标准错误重定向第一...在这之前呢? – Brian
@Brian,请参阅编辑。让我知道如果它仍然不清楚。 –
嗯...当时,STDOUT的当前位置是终端。所以它将STDERR重定向到STDOUT,但它仍然只是终端。但是,那么>>应该重定向终端的STDOUT,它现在包括我的bash脚本中的STDERR不是吗? – Brian