2

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.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • `sed -n 's/.* \([0-9]*\).*/\1/p'` and `sed -n 's/.* [0-9]*\.\([0-9]*\).*/\1/p'`? – Wiktor Stribiżew Jan 26 '22 at 09:09
  • Thank you. This is exactly what I am looking for. I think I tried variations on this but without the space in front of the \([0-9]*\). – Aaron Williams Jan 26 '22 at 09:35
  • If you use GNU make there is no need for `sed` or `perl`. Its [Functions for Transforming Text](https://www.gnu.org/software/make/manual/make.html#toc-Functions-for-Transforming-Text) (see my answer below) are sufficient. – Renaud Pacalet Jan 26 '22 at 12:12
  • Please check the existing answers and if you still need help, please consider adding details to the question. – Wiktor Stribiżew Feb 16 '22 at 14:32

3 Answers3

3

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.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
1

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
Kent
  • 189,393
  • 32
  • 233
  • 301
1

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
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51