Guard Rails for CLI Autopilot
The Linux command prompt is faster and more powerful than a GUI will ever be for
moving files around and navigating a file system. Once you've spent enough time
with cd
, ls
, mv
, cp
, and rm
, you develop muscle memory that lets you
make things happen to your files without even thinking about it, and there's
where the danger lies. It's too easy to get caught up in a flow and not realize
you just deleted a whole directory of important files until it's too late.
After nuking files I actually needed one too many times during mindless terminal sessions, I decided to put some guardrails in place that either force me to think before doing anything irrevocable, or give me a chance to fix my mistake after I've done something stupid.
Moving and Copying Files Without Overwriting
So here I am organizing some photos from a memory card I've just downloaded onto
my computer. I have the JPEG files in an ./inbox/
directory. I'm moving the
keepers into a date-labeled directory at the same level as ./inbox/
, and I'm
moving the ones I'm pretty sure I will trash but want to look at again with
fresh eyes before I do that into another directory also on the same level. I've
been doing this for about 10 minutes up to this point, so everything is
automatic by now and I'm banging out commands without thinking about them. I've
gone through all but two of the photos. They're both keepers. I issue the
following command to move them both to the "keepers" directory:
% mv inbox/*.jpg
I immediately realized what I had done once I hit "enter". I forgot to supply the destination directory, but since I did supply a glob that expanded to two different files, so I ended up overwriting the second file with the first.
This was the last straw that made me finally start looking into idiot-proofing
my shell. It turns out mv
has all you need to prevent situations like this,
but it isn't the default behavior. The -i
or --interactive
option will
require you to confirm that you want to overwrite a file if the command you
issued would do so. If the command wouldn't overwrite anything, then it requires
no confirmation, and works like normal mv
. cp
uses the same option to enable
this behavior too.
After adding the next few lines to my ~/.zshrc
, I'll get a prompt that will
(hopefully) make me snap out of it when I try to do something stupid with mv
or cp
on autopilot again:
## confirm before trying to overwrite a file with mv or cp alias mv='mv --interactive' alias cp='cp --interactive'
Reversible Deletes
rm
is the most dangerous command and requires the most care. Once you hit
"enter", the file is gone and you can't get it back without resorting to
unreliable and cumbersome file system tricks.
I want to be able to easily undelete a file after I realize I've done something stupid. The easiest way to do this would be to move files to a purgatory folder when I delete them so that I can clear them later when I'm sure I want them gone, or restore them if I've made a mistake. Luckily, the XDG trash spec defines a protocol with exactly this behavior that plenty of applications and desktop environments implement.
I want something that I can alias to rm
and behaves the same way I'm used to.
I know a lot of people advise against using an alias for rm
like this because
I might be on a different machine without the alias set, but I rarely use
different machines, and I still want to use the same workflow as before, but
with a just-in-case back-up plan if I need it.
trash-d is a drop-in replacement for rm
that implements the XDG trash spec
written in D. It uses the same options as rm
along with a few extra ones
specifically related to managing the trash can. After installing the trash-d
package from the AUR I get the trash
command. Adding the following lines to
~/.zshrc
, then gives me reversible deletes:
## use trash-d instead of rm to allow for reversible deletes alias rm='trash'
Now rm --list
shows me what's in the trash can, rm --restore <file>
let's me
restore a file I've deleted by mistake, and rm --empty
clears the trash can.
Automatically Clear Trash
I can empty the trash can manually with the options provided by trash-d
, but
I don't want to have to think about it if nothing has gone wrong. Most of the
times I delete files I actually want them deleted, so I would hate to always
have to do it twice in the normal case.
I could set up a cron job to automatically clear the trash every week or so, but I could delete an important file just before the job runs and not have time to realize I made a mistake before the file goes away permanently.
Instead of automatically clearing the whole trash can periodically, I need
something that automatically removes individual files from the trash can, but
only if those files have been in the trash longer than a set time period. That's
where autotrash
comes in. It's a python script that removes files from the
trash can older than a configurable age, and it runs automatically on a per-user
basis with either a system-d unit or cron job.
After installing it with the AUR package, there's an easy setup command to install a system-d user unit that runs daily and automatically removes files that have been in the trash longer than a set number of days. I have mine set up to nuke all the files older than 2 weeks:
% autotrash -d 14 --install
Don't Clobber Existing Files When Redirecting
Once in a while I need to save the output of some command into a file with
% chatty-command > saved_file
The few times I need to do this, I almost never check if the file already
exists, and the output would happily clobber whatever was there before and I
might not ever realize what happened. The last guardrail I put in place prevents
me from doing this unless I'm sure I want to. ZSH has an option to configure
this behavior called CLOBBER
. Adding the following line to my \~/.zshrc
causes the >
shell redirection to fail if the destination file exists.
# don't overwrite existing files with >. require >! instead. unsetopt CLOBBER
If I'm sure I want to overwrite the file, I need to use >!
instead. This is
exactly what I want, as long as I don't develop the habit of using >!
by
default.
Be Careful
These changes are not a replacement for being careful! Just because you have guard rails on the side of a highway doesn't mean you drive around smashing into them like you're in a pinball machine. You hopefully never need to use them, but they're there for the rare case when something goes wrong.
The first line of defense against doing something stupid at the command prompt should still be paying attention to what you're doing. Sometimes muscle memory takes over though, so hopefully these config changes will get you out of a jam after that happens.