Bash – How to tell if a program is printing to stderr or stdout in the terminal

bashshell-script

NOTE: a newline appears but od -c doesn't display it.

My music player's status command (quodlibet --status | od -c) has three states, and I'm trying to write a conditional based on that output. The outputs from that command are like this (may differ depending on the configuration).

  1. I think this is printing to stderr because od -c doesn't display properly, even though it does for the other commands.

    not-running
    0000000
    
  2. paused

    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
    
  3. playing

    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
    

My goal is to remove everything except "not-running", "paused", or "playing" and use that in a conditional, like this:

#!/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

In the case where the player isn't running though this always prints a newline in the terminal after "not-running." Even if I do something like this

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

If I pipe that output to od -c, I get the same

not-running
0000000

which isn't right. The newline doesn't show up, but its their in the terminal.

Questions

  • What's causing this?
  • Is the command printing to standard error when the program isn't running?
  • How can I determine this?

Best Answer

Couple of ways to approach this.

  1. merge streams

    You could by pass determining the difference all together and simply merge STDERR and STDOUT.

    Example

    quodlibet --status 2>&1 | ...
    
  2. use grep

    You could chop the output down by using the -o & -E switches to grep.

    Example

    $ 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
    

    This will cut everything out except for the strings that match the regex argument to grep.

  3. determine the stream's type

    You can use the -t switch to determine the type of the file descriptor stream.

    excerpt from Bash man page

    -t fd True if file descriptor fd is open and refers to a terminal.

    where fd is one of:

    0: stdin
    1: stdout
    2: stderr

    Example

    This detects if the output is coming from STDOUT.

    $ if [ -t 1 ]; then echo "from STDOUT"; fi
    from STDOUT
    

    Returns "from STDOUT" since the output is coming through while:

    $ (if [ -t 1 ]; then echo "from STDOUT"; fi) | cat
    

    Returns nothing, since the output is being directed to cat.

Related Question