Bash/Zsh shell expansion
Shell expansion is an incredibly handy shortcut. Previously to today, I’ve only ever used glob
(*
), which will expand to include all directories and files within the glob scope (e.g. *
would
list all files and directories in the current directory, test/*
would list all files and
directories in test/
).
There are more though! Today I’m covering { range }
and { list }
, which are convient ways to
expand a known range or list of values. In most cases, it can be used to avoid a for loop, the exact
syntax for which I always have to look up.
Range expansion
Syntax: {start value...end value}
Example: {0..5}
, {5..10}
.
This expression expands numbers, and as far as I can tell, character ranges like {a..z}
. This is great
if you have directories that are incrementally numbered, and you want to target a subset of them.
This isn’t a magical directive that gets passed to shell scripts - it gets expanded before that and
passed to the script, which means that this expansion will work with any script that accepts
multiple arguments - things like echo
, cp
, mv
and friends come to mind, but many scripts
accept a list of files to process somehow.
Negative numbers do not appear to be supported, so the minimum start value is ‘0’ - it can of course be a larger number than this. It’s worth pointing out that the range just passed each value to the command - it won’t skip values that don’t map to a file or directory for example.
Examples:
Make 10 new directories:
> mkdir {0..10}
> ls
0 1 10 2 3 4 5 6 7 8 9
Remove the first 5:
> rm {0..5}
> ls
10 6 7 8 9
Add 5 more, but start from 50:
> mkdir {50..55}
> ls
10 50 51 52 53 54 55 6 7 8 9
List expansion
Syntax: {first value, second value, ..., last value}
Examples: {cats,dogs,birds,cows}
, {1,2,3,5,8,13}
This expression expands to each value in the list. In other words, it’s not necessarily as handy as the range expression for passing directly to a command, BUT it can be used as part of a wider filename.
As an example, let’s say that we have a directory structure like:
|-livestock
|---cows
|---deer
|---sheep
|-pets
|---birds
|---cats
|---dogs
You can use list expansion as part of a file path, for example to list all the animals:
> ls {livestock,pets}
livestock:
cows deer sheep
pets:
birds cats dogs
To list all the animals whose name starts with ‘c’:
> ls {livestock,pets}/c*
livestock/cows:
pets/cats: