仅在成功时隐藏shell命令的输出吗?


12

隐藏shell命令的输出通常涉及重定向stderr和stdout。是否有任何内置工具或命令默认情况下会隐藏输出,但在发生错误时会转储所有累积的输出?我想将其作为远程ssh命令的包装器运行。现在,我让他们使用重定向,但是对于导致它们失败的原因却一无所知,它们太冗长了。

编辑:最后,我根据@Belmin的答案创建了以下模板,我对其进行了一些调整以从脚本中累积所有先前的命令,使用当前的进程标识符,自动删除日志,并添加失败红色错误出现问题时发出的消息。在此模板中,初始silent包装器将成功,然后使第三条命令失败,因为该目录已存在:

#!/bin/sh

set -e

SILENT_LOG=/tmp/silent_log_$$.txt
trap "/bin/rm -f $SILENT_LOG" EXIT

function report_and_exit {
    cat "${SILENT_LOG}";
    echo "\033[91mError running command.\033[39m"
    exit 1;
}

function silent {
    $* 2>>"${SILENT_LOG}" >> "${SILENT_LOG}" || report_and_exit;
}

silent mkdir -v pepe
silent mkdir -v pepe2
silent mkdir -v pepe
silent mkdir -v pepe2

2
如果仅重定向stdout,stderr仍会显示;这对您是否足够,或者如果有错误,您是否还想查看stdout?
Kromey 2014年

我想同时看到这两者,但前提是出问题了,否则我什么也不想看到。
Grzegorz Adam Adam Hankiewicz 2014年

2
我要做的是将stdout&stderr打印到日志文件中,以免使屏幕混乱。我还打印错误输出到屏幕上,因此如果和错误,我可以看到它。如果需要详细信息,我可以检查日志文件,该文件包含程序输出和上下文中的程序错误。这样,我可以“看到两者,但仅在出现问题时才能看到”。这有帮助吗?见stackoverflow.com/questions/2871233/...
斯特凡Lasiewski

1
使用两个单独的重定向将stderr和stdout重定向到同一文件是否安全?我认为我们应该始终使用2>&1,例如:$* >>"${SILENT_LOG}" 2>&1" || report_and_exit
psmith

Answers:


3

我会这样设置一个bash函数

function suppress { /bin/rm --force /tmp/suppress.out 2> /dev/null; ${1+"$@"} > /tmp/suppress.out 2>&1 || cat /tmp/suppress.out; /bin/rm /tmp/suppress.out; }

然后,您可以运行以下命令:

suppress foo -a bar

在您的系统上具有非root用户访问权限的攻击者可以尝试在rm和命令调用之间建立符号链接,该链接将指向/etc/passswd或某些其他关键文件并覆盖其内容。
Mitar

1
顺便说一句,上面的重定向顺序应该是:$* > /tmp/surpress.out 2>&1这确实捕获了stderr。
Mitar

2
$*不是处理任意输入的最佳方法。特别是当它包含空格或标志时。${1+"$@"}根据stackoverflow.com/questions/743454/…,
balrok

每个注释均已修改。谢谢-很好的信息。
Belmin Fernandez


7

为此目的编写脚本应该足够容易。

像这样的完全未经测试的脚本。

OUTPUT=`tempfile`
program_we_want_to_capture &2>1 > $OUTPUT
[ $? -ne 0 ]; then
    cat $OUTPUT
    exit 1
fi
rm $OUTPUT

另一方面,对于作为脚本一部分运行的命令,我通常希望得到比仅打印所有输出更好的东西。我经常将所见所闻限制为未知。这是我根据十年前阅读的内容改编而成的脚本。

#!/bin/bash

the_command 2>&1 | awk '
BEGIN \
{
  # Initialize our error-detection flag.
  ErrorDetected = 0
}
# Following are regex that will simply skip all lines
# which are good and we never want to see
/ Added UserList source/ || \
/ Added User/ || \
/ init domainlist / || \
/ init iplist / || \
/ init urllist / || \
/ loading dbfile / || \
/^$/ {next} # Uninteresting message.  Skip it.

# Following are lines that we good and we always want to see
/ INFO: ready for requests / \
{
  print "  " $0 # Expected message we want to see.
  next
}

# any remaining lines are unexpected, and probably error messages.  These will be printed out and highlighted.
{
  print "->" $0 # Unexpected message.  Print it
  ErrorDetected=1
}

END \
{
  if (ErrorDetected == 1) {
    print "Unexpected messages (\"->\") detected in execution."
    exit 2
  }
}
'
exit $?

5

我认为没有做到这一点的干净方法,我唯一能想到的就是

  • 捕获命令的输出。
  • 检查命令的返回值以及是否失败
    • 显示捕获的输出。

实施此项目虽然可能是一个有趣的项目,但可能超出了问答环节。


应该是有功能的。嗯,让我尝试一下。
Belmin Fernandez 2014年

1

用类似的东西做空 tehcommand &>/tmp/$$ || cat /tmp/$$

取决于您想要/需要多少可用性/类型。(例如,将其用作管道或通过参数传递命令)

@zoredache短脚本基本上是对此的原始包装,它将提供更高的鲁棒性,处理并发性等


1

尝试这样:

out=`command args...` || echo $out

2
我写为out="$(command args...)" || echo "$out"
kasperd
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.