11

I'm trying to write a conky script that shows my MPD album art, a 'folder.jpg' in the album folder. My current plan is to use mpc -f %file%, which prints out the file name and path, and then cut out the actual file name (i.e. everything after the last /), and use that as the path to for conky's image object.

I'm having trouble with grep/cut, particularly since some songs are nested in two folders, while others are in one. (grep -m 1 . |cut -f1 -d / works for the single folder albums)

How would I go about this? Is there a simpler way I'm missing?

Volker Siegel
  • 16,983
  • 5
  • 52
  • 79
rargh
  • 163
  • 1
  • 1
  • 10

3 Answers3

11

You can use sed to remove the rest - everything starting with the last slash:

mpc -f %file% | head -1 | sed 's:/[^/]*$::'

The pattern /[^/]*$ matches a slash, followed by any characters except slash, up to the end of the line. It is replaced by the empty string.
The head -1 ignores some status output following the line we want - but see below for how to not pring them in the first place.

In case you are not used to sed, the command may look unusual because of the : used. You may have seen sed commands with / as separator before, like 's/foo/bar/' - I prefer to use the separator : for readability, as the expression contains / itself. Alternatively, we could escape the / in the expression: 's/\/[^\/]*$//' - that does not make it more readable.


The way you use it with mpc gives you two additional status lines. The option -q for quiet switches off all the output. You need to combine -q with explicitly printing the current playing file to get the line yon need, and nothing more:

mpc -q -f %file% current | sed 's:/[^/]*$::'

Instead of removing everything starting with the last slash, one could explicitly print everything before the last slash:

mpc -q -f %file% current | sed 's:^\(.*\)/.*$:\1:'

That matches any characters that are followed by a / and any other characters; It matches as much as possible, so that the / that is matched will be the last one.

Volker Siegel
  • 16,983
  • 5
  • 52
  • 79
3

If you want to apply this rule on a single string, then instead of sed (see the other answer), you can use the dirname command:

$ dirname "1 2/3 4/5 6/file"
1 2/3 4/5 6
vinc17
  • 11,912
  • 38
  • 45
2

Grep isn't the last tool for the job. grep -m 1 . prints the first non-empty line, which isn't useful. You can construct complex solutions that involve grep and other tools, but the straightforward way is with sed. One way is to replace a final run of non-slash characters, plus the preceding slash, by the empty string:

mpc -f %file% | sed 's:/[^/]*$::'

Alternatively, keep everything up to the last slash and discard what follows:

mpc -f %file% | sed 's:^\(.*\)\(/.*\)$:\1:'

Beware that both methods leave the input unchanged if it doesn't contain a /, i.e. if you pass a file name with no directory indication. While you can solve this in sed if it's an issue, it's easier to invoke the dirname command:

dirname -- "$(mpc -f %file%)"

In a shell script, you can also use parameter expansion constructs, but this is more complex if you just want to print out the result:

full_path="$(mpc -f %file%)"
case "$full_path" in
  */*) directory_part="${full_path%/*}"
  *) directory_part="."
printf '%s\n' "$directory_part"
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175