Looking for a simpe replacement to Makefiles


At my company I popularized the use of Makefiles to run simple chunks of commands repeatedly. We have make commands like reset-all that will clean, purge the database, run some fixtures. We have lint that will lint the javascript sub-app, the PHP/Elixir/Other main app, run a formatter, etc.

The problem is that we do not really know make, and not really use it. We just need to reference a group of commands with a single alias because we will always run those commands together, in the same order. And we can compose aliases in higher-order aliases (some_alias: other1 other2\n mix format).

Plus, using variables, environment variables and arguments can be confusing with make, notably when you do not know it and you think it is “just bash”.

Why do we use it ? Because make is available on any OS, you put all your commands in a single file, you can (cd ... ; and do stuff elsewhere), you can install autocompletion easily, and it just works.

For example, a replacement would be to have a bash script that registers functions. But you would have to “run” the bash script to define those functions before you can use them. And as long as you do not close the session, those functions will stick around. With make, the aliases are only available where they make sense, i.e. the app root directory.

But I feel we are abusing make, and as I said, the bashy-but-not-bash syntax makes it hard to write advanced bash constructs.

So, do you know any other tool that packs the aforementioned features, but beeing more “just bash” ? Also, make does not stop if one of the command fails sometimes.

Thank you

If it is used for Elixir project, then maybe you could use Mix tasks for that? But if you want to have Makefile-like syntax, but which is more suitable as a simple task runner, then maybe Just is something for you. It has cleaner syntax than Make while still being straightforward and avoiding Make pitfalls (like missing .PHONY).

But if you want “just bash” then you can create file run in the root with:


root_dir=`git rev-parse --show-toplevel`

shift 1


if [ -x "$task_path" ]; then
  exec "$task_path" "$@"

And then you can create executables in ./run.d that can be executed via ./run task.


What does shift 1 do ?

For example you invoke the bash script with some arguments ./run deploy arg1 arg2 then in the bash script $1 references the value deploy and assigns it to the var task, but after you use shift 1 if you try to use again $1 in the script it will give you the value arg1.

In this bash script shift 1 is being used only to remove deploy value from the list of args that $@ is holding, because it is being used later to execute the deploy task exec "$task_path" "$@".

So, when bash expands the exec command it will do it to exec "/path/to/task/deploy" "arg1" "arg2", but if shift 1 had not been used it would expand it to exec "/path/to/task/deploy" "deploy" "arg1" "arg2", and it would fail to execute your task.

To debug a bash script run it with bash -x ./script-name.sh and it will output how it’s executing each line in the file.


Looks like your case is at least partially about efficiently running a bunch of Elixir/Phoenix code checking tools with one command. If that’s the case then ex_check (that I’m an author of) may be a fitting choice for you.

If works cross-platform, offers native Elixir config syntax (way simpler than make) and even shares some of more powerful traits of make such as ability to run not just mix task but also arbitrary commands (e.g. JS tests) or ability to define deps between them.

The upcoming release (currently on master) also empowers the case of JS linting that you’ve mentioned - allowing to run linter in check mode on read-only CI env while the local invocation will append the —fix arg to do the fixing as well. Or your CI may commit fixes too - it’s up to you, all described in README and docs.


@karolsluszniak @hauleth I do not want to run elixir specific code. We use make because it is a tool that fits all our projects: Elixir, PHP, browser JS, node JS, we also have some C# or Java stuff that we rarely use but we may use that here too.

Looks like “just” is just what I want, I will try it.

Thank you all.


After two years we now use Just extensively and it is great. Thanks @hauleth !


just is absolutely great, I use it everywhere, .gitignore the Justfile because none of the teams I worked with wanted to learn it (though it takes 5-10 minutes), back up all the Justfile-s myself through an automatically running script every 15 minutes, and life is pretty good.

just is a tool done right. Easy to learn, brings value, stays out of the way.

1 Like