Run – Easily manage and invoke small scripts and wrappers
source link: https://github.com/TekWizely/run
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Run: Easily manage and invoke small scripts and wrappers
Do you find yourself using tools like make
to manage non build-related scripts?
Build tools are great, but they are not optimized for general script management.
Run aims to be better at managing small scripts and wrappers, while incorporating a familiar make-like syntax.
Runfile
Where make has the ubiquitous Makefile, run has the cleverly-named "Runfile"
By default, run will look for a file named "Runfile"
in the current directory, exiting with error if not found.
Read below for details on specifying alternative runfiles, as well as other special modes you might find useful.
Commands
In place of make's targets, runfiles contain 'commands'
.
Similar to make, a command's label is used to invoke it from the command-line.
Scripts
Instead of recipes, each runfile command contains a 'script'
which is executed when the command is invoked.
You might be used to make's (default) behavior of executing each line of a recipe in a separate sub-shell.
In run, the entire script is executed within a single sub-shell.
TOC
Examples
- Simple Command Definitions
- Simple Title Definitions
-
- Boolean (Flag) Options
- Getting
-h
&--help
For Free
- Using an Alternative Runfile
-
-
- Per-Command Variables
- Exporting Previously-Defined Variables
- Pre-Declaring Exports
- Forgetting To Define An Exported Variable
- Referencing Other Variables
- Conditional Assignment
-
-
- Per-Command Shell Config
- Global Default Shell Config
Simple Command Definitions
Runfile
hello: echo "Hello, world"
We'll see that hello
shows as an invokable command, but has no other help text.
list commands
$ run list Commands: list (builtin) List available commands help (builtin) Show Help for a command hello Usage: run [-r runfile] help <command> (show help for <command>) or run [-r runfile] <command> [option ...] (run <command>)
show help for hello command
$ run help hello hello: No help available.
invoke hello command
$ run hello Hello, world
Simple Title Definitions
We can add a simple title to our command, providing some help content.
Runfile
## Hello world example. hello: echo "Hello, world"
output
$ run list Commands: list (builtin) List available commands help (builtin) Show Help for a command hello Hello world example. ...
$ run help hello hello: Hello world example.
Title & Description
We can further flesh out the help content by adding a description.
Runfile
## # Hello world example. # Prints "Hello, world". hello: echo "Hello, world"
output
$ run list Commands: list (builtin) List available commands help (builtin) Show Help for a command hello Hello world example. ...
$ run help hello hello: Hello world example. Prints "Hello, world".
Arguments
Positional arguments are passed through to your command script.
Runfile
## # Hello world example. hello: echo "Hello, ${1}"
output
$ run hello Newman Hello, Newman
Command-Line Options
You can configure command-line options and access their values with environment variables.
Runfile
## # Hello world example. # Prints "Hello, <name>". # OPTION NAME -n,--name <name> Name to say hello to hello: echo "Hello, ${NAME}"
output
$ run help hello hello: Hello world example. Prints "Hello, <name>". Options: -h, --help Show full help screen -n, --name <name> Name to say hello to
$ run hello --name=Newman $ run hello -n Newman Hello, Newman
Boolean (Flag) Options
Declare flag options by omitting the '<...>'
segment.
Runfile
## # Hello world example. # OPTION NEWMAN --newman Say hello to Newman hello: NAME="World" [[ -n "${NEWMAN}" ]] && NAME="Newman" echo "Hello, ${NAME}"
output
$ run help hello hello: Hello world example. ... --newman Say hello to Newman
Setting a Flag Option to TRUE
$ run help --newman=true # true | True | TRUE $ run help --newman=1 # 1 | t | T $ run help --newman # Empty value = true Hello, Newman
Setting a Flag Option to FALSE
$ run help --newman=false # false | False | FALSE $ run help --newman=0 # 0 | f | F $ run help # Default value = false Hello, World
Getting -h
& --help
For Free
If your command does not explicitly configure options -h
or --help
, then they are automatically registered to display the command's help text.
$ run hello --help hello: ...
Run Tool Help
Invoking the help
command with no other arguments shows the help page for the run tool itself.
$ run help Usage: run -h | --help (show help) or run [-r runfile] list (list commands) or run [-r runfile] help <command> (show help for <command>) or run [-r runfile] <command> [option ...] (run <command>) Options: -h, --help Show help screen -r, --runfile <file> Specify runfile (default='Runfile') Note: Options accept '-' | '--' Values can be given as: -o value | -o=value Flags (booleans) can be given as: -f | -f=true | -f=false Short options cannot be combined
Using an Alternative Runfile
You can specify a runfile using the -r | --runfile
option:
$ run --runfile /path/to/my/file <command>
When specifying a runfile, the file does not have to be named "Runfile"
.
Runfile Variables
You can define variables within your runfile:
Runfile
NAME := "Newman" ## # Hello world example. # Tries to print "Hello, ${NAME}" hello: echo "Hello, ${NAME:-world}"
Local By Default
By default, variables are local to the runfile and are not part of your command's environment.
For example, you can access them within your command's description:
$ run hello -h hello: Hello world example. Tries to print "Hello, Newman"
But not within your commands script:
$ run hello Hello, world
Exporting Variables
To make a variable available to your command script, you need to export
it:
Runfile
EXPORT NAME := "Newman" ## # Hello world example. # Tries to print "Hello, ${NAME}" hello: echo "Hello, ${NAME:-world}"
output
$ run hello Hello, Newman
Per-Command Variables
You can create variables on a per-command basis:
Runfile
## # Hello world example. # Prints "Hello, ${NAME}" # EXPORT NAME := "world" hello: echo "Hello, ${NAME}"
help output
$ run hello -h hello: Hello world example. Prints "Hello, world"
command output
$ run hello Hello, world
Exporting Previously-Defined Variables
You can export previously-defined variables by name:
Runfile
HELLO := "Hello" NAME := "world" ## # Hello world example. # EXPORT HELLO, NAME hello: echo "${HELLO}, ${NAME}"
Pre-Declaring Exports
You can declare exported variables before they are defined:
Runfile
EXPORT HELLO, NAME HELLO := "Hello" NAME := "world" ## # Hello world example. hello: echo "${HELLO}, ${NAME}"
Forgetting To Define An Exported Variable
If you export a variable, but don't define it, you will get a WARNING
Runfile
EXPORT HELLO, NAME NAME := "world" ## # Hello world example. hello: echo "Hello, ${NAME}"
output
$ run hello run: Warning: exported variable not defined: HELLO Hello, world
Referencing Other Variables
You can reference other variables within your assignment:
Runfile
SALUTATION := "Hello" NAME := "Newman" EXPORT MESSAGE := "${SALUTATION}, ${NAME}" ## # Hello world example. hello: echo "${MESSAGE}"
Shell Substitution
You can invoke sub-shells and capture their output within your assignment:
Runfile
SALUTATION := "Hello" NAME := "$( echo 'Newman )" # Trivial example EXPORT MESSAGE := "${SALUTATION}, ${NAME}" ## # Hello world example. hello: echo "${MESSAGE}"
Conditional Assignment
You can conditionally assign a variable, which only assigns a value if one does not already exist.
Runfile
EXPORT NAME ?= "world" ## # Hello world example. hello: echo "Hello, ${NAME}"
example with default
$ run hello Hello, world
example with override
NAME="Newman" run hello Hello, Newman
Script Shells
Run's default shell is 'sh'
, but you can specify other shells.
All of the standard shells should work.
Per-Command Shell Config
Each command can specify its own shell:
## # Hello world example. # NOTE: Requires ${.SHELL} hello (bash): echo "Hello, world"
Global Default Shell Config
You can set the default shell for the entire runfile:
Runfile
# Set default shell for all actions .SHELL = bash ## # Hello world example. # NOTE: Requires ${.SHELL} hello: echo "Hello, world"
Other Executors
You can even specify executors that are not technically shells.
Python Example
Runfile
## Hello world python example. hello (python): print("Hello, world from python!")
Script Execution : env
Run executes scripts using the following command:
/usr/bin/env $SHELL $TMP_SCRIPT_FILE [ARG ...]
Any executor that is on the PATH
, can be invoked via env
, and takes a filename as its first argument should work.
Custom #!
Support
If you want a custom #!
line in your script, you can use the #!
executor.
C Example
Here's an example of running a c
program from a shell script using a custom #!
header:
Runfile
## # Hello world c example using #! executor. # NOTE: Requires gcc hello (#!): #!/usr/bin/env sh sed -n -e '7,$p' < "$0" | gcc -x c -o "$0.$$.out" - $0.$$.out "$0" "$@" STATUS=$? rm $0.$$.out exit $STATUS #include <stdio.h> int main(int argc, char **argv) { printf("Hello, world from c!\n"); return 0; }
Script Execution: Direct
NOTE: The #!
executor does not use /user/bin/env
to invoke your script. Instead it attempts to make the temporary script file executable then invoke it directly.
Special Modes
Shebang Mode
In shebang mode
, you make your runfile executable and invoke commands directly through it:
runfile.sh
#!/usr/bin/env run shebang ## Hello example using shebang mode hello: echo "Hello, world"
output
$ chmod +x runfile.sh $ ./runfile.sh hello Hello, world
Filename used in help text
In shebang mode, the runfile filename replaces references to the run
command:
shebang mode help example
$ ./runfile.sh help Usage: runfile.sh -h | --help (show help) or runfile.sh list (list commands) or runfile.sh help <command> (show help for <command>) or runfile.sh <command> [option ...] (run <command>) ...
shebang mode list example
$ ./runfile.sh list Commands: list (builtin) List available commands help (builtin) Show Help for a command hello Hello example using shebang mode Usage: runfile.sh help <command> (show help for <command>) or runfile.sh <command> [option ...] (run <command>)
Main Mode
In main mode you use an executable runfile that consists of a single command, aptly named main
:
runfile.sh
#!/usr/bin/env run shebang ## Hello example using main mode main: echo "Hello, world"
In this mode, run's built-in commands are disabled and the main
command is invoked directly:
output
$ ./runfile.sh Hello, world
Filename used in help text
In main mode, the runfile filename replaces references to command
name:
main mode help example
$ ./runfile.sh --help runfile.sh: Hello example using main mode
Installing
Go Get
$ GOPATH=/go/path/ go get github.com/tekwizely/run $ /go/path/bin/run help
Pre-Compiled Binaries
See the Releases page as some releases may be accompanied by pre-compiled binaries for various platforms.
Package Managers
I hope to have brew
, deb
and other packages available soon.
Contributing
To contribute to Run, follow these steps:
git checkout -b <branch_name> git commit -m '<commit_message>' git push origin <project_name>/<location>
Alternatively see the GitHub documentation on creating a pull request .
Contact
If you want to contact me you can reach me at [email protected] .
License
The tekwizely/run
project is released under the MIT License. See LICENSE
file.
Just Looking for Bash Arg Parsing?
If you happened to find this project on your quest for bash-specific arg parsing solutions, I found this fantastic S/O post with many great suggestions:
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK