Always Use Dry-run Options If Possible

& (verbiage overflow)Tue 04 November 2014RSS

When I learn a new command-line tool, I have taken to checking the documentation for “dry-run” functionality. Using an option --dry-run (sometimes --dry_run or --dryrun) simulates a command without actually running it. That way, if there is an error or something you didn’t expect, you can make changes before actually running the command for real. Especially when the command may cause expense (opening a connection and writing files to a server) or some far-reaching change (deleting or altering code or state), it’s a good idea to take a little time to be sure you expect what is coming.

Below I list six programs that have dry-run options, illustrating various characteristics of the principle: Git, Homebrew, Make, Bash, TeX Live Manager, and Trial. But before I begin, I want to make two larger points.

First, one of the most common causes of inadvertent damage at the command line is the use of rm to delete files and directories. And rm has no dry-run option at this time. But there is trash-cli, which moves files to the trash while leaving you the option of restoring anything you inadvertently delete. Note that the author recommends against mapping rm to trash-cli.

Second, I’m aware of three issues to be cautious about when doing dry runs.

  1. A dry run may print full prospective output to the terminal; but sometimes, depending on the program, it merely reports errors. It is good to know which of these you are getting.
  2. Some programs use -n as shorthand for the dry-run option or even instead of it. But the -n option is also widely used for “number” and for “not [some other default functionality]”, and you can get into a serious pickle if -n doesn’t behave as you thought it would. Read the docs, Comrade Coder.
  3. Some programs report to you explicitly that a dry-run is merely that; others assume you are aware of what you are doing. That means that if you are not careful, you may think you have run a command when you have only done a dry run of it. In the first Git example, below, a dry run produces output indistinguishable from actually running the command; in the second and third Git examples, the output distinguishes them quite clearly.

1. Git

Version control systems tend to have dry-run functionality, since you can create a huge snarl of work for yourself and others if you gum up a repository with erroneous commits. Here are two examples from Git, where --dry-run is usually available; in some cases -n has the same effect:

$ git add -Avn ..
add ...

I am asking git to verbosely add any changed files in the current directory and below, including any files previously committed. The output gives no indication that this is a dry run, so you must remember to use git add -Av ... afterwards so that the files are actually staged.

$ git commit --dry-run
On branch master
Your branch is up-to-date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
        modified:   ...

An actual commit, in contrast, would report something like this:

[master 52a0905] <commit message>
 1 file changed, 19 insertions(+), 3 deletions(-)

If you include other options with git commit, you will see that full prospective commit behavior in the terminal output. I’m partial to git commit -v for “verbose” commit-content and git commit -o for committing “only” specified files.

Note that git commit -n is not the same as git commit --dry-run; this is a case where you must avoid being lazy about typing out the full option.

When pushing, the dry run does actually contact the server but omits the rest of the rigamarole:

$ git push --dry-run
Host key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48
To git@github.com:brannerchinese/MelodyOfLyric.git
   1bceabf..53033b0  master -> master

$ git push
Host key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 484 bytes | 0 bytes/s, done.
Total 5 (delta 4), reused 0 (delta 0)
To git@github.com:brannerchinese/MelodyOfLyric.git
   1bceabf..53033b0  master -> master

2. Homebrew

Homebrew, the package management system for Unix software on Darwin (Macintosh), allows a --dry-run option, which can be shortened to -n:

$ brew link -n ghostscript
Would link:
/usr/local/bin/dvipdf
/usr/local/bin/eps2eps
/usr/local/bin/font2c
/usr/local/bin/gs
/usr/local/bin/gsbj
/usr/local/bin/gsc
...

$ brew link ghostscript
Linking /usr/local/Cellar/ghostscript/9.15... 64 symlinks created

Its output is more explicit than actually running the command, and it thoughtfully uses the modal auxiliary verb “would” to indicate the counterfactual state.

3. Make

The make program is a build-process manager. Running it can initiate a very long process during which many sorts of things may go wrong, so it is a good idea to do a dry run first. Using

$ make -n

prints to stdout all commands that would be executed by make, without actually executing them; there is not necessarily any output other than those commands. But I have seen a case (mailvelope) where it marks prospective output as counterfactual, too, by use of echo: so rather than

build          - copy common folder and dependencies

it prints

echo "build          - copy common folder and dependencies"

Option -n can be replaced more explicitly with --dry-run. Both options are also available for rake (Ruby’s equivalent to make).

4. Bash

The Bash Unix shell, when invoked to read shell scripts, has a dry-run option:

bash -n <script>

This reads <script> without executing it and reports any syntax errors. It does not show the actual commands issued or their results, and if there are no syntax errors there will be no output at all.

5. TeX Live Manager (tlmgr)

TeX Live Manager, the package manager for LaTeX, has a --dry-run option for update, install, backup, and several other commands. It shows the expected output for the command, though without valid download-timing data:

$ sudo tlmgr update --all --dry-run
Password:
tlmgr: package repository http://ctan.math.washington.edu/tex-archive/systems/texlive/tlnet
update: dry run, no changes will be made
tlmgr: saving backups to /usr/local/texlive/2014/tlpkg/backups
[ 1/18, ??:??/??:??] update: biblatex-anonymous [53k] (35451 -> 35491)
[ 2/18, 00:00/00:00] update: biblatex-realauthor [76k] (35452 -> 35499)
[ 3/18, 00:00/00:00] update: bibleref-french [642k] (27098 -> 35497)
...

TeX Live Manager tells you clearly, “dry run, no changes will be made;” here is how the actual output would look:

$ sudo tlmgr update --all
Password:
tlmgr: package repository http://ctan.mirrors.hoobly.com/systems/texlive/tlnet
tlmgr: saving backups to /usr/local/texlive/2014/tlpkg/backups
[ 1/18, ??:??/??:??] update: biblatex-anonymous [53k] (35451 -> 35491) ... done
[ 2/18, 00:03/16:09] update: biblatex-realauthor [76k] (35452 -> 35499) ... done
[ 3/18, 00:05/11:00] update: bibleref-french [642k] (27098 -> 35497) ... done
...
tlmgr: package log updated: /usr/local/texlive/2014/texmf-var/web2c/tlmgr.log
running mktexlsr ...
done running mktexlsr.
running mtxrun --generate ...
done running mtxrun --generate.
running updmap-sys ...
done running updmap-sys.

6. Trial

Trial is a Python unit-testing system for use with Twisted. Running

$ trial -n

will iterate through all tests and report them passing, without actually running them. Option -n can be replaced more explicitly with --dry-run.


Many other programs —

— and countless others support dry-run functionality.

Read the docs and do dry runs.

[end]

Comments are enabled.