Technical notes › Quickly create files from templates
An automation path I’ve seen few people reach for is having an easy ability to create a file from a template, automatically filling in its contents before opening it in your editor. I haven’t run the statistics on this, but probably something like 99% of the times I need to create a file in some folder, I already have a terminal open in that directory, so a command-line function is a nice and easy way to do it.
Since writing this function, I’ve started using it for all sorts of things:
Starting new projects with the configuration files I like. For example, when starting a Rust project, I’ll use my own
Cargo.tomltemplate rather than running
cargo init, because my template includes the common dependencies, options, and profiles I’m going to be setting anyway.
Initialising small playground scripts for when I want to test something. For example, I have a “Ruby + WEBrick” template that imports WEBrick and starts it listening on a port, so if I want to test something in isolation without all my existing code getting in the way, I can quickly spin up a new Web server.
A bunch of uncategorisable stuff such as “HTML5 page” which has the usual structure and common
<head>tags in it.
My name is Newt
Because this creates new files from templates, I called my function
function newt -d "Creates a new file from a template" -a template destination # check that all args are given if test -z "$template" echo "newt: Template argument not given" >&2 return 3 else if test -z "$destination" echo "newt: Destination argument not given" >&2 return 3 end # use template name if target is a directory if test -d "$destination" set destination "$destination/"(basename $template) end # check that target is available if test -e "$destination" echo "newt: ‘$destination’ already exists" >&2 return 1 end # check that the chosen template exists set -l tempeh "$HOME/.config/templates/$template" if test ! -f "$tempeh" echo "newt: No such template ‘$template’" >&2 return 2 end # apply the template and start editing it cp $tempeh $destination and eval $EDITOR $destination end
The script takes two arguments:
template, the relative path to the template file, and
destination, where it should put it.
It’ll then do a simple
cp to copy the template into the destination, and then open it in whichever editor you have
$EDITOR set to.
One of the great things about having all the templates as just files in a folder is that it’s dead simple to write a small shell completion function for
newt, letting you tab-complete the names of the templates:
function __fish_list_newt_templates pushd $HOME/.config/templates fd -t f | sed -e 's,^\./,,' popd end complete -c newt -n __fish_is_first_arg -a "(__fish_list_newt_templates)" --no-files
These completions work by listing the templates directory using fd to list all files, skipping directories, and then stripping their prefix.
(There’s probably a better way to do this, but I failed to find it.)
We only want the first argument to be completed, so the completion is guarded with
You might find that your text editor already comes with a similar feature. If you’re lucky, it’ll use the same simple-tree-of-text-files set of templates used here, making it nice and easy to integrate the two together.
My primary text editor, BBEdit, calls this feature “Stationery” — that name being the very, very old Mac terminology for such a thing — and so I’ve simply symlinked
~/.config/templates to the BBEdit Stationery folder, meaning I have access to the same set of templates from both within the application and from the command-line.∎