A quote says "If your only tool is a hammer, everything will look like a nail". That is why getting fixated on one tool is not productive, instead try diverse approaches to solve problems. Complex problems can require complex solutions, and knowing versatile and powerful tools in advance can be the deciding point of being able to solve them.
One of these powerful tools is the command line. Learning the basics of its usage just to be able to move around and get some stuff done is fine. This can make to always lean towards a graphical user interface (GUI) when possible, for example using websites or desktop apps.
Sometimes the GUI approach will be the optimal one for the task. For example when doing the task only once and if the GUI provides sensible options. Be wary of the occasions when following the GUI approach due to being the more convenient path at that time.
The terminal app uses a shell. There are different types of shells, Bash being
the most popular in Linux systems. There is also zsh or fish, and Powershell
which was initially intended for Windows. In Windows, there is also cmd.exe
which is not a shell. There are other shells, and all give the ability to
interact with the OS by running commands.
When you have tried different shells, you will end up having your preference. Personally, I stick with Bash which is the default shell in many Linux distributions. Zsh has a great ecosystem and is visually appealing. macOS chose it as the default shell. Most of the developers I have worked with are fond of zsh. It supports many interesting plugins.
Let's imagine that you can perform a task by both a GUI way and a command-line counterpart. For example, creating an emulator in Android Studio with certain settings. The GUI approach can be easier, it has a wizard form where we can set up the name, OS version, or device model. The command-line approach requires researching how to pass these values, in which conditions, and then to write the actual text.
Writing the commands text can be the most tedious part of the process even if you know by memory all the options and sub-parts. I will list some tricks for not having to write the commands manually.
The first trick that you may notice right away is that you can press the up key to access previous commands. This can be configured in order to save more or less items. If you don't want a command to be saved in the history, you can start it with a blank space.
A less-known feature is that you can press Control+r to search the history. You can start typing the command and it will suggest a match. If the command that you are looking for was before than the current match, you can press Control+r again. To exit this view you can press Control+c.
One of the best first steps is auto-completion. Once you have auto-completion enabled, just pressing Tab will display a list of available options. The first characters entered will filter the options displayed by the auto-completion. The downside is that only the most used packages will already have auto-completion. Creating custom auto-completion for other commands is time-consuming.
An example of great auto-completion is git
. When the cursor is at
the end of this line:
$ git checkout a
If pressing Tab, the shell will display the available git branches
and tags that start with the letter a
. It will also automatically fill the
line when there is only one case.
This becomes useful when spending enough time in the terminal. I give this as
my first recommendation to improve the command-line UX because in Linux and
macOS there are plenty of auto-completion scripts available. They assist the
navigation with common commands like cp
or cd
, and other powerful commands
like rsync
.
Downloading completion scripts for specific commands is also possible. One
example is docker
. Working with containers and images in the command-line
becomes easier when downloading its auto-completion. Be aware that the
auto-completion scripts can be different by each shell.
Another common way to save time in the command-line is by creating aliases. You
can define them by the current terminal session with the alias
keyword. For
example:
$ alias hw='echo "hello world"'
After this, you can run the hw
command directly. We can't use aliases defined
like in the previous example after closing the terminal. If you want to persist
them for future terminals, you can write them in your ~/.bash_profile
,
~/.bashrc
, ~/.zshrc
, etc.
Alias are powerful because they allow chaining commands or partial commands. For example:
# mutiple commands - copy this one at your own risk :)
alias yolo='git add -A .; git commit -m "You Only Live Once"; git push origin master --force'
# part of the command
alias ef='echo "foo"'
# running: `ef bar` will echo "foo bar"
I save them with the first letter capitalized because Unix commands are lowercase in most cases. The capital letter allows to autocomplete them faster:
$ alias GitCommit='git commit -m'
I can type G
, press Tab, and if there are no other git aliases, it
would expand to GitCommit
. Another popular pattern is to use the initials,
gc
in this case.
After you know how to set up and use autocomplete and aliases, your terminal experience will start to gradually improve. But there are still more tricks to get it to the next level.
I would recommend learning the most important commands like cd
, ls
.
Learning the options is not important, but knowing their purpose is helpful. An
easy way is to read the manual that most of these command bring. Running man cp
or man rsync
will show the manual directly in the terminal. At the top
of the text there is a short description.
If you start to learn them little by little, creating aliases and checking the auto-completion at the same time, you will start to muscle memory and they will become natural. There are lists of curated Bash recommendations like this one.
At this point is practical to learn fundamental concepts of Linux which include streams, file descriptors and permissions, symbolic links, or pipes. Having a rough understanding of these concepts and how to use them in the commands will allow combining built-in scripts in one line.
The next step I recommend is installing fzf, which is a fuzzy search tool with integrations. It saves more time than aliases or autocomplete but has fewer uses. The project's documentation lists the common uses. Once you learn the instructions, it is quick to create commands that pipe into fzf if you have a fragment of a text that you need to search in a text.
To continue and further improve, my advice is to learn how to program in Bash. Functions and variables are easy to write and a lot more powerful than aliases. They can allow automating almost any task that uses the command-line, and they can accept input and all the common process flows.
When functions become too large for your configuration files, you can create separate scripts. Bash is a Turing-complete programming language, but it doesn't have some complex features like static types or classes. The syntax can be tricky until you get used to it.
You can find guides online to learn Bash effectively: GNU, TLDP, or Google
Even if Bash is a great programming language for scripting and automating tasks, for complex logic, or when you need to write a lot of code, I would advocate for a different one. You may disagree, but my experience has a lot of memories of debugging time, sometimes not that fun.
Getting work done from the command-line is possible also thanks to TUI applications. Some examples of TUIs are installation and bootstrapping wizards, wifi-menu, or more complex applications like terminal editors, e.g. vim and emacs.
I highly recommend learning to use a TUI editor. There are more simple alternatives like nano which is in most Linux distributions. Even if you don't use it as your main editor, it is convenient to edit text from the terminal when working on a remote machine.
Nowadays you can create your own in a short time. Some frameworks and libraries go from the historical ncurses (replacement for curses) to more modern like ink.
C is the classic programming language for writing CLI and TUI tools because it is fast, simple, and flexible. But it needs special care for memory handling to prevent leaks. There are other alternatives, Python can give more coding speed with clear syntax and with a great ecosystem. Rust can give speeds comparable to C with a more powerful compiler. For small and personal utilities the best solution can be writing it directly in Bash.
I hope you found an idea you can integrate into your workflow even if you are a seasoned command-line user. Or if you don't want to use the terminal as much, saving a bit extra time when dealing with commands is already a success. Try to use it more in some of the frequent tasks that you perform through a GUI. After spending the time and using some of these tricks, it is possible that you will start to see the fun and profitable benefits of those wordy scripts.