1. Introduction
Can we undo a command run in a Linux shell? After all, it’s a program, and many have an undo feature. The short answer to this is no.
In this tutorial, we’ll explore why a universal undo isn’t usually feasible in the shell, and what safeguarding options we have.
2. Shell Undo
To get to the root of the question, we first need to explore what a shell is.
A shell is an execution environment that enables us to enter commands at a command prompt. Then, a shell interprets our input, finds the commands to execute, and passes the arguments to the commands.
Essentially, we can run any command with endless combinations. So, for undo to be a possibility, a shell needs to have an awareness of what we’ve done and what the consequences were**.** Also, it needs to keep a history of system-wide states for each step of the process.
As we can see, it may become endlessly complex. Undo isn’t a feature any shell currently has. Thus, we usually need to take responsibility for our actions and make sure we don’t make irreversible changes that we didn’t intend to.
3. Common Commands
Let’s look at some common Linux commands, and see what options we have with regards to undoing. Of course, we aren’t concerned with commands that only output information without modifying anything.
3.1. cd
For example, to undo a cd, we can move back to the original directory with the – option:
$ pwd
/
$ cd /home/user/Desktop/
$ pwd
/home/user/Desktop
$ cd -
$ pwd
/
If we didn’t have this option, and the prompt didn’t indicate the full directory or was modified not to include it, we would need to log that with the pwd command. So, in general, it’s a good idea to log or backup contents and configurations before making any modifications. This way, we can recover the previous state without doing any guesswork.
3.2. mv and cp
Actions like cp or mv should also be easily reversible by moving, renaming back, or deleting the new files.
However, by default, these commands won’t warn if we happen to replace any files:
$ ls ./dir1
img1.png img2.png
$ ls ./dir2
img1.png
$ mv ./dir1/* ./dir2
In this case, we overwrite img1.png without being asked or given any warning. The same would happen with the cp command.
Still, many commands have an interactive option -i, or similar, which provides a warning prompt to confirm replacing files. For instance, mv -i or cp -i do exactly that.
If we try to run the previous scenario with -i, the mv command asks whether we want to override img1.png:
$ mv -i ./dir1/* ./dir2
overwrite ./dir2/img-1.png? (y/n [n])
To avoid similar issues with other commands, we should run them without suppressing any prompts or warnings, and be extra careful with forced runs.
3.3. rm
Finally, it’s much harder to undo an rm call. Unlike GUI delete, rm permanently deletes files. Although there’s some chance we can recover deleted files with third-party tools, it’s much better to move files to a virtual trash bin first instead of immediately deleting them.
We can do that with the trash-cli and similar command line tools. In addition, it works with the same trash interface as the GUI.
4. Prevention and Remediation
Often, we run complex commands or combinations of multiple commands. Therefore, we don’t have a clear reverse route to undo the action. In such cases, we can benefit from using safeguarding tools.
4.1. Universal Precautions
Aside from planning the changes carefully, especially bulk changes, we might want to perform a data backup. It doesn’t need to be complex. In fact, a basic copy of a directory or file might be enough of a safeguard.
Still, we can utilize tarballs or compression to organize better. For instance, we can create a backup of a directory with a date timestamp before modifying it:
$ tar -czvf "dir1-$(date +'%d%m%Y').tar.gz" dir1
Also, it’s important to set proper permissions for users and files. The chown and chmod commands help here. At the same time, we should get out of the habit of using sudo unnecessarily.
4.2. Dry Run
Another option to consider is the dry run. Many tools offer a –dry-run or a similar option to test the changes before execution, and see if anything can potentially go wrong. After eliminating such issues beforehand, we’ll be less likely to need an undo. On the other hand, in cases like rsync, we can see the changes and use them as an undo.
For example, when we want to install a package with apt, we can simulate the installation to see if there are any missing dependencies, and avoid dealing with a half-installed package:
$ apt install {package} --dry-run
In the absence of this feature, in some cases, we can do our own test runs with sample files.
4.3. Sandboxes
What if we’re running a tool we aren’t familiar with, or a tool not widely used or tested by the community? We can potentially run into problems if we don’t set safety measures.
Creating an isolated environment with containerization tools like lxc can be handy:
$ lxc-create -n container1 -t /usr/local/share/lxc/templates/lxc-centos
However, this isn’t always feasible.
In such instances, we can at least use the chroot command to change the root directory of the command we want to run:
$ chroot /temp/new-root {command}
This ensures the command doesn’t have system-wide access.
5. Conclusion
In this article, we saw why there’s no universal undo feature in the current Linux shells. Some commands can be undone by simply issuing the reverse action. However, in cases when that isn’t possible, we have many tools to safeguard against potentially unwanted activity.
As the saying goes, prevention is better than cure. With enough knowledge and forethought, we might not even need an undo feature.