Shell已输出但无法通过管道输出数据

zzoitvuj  于 2023-05-18  发布在  Shell
关注(0)|答案(1)|浏览(186)

命令/usr/sbin/postlog hello在终端中显示输出。我将结果通过管道传输到cat -n,并想添加行号,但它根本不起作用,即使我同时通过管道传输stdout和stderr。我不知道为什么会这样。

root 18:03:27# /usr/sbin/postlog hello
postfix/postlog: hello

root 18:03:38# /usr/sbin/postlog hello | cat -n
postfix/postlog: hello

root 18:03:49# /usr/sbin/postlog hello |& cat -n

root 18:03:56# /usr/sbin/postlog hello 2>&1 | cat -n
sd2nnvve

sd2nnvve1#

我可以重现这个问题,并发挥了一点。根据手册页,输出被发送到postlog-demon,也被发送到stderr,但后者只有如果stderr连接到终端。这似乎是一个奇怪的设计决策:如果您将stderr重定向到管道或文件,postlog不会写入stderr,如果您不重定向,您会看到输出,但无法捕获。我不明白,为什么它是这样设计的,但建议你写一个简单的封面脚本,它将它的参数回声到stdout**,并**将其馈送给日志恶魔,即。比如

  • 脚本mypostlog*
#!/bin/bash
/usr/sbin/postlog "$@" 2>/dev/null
echo "$@"

然后可以将此脚本用作

mypostlog|cat -n

更新

正如艾德Morton指出的那样,这也会抑制postlog错误消息。如果你不想这样的话,你可以做一个

#!/bin/bash
errfile=/tmp/mypostlog.err.$$
/usr/sbin/postlog "$@" 2>$errfile
printf "%s " "$@"
cat $errfile >&2
rm $errfile

错误文件将仅包含错误,但不包含日志记录。
解决方案仍然不完美,因为postlog选项也显示在echo中。也就是说,如果你做一个

mypostlog -p warn MY WARNING

不仅会在日志中显示 MY WARNING,还会写入stdout -p warn MY WARNING,而不是普通的 MY WARNING。如果您不希望发生这种情况,那么您还必须解析选项。
我还替换了我最初的建议printf中的echo,以捕捉日志文本是echo的有效选项(例如-e)的情况。
建议:

#!/usr/bin/env bash
errfile=$(mktemp) || { printf '%s failed to create temp file.\n' "$0" >&2; exit; }
trap 'rm -f "$errfile"; exit' 0
/usr/sbin/postlog "$@" 2>"$errfile" &&
printf '%s\n' "$*" ||
cat "$errfile" >&2

相关问题