将输出写入日志文件和控制台

在Unix shell中,我有一个env文件( env文件定义了运行用户脚本所需的参数,如日志文件名和path,将输出和错误redirect到日志文件,数据库连接详细信息等 ),redirect所有的输出)和使用以下代码从执行的脚本的日志文件错误:

exec 1>>${LOG_FILE} exec 2>>${LOG_FILE} 

env文件在每个脚本的开始处执行。 由于env文件中的上述代码,所有可能是用户输出或错误的控制台输出都会直接输出到日志文件,而这正是我真正需要的。

但有一些select性的用户输出,我想在控制台和日志文件中显示。 但是由于上面的代码,我无法做到这一点。

我知道,如果我删除上面的代码,我可以得到所需的结果,但我将不得不手动写入所有其他输出到日志文件,这不是一件容易的事情。

有没有办法在控制台和日志文件中获取输出而不删除上述代码?

 exec 3>&1 1>>${LOG_FILE} 2>&1 

会将stdout和stderr输出发送到日志文件中,但也会让您将fd 3连接到控制台,这样您就可以执行

 echo "Some console message" 1>&3 

写一条消息给控制台,或者

 echo "Some console and log file message" | tee /dev/fd/3 

向控制台日志文件写入消息 – tee将其输出发送到它自己的fd 1(这里是LOG_FILE )和你告诉它写入的文件(这里是fd 3,即控制台) 。

例:

 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 

会打印

 This is the console (fd 3) This is both the log and the console 

在控制台上,并把

 This is stdout This is stderr This is both the log and the console 

进入日志文件。

是的,你想用tee

tee – 从标准input读取并写入标准输出和文件

只需input你的命令来开球,并通过文件作为参数,如下所示:

 exec 1 | tee ${LOG_FILE} exec 2 | tee ${LOG_FILE} 

这既将输出打印到STDOUT,又将相同的输出写入日志文件。 有关更多信息,请参阅man tee

请注意,这不会将stderr写入日志文件,因此如果要合并这两个stream,请使用:

 exec 1 2>&1 | tee ${LOG_FILE} 

我尝试了joonty的答案,但我也得到了答案

exec:1:找不到

错误。 这是什么对我最好( 确认在zsh工作):

 #!/bin/bash LOG_FILE=/tmp/both.log exec > >(tee -a ${LOG_FILE} ) exec 2> >(tee -a ${LOG_FILE} >&2) echo "this is stdout" chmmm 77 /makeError 

之后的文件/tmp/both.log包含

 this is stdout chmmm command not found 

/tmp/both.log被附加,除非你从发球区域删除-a。

对于日志文件,您可能需要input文本数据。 以下代码可能有帮助

 # 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 

输出:2.日志文件将在第一次运行中创build,并继续从下次运行更新。 如果以后运行日志文件丢失,脚本将创build新的日志文件。

我find了一种方法来获得所需的输出。 虽然可能有点不正常。 反正在这里呢。 在redir.env文件中,我有以下代码:

 #####redir.env##### export LOG_FILE=log.txt exec 2>>${LOG_FILE} function log { echo "$1">>${LOG_FILE} } function message { echo "$1" echo "$1">>${LOG_FILE} } 

然后在实际的脚本中,我有以下代码:

 #!/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 

这里回声输出仅用于控制台, 日志输出只logging文件和消息输出到日志文件和控制台。

执行上面的脚本文件后,我有以下输出:

在控制台

在控制台
回声仅限于控制台
控制台和日志

对于日志文件

日志文件中仅写入日志文件
这是stderr。 只写入日志文件
控制台和日志

希望这个帮助。

我想在stdout和日志文件上显示日志以及时间戳。 上面的答案都没有为我工作。 我使用了进程replaceexec命令,并提出了以下代码。 示例日志:

 2017-06-21 11:16:41+05:30 Fetching information about files in the directory... 

在脚本的顶部添加以下行:

 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) 

希望这有助于某人!

  # #------------------------------------------------------------------------------ # echo pass params and print them to a log file and terminal # with timestamp and $host_name and $0 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 

我发现将stdout和stderr附加到日志文件非常有用。 我很高兴看到alfonx与exec > >(tee -a)的解决scheme,因为我想知道如何使用exec来完成这个任务。 我遇到了一个使用here-doc语法和创造性的解决scheme. : https : //unix.stackexchange.com/questions/80707/how-to-output-text-to-both-screen-and-file-inside-a-shell-script

我发现在zsh中,可以使用“multios”结构修改here-doc解决scheme将输出复制到stdout / stderr和日志文件:

 #!/bin/zsh LOG=$0.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 

它不像exec解决scheme那样可读,但它的好处是允许你只logging脚本的一部分。 当然,如果你省略了EOF,那么整个脚本就会被执行。 我不确定zsh是如何实现多路复用的,但是它可能比tee开销less。 不幸的是,似乎不能用exec来使用multios。

试试这个,它会做的工作:

 log_file=$curr_dir/log_file.txt exec > >(tee -a ${log_file} ) exec 2> >(tee -a ${log_file} >&2)