The simplest build tool on earth. An all-purpose build tool and a build file all in one. It's trying to be better than the usual home-grown Shell hell.
41
stars
34
commits
Shell
primary language
Oct 29, 2025
updated
Do or do.sh [dosh] is a build tool and a build file in one and the same self-executable shell script 🪄. (Read that again)
There are many build-tools that are more powerful, versatile or expressive than Do.sh. If you are already using a well-known build tool, then keep on using it. Do is for use cases where the major build tools aren't the best fit. The second purpose of Do is to tame the complexity of usual Shell build scripts. Do provides a consistent reference, interface, documentation and best practices on how to write build scripts.
Do scripts should be recognizable and understandable even if they are customized.
Some use cases where Do can shine are:
go already provides some build tool like functionality and most of the major build tools are too much to justify the overhead. A combination of a few commands will Do it.If you have some other use cases where Do can shine, open an issue or submit a PR.
The simplest way to use Do is to copy and paste the content of the do.sh file into your project and extend it as needed.
Do expects one argument on what to do, If more than one argument is provided, then the following arguments are all passed on to the task. See do.arguments.sh in examples directory.
$ ./do.sh build
I am building
...
If no argument is provided Do prints out a help message with all the available tasks.
$ ./do.sh
Usage:
./do.sh (all|build|deploy|test)
Take also a look into the Examples Directory to see different use cases of Do.
The concept of Do is simple to explain. Functions are Tasks and Tasks can be combined to new Tasks. Tasks can also accept parameters and return values.
It is possible to define as many tasks as needed. The Do template for defines build, test, deploy, all for your convenience.
#!/usr/bin/env sh
# Do - The Simplest Build Tool on Earth.
# Documentation and examples see https://github.com/8gears/do
set -e -u # -e "Automatic exit from bash shell script on error" -u "Treat unset variables and parameters as errors"
build() {
echo "I am ${FUNCNAME[0]}ing"
exit 1
}
test() {
echo "I am ${FUNCNAME[0]}ing"
}
deploy() {
echo "I am ${FUNCNAME[0]}ing"
}
all() {
build && test && deploy
}
_hidden() {
echo "I am a hidden task and won't appear in the usage desciption because I start with an _ (underscore). If you know me you can still call me directly"
}
"$@" # <- execute the task
[ "$#" -gt 0 ] || printf "Usage:\n\t./do.sh %s\n" "($(compgen -A function | grep '^[^_]' | paste -sd '|' -))"
In case no argument was provided the line let $# || echo "Usage:\n\t./do.sh ($(compgen -A function | paste -sd '|' -))" will print out a help message with all the available tasks in this build file.
It is important to be disciplined with Do and avoid adding too much complexity, which is common in the case of shell scripts. Otherwise, it would blur the simple syntax of Do and make it harder for others to understand the build file. In doubt KISS.
For your convenience you can create an alias in your ~/.zsrc|.bashrc file
alias doo='./do.sh'
From now on you can type >doo instead of ./do.sh The second ois there too not get confused with the reserved looping construct worddo.
The examples directory contains a few different usage examples for do.
You can contribute by improving do.sh or by providing examples on how to use Do in an elegant or creative way.
Follow the KISS principle. Don't add complexity. Don't make it bigger than needed.
Create an issue describing the problem you a trying to solve to start a discussion. Do the changes and open a merge request.
There aren't any public projects yet, If you have one open a PR to add your project here.
34 commits
Shell
100.0%
The simplest build tool on earth. An all-purpose build tool and a build file all in one. It's trying to be better than the usual home-grown Shell hell.
41
stars
34
commits
Shell
primary language
Oct 29, 2025
updated
Do or do.sh [dosh] is a build tool and a build file in one and the same self-executable shell script 🪄. (Read that again)
There are many build-tools that are more powerful, versatile or expressive than Do.sh. If you are already using a well-known build tool, then keep on using it. Do is for use cases where the major build tools aren't the best fit. The second purpose of Do is to tame the complexity of usual Shell build scripts. Do provides a consistent reference, interface, documentation and best practices on how to write build scripts.
Do scripts should be recognizable and understandable even if they are customized.
Some use cases where Do can shine are:
go already provides some build tool like functionality and most of the major build tools are too much to justify the overhead. A combination of a few commands will Do it.If you have some other use cases where Do can shine, open an issue or submit a PR.
The simplest way to use Do is to copy and paste the content of the do.sh file into your project and extend it as needed.
Do expects one argument on what to do, If more than one argument is provided, then the following arguments are all passed on to the task. See do.arguments.sh in examples directory.
$ ./do.sh build
I am building
...
If no argument is provided Do prints out a help message with all the available tasks.
$ ./do.sh
Usage:
./do.sh (all|build|deploy|test)
Take also a look into the Examples Directory to see different use cases of Do.
The concept of Do is simple to explain. Functions are Tasks and Tasks can be combined to new Tasks. Tasks can also accept parameters and return values.
It is possible to define as many tasks as needed. The Do template for defines build, test, deploy, all for your convenience.
#!/usr/bin/env sh
# Do - The Simplest Build Tool on Earth.
# Documentation and examples see https://github.com/8gears/do
set -e -u # -e "Automatic exit from bash shell script on error" -u "Treat unset variables and parameters as errors"
build() {
echo "I am ${FUNCNAME[0]}ing"
exit 1
}
test() {
echo "I am ${FUNCNAME[0]}ing"
}
deploy() {
echo "I am ${FUNCNAME[0]}ing"
}
all() {
build && test && deploy
}
_hidden() {
echo "I am a hidden task and won't appear in the usage desciption because I start with an _ (underscore). If you know me you can still call me directly"
}
"$@" # <- execute the task
[ "$#" -gt 0 ] || printf "Usage:\n\t./do.sh %s\n" "($(compgen -A function | grep '^[^_]' | paste -sd '|' -))"
In case no argument was provided the line let $# || echo "Usage:\n\t./do.sh ($(compgen -A function | paste -sd '|' -))" will print out a help message with all the available tasks in this build file.
It is important to be disciplined with Do and avoid adding too much complexity, which is common in the case of shell scripts. Otherwise, it would blur the simple syntax of Do and make it harder for others to understand the build file. In doubt KISS.
For your convenience you can create an alias in your ~/.zsrc|.bashrc file
alias doo='./do.sh'
From now on you can type >doo instead of ./do.sh The second ois there too not get confused with the reserved looping construct worddo.
The examples directory contains a few different usage examples for do.
You can contribute by improving do.sh or by providing examples on how to use Do in an elegant or creative way.
Follow the KISS principle. Don't add complexity. Don't make it bigger than needed.
Create an issue describing the problem you a trying to solve to start a discussion. Do the changes and open a merge request.
There aren't any public projects yet, If you have one open a PR to add your project here.
34 commits
Shell
100.0%