#!/bin/bash
开始,而不是 #!/bin/sh
,因为它需要 bash。 - Tor Klingbergdo_something 2>&1 | tee -a some_file
这会将标准错误重定向到标准输出,并将标准输出重定向到some_file
,同时将其打印到标准输出。
$?
不再指 do_something
的退出状态,而是指 tee
的退出状态。 - Flimm你可以将stderr重定向到stdout,并将stdout重定向到文件:
some_command >file.log 2>&1
请参阅第20章 I/O 重定向
这种格式比最流行的&>
格式更受欢迎,后者只适用于Bash。在Bourne shell中,它可能被解释为在后台运行命令。此外,该格式更易读 - 2(标准错误)被重定向到1(标准输出)。
# Close standard output file descriptor
exec 1<&-
# Close standard error file descriptor
exec 2<&-
# Open standard output as $LOG_FILE file for read and write.
exec 1<>$LOG_FILE
# Redirect standard error to standard output
exec 2>&1
echo "This line will appear in $LOG_FILE, not 'on screen'"
tee FILE1 FILE2 ... >(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(文件描述符#1)和/dev/stderr(文件描述符#2)的终端。在实践中,它可以是管道,套接字或其他任何东西。
运行具有上述行以及以下行的脚本的结果:
echo "Will end up in standard output (terminal) and /var/log/messages"
...如下:
$ ./my_script
Will end up in standard output (terminal) and /var/log/messages
$ tail -n1 /var/log/messages
Sep 23 15:54:03 wks056 my_script_tag[11644]: Will end up in standard output (terminal) and /var/log/messages
ls -l /proc/self/fd/
ps xf
bash your_script.sh 1>file.log 2>&1
1>file.log
指示 shell 将标准输出重定向到文件file.log
,2>&1
告诉它将标准错误(文件描述符2)重定向到标准输出(文件描述符1)。
注意:顺序很重要,如liw.fi所指出的,2>&1 1>file.log
不起作用。
奇怪的是,这个有效:
yourcommand &> filename
但是这会导致语法错误:
yourcommand &>> filename
syntax error near unexpected token `>'
你必须使用:
yourcommand 1>> filename 2>&1
&>>
在 BASH 4 上可用:$ echo $BASH_VERSION
4.1.5(1)-release
$ (echo to stdout; echo to stderr > /dev/stderr) &>> /dev/null
注:将标准输出和标准错误重定向到 /dev/null
。 - user272735简短回答:Command >filename 2>&1
或 Command &>filename
解释:
考虑以下代码,它将单词“stdout”打印到标准输出并将单词“stderror”打印到标准错误输出。
$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror
请注意,'&' 运算符告诉 bash 2 是一个文件描述符(指向 stderr),而不是文件名。如果我们省略 '&',此命令将把 'stdout' 打印到标准输出,并创建一个名为 "2" 的文件,并将 'stderror' 写入该文件中。1,2
重定向到 /dev/null
,以下两行代码分别从 stdout 和 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从左到右处理; 因此Bash首先看到>/dev/null
(与1>/dev/null
相同),并将文件描述符1设置为指向/dev/null而不是标准输出。做完这个之后,Bash然后向右移动并看到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,从而删除通常发送到标准输出的所有内容。因此,我们剩下的就是子shell中未发送到标准输出的内容(圆括号中的代码),即"stderror"。
有趣的事情在于,即使1只是指向stdout的指针,通过2>&1
将指针2重定向到1并不形成指针链2 -> 1 -> stdout。如果是这样的话,由于将1重定向到/dev/null,代码2>&1 >/dev/null
会生成指针链2 -> 1 -> /dev/null,因此代码将不会产生任何输出,与上面所看到的不同。
最后,我要注意到有一种更简单的方法:
从3.6.4章节这里,我们可以看到可以使用运算符&>
来重定向stdout和stderr。因此,要将任何命令的stderr和stdout输出都重定向到/dev/null
(即删除输出),我们只需键入
$ command &> /dev/null
或者对于我的例子:
$ (echo "stdout"; echo "stderror" >&2) &>/dev/null
要点:
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" )
相关内容:将标准输出和标准错误写入syslog。
这个方法基本可行,但是在xinetd中无法正常工作 ;(
我希望能将stdout和stderr的输出都记录在日志文件中,但是仍然需要让stderr在控制台上显示。因此,我需要通过tee命令来复制stderr的输出。
以下是我找到的解决方案:
command 3>&1 1>&2 2>&3 1>>logfile | tee -a logfile
在需要使用“piping”的情况下,您可以使用 |&
。
例如:
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的解决方案可以分别管道化标准输出和标准错误(从"sort -c"的标准错误,或从"sort -h"的标准错误)。
&
结合使用时&
的作用。 - not2qubit