Shell scripts are great, for many reasons, but one of the most tangible benefits is simple: you can stop running the same lengthy, obscure commands again and again. You might have a text file of commands you copy and paste, or you might find yourself on Stack Overflow looking up the same thing every day.
Overcome these bad habits, learn how to script your shell, and reclaim some valuable time.
Get intimate with your shell
If you’re undertaking any serious kind of scripting, you’ll need to know about your shell. It’s probably bash, but it may also be zsh, or even the ancient, original shell, sh (the Thompson shell).
You may even have changed your shell to something else altogether, like dash or fish. Whichever shell you’re using, you should read its manual and get to know its syntax and capabilities. POSIX shells—like bash, ksh, and zsh—are largely compatible, but each may introduce its own features on top.
While you’re exploring, you’ll probably uncover aspects of the shell that are totally new, or that you’d heard of, but never fully understood. This could be anything from special characters to expansion rules and test patterns.
Identify common tasks
This one seems obvious, but deciding what to script will be the biggest factor in how much time you save doing so. If you can speed up a task that you run every day, that’s a big win, but if it’s something you’ll only ever do once, it’s not worth investing too much time in.
The history command is a good way of seeing which other commands you run most. You can browse it manually or build a little pipeline to get summary info:
history | sed ‘s/^ *[0-9]* *//’ | cut -d’ ‘ -f1 | sort | uniq -c | sort -n
If you’re using zsh, change this command to history 0 | ….
This will fetch the first word of each command you’ve run, count the instances, and sort them to show the most frequent last:
This can help steer you in the right direction, and may even tell you how much use you’re making of any existing scripts you’ve written. Here’s a similar command that will tell you a bit about which manual pages you read the most:
history | sed ‘s/^ *[0-9]* *//’ | cut -d’ ‘ -f1- | grep ^man | sort | uniq -c | sort -n
For example, on my system, this tells me I use man to get help on cp, git, strftime, jq, and ls the most. I know the ls command has many options, so any scripts I can write that help encapsulate some of the more obscure ones will probably be worthwhile.
Use good names
I’ve found that one of the biggest barriers to replacing a command or using a new program is simply remembering it. The ls command is seared into my brain and muscle memory, but I find eza, a modern alternative, too obscure to remember; that name just doesn’t say “list files” to me.
There are ways to deal with this for third-party programs. You could use an alias, for example:
alias list=eza
This isn’t perfect, though, since it doesn’t rename the man page or help other users, but for your own purposes, it can be a useful workaround. However, there’s no excuse for your own scripts, so give them good names to begin with. Here are some tips:
- Shorter names are always easier to work with, provided you can associate them with the task that your script carries out.
- Names that leverage existing knowledge are convenient. The lsd program is another ls alternative that’s much easier to remember; it even benefits from tab completion.
- On the other hand, if your script has a short, unique prefix, it will be easier to tab complete. My system has over 60 commands that begin with “co,” but only 12 beginning with “q”—and one of those is my own script!
- Scripts should always be named in lowercase. There’s no better way to lose a script than giving it an initial capital letter.
- Prefer commands without an extension. If you save your script as foo.sh, create an alias or symlink named “foo.” Not only is this cleaner, but it’s also easier to change the extension—if you rewrite the script in another language, for example.
Related
I automated Linux backups with a simple bash script and cron (and it’s better than a GUI)
Skip one-click backup apps. This rsync script gives you full control over what gets saved and when, plus logs and a few hard-won lessons.
Keep them in a sensible place
You can put your scripts anywhere you like, but to run them conveniently, you’ll want them in a directory that’s named in your PATH variable.
If you’re writing scripts for several users to run on one system, you should put them in /usr/local/bin. This follows the standard Linux directory structure.
Your personal scripts belong inside your home directory, not a global directory like /bin or /usr/bin. The traditional location was ~/bin, which you may need to create. If you don’t like seeing too many directories in your home, you can use a hidden one instead: ~/.bin.
The latest convention is to follow the XDG spec and use a folder like ~/.local/bin. You may already have this directory, even if you’re unaware of it, with third-party software inside.
Related
This IDE Actually Made Me a Better Programmer
One IDE to rule them all. You won’t want to use anything else.
Use functions for more maintainable code
When your scripts become longer than a certain size—typically, beyond one or two pages—they can become unwieldy, with repeated code and unnecessary duplication. Any code you find yourself repeating is a candidate for moving into a function, reducing the overall size of your script and making it more maintainable.
There are two main forms of syntax to declare a function:
foo() {
}
function foo {
}
I recommend the first style, which is a bit shorter and more widely compatible. With either style, you’ll have access to parameters in the same way your main script does, i.e., using $1 for the first parameter, $2 for the second, and so on. You can call a function in the same way you’d call any command:
foo param1 param2
Another advantage of writing functions is that you can reuse them across scripts, as well as within them. You can import a file containing shell functions by sourcing it:
. ./shell-functions.sh
As with any programming, comments are a valuable feature that you should neither overuse nor underuse. It’s vital to comment any parts of your code that may be difficult to understand at a later date, although such parts are ideally kept to a minimum.
In shell scripts, comments begin with a # symbol. They can occur anywhere on a line and always run until the end of the line:
Comments can be particularly useful when documenting the parameters that a function expects, since they are not explicitly declared:
# $1 the post URL
twitter() {
}

