bash 将输出写入日志文件和控制台
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18460186/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Writing outputs to log file and console
提问by abinash shrestha
In Unix shell, I have a env file (env file defines the parameters required for running the user script like log file name and path, redirect outputs and errors to log file, database connection details, etc) which redirects all the outputs (echo messages) and errors to the log file from the executed script using the following code:
在 Unix shell 中,我有一个 env 文件(env 文件定义了运行用户脚本所需的参数,如日志文件名和路径、将输出和错误重定向到日志文件、数据库连接详细信息等),它重定向所有输出(回显消息)) 和使用以下代码从执行的脚本到日志文件的错误:
exec 1>>${LOG_FILE}
exec 2>>${LOG_FILE}
The env file is executed at the beginning of each script. Due to the above code in env file all the console outputs that might be user outputs or errors are directly output to the log file which is what I actually needed.
env 文件在每个脚本的开头执行。由于 env 文件中的上述代码,所有可能是用户输出或错误的控制台输出都直接输出到我实际需要的日志文件中。
But there are some selective user outputs which I want to be displayed in both the console and the log file. But because of the above code I am not able to do so.
但是有一些选择性的用户输出我想同时显示在控制台和日志文件中。但是由于上面的代码,我无法这样做。
I know that if I remove the above code I can get the desired result for this case, but I will have to manually write all other outputs to the log file which is not an easy task.
我知道如果我删除上面的代码,我可以获得这种情况所需的结果,但是我必须手动将所有其他输出写入日志文件,这不是一件容易的事。
Is there a way to get the output in both the console and the log file without removing the above codes?
有没有办法在不删除上述代码的情况下同时在控制台和日志文件中获取输出?
回答by Ian Roberts
exec 3>&1 1>>${LOG_FILE} 2>&1
would send stdout and stderr output into the log file, but would also leave you with fd 3 connected to the console, so you can do
会将 stdout 和 stderr 输出发送到日志文件中,但也会让您将 fd 3 连接到控制台,因此您可以这样做
echo "Some console message" 1>&3
to write a message just to the console, or
只向控制台写一条消息,或
echo "Some console and log file message" | tee /dev/fd/3
to write a message to boththe console andthe log file - tee
sends its output to both its own fd 1 (which here is the LOG_FILE
) and the file you told it to write to (which here is fd 3, i.e. the console).
写一个消息都控制台和日志文件-tee
将其输出发送到它自己的fd 1(这里是LOG_FILE
),你告诉它写入文件(这里的fd是3,即控制台)。
Example:
例子:
exec 3>&1 1>>${LOG_FILE} 2>&1
echo "This is stdout"
echo "This is stderr" 1>&2
echo "This is the console (fd 3)" 1>&3
echo "This is both the log and the console" | tee /dev/fd/3
would print
会打印
This is the console (fd 3)
This is both the log and the console
on the console and put
在控制台上并把
This is stdout
This is stderr
This is both the log and the console
into the log file.
进入日志文件。
回答by Jon Cairns
Yes, you want to use tee
:
是的,您想使用tee
:
tee - read from standard input and write to standard output and files
tee - 从标准输入读取并写入标准输出和文件
Just pipe your command to tee and pass the file as an argument, like so:
只需将您的命令通过管道发送到 tee 并将文件作为参数传递,如下所示:
exec 1 | tee ${LOG_FILE}
exec 2 | tee ${LOG_FILE}
This both prints the output to the STDOUT and writes the same output to a log file. See man tee
for more information.
这将输出打印到 STDOUT 并将相同的输出写入日志文件。有关man tee
更多信息,请参阅。
Note that this won't write stderr to the log file, so if you want to combine the two streams then use:
请注意,这不会将 stderr 写入日志文件,因此如果您想合并两个流,请使用:
exec 1 2>&1 | tee ${LOG_FILE}
回答by alfonx
I tried joonty's answer, but I also got the
我尝试了 joonty 的回答,但我也得到了
exec: 1: not found
执行:1:未找到
error. This is what works best for me (confirmedto work in zsh also):
错误。这是最适合我的(确认也可以在 zsh 中工作):
#!/bin/bash
LOG_FILE=/tmp/both.log
exec > >(tee ${LOG_FILE}) 2>&1
echo "this is stdout"
chmmm 77 /makeError
The file /tmp/both.log afterwards contains
文件 /tmp/both.log 之后包含
this is stdout
chmmm command not found
The /tmp/both.log is appended unless you remove the -a from tee.
除非您从 tee 中删除 -a,否则会附加 /tmp/both.log。
Hint: >(...)
is a process substitution. It lets the exec
to the tee
command as if it were a file.
提示:>(...)
是一个进程替换。它让exec
到tee
命令,好像它是一个文件。
回答by Jyoti Dhiman
I wanted to display logs on stdout and log file along with the timestamp. None of the above answers worked for me. I made use of process substitutionand execcommand and came up with the following code. Sample logs:
我想在标准输出和日志文件上显示日志以及时间戳。以上答案都不适合我。我使用了进程替换和exec命令并想出了以下代码。示例日志:
2017-06-21 11:16:41+05:30 Fetching information about files in the directory...
Add following lines at the top of your script:
在脚本顶部添加以下几行:
LOG_FILE=script.log
exec > >(while read -r line; do printf '%s %s\n' "$(date --rfc-3339=seconds)" "$line" | tee -a $LOG_FILE; done)
exec 2> >(while read -r line; do printf '%s %s\n' "$(date --rfc-3339=seconds)" "$line" | tee -a $LOG_FILE; done >&2)
Hope this helps somebody!
希望这对某人有帮助!
回答by user2197712
for log file you may date to enter into text data. following code may help
对于日志文件,您可以输入文本数据。以下代码可能会有所帮助
# declaring variables
Logfile="logfile.txt"
MAIL_LOG="Message to print in log file"
Location="were is u want to store log file"
cd $Location
if [ -f $Logfile ]
then
echo "$MAIL_LOG " >> $Logfile
else
touch $Logfile
echo "$MAIL_LOG" >> $Logfile
fi
ouput: 2. Log file will be created in first run and keep on updating from next runs. In case log file missing in future run , script will create new log file.
输出: 2. 日志文件将在第一次运行时创建,并在下次运行时继续更新。如果将来运行时缺少日志文件,脚本将创建新的日志文件。
回答by abinash shrestha
I have found a way to get the desired output. Though it may be somewhat unorthodox way. Anyways here it goes. In the redir.env file I have following code:
我找到了一种获得所需输出的方法。虽然它可能有点不正统的方式。反正就到这里了。在 redir.env 文件中,我有以下代码:
#####redir.env#####
export LOG_FILE=log.txt
exec 2>>${LOG_FILE}
function log {
echo "">>${LOG_FILE}
}
function message {
echo ""
echo "">>${LOG_FILE}
}
Then in the actual script I have the following codes:
然后在实际脚本中我有以下代码:
#!/bin/sh
. redir.env
echo "Echoed to console only"
log "Written to log file only"
message "To console and log"
echo "This is stderr. Written to log file only" 1>&2
Here echooutputs only to console, logoutputs to only log file and messageoutputs to both the log file and console.
这里echo只输出到控制台,日志只输出到日志文件,消息输出到日志文件和控制台。
After executing the above script file I have following outputs:
执行上述脚本文件后,我有以下输出:
In console
在控制台中
In console
Echoed to console only
To console and log
在控制台中
仅回显到控制台
到控制台并登录
For the Log file
对于日志文件
In Log FileWritten to log file only
This is stderr. Written to log file only
To console and log
在日志文件中 仅写入日志文件
这是标准错误。仅写入日志文件
控制台和日志
Hope this help.
希望这有帮助。
回答by amousa
Try this, it will do the work:
试试这个,它会做的工作:
log_file=$curr_dir/log_file.txt
exec > >(tee -a ${log_file} )
exec 2> >(tee -a ${log_file} >&2)
回答by Yordan Georgiev
#
#------------------------------------------------------------------------------
# echo pass params and print them to a log file and terminal
# with timestamp and $host_name and #!/bin/zsh
LOG=##代码##.log
# 8 is an arbitrary number;
# multiple redirects for the same file descriptor
# triggers "multios"
. 8<<\EOF /dev/fd/8 2>&2 >&1 2>>$LOG >>$LOG
# some commands
date >&2
set -x
echo hi
echo bye
EOF
echo not logged
PID
# usage:
# doLog "INFO some info message"
# doLog "DEBUG some debug message"
# doLog "WARN some warning message"
# doLog "ERROR some really ERROR message"
# doLog "FATAL some really fatal message"
#------------------------------------------------------------------------------
doLog(){
type_of_msg=$(echo $*|cut -d" " -f1)
msg=$(echo "$*"|cut -d" " -f2-)
[[ $type_of_msg == DEBUG ]] && [[ $do_print_debug_msgs -ne 1 ]] && return
[[ $type_of_msg == INFO ]] && type_of_msg="INFO " # one space for aligning
[[ $type_of_msg == WARN ]] && type_of_msg="WARN " # as well
# print to the terminal if we have one
test -t 1 && echo " [$type_of_msg] `date "+%Y.%m.%d-%H:%M:%S %Z"` [$run_unit][@$host_name] [$$] ""$msg"
# define default log file none specified in cnf file
test -z $log_file && \
mkdir -p $product_instance_dir/dat/log/bash && \
log_file="$product_instance_dir/dat/log/bash/$run_unit.`date "+%Y%m"`.log"
echo " [$type_of_msg] `date "+%Y.%m.%d-%H:%M:%S %Z"` [$run_unit][@$host_name] [$$] ""$msg" >> $log_file
}
#eof func doLog
回答by Metamorphic
I find it very useful to append both stdout and stderr to a log file. I was glad to see a solution by alfonx with exec > >(tee -a)
, because I was wondering how to accomplish this using exec
. I came across a creative solution using here-doc syntax and .
: https://unix.stackexchange.com/questions/80707/how-to-output-text-to-both-screen-and-file-inside-a-shell-script
我发现将 stdout 和 stderr 都附加到日志文件中非常有用。我很高兴看到 alfonx 的解决方案exec > >(tee -a)
,因为我想知道如何使用exec
. 我遇到了一个使用 here-doc 语法的创造性解决方案.
:https: //unix.stackexchange.com/questions/80707/how-to-output-text-to-both-screen-and-file-inside-a-shell -脚本
I discovered that in zsh, the here-doc solution can be modified using the "multios" construct to copy output to both stdout/stderr and the log file:
我发现在 zsh 中,可以使用“multios”构造修改 here-doc 解决方案以将输出复制到 stdout/stderr 和日志文件:
##代码##It is not as readable as the exec
solution but it has the advantage of allowing you to log just part of the script. Of course, if you omit the EOF then the whole script is executed with logging. I'm not sure how zsh
implements multios, but it may have less overhead than tee
. Unfortunately it seems that one cannot use multios with exec
.
它不像exec
解决方案那样可读,但它的优点是允许您只记录脚本的一部分。当然,如果您省略 EOF,则整个脚本将通过日志记录执行。我不确定如何zsh
实现 multios,但它的开销可能比tee
. 不幸的是,似乎不能将 multios 与exec
.