I am trying to have my Makefile echo text without the trailing new line, but am unable to. I am experiencing the behavior on OS X (on Linux everything works as expected).
a: @echo -n "hello" b: @echo -n hello c: @/bin/echo -n "hello"
Output:
$make a -n hello $make b hello$make c hello$
In other words, the make a
is broken. What exactly is happening? Is make using a built-in echo? Clearly the presence of the double quotes changes the behavior, but why?
As discovered by @chepner, using the full path to /bin/echo
in the makefile understands the -n flag correctly.
Let's create a small Makefile to see how make executes it: $ cat Makefile all: foo bar foo: printf "%s\n" "Target foo executing..." printf "%s\n" "Hello from foo!" bar: printf "%s\n" "Target bar executing..." printf "%s\n" "Hello from bar!"
The ' @ ' is discarded before the line is passed to the shell. Typically you would use this for a command whose only effect is to print something, such as an echo command to indicate progress through the makefile: @echo About to make distribution files.
If you want to inhibit the display of commands during a particular make run, you can use the -s option. If you want to inhibit the display of all command lines in every run, add the special target . SILENT to your makefile .
The problem comes from the unfortunate interaction of two facts.
First, make
has two modes of operations depending on the complexity of the recipe to be run:
make
will directly run the recipe with its builtin commands. This is what happens in your b
case.make
will spawn a shell to interpret and run the recipe. This is what happens in your a
case.Second, make
uses /bin/sh
as a shell but the functionality of /bin/sh
is implemented differently on Mac OS X and Linux:
/bin/sh
is implemented by bash
. Also on Mac OS X, bash
is compiled with --enable-strict-posix-default
. One consequence of this flag is that the echo
command does not understand the -n
flag./bin/sh
is implemented by dash
which is less strict with respect to POSIX specification. Therefore the flag -n
is implemented in the echo
command.BTW, the Makefile buitlin echo
command understands the -n
flag which explains why the b
case always works.
The clean and portable way of fixing your problem is to replace your @echo -n
recipes with @printf
recipes.
Something about the quotes confuses make
. Your code behaves the same for me, but the following works as expected:
help: @echo -n Shouldn\'t print a newline
Hardcoding the path to the executable also works:
help: @/bin/echo -n "Shouldn't print a newline"
The Mac OS X man page for echo
, while discussing the existence of shell built-in echo
s, mentions that the echo
of sh(1)
does not support the -n
option, but that fails to explain (to me, anyway) why my first alternative works.
Confirmation that make
is using sh
to execute the commands by default. Make manual 5.3.2 Choosing the Shell specifies this hehavrior:
The program used as the shell is taken from the variable SHELL. If this variable is not set in your makefile, the program /bin/sh is used as the shell. The argument(s) passed to the shell are taken from the variable .SHELLFLAGS. The default value of .SHELLFLAGS is -c normally, or -ec in POSIX-conforming mode.
In
SHELL = bash help: @echo -n "Shouldn't print a newline" @echo -n Shouldn\'t print a newline
both echo statements behave the same (no newlines printed). So without that variable, we have bash
pretending to be sh
, but evaluating the two lines differently. Question 1: why? Question 2: is the second line the native bash
echo or /bin/echo
, rather than the emulated sh
echo
?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With