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?

  • Do you want the directory part up to the last /, or the file name without leading directory parts? “Cut out” is ambiguous, and we've interpreted it differently. – Gilles Sep 2 '14 at 23:01
  • @Gilles From his example with single folder albums, the OP wants to keep the part before the last slash. – vinc17 Sep 2 '14 at 23:03

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.

  • Great, thanks. The -q flag helped a lot too. – rargh Sep 3 '14 at 8:40

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

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"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.