The terminal is a very powerful tool. It enables you to do any kind of operation on any system, scale it, and automate it. But using a powerful tool has its risks: when working on important infrastructure or data, execution of a wrong command can lead to system downtime, loss of data, or in better cases, loss of your precious time.
When the stakes are high, stricter precautions are called for. Some precautions, although they can seem unnecessary or even ridiculous in a normal context can become necessary or beneficial when working on critical systems, or on data that is very important to you or others.
Usual issues when working with shell are;
- Having critical secrets in your command line history
- Having commands that greatly alter state(e.g. git reset, rm) in your history
- Accidentally executing deletion/modification commands that affect a large quantity of/wrong set of files
- Working with multi-line/long commands
In this short article, I am going to share with you some tips that I use to mitigate these issues. The examples I am going to give will be in bash as it is the most popular shell, but you can probably adapt them easily to your chosen shell.
The scripts I share in this article can be found at the repository and also can be installed by running
npm i -g safe-bash
1. Storing terminal secrets in a safer location
Storing secrets like:
- cloud account(s)
- service tokens
- ssh keys
as plain-text files in a non-encrypted drive is a security risk. To mitigate the risks, there are some options. The basic idea is keeping your secrets encrypted when you are not close to your computer and actively using it/locked it.
- Encrypt your home folder
- Use a command-line tool such as pass to store and retrieve secrets
- Use the keyring of your system (e.g. gnome-keyring) to store and retrieve secrets
- Use a password database like Keepass to store ssh keys and secrets
I would recommend using Keepass as it is extendable and configurable to support features like:
- Storing ssh keys and serving them to ssh-agent (Your ssh keys will be safely encrypted as you lock your computer)
- Storing secrets and serving them via its keyring (Which can be accessed from the command line). I described how this can be done in another article.
2. Having a safer command-line history
Command-line history is very useful, and also a potentially dangerous feature, because of two reasons:
- Secrets/passwords of the services you use may be recorded in your history file. This means your credentials are in a plaintext file that you may forget to check or clean.
- Commands that destroy data or make irreversible changes might be recorded in your history.
HISTIGNORE is an important environment variable that may look like this:
rm *:exit:*poweroff:*reboot:git reset*:g reset*:*password*:export AWS_*: *
If yours is empty, you can start using it today to great effect.
As you can see, if it is defined, it will ignore rm, exit, poweroff, reboot (along with sudo poweroff and sudo reboot), git reset commands, and commands that seem like they include sensitive information.
And also there is the part at the end, which is for ignoring any command that starts with a space character. This enables you to just put a space character at the beginning of any command that you don’t want in your history. A sample use case may be environment variables for a deployment tool.
You can put the line
HISTIGNORE='rm *:exit:*poweroff:*reboot:git reset*:g reset*:*password*:export AWS_*: *'
to your .bashrc file to start using it.
Using it will prevent you from having sensitive information in your command line history, as well as preventing you from executing potentially dangerous commands accidentally.
Cleaning up your history
HISTIGNORE will only ignore the new commands you type in. To clean up your history to that point of time, you will need a script:
This is also good for correcting mistakes.
Before trying it out, you can backup your history file with:
cp ~/.bash_history ~/.bash_history.bkp
After pasting this script into a file named history-clean-pattern.sh, you can try it using
to clean your history from commands that you choose.
3. Avoiding rm
The antagonist of worst nightmares, rm command is here to ruin your day. By default, the rm command obliterates everything you point it to. If you make a mistake, your only options are to have a backup ready or use disk rescue software and pray that the files are not corrupted.
You can fix that by not using the rm command. Safer alternatives like safe-rm exist that just move the removed files to trash or a default location until they are deemed unnecessary. Doing your work mostly using non-destructive commands like mv may also help.
4. Editing critical commands before execution
Editing long/multi-line commands before execution is the best idea after writing a dedicated script if you are going to start a long-running/critical operation.
To edit your commands before execution, you can use the keyboard shortcut Ctrl+x Ctrl+e for bash. This will open the editor defined with $VISUAL environment variable, which can also be set in your .bashrc. After working on your command, it will be executed when the file is saved. If you exit without saving the file, the command will not be executed.
Important: If you use this keyboard shortcut while you already have a command written on your prompt, it will be executed even if you don’t save the file. So it is best to use it with an empty prompt.
We can improve on this with a script:
This script does the following:
- Creates a temporary file.
- Opens it for editing using $VISUAL or if not defined, nano.
- If the file is non-empty, executes it as a shell command.
this means you will always start from an empty file.
Confirming commands before execution
To ask for confirmation on a shell command, you can also use a simple script.
This will also prevent pasted commands from being executed immediately.
- Using dry-run flags each time for tools like rsync before executing any actual command is a reasonable practice.
- Using the commands that will do the smallest possible desired effect, and working incrementally is preferable to doing all operations at once.
- Making your scripts output the series of commands that it will execute rather than executing them directly can be useful for reviewing them.
“Slow Is Steady, Steady Is Smooth, Smooth Is Fast” is a military saying that means going slow is sometimes the best option to get us further at the end of the day. No rule or script can replace attention. Planning and slow, steady, and careful action can prevent setbacks, and help us deliver constantly to reach our goals. Given that, I hope these tips will help you avoid a setback or two.
Do you know of any other tips for using the terminal more safely? If you do, let me know!