rav
rav

Reputation: 90

zsh run command if process is running

I want to get some info from cmus-remote if cmus is running

#!/bin/zsh

pgrep cmus>& /dev/null
if [ $? -eq 0 ]; then
  title=$(cmus-remote -Q | grep tag | grep title | sed 's/tag title //')
  artist=$(cmus-remote -Q | grep tag | grep " artist " | sed 's/tag artist //')
  album=$(cmus-remote -Q | grep tag | grep " album " | sed 's/tag album //')
  track=$(cmus-remote -Q | grep tag | grep tracknumber | sed 's/tag tracknumber //')
  echo $track $title - $artist - $album
else
  echo ""
fi

the output for a running cmus is correct, when cmus isn't running I get

cmus-remote: cmus is not running
cmus-remote: cmus is not running
cmus-remote: cmus is not running
cmus-remote: cmus is not running
-

I have a workaround by appending >& /dev/null on each corresponding line but that's not what I want, I would like the code not to be executed at all. And I don't the output from the else case.

Upvotes: 0

Views: 892

Answers (3)

Adaephon
Adaephon

Reputation: 18339

The best authority on whether cmus is running and whether cmus-remote can retrieve any information is cmus-remote. As such you could just replace pgrep cmus with cmus-remote as this will exit with return code 1, if cmus:

cmus-remote >& /dev/null
if [ $? -eq 0 ]; then
   # stuff
fi

Alternatively you could forego checking beforehand and reduce the amount of external commands called. Just try to parse the output cmus-remote -Q and ignore output on stderr:

#!/bin/zsh

cmus-remote -Q 2> /dev/null | awk '
BEGIN {
  tags["album"] = "";
  tags["artist"] = "";
  tags["title"] = "";
  tags["tracknumber"] = ""
}

$1 == "tag" && $2 in tags { 
  tag=$2;
  $1=$2="";
  sub(/  /,"");
  tags[tag] = $0
}

END {
  if (tag)
    printf "%s %s - %s - %s\n", tags["tracknumber"], tags["title"], tags["artist"], tags["album"];
  else
    print ""
}'

This calls cmus-remote just once and pipes stdout to awk (also called just once). If cmus is not running the error message will be passed to /dev/null. awk then parses the output of cmus-remote -Q and creates the desired output. If cmus is not running or if there were no tags, it will print an empty string.

Upvotes: 0

Ashish K
Ashish K

Reputation: 935

pgrep cmus>& /dev/null
if [ $? -eq 0 ]; then
  title=$(cmus-remote -Q | grep tag | grep title | sed 's/tag title //') > /dev/null 2>&1
  artist=$(cmus-remote -Q | grep tag | grep " artist " | sed 's/tag artist //') > /dev/null 2>&1
  album=$(cmus-remote -Q | grep tag | grep " album " | sed 's/tag album //') > /dev/null 2>&1
  track=$(cmus-remote -Q | grep tag | grep tracknumber | sed 's/tag tracknumber //') >/ dev/null 2>&1
  echo $track $title - $artist - $album
else
  echo ""
fi

Adding > /dev/null 2>&1

2 refers to the second file descriptor of the process, i.e. stderr.

> means redirection.

&1 means the target of the redirection should be the same location as the first file descriptor, i.e. stdout.

So this command first redirects stdout to /dev/null and then redirects stderr there as well. This effectively silences all output (regular or error).

In your case cmus-remote: cmus is not running is an stderr so the redirection that you should use should be able to redirect both STDOUT and STDERR

Upvotes: 0

Chris Overgaauw
Chris Overgaauw

Reputation: 78

The actual problem that you seem to be having is that your pgrep is returning a hit while you're not expecting it to.

pgrep cmus>& /dev/null
if [ $? -eq 0 ]; then
  //statements here are not evaluated if pgrep\'s exit status is not equal to 0

Your pgrep exit code = zero. but it is probably not an exact match (cmus) that was found. Try narrowing your search with pgrep (i.e. by the usage of the u or x flag)

tip: run your bash script with -X to see what the exit code actually was and compare them to the documented exit codes on https://linux.die.net/man/1/pgrep

Upvotes: 1

Related Questions