Multi-line bash commands in makefile Multi-line bash commands in makefile bash bash

Multi-line bash commands in makefile


You can use backslash for line continuation. However note that the shell receives the whole command concatenated into a single line, so you also need to terminate some of the lines with a semicolon:

foo:    for i in `find`;     \    do                   \        all="$$all $$i"; \    done;                \    gcc $$all

But if you just want to take the whole list returned by the find invocation and pass it to gcc, you actually don't necessarily need a multiline command:

foo:    gcc `find`

Or, using a more shell-conventional $(command) approach (notice the $ escaping though):

foo:    gcc $$(find)


As indicated in the question, every sub-command is run in its own shell. This makes writing non-trivial shell scripts a little bit messy -- but it is possible! The solution is to consolidate your script into what make will consider a single sub-command (a single line).

Tips for writing shell scripts within makefiles:

  1. Escape the script's use of $ by replacing with $$
  2. Convert the script to work as a single line by inserting ; between commands
  3. If you want to write the script on multiple lines, escape end-of-line with \
  4. Optionally start with set -e to match make's provision to abort on sub-command failure
  5. This is totally optional, but you could bracket the script with () or {} to emphasize the cohesiveness of a multiple line sequence -- that this is not a typical makefile command sequence

Here's an example inspired by the OP:

mytarget:    { \    set -e ;\    msg="header:" ;\    for i in $$(seq 1 3) ; do msg="$$msg pre_$${i}_post" ; done ;\    msg="$$msg :footer" ;\    echo msg=$$msg ;\    }


The ONESHELL directive allows to write multiple line recipes to be executed in the same shell invocation.

all: fooSOURCE_FILES = $(shell find . -name '*.c').ONESHELL:foo: ${SOURCE_FILES}    FILES=()    for F in $^; do        FILES+=($${F})    done    gcc "$${FILES[@]}" -o $@

There is a drawback though : special prefix characters (‘@’, ‘-’, and ‘+’) are interpreted differently.

https://www.gnu.org/software/make/manual/html_node/One-Shell.html