I am writing a script to create a Makefile. I used a for-loop to iterate through all my arguments to 'echo ... >> Makefile' into the command section of each target. The expected output goes something like this:

$ makemake.sh a.out -Hello -World
$ cat Makefile

> a.out : appointment.o calendar.o day.o dayofweek.o time.o year.o 
>   g++ -ansi -Wall -g -o a.out -Hello -World

However, using the technique above:

echo -n "g++ -ansi -Wall -g -o " >> Makefile
  for arg in $@; do
    echo -n "$@ " >> Makefile

Yields the following:

a.out : appointment.o calendar.o day.o dayofweek.o time.o year.o 
    g++ -ansi -Wall -g -o a.out -Hello -World a.out -Hello -World a.out -Hello -World 

My professor recommended I use shift, but this would make it more difficult to recall arguments for other targets.

Why is this happening and what can I do? Though I still seek an answer, I am very interested in the logic behind this reaction.

  • Did you want to try using $arg in that loop? – cricket_007 Apr 20 '17 at 1:58
  • 1
    each line in a makefile runs in a separate shell, you need to escape the newlines to make a single line (and then add semicolons to make separate statements) – grochmal Apr 20 '17 at 2:03

Your code has multiple issues.

  • You are looping over arg but inside the loop you refer to "$@", not to "$arg". (This is, obviously, what causes the problematic output you observe.)
  • Your output needs to contain a tab at the beginning in order for the action line to be valid Makefile syntax.
  • You are not correctly quoting "$@" in the for line.

But apart from that, your code is also needlessly complex. Try this.

printf '\tg++ -ansi -Wall -g -o' >>Makefile
printf ' %s' "$@" >>Makefile

Incidentally, if this is happening inside a control structure of some sort, it's probably both more efficient and more elegant to redirect just once. Each redirection causes the file to be opened and closed separately, and often, the flow is easier if you can just write once, regardless of whether the output file already exists.

if things are as you wish them to be; then
    execute code which generates output
fi >Makefile

In make, you can refer to the target as $@. So you could do this in your case:

shift; echo -e "\tg++ -ansi -Wall -g -o \$@ $@" >> Makefile

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.