How do I extract a version number when there is another number in front with sed

Viewed 93

OpenSUSE, in their infinite wisdom, has decided that ld -v will return GNU ld (GNU Binutils; SUSE Linux Enterprise 15) 2.37.20211103-7.26 I need to extract the 2 and 37 values and throw out the rest, and this needs to work with ld that isn't so screwed up. I have tried numerous examples found here and elsewhere for extracting the version, but they all get hung up on 15. Does anyone have any idea on how I can extract this using sed?

Currently in the Makefile I am using

LD_MAJOR_VER := $(shell $(LD) -v | perl -pe '($$_)=/([0-9]+([.][0-9]+)+)/' | cut -f1 -d. )
LD_MINOR_VER := $(shell $(LD) -v | perl -pe '($$_)=/([0-9]+([.][0-9]+)+)/' | cut -f2 -d. )

though I would much prefer to use sed like it did before SuSE screwed up our build process with their 15.3 update. Any help would be greatly appreciated.

3 Answers

I would do it in two steps, it can make it clear:

  1. get the version information
  2. get the major/minor or whatever from the version information

It would be easier to use awk to solve it, but since you said you prefer sed:

kent$  ver=$(sed 's/.*[[:space:]]//' <<< "GNU ld (GNU Binutils; SUSE Linux Enterprise 15) 2.37.20211103-7.26")

kent$  echo $ver
2.37.20211103-7.26

kent$  major=$(sed 's/[.].*//' <<< $ver)
kent$  echo $major
2

kent$  minor=$(sed 's/^[^.-]*[.]//;s/[.].*//' <<< $ver) 
kent$  echo $minor 
37

You can use

LD_MAJOR_VER := $(shell $(LD) -v | sed -n 's/.* \([0-9]*\).*/\1/p')
LD_MINOR_VER := $(shell $(LD) -v | sed -n 's/.* [0-9]*\.\([0-9]*\).*/\1/p')

Details:

  • -n - an option that suppresses default line output with sed
  • .* \([0-9]*\).* - a regex that matches the whole string:
    • .* - any zero or more chars
    • - space
    • \([0-9]*\) - Group 1 (the parentheses are escaped to form a capturing group since this is a POSIX BRE pattern): any zero or more digits
    • .* - any zero or more chars
  • \1 - the replacement is the Group 1 value
  • p - only prints the result of the substitution.

In the second regex, [0-9]*\. also matches zero or more digits (the major version number) with a dot after it to skip that value.

If you use GNU make then its Functions for Transforming Text solve all this:

LD_VERSION   := $(subst ., ,$(lastword $(shell $(LD) -v)))
LD_MAJOR_VER := $(word 1,$(LD_VERSION))
LD_MINOR_VER := $(word 2,$(LD_VERSION))

Moreover it is probably very robust and should work with any version string where the version is the last word and its component are separated by dots. Demo (where the version string is passed as a make variable instead of being returned by $(LD) -v):

$ cat Makefile
LD_VERSION   := $(subst ., ,$(lastword $(LD_VERSION_STRING)))
LD_MAJOR_VER := $(word 1,$(LD_VERSION))
LD_MINOR_VER := $(word 2,$(LD_VERSION))

.PHONY: all

all:
    @echo $(LD_MAJOR_VER)
    @echo $(LD_MINOR_VER)

$ make LD_VERSION_STRING='blah blah blah 1.2.3.4.5.6.7'
1
2
$ make LD_VERSION_STRING='GNU ld (GNU Binutils for Debian) 2.35.2'
2
35
$ make LD_VERSION_STRING='GNU ld (GNU Binutils; SUSE Linux Enterprise 15) 2.37.20211103-7.26'
2
37
Related