Arguably one of the most common uses for shell scripting is the automation of mundane tasks. These tasks generally fall into two categories:
- Simple, fully automated processes
- Potentially dangerous, step-through processes
In the simple case, it is often desirable to log the success or failure of each step for later review in the event that something goes awry. In the latter case, it is common to prompt the user before each step and branch appropriately based on their response.
Both of these cases can be rather cumbersome to do in a scripting language like Bash, especially if you are unfamiliar with the argument passing and quoting rules of the language.
Many moons ago I created a little Bash include script which had some handy functions for handling these common tasks, and today I would like to introduce its standalone, grown up replacement: “Runt”.
Runt makes it easy to run commands and give useful output when it’s appropriate to do so (such as in error conditions). It also supports prompting the user interactively before executing a step. Let’s look at a few examples.
The most simple case is to run the command with a friendly description, and notify upon completion:
% runt -d "Updating APT repository" -- apt-get update [INFO] Updating APT repository ... [OKAY] Updating APT repository completed successfully!
For more dangerous commands, prompting the user may be appropriate. The user is given the chance to abort, or simply skip this particular step (while simulating success):
% runt -vi -d "Performing an APT upgrade" -- apt-get -yy upgrade [INFO] Performing an APT upgrade ... [INFO] Will execute: apt-get -yy upgrade Press ENTER to continue. Type "skip" and press ENTER to skip step. Type "info" and press ENTER for details. Or press Ctrl-C to abort. >>> [OKAY] Performing an APT upgrade completed successfully! [OKAY] The output of the command was: Reading package lists... Building dependency tree... Reading state information... 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
There are a number of options provided by Runt, including “terse” init-style output:
% runt -t -d "Checking for passwd" -- test -f /etc/passwd * Checking for passwd ... [ ok ]
Of course, if something goes wrong, you’ll get more useful output:
% runt -t -d "Simulating an error" -- ls /not/a/real/path * Simulating an error ... [ !! ] [ERROR] Simulating an error exited with error (2) [ERROR] The command executed was 'ls /not/a/real/path' [ERROR] The output of the command was: ls: cannot access /not/a/real/path: No such file or directory [ERROR] Execution failed!
If no description is supplied (using -d), one will be made for you:
% runt -- test -f /etc/passwd [INFO] Running 'test -f /etc/passwd' ... [OKAY] Running 'test -f /etc/passwd' completed successfully!
Runt also supports executing commands on a remote server (via SSH):
% runt -s "some.host.com" -- true [INFO] Running 'true' ... [INFO] Executing on server: some.host.com Password: [OKAY] Running 'true' completed successfully!
Setting a working directory works on local and remote hosts:
% runt -v -w /etc -- ls passwd [INFO] Running 'ls passwd' ... [INFO] Command to execute: ls passwd [INFO] Working directory: /etc [OKAY] Running 'ls passwd' completed successfully! [INFO] The output of the command was: passwd
Detailed in-line help is also available:
% runt --help Usage: ./runt [options] (command) [...]
Hopefully someone is able to get a bit of use out of the tool. It’s proven useful to me in its various forms on a number of occasions during my career as a sysadmin.
Update: Runt has been rewritten as a Python script and additional functionality has been added (as of version 1.2).