我想将一个进程的stdout和stderr都重定向到一个文件。 我该如何在Bash中做到这一点?


#1楼

对于tcsh,我必须使用以下命令:

command >& file

如果使用command &> file ,它将给出“无效的空命令”错误。


#2楼

# 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>&1echo "This line will appear in $LOG_FILE, not 'on screen'"

现在,简单的回显将写入$ LOG_FILE。 对守护有用。

对于原始帖子的作者,

这取决于您需要实现的目标。 如果您只需要重定向从脚本中调用的命令,就可以给出答案。 我的是关于当前脚本中进行重定向这会影响上述代码段之后的所有命令/内置命令(包括forks)。


另一个很酷的解决方案是立即重定向到std-err / out并同时重定向到记录器或日志文件,这涉及将“流”分成两部分。 此功能由'tee'命令提供,该命令可以一次写入/附加到多个文件描述符(文件,套接字,管道等):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 EXITget_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 elementlocal pids=( "$$" )running_pids=("${pids[@]}")while :; docurrent_pid="${running_pids[0]}"[ -z "$current_pid" ] && breakrunning_pids=("${running_pids[@]:1}")get_pids_of_ppid $current_pidlocal new_pids="$RETVAL"[ -z "$new_pids" ] && continuefor element in $new_pids; dorunning_pids+=("$element")pids=("$element" "${pids[@]}")donedonekill ${pids[@]} 2>/dev/null
}

因此,从一开始。 假设已将终端连接到/ dev / stdout(FD#1)和/ dev / stderr(FD#2)。 实际上,它可以是管道,插座或其他任何东西。

  • 创建FD#3和#4,并分别指向与#1和#2相同的“位置”。 从现在开始更改FD#1不会影响FD#3。 现在,FD#3和#4分别指向STDOUT和STDERR。 这些将用作真实终端STDOUT和STDERR。
  • 1>>(...)将STDOUT重定向到parens中的命令
  • parens(sub-shell)从exec的STDOUT(pipe)执行'tee'读取,并通过另一个管道重定向到'logger'命令到parens中的sub-shell。 同时将相同的输入复制到FD#3(端子)
  • 第二部分,非常相似,是关于对STDERR和FD#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

如果要查看更清晰的图片,请将以下两行添加到脚本中:

ls -l /proc/self/fd/
ps xf

#3楼

“最简单”的方式(仅限bash4): ls * 2>&- 1>&-


#4楼

我想要一个解决方案,将stdout和stderr的输出写入日志文件,并且stderr仍在控制台上。 所以我需要通过tee复制stderr输出。

这是我发现的解决方案:

command 3>&1 1>&2 2>&3 1>>logfile | tee -a logfile
  • 第一次交换stderr和stdout
  • 然后将标准输出附加到日志文件
  • 将stderr管道连接到tee并将其附加到日志文件

#5楼

简短答案: Command >filename 2>&1Command &>filename


说明:

考虑以下代码,该代码将单词“ stdout”打印到stdout,将单词“ stderror”打印到stderror。

$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror

请注意,“&”运算符告诉bash 2是文件描述符(指向stderr),而不是文件名。 如果我们省略了“&”,此命令会将stdout打印到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而不是stdout。 完成此操作后,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

标准错误

这里的理由是Bash从左到右进行评估,看到2>&1,因此将文件描述符2设置为指向与文件描述符1相同的位置,即stdout。 然后,它将文件描述符1(记住> / dev / null = 1> / dev / null)设置为指向> / dev / null,从而删除通常发送到标准输出的所有内容。 因此,剩下的就是子shell中没有发送到stdout的内容(括号中的代码),即“ stderror”。 需要注意的有趣的是,即使1只是指向stdout的指针,通过2>&1将指针2重定向到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

关键要点:

  • 文件描述符的行为类似于指针(尽管文件描述符与文件指针不同)
  • 将文件描述符“ a”重定向到指向文件“ f”的文件描述符“ b”,会导致文件描述符“ a”指向与文件描述符b相同的位置-文件“ f”。 它不形成指针链a-> b-> f
  • 由于上述原因,顺序很重要, 2>&1 >/dev/null是!= >/dev/null 2>&1 。 一个产生输出,另一个不产生!

最后看看这些出色的资源:

Bash有关重定向的文档 ,文件描述符表的说明 , 指针简介


#6楼

以下功能可用于自动切换beetwen stdout / stderr和日志文件的输出过程。

#!/bin/bash#set -x# global varsOUTPUTS_REDIRECTED="false"LOGFILE=/dev/stdout# "private" function used by redirect_outputs_to_logfile()function save_standard_outputs {if [ "$OUTPUTS_REDIRECTED" == "true" ]; thenecho "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"exit 1;fiexec 3>&1exec 4>&2trap restore_standard_outputs EXIT}# Params: $1 => logfile to write tofunction redirect_outputs_to_logfile {if [ "$OUTPUTS_REDIRECTED" == "true" ]; thenecho "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"exit 1;fiLOGFILE=$1if [ -z "$LOGFILE" ]; thenecho "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"fiif [ ! -f $LOGFILE ]; thentouch $LOGFILEfiif [ ! -f $LOGFILE ]; thenecho "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"exit 1fisave_standard_outputsexec 1>>${LOGFILE%.log}.logexec 2>&1OUTPUTS_REDIRECTED="true"}# "private" function used by save_standard_outputs() function restore_standard_outputs {if [ "$OUTPUTS_REDIRECTED" == "false" ]; thenecho "[ERROR]: ${FUNCNAME[0]}: Cannot restore standard outputs because they have NOT been redirected"exit 1;fiexec 1>&-   #closes FD 1 (logfile)exec 2>&-   #closes FD 2 (logfile)exec 2>&4   #restore stderrexec 1>&3   #restore stdoutOUTPUTS_REDIRECTED="false"}

脚本内部用法示例:

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"

#7楼

@ fernando-fabreti

除了您所做的之外,我还对功能做了些微改动,并删除了&-结束符,它对我来说很有效。

    function saveStandardOutputs {if [ "$OUTPUTS_REDIRECTED" == "false" ]; thenexec 3>&1exec 4>&2trap restoreStandardOutputs EXITelseecho "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"exit 1;fi}# Params: $1 => logfile to write tofunction redirectOutputsToLogfile {if [ "$OUTPUTS_REDIRECTED" == "false" ]; thenLOGFILE=$1if [ -z "$LOGFILE" ]; thenecho "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"fiif [ ! -f $LOGFILE ]; thentouch $LOGFILEfiif [ ! -f $LOGFILE ]; thenecho "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"exit 1fisaveStandardOutputsexec 1>>${LOGFILE}exec 2>&1OUTPUTS_REDIRECTED="true"elseecho "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"exit 1;fi}function restoreStandardOutputs {if [ "$OUTPUTS_REDIRECTED" == "true" ]; thenexec 1>&3   #restore stdoutexec 2>&4   #restore stderrOUTPUTS_REDIRECTED="false"fi}LOGFILE_NAME="tmp/one.log"OUTPUTS_REDIRECTED="false"echo "this goes to stdout"redirectOutputsToLogfile $LOGFILE_NAMEecho "this goes to logfile"echo "${LOGFILE_NAME}"restoreStandardOutputs echo "After restore this goes to stdout"

#8楼

对于这种情况,当需要“管道”时,可以使用:

|&

例如:

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(从“ sort -c”的STDERR或从STDERR到“ sort -h”的管道)。


#9楼

在您考虑使用exec 2>&1类的情况下,我发现如果可能的话,使用如下bash函数重写代码会更容易阅读:

function myfunc(){[...]
}myfunc &>mylog.log

#10楼

do_something 2>&1 | tee -a some_file

这将把stderr重定向到stdout,并将stdout重定向到some_file 并将其打印到stdout。


#11楼

bash your_script.sh 1>file.log 2>&1

1>file.log指示shell将STDOUT发送到文件file.log2>&1告诉它将STDERR(文件描述符2)重定向到STDOUT(文件描述符1)。

注意:顺序很重要,如liw.fi所指出, 2>&1 1>file.log file.log不起作用。


#12楼

您可以将stderr重定向到stdout,然后将stdout重定向到文件中:

some_command >file.log 2>&1

参见http://tldp.org/LDP/abs/html/io-redirection.html

该格式比仅在bash中起作用的最受欢迎的&>格式更受青睐。 在Bourne Shell中,它可以解释为在后台运行命令。 同样,格式更易读2(是STDERR)重定向到1(STDOUT)。

编辑:更改顺序,如注释中指出


#13楼

在这里看看。 应该:

yourcommand &>filename

(将stdoutstderr都重定向到文件名)。


#14楼

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&stderr写入syslog。

它几乎可以工作,但不是从信德()


#15楼

奇怪的是,这有效:

yourcommand &> filename

但这给出了语法错误:

yourcommand &>> filename
syntax error near unexpected token `>'

您必须使用:

yourcommand 1>> filename 2>&1

在Bash中重定向stderr和stdout相关推荐

  1. c中的stderr、stdout、stdin差别

    linux下,一切皆文件.在所有的文件描述符中,有三个是已经被固定占用了,分别是stdin(文件描述符为0).stdout(文件描述符为1).stderr(文件描述符为2).stdin是标准输入,默认 ...

  2. linux重定向stderr,在Bash和其他Linux Shell中将stderr重定向到stdout的方法

    本文介绍重定向输出及在Bash和其他Linux Shell中将stderr重定向到stdout的方法. 前言 将命令的输出重定向到文件或将其通过管道传递到另一个命令时,您可能会注意到错误消息被打印在屏 ...

  3. Bash中的管道输出和捕获退出状态

    我想执行Bash中长时间运行的命令,都捕获它的退出状态,并且发球它的输出. 所以我这样做: command | tee out.txt ST=$? 问题在于变量ST捕获了tee而不是命令的退出状态. ...

  4. 如何检查Bash中是否设置了变量?

    我如何知道是否在Bash中设置了变量? 例如,如何检查用户是否将第一个参数赋予函数? function a {# if $1 is set ? } #1楼 检查是否设置了变量 var="&q ...

  5. Linux中重定向的实验总结,Linux中重定向命令行的总结

    1. 标准输入的控制 语法:命令< 文件将文件做为命令的输入. 例如: mail -s "mail test" < file1 将文件file1 当做信件的内容,主 题 ...

  6. ubuntu命令行语法_Linux中重定向命令行的总结(ubuntu学习第三讲)

    1. 标准输入的控制 语法:命令< 文件将文件做为命令的输入. 例如: mail -s "mail test" test@gzu521.com < file1 将文件f ...

  7. linux作业控制 信号,bash中的作业控制机制

    作业控制 在shell中通过command &可以创建后台作业, 通过jobs -l命令可以查看当前shell中维护的作业列表, 包括他们的作业号, 进程号, 运行状态. 其中作业号(jobI ...

  8. fprintf()中的stderr解析

    首先在test.c中输入如下的代码 void main() { fprintf(stderr,"stderr!"); fprintf(stdout,"stdout!&qu ...

  9. linux bash输入输出重定向

    简单地用 < 或 > 时,相当于使用 0< 或 1> ls > file1 ls -alh >>file2read a< test_file.txt e ...

最新文章

  1. codevs——1220 数字三角形(棋盘DP)
  2. js 外部文件加载处理
  3. Java集成PageOffice在线打开编辑word文件 - Spring Boot
  4. blockboard vs canvas
  5. centos 上安装bugzilla 详解
  6. 有道云笔记语音速记功能体验:让你在移动办公中解放双手
  7. 按位与、按位或、按位异或、左移、右移运算符的简单介绍(部分二进制运算符的简单介绍)...
  8. 从事IT行业的应该如何学习最高效的休息方式
  9. 2021年啤酒酿造行业发展研究报告
  10. goeasy小demo
  11. word2010设置护眼背景
  12. 使用 Nginx 实现 URL 的重定向
  13. 企业为什么要选择阿里云国际版上云?
  14. CodeForces - 1144C Two Shuffled Sequences【优先队列】
  15. 输出满足某种条件的素数(C语言)
  16. 音频基础之麦克风、功放、扬声器
  17. 艾德卡EDEKA EDI 需求分析
  18. windows 批量 jpg 转 bmp 方法
  19. 一切从游戏开始-完整的一个python to hack 实例
  20. “人生搜索引擎” # Rewind

热门文章

  1. nui UI 具有右键属性的菜单树
  2. MediaPlayer生命周期
  3. Apache CXF实现Web Service(5)—— GZIP使用
  4. Nginx 反向代理、负载均衡、页面缓存、URL重写、读写分离及简单双机热备详解...
  5. F5实现2台机器的热备 Priority Group Activation
  6. 兔子未来的方向在哪里
  7. gitlab用户,组,项目权限管控
  8. 迭代器,lower_bound说明
  9. 【原创】搭建spark环境二
  10. Eclipse用法与技巧——导入工程时报错(already exist in the workspace)