Shell knowledge to get you through the day
Tags: beginners, tutorial, bash, shell
Published: 2021-03-29 17:58:14

Following on from the [Docker knowledge to get you through the day](https://benmatselby.dev/post/docker-101/), and [Git commands to get you through the day](https://benmatselby.dev/post/git-101/) posts, this will cover Shell commands. Once again, it aims to get you through the day.

First of all, it's worth noting that there are many shells: bash, sh, zsh etc. For a comprehensive list of shells, and their comparison, head over to [Wikipedia](https://en.wikipedia.org/wiki/Comparison_of_command_shells).

## Basic commands

Let's cover off some basics that will hopefully get you on your way.

---

`man` is the manual application. Use this to find information about all the other commands, and options. e.g. `man ls` will give you the manual page for the `ls` command.

For extra points, you can define an environment variable that changes how you view the manual. e.g.

```shell
MANPAGER=cat man ls
```

This will output the entire manual to the screen, without any interaction. My `MANPAGER` is set to `less -X`. With your new knowledge of the `man` command, find out what `-X` means for `less`.

---

`ls` lists files in a given directory. `ls -lGh` is a favourite of mine which lists all the files in the current directory, enables colourised output, and provides human readable file sizes! There are many options to `ls`, so I recommend you read the output from `man ls` and find what output suits your needs.

Whilst we are talking about listing files, I always like to remind folks about `git ls-files` which lists all the files in a git repo. Sorry to slip in a `git` command there.

---

`df` and `du` are two disk related commands that I use quite often.

`df` displays information about free disk space. I recommend running it with `df -h` so the output is a little more human readable.

`du` comes in really handy when you want summary information about folder/file sizes. The `-d` flag allows you to define the depth of the summary. For example to find the total size of your `node_modules` folder:

```shell
❯ du -d 0 -h node_modules
198M  node_modules
```

If you want to know the size of all the packages, individually, in `node_modules`, then you can run

```shell
❯ du -d 1 -h node_modules
 16K  node_modules/write
 12K  node_modules/callsites
 16K  node_modules/is-extendable
 ...
```

---

`vim`, `less`, `tail`, and `cat` allow you to view file content. Each of these commands take a file as a parameter. `vim` is too big to cover here, so try running `vimtutor` to see if that helps you learn vim.

`tail` is handy when coupled with the `-f` flag, to "follow" the output of a file, e.g. a log file `tail -f /path/to/file`.

`cat` simply outputs all the content to the terminal, with no paging.

`less` allows you to page through content with `ctrl+f` and `crtl+b`.

---

The following commands help with process management: `ps`, `kill`, `pgrep`, `top` or `htop`.

`ps aux` will output all the processes, for any user, running on the machine. You can drop the `x` if you want to get processes running for any user with a controlling terminal, i.e. you ran the command from a terminal. Another way to get process information is `pgrep` which takes a command parameter. For example we can run `pgrep -l vim` which will output the process IDs (PID) of all running `vim` commands.

The output from `ps` and `pgrep` then can be used to stop a proces. For example `kill [pid]` will kill the process with the same `[pid]`.

`top`, and the more functional sister command `htop`, will show you statistical information about running commands. This covers memory, CPU, how long it's been running etc.

---

Understanding where things are installed is really handy, and there are a few commands that can help.

`which` will explain where the command you pass in as a parameter is being run. So `which go` will show you the version of go being used when you run `go`.

`where` will show you all the versions of the command you pass in. So I have two versions of bash right now.

```shell
❯ where bash
/opt/homebrew/bin/bash
/bin/bash

❯ which bash
/opt/homebrew/bin/bash
```

So I have two versions of `bash`, but the one I would use is the `homebrew` version, as shown by the output of `which`.

`type` helps explain what kind of "thing" the command is. Some examples are shown below.

```shell
❯ type bash
bash is /opt/homebrew/bin/bash

❯ type envg
envg is an alias for env | grep -i

❯ type dhagen
dhagen is a shell function from /Users/ben/.oh-my-zsh/custom/docker.zsh
```

The order of precedence for determining which commands to run, is defined by the `$PATH` environment variable. Run `echo $PATH` to understand the ordering, with the first path taking priority.

---

`sed` is really useful for automating changes to files/content.

```shell
date | sed "s| |-|g"
Sun-28-Mar-2021-21:22:58-BST
```

This takes the output of `date` (an arbitrary example) and replaces spaces for hyphens.

---

Remember the time when you ran that command, but cannot quite remember it? Well `history` has your back. By running this command, it will output all the commands you have ran previously.

Two tips:

- Add a space before running a command, and it won't be stored in your history file. Handy if you are entering a password, for example.
- `ctrl+r` will reverse look up your history.

---

Some little tidbits I find useful:

- `echo $?` will get you the exit code of the last command executed.
- `!$` will get the last parameter of the previous command.
- `!!` will get the entire last command, so `sudo !!` runs the previous command as `sudo`.
- `{1..5}` represents numbers 1 to 5. So we can run `for x in {1..5}; do echo $x; done`.

---

## Pipes

Pipes allow you to chain commands together. It allows you to take the output from one command and **pipe** it into the next command.

`env | sort` will sort all your environment variables, so it's easier to find what you're looking for. You could even create this as an [alias](#aliases).

`history | grep [command]` will find a command in your history (commands you have run before).

These are just arbitrary examples, but you can keep chaining commands together, to deliver the output you want.

## Environment variables

Environment variables help you configure your system and applications. You can set them in the following way:

`export MY_ENV_VAR=boo` It's customary to capitalise the name of the environment, but it's not mandatory. To remove an environment variable you can run `unset MY_ENV_VAR`.

You can set environment variables to be loaded when you start your shell/terminal, if you add the `export` statements to something like `~/.bashrc`, `~/.bash_profile`, `~/.zshrc` etc.

## Aliases

Aliases are great. They can be used to provide a shorter command so you are more efficient. A great community project for aliases, is [oh-my-zsh](https://ohmyz.sh).

Just like environment variables, we can set, unset, and store them in a config file.

`alias week='date +%V'` will get you the week number if you run `week`. To get rid of this alias, you can run `unalias week`.

---

I hope this provides some useful knowledge to get you through your day in the terminal.

---

### See also

- [Docker knowledge to get you through the day](https://benmatselby.dev/post/docker-101/)
- [Git commands to get you through the day](https://benmatselby.dev/post/git-101/)
- [101 Bash Commands and Tips for Beginners to Experts](https://dev.to/awwsmm/101-bash-commands-and-tips-for-beginners-to-experts-30je)
- [ohmyzsh](https://github.com/ohmyzsh/ohmyzsh) - "A delightful community-driven (with 1800+ contributors) framework for managing your zsh configuration."
- [fzf](https://github.com/junegunn/fzf) - A command line fuzzy finder. You can hook this into `crtl-r` which I highly recommend.