Question

Given the string "foo-bar-1.4.5" or "for-bar-baz-1.8.3" how can I break these strings into 2 parts: first part everything before the last "-" ("foo-bar", "foo-bar-baz") and the last part ("1.4.5" and "1.8.3") respectively?

I can imagine a few strategies, like splitting on "-" then adding everything but the last part back together. Or maybe a regex with substitution. Bash is the biggest thing in my way though. I'm not sure what the syntax would look like and I've tried a few things with sed and awk but my lack of comfort with bash arrays is hanging me up. I figure one of you bash experts can bang this out in short order and teach me via an example pretty fast.

EDIT: I won't know the number of "-" before the command is run. The method should handle n >= 1 of "-".

Was it helpful?

Solution

You can use parameter expansion for this:

${var#pattern} removes the shortest matching pattern from the beginning of var. Using ## removes the longest matching pattern. % and %% work similarly, but remove from the end of var.

#!/bin/bash
first="foo-bar-1.4.5"
second="foo-bar-baz-1.8.3"

echo ${first%-*}
echo ${first##*-}

echo ${second%-*}
echo ${second##*-}

Output:

foo-bar
1.4.5
foo-bar-baz
1.8.3

OTHER TIPS

To use a regular expression in bash:

s="foo-bar-1.4.5"
[[ $s =~ (.*)-(.*) ]]
name=${BASH_REMATCH[1]}
version=${BASH_REMATCH[2]}

bash only uses greedy matching, so the first .* will match as much as possible, leaving only the last - to match the literal - in the regular expression.

Using bash built-in features is the right way to go. However, for reference, here is an option using awk:

$ cat file
foo-bar-1.4.5
for-bar-baz-1.8.3

$ awk 'BEGIN{FS=OFS="-"}{last = $NF; NF--; printf "First = %s\nLast = %s\n", $0, last}' file
First = foo-bar
Last = 1.4.5
First = for-bar-baz
Last = 1.8.3
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top