Bill Mill web site logo

Let's write a bash script

I used to fear and loathe writing bash scripts, but nowadays I enjoy the process. Let's write a bash script.

The Prerequisites

The #1 thing that has made me comfortable writing bash scripts is shellcheck. Despite being written in haskell (jokes) it's the most useful linter, by far, that I have ever used.

Before I had shellcheck, I lacked confidence when writing bash scripts. With the lessons I learned from it and its superb wiki, I have become a proficient bash coder mostly confident that I will not wipe my hard drive by accident.

For this script, I'm going to write the basics of a script to download youtube videos and make gifs out of them. If you want to follow along at home, you should install yt-dlp and ffmpeg.

(For a fully fleshed-out version of this script, check out ytgif)

Let's start

The first two lines of every bash script I write start with:

#!/usr/bin/env bash
set -euo pipefail

The first line is a shebang that tells our operating system we want it to use bash to execute our code.

The second is an incantation to tell bash that we want the script:

This makes it a tiny bit safer to write bash - it's still a footgun that fires razor blade grenades, but there's a safety on the trigger.


The next thing I do is to write a usage function. Yes, bash has functions. Yes, they're awful. Yes, you should still use them.

This function prints out a documentation string and exits the program. Whenever our script is unsure about its arguments or spots an error, it will call usage to give the user some help and exit the program.

function usage {
function usage {
        cat <<"EOF"
Usage: youtube-gif [OPTIONS] <youtube-url> <output_file>

Download the video named in youtube-url and create a gif of it.


  -v:             print more verbose output



        exit 1

I put this usage function first because it helps serve as documentation for what's going on with the script. Remember that anyone unfortunate enough to have to read your bash script may be frightened by bash, and be kind.


Parsing arguments in bash relies

1: there are various problems making pipefail imperfect. It's still better than not setting it. up