How to write exactly bash scripts into Makefiles?

If you really want to “write exactly bash scripts into Makefiles” then you'll need to do it a bit indirectly. If you just paste the script after the target line, then you'll run into two problems that just cannot be bypassed: the command lines need to be indented with a tab, and dollar signs need to be escaped.

If you use GNU make (as opposed to BSD make, Solaris make, etc.), then you can define your script as a variable using the multi-line definition syntax, and then use the value function to use the raw value of the variable, bypassing expansion.

In addition, as explained by skwllsp, you need to tell make to execute the command list for each target as a single shell script rather than line by line, which you can do in GNU make by defining a .ONESHELL target.

define my_important_task =
# script goes here
endef

my-important-task: ; $(value my_important_task)

.ONESHELL:

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

If the .ONESHELL special target appears anywhere in the makefile then all recipe lines for each target will be provided to a single invocation of the shell.

You will still need to put a tab character at the beginning of each line, and to double all dollar signs (i.e. replace $ by $$ everywhere in the script).


If the problem is that your top-level project directory is cluttered with dozens of scripts, then the obvious solution is to create a subdirectory (e.g. called scripts) to put them in.

Run them as ./scripts/scriptname and/or add the scripts directory to your PATH.

If you still want a Makefile to run them with, just create Makefile entries that run ./scripts/scriptname for those targets. e.g.

my-important-task: 
    ./scripts/my-important-task.sh my-parameter

NOTE: If the scripts in ./scripts call other scripts in the same directory, they'll need to either specify the full path to the script, or have the scripts directory in the PATH.

Tags:

Bash

Make