views:

75

answers:

3

hi,

I'm trying to strip the version out of a package name using only Bash. I have one solution but I don't think that's the best one available, so I'd like to know if there's a better way to do it. by better I mean cleaner, easier to understand.

suppose I have the string "my-program-1.0" and I want only "my-program". my current solution is:

#!/bin/bash

PROGRAM_FULL="my-program-1.0"
INDEX_OF_LAST_CHARACTER=`awk '{print match($0, "[A-Za-z0-9]-[0-9]")} <<< $PROGRAM_FULL`
PROGRAM_NAME=`cut -c -$INDEX_OF_LAST_CHARACTER <<< $PROGRAM_FULL`

actually, the "package name" syntax is an RPM file name, if it matters.

thanks!

+1  A: 

How about:

$ echo my-program-1.0 | perl -pne 's/-[0-9]+(\.[0-9]+)+$//'
my-program
Jon Ericson
Nitpicky details: this will match against `program-.` but not `program-1.2.3`.
Jefromi
@Jefromi: Not any more. ;-) Perl's RE syntax looks much nicer.
Jon Ericson
Yeah, perl >> sed. Was just trying to keep things simple... +1.
Jefromi
+1  A: 

Pretty well-suited to sed:

# Using your matching criterion (first hyphen with a number after it
PROGRAM_NAME=$(echo "$PROGRAM_FULL" | sed 's/-[0-9].*//')

# Using a stronger match
PROGRAM_NAME=$(echo "$PROGRAM_FULL" | sed 's/-[0-9]\+\(\.[0-9]\+\)*$//')

The second match ensures that the version number is a sequence of numbers separated by dots (e.g. X, X.X, X.X.X, ...).

Edit: So there are comments all over based on the fact that the notion of version number isn't very well-defined. You'll have to write a regex for the input you expect. Hopefully you won't have anything as awful as "program-name-1.2.3-a". Absent any additional request from the OP though, I think all the answers here are good enough.

Jefromi
Might want to test the second version. ;-)
Jon Ericson
@Jon Ericson: I did. Works as expected for `name-X`, `name-XX`, `name-X.X`, `name-X.X.X`, and assorted other permutations. It refuses to replace anything that's not a properly formatted version number, like `name-X.`. Is that not the desired behavior?
Jefromi
On my box: `$ echo my-program-1.0 | sed 's/-[0-9]\+\(\.[0-9]\+\)*$//'` produces `my-program-1.0`According to the documentation, sed does not support the `+` syntax.
Jon Ericson
@Jon Ericson: Whoa. What system is that?
Jefromi
I tried both on Solaris and Linux. There might be a setting to turn on Perl style REs on Linux that I don't have set.
Jon Ericson
@Jon Ericson: It's not perl style - you don't have to escape the + in perl. And... well, here's what I know. Right now I only have access to a CentOS 5 box, and its sed says that it essentially supports POSIX.2 BREs, and the documentation for those definitely mentions +. It's pretty, well, basic.
Jefromi
@Jon Ericson: I hate to suggest this, but you couldn't have botched the quoting, so that the `\+` turned into a `+` before it got to sed?
Jefromi
the second version is a nice enforcing expression, but that won't work for me as I'm dealing with RPM file names (for example, alsa-lib-1.0.17-1.el5.i386.rpm). removing everything after the first hyphen with a number after it will do it :-)
cd1
@Jon: You probably need to escape the parentheses or use the `-r` option. For me, with GNU sed 4.2.1, `echo my-program-1.0 | sed 's/-[0-9]\+\(\.[0-9]\+\)*$//'` works, as does `sed -r 's/-[0-9]+(\.[0-9]+)*$//'`
Dennis Williamson
Crap. I take back the Linux comment. `uname` reveals I was on another SunOS system. Sorry for the noise.
Jon Ericson
+1  A: 

Bash:

program_full="my-program-1.0"
program_name=${program_full%-*}    # remove the last hyphen and everything after

Produces "my-program"

Or

program_full="alsa-lib-1.0.17-1.el5.i386.rpm"
program_name=${program_full%%-[0-9]*}    # remove the first hyphen followed by a digit and everything after

Produces "alsa-lib"

Dennis Williamson
The first is correct since it takes advantage of the fact that the version can never have a hyphen. The second is not since parts of the name can start with a digit.
Ignacio Vazquez-Abrams
@Ignacio: True, it would have to be a name like "abc-2def-1.0.42-2.foo.i286.rpm" which would incorrectly become "abc".
Dennis Williamson