如何判断程序是否正在终端中打印到 stderr 或 stdout?

Mic*_*l A 8 bash shell-script

注意:出现换行符,但 od -c 不显示。

我的音乐播放器的状态命令 ( quodlibet --status | od -c) 具有三种状态,我正在尝试根据该输出编写一个条件。该命令的输出是这样的(可能因配置而异)。

  1. 我认为这是打印到 stderr 因为od -c不能正确显示,即使它对其他命令也是如此。

    not-running
    0000000
    
    Run Code Online (Sandbox Code Playgroud)
  2. 暂停

    0000000   p   a   u   s   e   d       P   a   n   e   d   B   r   o   w
    0000020   s   e   r       1   .   0   0   0       s   h   u   f   f   l
    0000040   e       o   n       0   .   2   2   8  \n
    0000053
    
    Run Code Online (Sandbox Code Playgroud)
  3. 0000000   p   l   a   y   i   n   g       P   a   n   e   d   B   r   o
    0000020   w   s   e   r       1   .   0   0   0       s   h   u   f   f
    0000040   l   e       o   n       0   .   2   3   2  \n
    0000054
    
    Run Code Online (Sandbox Code Playgroud)

我的目标是删除除“未运行”、“暂停”或“正在播放”之外的所有内容,并在有条件的情况下使用它,如下所示:

#!/bin/bash

status=$(quodlibet --status | awk '{split($0,m," "); printf "%s",m[1]}' | tr -d '\000\007\010\n')
if [ "$status" = "playing" ]; then
  quodlibet --print-playing '<artist>: <title>' | cut -c1-45
else
  echo -n "$status"
fi
Run Code Online (Sandbox Code Playgroud)

在播放器没有运行的情况下,这总是在“未运行”后在终端中打印一个换行符。即使我做这样的事情

echo -n "$(quodlibet --print-playing '<artist>: <title>' | cut -c1-45)"
Run Code Online (Sandbox Code Playgroud)

如果我将该输出通过管道传输到od -c,我会得到相同的结果

not-running
0000000
Run Code Online (Sandbox Code Playgroud)

这是不对的。换行符没有出现,但它在终端中。

问题

  • 这是什么原因造成的?
  • 当程序未运行时,命令是否打印到标准错误?
  • 我如何确定这一点?

slm*_*slm 6

有几种方法可以解决这个问题。

  1. 合并流

    您可以通过确定所有差异并简单地合并 STDERR 和 STDOUT。

    例子

    quodlibet --status 2>&1 | ...
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用 grep

    您可以使用-o&-E切换到grep.

    例子

    $ echo "...blah not-running blah..." | grep -Eo "not-running|paused|playing"
    not-running
    
    $ echo "...blah paused blah..." | grep -Eo "not-running|paused|playing"
    paused
    
    $ echo "...blah playing blah..." | grep -Eo "not-running|paused|playing"
    playing
    
    Run Code Online (Sandbox Code Playgroud)

    除了与 regex 参数匹配的字符串外,这将删除所有内容grep

  3. 确定流的类型

    您可以使用该-t开关来确定文件描述符流的类型。

    摘自 Bash 手册页

    -t fd 如果文件描述符 fd 已打开并指向终端,则为真。

    其中 fd 是以下之一:

    0:标准输入
    1:标准输出
    2:标准错误

    例子

    这会检测输出是否来自 STDOUT。

    $ if [ -t 1 ]; then echo "from STDOUT"; fi
    from STDOUT
    
    Run Code Online (Sandbox Code Playgroud)

    返回“来自 STDOUT”,因为输出正在通过:

    $ (if [ -t 1 ]; then echo "from STDOUT"; fi) | cat
    
    Run Code Online (Sandbox Code Playgroud)

    不返回任何内容,因为输出被定向到cat