70

This is a silly question, but.... with GNU Make:

VAR = MixedCaseText
LOWER_VAR = $(VAR,lc)

default:
        @echo $(VAR)
        @echo $(LOWER_VAR)

In the above example, what's the correct syntax for converting VAR's contents to lower case? The syntax shown (and everything else I've run across) result in LOWER_VAR being an empty string.

DonGar
  • 7,344
  • 8
  • 29
  • 32

8 Answers8

70

you can always spawn off tr

LOWER_VAR = `echo $(VAR) | tr A-Z a-z`

or

LOWER_VAR  = $(shell echo $(VAR) | tr A-Z a-z)

The 'lc' functions you trying to call is from GNU Make Standard Library

Assuming that is installed , the proper syntax would be

LOWER_VAR  = $(call lc,$(VAR))
vrdhn
  • 4,024
  • 3
  • 31
  • 39
  • 2
    In my case, the $(call lc,$VAR) syntax is also resulting in an empty string. I guess that library isn't installed, and it would be non-optimal for me to require all of our developers to install it. However, the spawn out is working. – DonGar Mar 20 '09 at 01:07
  • Optionally, put a $(strip) around it to get rid of the newline at the end: $(strip ($shell echo $(VAR) | tr A-Z a-z)) – Atafar Jun 03 '20 at 13:47
  • @DonGar I just spent too much time on this only to realize the issue I encountered was the same. This was on GNU make 4.1 – sherrellbc Oct 19 '22 at 16:24
66

You can do this directly in gmake, without using the GNU Make Standard Library:

lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))

VAR = MixedCaseText
LOWER_VAR = $(call lc,$(VAR))

all:
        @echo $(VAR)
        @echo $(LOWER_VAR)

It looks a little clunky, but it gets the job done.

If you do go with the $(shell) variety, please do use := instead of just =, as in LOWER_VAR := $(shell echo $VAR | tr A-Z a-z). That way, you only invoke the shell one time, when the variable is declared, instead of every time the variable is referenced!

starball
  • 20,030
  • 7
  • 43
  • 238
Eric Melski
  • 16,432
  • 3
  • 38
  • 52
  • 8
    The only solution I've seen that works regardless of OS and shell tools. – mtalexan Dec 26 '13 at 15:11
  • 2
    @mtalexan it doesn't work though; A-Z covers only a tiny subset of characters that you might want to convert to lower case. É.h, Проблемы.c, etc, etc, etc. – James Moore Aug 30 '17 at 00:22
  • 1
    @James Moore, you're right but the tr syntax given in the other answer also isn't guaranteed to be supported on non-bash shells. Technically the syntax given above will support all ASCII characters and can be expanded for Unicode characters as desired since it's a map transform – mtalexan Aug 30 '17 at 04:27
  • a great example of 'divide and conquer' application :) – Lucas Siqueira Nov 09 '17 at 19:24
  • *"It looks a little clunky, but it gets the job done."* - And how! Many thanks for this. – AJM Jan 27 '23 at 15:45
23

To handle capital letters with accents:

LOWER_VAR  = $(shell echo $VAR | tr '[:upper:]' '[:lower:]')

Results:

$ VAR="Éclipse"
$ echo $VAR | tr A-Z a-z
Éclipse
$ echo $VAR | tr '[:upper:]' '[:lower:]'
éclipse
Rei Vilo
  • 589
  • 5
  • 8
  • For removing all spaces, try `LOWER_VAR = $(shell $VAR | tr '[:upper:]' '[:lower:]' | sed 's/ //g')` – Rei Vilo Jun 11 '12 at 11:12
  • 2
    I believe you mean "LOWER_VAR = $(shell echo $(VAR) | tr '[:upper:]' '[:lower:]')". Without the echo this does not really make sense. – moin moin Sep 03 '15 at 06:01
  • Yep - another way to make this work is to replace `$VAR` with `$1`, so usage would be `$(call LOWER_VAR,value or $V or $(VARIABLE))`. As a rule, I single-quote my echo statements: `echo '$1'` isn't foolproof, but it reduces the chance of redirection, shell expansion, etc. – John P Aug 02 '18 at 04:37
8

I find this slightly cleaner...

$(shell tr '[:upper:]' '[:lower:]' <<< $(VAR))
altendky
  • 4,176
  • 4
  • 29
  • 39
3

If Python is installed this runs even on Windows:

$(shell python -c "print('$(VAR)'.lower())")
Rajan
  • 1,512
  • 2
  • 14
  • 18
mh001
  • 51
  • 2
1

GNU make doesn't include string functions for case conversion. Thus, there is no lc function defined, by default.

But GNU Make usually comes with GNU Guile support enabled (e.g. this is the case on Fedora 33).

Thus, you can just call a Guile function for converting the case:

VAR = MixedCaseText
LOWER_VAR = $(guile (string-downcase "$(VAR)"))

default:
        @echo $(VAR)
        @echo $(LOWER_VAR)

Or if you want to encapsulate the Guile call:

VAR = MixedCaseText
LOWER_VAR = $(call to_lower,$(VAR))


define to_lower
$(guile (string-downcase "$(1)"))
endef


default:
        @echo $(VAR)
        @echo $(LOWER_VAR)
maxschlepzig
  • 35,645
  • 14
  • 145
  • 182
  • 1
    The "usual" in this answer comes with a big bag of salt. To see if your installation supports Guile you can use for example `echo '$(info $(.FEATURES))' | make -f -`. – stefanct Oct 03 '22 at 02:51
  • @stefanct alternatively check by dumping its database, e.g.: `make -p -f /dev/null | grep guile` - FWIW, Fedora 37 still comes with Guile support – maxschlepzig Aug 30 '23 at 20:54
0

I wrote this while looking for a solution. It is a bit verbose but believe it explains the steps and keeps really long lines out on the Makefile.

You can easily be modify it to perform any substitution you may want.

Hope it helps someone.

# set the separator for the *_TABLE variables, needed as otherwise `$(addprefix ...)` fails
luc_JOIN ::= ,

# define the upper and lower cased characters
lc_CHARS ::= a b c d e f g h i j k l m n o p q r s t u v w x y z
uc_CHARS ::= A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

# join the above to create the *_TABLE variables (i.e `a,A b,B ...`, `A,a B,b ...`)
lc_TABLE ::= $(join $(uc_CHARS),$(addprefix $(luc_JOIN),$(lc_CHARS)))
uc_TABLE ::= $(join $(lc_CHARS),$(addprefix $(luc_JOIN),$(uc_CHARS)))

# an internal macro to recursively create `$(subst ...)` from provided *_TABLE and string, (e.g. `$(subst a,A,$(subst b,B,...))`)
luc_internal = $(if $1,$$(subst $(firstword $1),$(call luc_internal,$(wordlist 2,$(words $1),$1),$2)),$2)

# the actual macros to $(call ...), which calls the luc_internal with the correct *_TABLE
lc = $(eval lc_RESULT ::= $(call luc_internal,$(lc_TABLE),$1))$(lc_RESULT)
uc = $(eval uc_RESULT ::= $(call luc_internal,$(uc_TABLE),$1))$(uc_RESULT)

# a mixed case value
VAR = SOME text

default:
    @echo $(call lc,$(VAR))
    @echo $(call uc,$(VAR))
0

Being impressed by the Eric Melski answer, I was curious how make handles recursion (I'm looking at you C preprocessor). Somewhat more involved, than original answer, but it's fascinating what a 50 years old tool can do. Not saying you should use this code, but I guess you could.

pop2 = $(wordlist 3,$(words $(1)),$(1))
sub1 = $(subst $(word 1,$(1)),$(word 2,$(1)),$(2))
map = $(if $(1),$(call sub1,$(1),$(call map,$(call pop2,$(1)),$(2))),$(2))

upperMap := a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z
upper = $(call map,$(upperMap),$(1))

lowerMap := A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z
lower = $(call map,$(lowerMap),$(1))

#Usage:
x := $(call upper,AaBbCcDdEe)
wonder.mice
  • 7,227
  • 3
  • 36
  • 39