Reputation: 6424
I am aware of questions like this one, but my question is specifically about makefile, specifically gnumake.
I have a command that prints line breaks and other whitespace to standard out. I want to capture that output into a variable and then later print the variable to a file.
Example Makefile:
OUTPUT=${shell cowsay hello}
all:
@echo "$(OUTPUT)" > output.txt
After running make, output.txt contains:
_______ < hello > ------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
I want it to retain the whitespaces and instead contain:
_______
< hello >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
The command I'm actually using is not cowsay, but it outputs similar whitespace and linebreaks.
Upvotes: 14
Views: 2978
Reputation: 11461
I suggest you encode the cowsay's output as base64:
$ cowsay hello
_______
< hello >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
$ cowsay hello | base64 -w0
IF9fX19fX18gCjwgaGVsbG8gPgogLS0tLS0tLSAKICAgICAgICBcICAgXl9fXgogICAgICAgICBcICAob28pXF9fX19fX18KICAgICAgICAgICAgKF9fKVwgICAgICAgKVwvXAogICAgICAgICAgICAgICAgfHwtLS0tdyB8CiAgICAgICAgICAgICAgICB8fCAgICAgfHwK
cow:
@echo IF9fX19fX18gCjwgaGV.... | base64 -d
make cow
Now simply running make cow
displays it properly (without wrong line breaks)
$ make cow
_______
< hello >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Upvotes: 3
Reputation: 15493
Since $(shell)
strips out newlines, simply replace them with another character or pattern. Once back in make, replace that character with a newline.
Here I chose :
as my newline replacement. YMMV
define \n
endef
cow := $(subst :,${\n},$(shell cowsay hello | tr \\n :))
$(error [${cow}])
Giving
$ make
Makefile:7: *** [ _______
< hello >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
]. Stop.
You will find it tricky to use ${cow}
in recipes though!
Upvotes: 0
Reputation: 9972
This is a negative answer, unfortunately. The GNU Make Manual states (emphasis added):
The
shell
function performs the same function that backquotes perform in most shells: it does command expansion. This means that it takes as an argument a shell command and evaluates to the output of the command. The only processingmake
does on the result is to convert each newline (or carriage-return / newline pair) to a single space. If there is a trailing (carriage-return and) newline it will simply be removed.
I don't think that eval
or define
will help.
The only work-around that I can see is to store the cowsay hello
command in a variable, instead of the command's output, as in:
OUTPUT=$$(seq 5) # seq 5 replaces cowsay hello
all:
@echo "$(OUTPUT)" > output.txt
This work-around is bad if cowsay hello
is expensive to calculate, or has side-effects. A second work-around is to keep its output, but replace the line-breaks with any arbitrary character(s), using for example sed
, and then adding the line-breaks back. For example:
OUTPUT=$(shell seq 5 | sed s/$$/xxx/) # add xxx to the end of each line
all:
@echo -n $(OUTPUT) ' ' | sed 's/xxx /\n/g' # replace xxx-space with line break
Upvotes: 6
Reputation: 17383
I want to capture that output into a variable and then later print the variable to a file.
There does not seem to be a way around make
's mechanism to translate newlines in the shell command output into spaces. A bit of a hack that stays close to your original approach would be to have the shell convert newlines into some uncommon character (like \1
) when assigning the output to the variable and then have it translate it back when echo
-ing that variable to the file. Something like this:
OUTPUT=$(shell cowsay hello | tr '\n' '\1')
all:
@echo "$(OUTPUT)" | tr '\1' '\n' > output.txt
For me, this results in
$ make
$ cat output.txt
_______
< hello >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Upvotes: 6