3

In bash I can split a string similar to How to split a string in shell and get the last field

foo=1:2:3:4:5
echo ${foo##*:}

how can I achieve something similar with make inside a makefile? Any solutions I found were a lot more complicated than the bash pendant.

I tried to use: $(shell ${foo##*:}) but this fails as a string does not seem to terminate properly.

Georg Heiler
  • 16,916
  • 36
  • 162
  • 292
  • is it a string or a variable inside the makefile? If it's a variable, then you can source the file and echo the variable. Please explain in bit more detail and give an example of the makefile section you're referring to. Also, do you want to change that file or just use the output somehow? – py9 Jul 18 '18 at 15:13
  • I just want to use the output. The variable is passed when calling the makefile , i.e. `make myvar=my/value/last.thing mytask` – Georg Heiler Jul 18 '18 at 17:35
  • 1
    @GeorgHeiler So, it is a make variable, not a shell variable. In your example `echo $(lastword $(subst /, ,$(myvar)))` does what you want (see my answer for a detailed explanation). – Renaud Pacalet Jul 18 '18 at 18:15
  • May I ask if you also find [these functions](https://github.com/markpiffer/gmtt#call-glob-matchstringpattern) too complicated to consider? – Vroomfondel Jul 18 '18 at 22:01
  • see the accepted answer - no – Georg Heiler Jul 19 '18 at 04:00
  • Um, I think you missed the link to https://github.com/markpiffer/gmtt#call-glob-matchstringpattern in my question? – Vroomfondel Jul 19 '18 at 06:45
  • Indeed, that also looks good. – Georg Heiler Jul 19 '18 at 13:27

3 Answers3

8

If foo is a make variable

From the Text functions section of the GNU make manual:

$(subst from,to,text) performs a textual replacement on the text text: each occurrence of from is replaced by to. The result is substituted for the function call.

So:

$(subst :, ,$(foo))

splits the content of make variable foo by replacing all : by a space. Still from GNU make manual:

$(lastword names…) The argument names is regarded as a series of names, separated by whitespace. The value is the last name in the series.

So:

$(lastword $(subst :, ,$(foo)))

should do what you want. Demo (host> is the shell prompt):

host> cat Makefile
foo := 1:2:3:4:5

all:
    $(info $(lastword $(subst :, ,$(foo))))
host> make
5

If foo is a shell variable

You must:

  1. Protect the $ signs of your recipe from the first expansion that make performs before passing the recipe to the shell,
  2. Consider that each line of your recipe is executed by a separate shell: if you define a shell variable on a line and use it on another one, it does not work as you would expect.
all:
    @foo=1:2:3:4:5 && \
    echo $${foo##*:}

should do what you want: the $ sign is properly escaped and it is a single-line recipe (thanks to the trailing \). Demo:

host> cat Makefile
all:
    @foo=1:2:3:4:5 && \
    echo $${foo##*:}
host> make
5
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
0

If you use a double dollar symbol you'll escape the dollar which can then be passed along to the shell.

e.g. echo $${foo##*.} inside your makefile.

borrible
  • 17,120
  • 7
  • 53
  • 75
0

I know this question is GNU make-releated but I want to show how simple is in BSD make:

FOO=1:2:3:4:5

all:
    @echo ${FOO:C/.*://}

And the test:

$ make
5

Explanation (man make): the :C... in ${FOO:C/.*://} named Variable modifier. The :C modifier works like sed's s command. in this case it changes all word in variable ${FOO} defined by sed-like expression: all character and the trailing colon replaced to nothing (aka delete it).

Please note that the .*: expression is greedy (as usual - the .* can contain many colons).

uzsolt
  • 5,832
  • 2
  • 20
  • 32