I have a bash variable populated with a filename and path:
SONG="~/Music/Mine/Cool Title Bro.flac"
In my attempts to make tagging dramatically easier, I applied a bit of transformation to the variable to isolate the title:
echo "${SONG#\~/Music/Mine/}" # which prints: Cool Title Bro.flac
I know it's also possible to remove the suffix with ${SONG%%.flac}
.
But is it possible to remove both the prefix and the suffix in a single operation?
This:
${SONG#\~/Music/Mine/%%.flac}
doesn't work presumably because it tries to match a literal %%.flac
as part of the prefix. The reverse does not work (%%.flac#~/[...]
), and I've even gone crazy and tried
${${SONG#~/Music/Mine/}%%.flac}
which also does not work.
This may be a prime example of over-engineering on my part, but it'd be excellent if there is a way to do this and I just haven't figured it out yet.
echo "1:"
if [[ "$SONG" =~ \~/Music/Mine/(.*)\.flac ]] ; then SONG=${BASH_REMATCH[1]} ; fi
echo $SONG
echo "2:"
[[ "$SONG" =~ \~/Music/Mine/(.*)\.flac ]] && SONG=${BASH_REMATCH[1]}
echo $SONG
1 and 2 use bash regular expressions. The first example has the added advantage of being able to break into an else
branch if your string doesn't match the format thats expected.* The second example is a bit cleaner. In both cases, if ${SONG}
doesn't match the pattern, it is left unchanged.
But using awk or sed might be easier to understand. For example:
echo "3:"
SONG=$(echo "$SONG" | sed -r 's:~/Music/Mine/(.*)\.flac:\1:')
echo $SONG
[*] See DennisWilliamson's note below regarding using ||
to get an else
branch.
In some cases, bash
's extended patterns are flexible enough to accomplish what you want. First, you have to turn them on:
shopt -s extglob
Then, you can specify a list of patterns that should be removed using parameter expansion:
echo ${SONG//@(*\/|.*)}
The extended pattern @(*\/|.*)
matches either everything up to a / (which must be escaped, to avoid confusing it with part of the parameter substitution syntax), or a period and everything following it. The //
indicates that each occurrence of the pattern should be substituted.
No, not possible. Use two operations.
tmp="${SONG#\~/Music/Mine/}"; echo "${tmp%.flac}"
Well ok, it's possible, if you're nuts.
a="~/Music/Mine/Cool Title Bro.flac"
echo "${a:b=$(b=${a%${a#\~/Music/Mine/}};echo ${#b}):$(c=${a%.flac};echo ${#c})-b}"
You could also use regex grouping in a shell that supports it. Example in jedwards answer
It can also be done using ksh93 pattern grouping.
song='~/Music/Mine/Cool Title Bro.flac'; echo "${song/'~/Music/Mine/'+(*).flac/\1}"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With