在Unix shell中,我有一个env文件( env文件定义了运行用户脚本所需的参数,如日志文件名和路径,将输出和错误重定向到日志文件,数据库连接详细信息等等)使用以下代码将所有输出( echo messages )和错误重定向到执行脚本的日志文件中:
exec 1>>${LOG_FILE}
exec 2>>${LOG_FILE}
env文件在每个脚本的开头执行。由于env文件中的上述代码,所有可能是用户输出或错误的控制台输出都直接输出到日志文件,这是我实际需要的。
但是我想在控制台和日志文件中显示一些选择性用户输出。但由于上述代码,我无法这样做。
我知道如果我删除上面的代码,我可以得到这种情况所需的结果,但是我必须手动将所有其他输出写入日志文件,这不是一件容易的事。
有没有办法在控制台和日志文件中获取输出而不删除上述代码?
答案 0 :(得分:84)
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(这里是{ {1}})和你告诉它写的文件(这里是fd 3,即控制台)。
示例:
LOG_FILE
会打印
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
进入日志文件。
答案 1 :(得分:36)
是的,您想使用tee
:
tee - 从标准输入读取并写入标准输出和文件
只需将命令传递给tee并将文件作为参数传递,如下所示:
exec 1 | tee ${LOG_FILE}
exec 2 | tee ${LOG_FILE}
这两者都将输出打印到STDOUT并将相同的输出写入日志文件。有关详细信息,请参阅man tee
。
请注意,这不会将stderr写入日志文件,因此如果要组合这两个流,请使用:
exec 1 2>&1 | tee ${LOG_FILE}
答案 2 :(得分:28)
我尝试过joonty的答案,但我也得到了
exec:1:未找到
错误。这对我来说最有效(confirmed也适用于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
除非从tee中删除-a,否则附加/tmp/both.log。
提示:>(...)
是流程替代。它允许exec
tee
命令,就好像它是一个文件一样。
答案 3 :(得分:4)
我想在stdout和日志文件上显示日志以及时间戳。上述答案都不适合我。 我使用了进程替换和 exec 命令,并提出了以下代码。 样本日志:
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)
希望这有助于某人!
答案 4 :(得分:3)
对于日志文件,您可以约会输入文本数据。以下代码可能有所帮助
# 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。首次运行时将创建日志文件,并在下次运行时继续更新。如果将来运行中缺少日志文件,脚本将创建新的日志文件。
答案 5 :(得分:1)
我找到了获得所需输出的方法。虽然这可能有点不正统。无论如何它在这里。在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
此处 echo 仅输出到控制台,日志输出到日志文件和消息输出到日志文件和控制台。
执行上述脚本文件后,我有以下输出:
在控制台
中在控制台中
仅回应控制台 控制和记录
对于日志文件
在日志文件中 只写日志文件
这是stderr。只写日志文件
控制和记录
希望得到这个帮助。
答案 6 :(得分:1)
#
#------------------------------------------------------------------------------
# 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
答案 7 :(得分:0)
我发现将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-script
我发现在zsh中,可以使用" multios"修改here-doc解决方案。构造将输出复制到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
解决方案那样可读,但它的优点是允许您只记录部分脚本。当然,如果省略EOF,则会使用日志记录执行整个脚本。我不确定zsh
如何实现多声道,但它的开销可能比tee
少。不幸的是,似乎不能使用带有exec
的多维数据集。
答案 8 :(得分:0)
试试这个,它会完成工作:
log_file=$curr_dir/log_file.txt
exec > >(tee -a ${log_file} )
exec 2> >(tee -a ${log_file} >&2)