This is still the header! Main site

Not Using Terminals, Part 3: Scripting

2024/03/27

In the previous two articles we covered how you can actually get by without using actual terminals. We talked about how you can run commands out of nowhere, commands on specific files; you can also use the output of these commands as compilation errors.

Admittedly though, there is still a lot of typing of commands, that is, either typing something onto a line or hitting the equivalent of the up arrow to locate the right invocation in history. Sure, it's not going into a terminal window, but... it doesn't seem all that different.

A still missing key to an efficient workflow is the use of shell scripts. An excessive number of shell scripts.

Instant scripting

For all their utility, shell scripts are surprisingly hard to create. To make one, you need to open your text editor, put in a shabang line, write some commands, close it, and give it executable permissions. Understandably, you typically don't end up doing this unless you have a strong reason to do so.

As a workaround, here is a super simple script that you can use to create brand new scripts.

#!/bin/bash

set -e # so that we stop the script on error

NEW_SCRIPT=~/bin/$1

cat >~/bin/$1 <<-EOF
#!/bin/bash

set -e
set -x # also print each command

EOF

shift # get rid of the first arg, which is the name of the new script
echo $@ '$@' >>$NEW_SCRIPT  # fill the rest of them into the script
# ... also add a literal $@ in case users of the new script add more args
chmod a+x $NEW_SCRIPT
          

You can use this either from Emacs or a more traditional command line if you have a command that you happen to like and want to save it for a future usage you can just prepend the name of this script and a name you make up for it:

~ $ ffmpeg -with -complex -options -i thing.mp4 thing2.mp4 --etc
(... outputs)
~ $ make_new_script our_converter ffmpeg -with -complex -options -i thing.mp4 thing2.mp4 --etc
~ $ ./our_converter --some-extra-arguments
(... more outputs)
          

As for how to make up unique names for all your possible repetitive shell scripts: you don't have to. Just put a date at the end of the filename so that you can still autocomplete based on what it does (or better yet, look at your scripts directory sorted by time). If a script turns out to be a permanent one, you can always remove the date later.

Enhancing them

The nice thing about scripts is that they are text files.

(We might use this space to point out that Emacs the operating system also includes a text editor.)

It is a pretty common command line workflow to repeatedly invoke commands, notice that they are broken / incorrect, hit "up arrow" and edit the invocation. This is much easier to do if you use a script instead, together with compilation mode!

Because these scripts do not have to be generic, you can also just include the entire long paths of files you're working on. If you need to pick between multiple files during your experiments, you can just edit the script on the fly. This is how such a script would typically look like:

#!/bin/bash

set -e

cd /the/video/output
# ... so that we don't have to think about where we came from

# INPUTS=/some/path/video1.mp4
# note: this was broken, use the below one

INPUTS=/some/path/other_video.mp4
# INPUTS=/we/can/swap_this_in_quickly.mp4

SUBS_DIR=../subtitles

# ffmpeg -i $INPUTS --add-or-remove-some-fancy-thing \
#     --frobnify 0xabcd \
#     --output-format X \
#    --add-subtitles-from $SUBS_DIR/abc.srt \
#    output.mp4

# ^ this worked but didn't drop enough frames

ffmpeg -i $INPUTS --add-or-remove-some-fancy-thing \
     --frobnify 0xabcd \
     --output-format X \
     --add-subtitles-from $SUBS_DIR/xyz.srt \
     --drop-frames 333 \
     ouput.mp4

# Look at the result
ffprobe output.mp4
          

We might have started out just throwing in a single command. Later, we added some more commands to inspect what we have done or to add some post-processing. We can also make a copy of the entire important command part, comment out the original if it happens to work already, and start experimenting on the new copy, in ways that we might or might not break it.

Meanwhile, in addition to being pretty convenient to experiment with, scripts can also serve as documentation on what we have done, including the ability to add comments to describe what happened.