重定向stderr和stdout在Bash
题
我想向两stdout and stderr过程的一个单一的文件。我该怎么做,在庆典?
解决方案
其他提示
do_something 2>&1 | tee -a some_file
这将会把stderr重定向到stdout和stdout到some_file
和强>它打印到标准输出。
可以重定向 stderr的至标准输出和标准输出到一个文件:
some_command >file.log 2>&1
请参阅 http://tldp.org/LDP/abs/html/io -redirection.html
此格式是优选的比最流行&>格式,只有在bash工作。在Bourne Shell中它可以被解释为在后台运行的命令。也格式是更具有可读性2(是STDERR)重定向到1(STDOUT)。
编辑:改变的顺序如在评论中指出
# Close STDOUT file descriptor
exec 1<&-
# Close STDERR FD
exec 2<&-
# Open STDOUT as $LOG_FILE file for read and write.
exec 1<>$LOG_FILE
# Redirect STDERR to STDOUT
exec 2>&1
echo "This line will appear in $LOG_FILE, not 'on screen'"
现在,简单的回声将写信给$LOG_FILE.用于daemonizing.
来文提交人原来的岗位,
这取决于你需要什么来实现。如果你只是需要重新定向的一个命令你打电话从你的脚本,这些问题的答案都已经定。地雷是有关重定向 内 前脚本,影响到所有的命令/建件程序(包括福克斯之后)在提到代码段。
另一个很酷的解决方案是有关重定向到两std-err/出并记录或登录文件在一旦其中涉及分裂"一流"变成两个。这一功能是由't'的命令,这可以写/追加的几个文件的描述(文件,插座、管道,等等):tee1文件2...>(cmd1)>(cmd2)...
exec 3>&1 4>&2 1> >(tee >(logger -i -t 'my_script_tag') >&3) 2> >(tee >(logger -i -t 'my_script_tag') >&4)
trap 'cleanup' INT QUIT TERM EXIT
get_pids_of_ppid() {
local ppid="$1"
RETVAL=''
local pids=`ps x -o pid,ppid | awk "\\$2 == \\"$ppid\\" { print \\$1 }"`
RETVAL="$pids"
}
# Needed to kill processes running in background
cleanup() {
local current_pid element
local pids=( "$$" )
running_pids=("${pids[@]}")
while :; do
current_pid="${running_pids[0]}"
[ -z "$current_pid" ] && break
running_pids=("${running_pids[@]:1}")
get_pids_of_ppid $current_pid
local new_pids="$RETVAL"
[ -z "$new_pids" ] && continue
for element in $new_pids; do
running_pids+=("$element")
pids=("$element" "${pids[@]}")
done
done
kill ${pids[@]} 2>/dev/null
}
因此,从一开始。让我们假设,我们的终端连接/dev/stdout(FD#1)和/dev/stderr(FD#2).在实践中,这可能是一个管、套或者什么的。
- 创建防卫和安全部队#3和第4点来相同的"位置"为1和2分别。改变FD#1不影响FD#3。现在,科特迪瓦国防安全部队#3和第4点来STDOUT and STDERR分别。这些将作为 真的 终端STDOUT and STDERR。
- 1>>(...)重定向STDOUT到命令在括号
- 括号(子壳)执行't'读exec的STDOUT(pipe)和重定向到'记录器'的命令通过另一个管子壳在括号.同时,它的副本相同的输入到FD#3(终端)
- 第二部分,非常类似,大约是做同样的把戏STDERR和科特迪瓦国防安全部队#2和#4。
结果运行的一个脚本具有上述行和此外,这一:
echo "Will end up in STDOUT(terminal) and /var/log/messages"
...如下:
$ ./my_script
Will end up in STDOUT(terminal) and /var/log/messages
$ tail -n1 /var/log/messages
Sep 23 15:54:03 wks056 my_script_tag[11644]: Will end up in STDOUT(terminal) and /var/log/messages
如果你想看到更清晰的画面,添加这些2条的脚本:
ls -l /proc/self/fd/
ps xf
bash your_script.sh 1>file.log 2>&1
1>file.log
指示壳发送STDOUT到文件file.log
,和2>&1
告诉它STDERR(文件描述符2)重定向到STDOUT(文件描述符1)。
注意:的顺序事项liw.fi指出,2>&1 1>file.log
不起作用
奇怪的是,工作的:
yourcommand &> filename
但是,这给出了一个语法错误:
yourcommand &>> filename
syntax error near unexpected token `>'
您必须使用:
yourcommand 1>> filename 2>&1
简短的回答: Command >filename 2>&1
或 Command &>filename
说明:
考虑下列代码打印的字"stdout"to stdout和单词"stderror"以stderror.
$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror
注意,'&'操作员会告诉bash,2个文件描述(其中指stderr)并不是一个文件的名称。如果我们留下了'&',这种命令将打印 stdout
到stdout,并创建一个文件命名为"2"写 stderror
那里。
通过试用上述代码,你可以看到自己究竟如何向经营者的工作。例如,通过改变其文件的两个描述 1,2
, 是重新定向到 /dev/null
以下两个代码行的删除标准输出,以及一切从stderror分别(印刷什么仍).
$ (echo "stdout"; echo "stderror" >&2) 1>/dev/null
stderror
$ (echo "stdout"; echo "stderror" >&2) 2>/dev/null
stdout
现在,我们可以解释为什么方案为什么以下代码没有输出产生:
(echo "stdout"; echo "stderror" >&2) >/dev/null 2>&1
为了真正理解这一点,我强烈建议你读这个 网页上的文件描述表.假设你已经做了阅读,我们可以继续进行。注意庆典的过程左到右;因此Bash看到 >/dev/null
第(这是相同的 1>/dev/null
),并设置文件的描述符1点至/dev/null而不是stdout。具有这样做,庆典,然后向右移动和看到 2>&1
.这套文件描述2 指向同一文件 作为文件描述符1(不以文件描述符1本身!!!!(见 这个资源上的指针 更多信息)).由于文件描述符1点/dev/null和文件描述符2点到同一文件作为文件描述符1、文件描述符2现在还有点/dev/null。因此,这两个文件的描述符点/dev/null,并且这就是为什么没有输出渲染。
测试,如果你真的了解的概念,试图猜测输出,当我们开关的重新定向的顺序:
(echo "stdout"; echo "stderror" >&2) 2>&1 >/dev/null
stderror
其理由是,评估从左到右,Bash看到2>&1,因而把该文件描述符2点到同一个地方文件的描述符1,即stdout。它然后将文件描述符1(记得>/dev/null=1>/dev/null)要点,以>/dev/null,因此删除一切,它通常会被送到到的标准。因此,我们所留下的是,这并不是发送给stdout在子shell(代码在括号内)-即"stderror".有趣的事要注意的是,即使1仅仅是一个指向标准输出,重新定向的指针2,1通过 2>&1
不会形成的链条的指针2->1->stdout。如果它这样做的结果向1/dev/null,代码 2>&1 >/dev/null
会得到的指链2->1->/dev/null,因此该守则将产生什么,相反,我们看到了什么上面。
最后,我注意到,有一个简单的方法来这样做:
从部分3.6.4 在这里,, 我们看到,我们可以使用的操作者 &>
重定向这两个stdout and stderr。因此,向这两个stderr和stdout输出的任何命令 \dev\null
(删除的产出),我们简单的类型
$ command &> /dev/null
或者在我的例子:
$ (echo "stdout"; echo "stderror" >&2) &>/dev/null
要点:
- 文件描述行为类似的指针(虽然文件的描述不同文件指针)
- 重新定向的一个文件,描述符"a"到一个文件,描述符"b",这点文件"f",导致文件,描述符"a"指向同一个地方作为文件描述的b-文件"f"。它不会形成的链条的指针一->b>f
- 由于上述,订单的事项,
2>&1 >/dev/null
是!=>/dev/null 2>&1
.一个产生输出和其他不!
最后看一看这些巨大的资源:
LOG_FACILITY="local7.notice"
LOG_TOPIC="my-prog-name"
LOG_TOPIC_OUT="$LOG_TOPIC-out[$$]"
LOG_TOPIC_ERR="$LOG_TOPIC-err[$$]"
exec 3>&1 > >(tee -a /dev/fd/3 | logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_OUT" )
exec 2> >(logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_ERR" )
它涉及:写STDOUT&标准错误到syslog
它几乎工作,但不能从xinted;(
我想要一个解决有的输出stdout加stderr写入记录文件和stderr仍然在控制台。所以我需要重复的stderr输出通过开球。
这是解决我发现:
command 3>&1 1>&2 2>&3 1>>logfile | tee -a logfile
- 第一次交换stderr和stdout
- 然后追加的stdout日志文件
- 管stderr开球的和追加它也记录文件
有关的情况下,当“管道”是必要可以使用:
<强> |&强>
例如:
echo -ne "15\n100\n"|sort -c |& tee >sort_result.txt
或
TIMEFORMAT=%R;for i in `seq 1 20` ; do time kubectl get pods |grep node >>js.log ; done |& sort -h
此基于bash的解决方案可以通过管道STDOUT和STDERR分开(从 “排序-c” STDERR或从STDERR为 “sort -h”)。
(仅bash4) “最简单” 的方式:ls * 2>&- 1>&-
The following functions can be used to automate the process of toggling outputs beetwen stdout/stderr and a logfile.
#!/bin/bash
#set -x
# global vars
OUTPUTS_REDIRECTED="false"
LOGFILE=/dev/stdout
# "private" function used by redirect_outputs_to_logfile()
function save_standard_outputs {
if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
echo "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"
exit 1;
fi
exec 3>&1
exec 4>&2
trap restore_standard_outputs EXIT
}
# Params: $1 => logfile to write to
function redirect_outputs_to_logfile {
if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
echo "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"
exit 1;
fi
LOGFILE=$1
if [ -z "$LOGFILE" ]; then
echo "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"
fi
if [ ! -f $LOGFILE ]; then
touch $LOGFILE
fi
if [ ! -f $LOGFILE ]; then
echo "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"
exit 1
fi
save_standard_outputs
exec 1>>${LOGFILE%.log}.log
exec 2>&1
OUTPUTS_REDIRECTED="true"
}
# "private" function used by save_standard_outputs()
function restore_standard_outputs {
if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
echo "[ERROR]: ${FUNCNAME[0]}: Cannot restore standard outputs because they have NOT been redirected"
exit 1;
fi
exec 1>&- #closes FD 1 (logfile)
exec 2>&- #closes FD 2 (logfile)
exec 2>&4 #restore stderr
exec 1>&3 #restore stdout
OUTPUTS_REDIRECTED="false"
}
Example of usage inside script:
echo "this goes to stdout"
redirect_outputs_to_logfile /tmp/one.log
echo "this goes to logfile"
restore_standard_outputs
echo "this goes to stdout"
For tcsh, I have to use the following command :
command >& file
If use command &> file
, it will give "Invalid null command" error.
@fernando-fabreti
Adding to what you did I changed the functions slightly and removed the &- closing and it worked for me.
function saveStandardOutputs {
if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
exec 3>&1
exec 4>&2
trap restoreStandardOutputs EXIT
else
echo "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"
exit 1;
fi
}
# Params: $1 => logfile to write to
function redirectOutputsToLogfile {
if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
LOGFILE=$1
if [ -z "$LOGFILE" ]; then
echo "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"
fi
if [ ! -f $LOGFILE ]; then
touch $LOGFILE
fi
if [ ! -f $LOGFILE ]; then
echo "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"
exit 1
fi
saveStandardOutputs
exec 1>>${LOGFILE}
exec 2>&1
OUTPUTS_REDIRECTED="true"
else
echo "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"
exit 1;
fi
}
function restoreStandardOutputs {
if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
exec 1>&3 #restore stdout
exec 2>&4 #restore stderr
OUTPUTS_REDIRECTED="false"
fi
}
LOGFILE_NAME="tmp/one.log"
OUTPUTS_REDIRECTED="false"
echo "this goes to stdout"
redirectOutputsToLogfile $LOGFILE_NAME
echo "this goes to logfile"
echo "${LOGFILE_NAME}"
restoreStandardOutputs
echo "After restore this goes to stdout"
In situations when you consider using things like exec 2>&1
I find easier to read if possible rewriting code using bash functions like this:
function myfunc(){
[...]
}
myfunc &>mylog.log