What’s the shell?

  • Multiple interfaces exist: GUIs, voice interfaces, AR/VR.
  • Graphical interfaces are limited.
  • For full control, use a textual interface: The Shell.
  • Platforms offer a variety of shells.
  • Introduction to “bash” (Bourne Again SHell).

Accessing the Shell

  • To start: you need a terminal.
  • A shell prompt is where you type commands.
# missing:$ ··································· bash

Using the shell

  • Typing a command at the prompt will execute it.
  • Arguments can be passed to commands.
# missing:$ ··································· bash

More Shell Commands

  • Commands are parsed by whitespace.
  • $PATH helps find executable programs.
# missing:$ ··································· bash
echo hello
# we expect hello

  • Understanding paths.
  • pwd shows the current directory.
  • cd changes directories.
  • Use ls to list contents.

Shell Permissions

# missing:$ ··································· bash
ls -l ~
  • Using mv, cp, mkdir.
  • The man command for manuals.

Connecting programs

  • Programs have input and output streams.
  • Redirection with < file and > file.
  • Using pipes | to chain commands.

More about Programs and Pipes

# missing:$ ··································· bash
ls -l / | tail -n1
  • Use of curl, grep, and cut.

A versatile and powerful tool

  • Understanding the “root” user.
  • The use of sudo for superuser actions.
  • Kernel parameters in sysfs.

Working with sysfs

  • Adjusting laptop screen brightness.
  • Permission issues.
  • Using tee to overcome permissions.

A small break…

Job Control

Interrupting a Job

  • Need to stop lengthy commands, like a find command in large directories.
  • Common way: Ctrl-C.
  • How and why does this work?

Killing a process

  • Shell communicates via signals.
  • Signals act as software interrupts.
  • Ctrl-C sends a SIGINT signal to the process.

A Python script that captures SIGINT and ignores it.

#!/usr/bin/env python
import signal, time
def handler(signum, time):
    print("\nI got a SIGINT, but I am not stopping")
signal.signal(signal.SIGINT, handler)
i = 0
while True:
    print("\r{}".format(i), end="")
    i += 1

  • Sending SIGINT to above program will not stop it.
  • SIGQUIT (by typing Ctrl-\) can be used instead.
$ python sigint.py
I got a SIGINT, but I am not stopping
I got a SIGINT, but I am not stopping
30^\[1]    39913 quit       python sigint.py

Additional Signals

  • SIGINT and SIGQUIT: Terminal related.
  • SIGTERM: Generic signal for graceful exit.
  • Use kill -TERM <PID> to send SIGTERM.

Pausing and Backgrounding Processes

  • SIGSTOP pauses a process.
  • Ctrl-Z sends SIGTSTP, a terminal version of SIGSTOP.
  • Continue with fg (foreground) or bg (background).
  • Check jobs with jobs command.

Example Session

$ sleep 1000
[1]  + 18653 suspended  sleep 1000
$ nohup sleep 2000 &
$ jobs
$ kill -STOP %1
$ kill -SIGHUP %1

Signals to Remember

Terminal Multiplexers


  • Want multiple terminal sessions? Use terminal multiplexers.
  • Examples: tmux and screen.
  • Run side-by-side sessions, detach and reattach later.

Using tmux

  • Keybindings form: <C-b> x.
  • Sessions, Windows, and Panes.
  • Detailed commands and hierarchy explained.



  • Shortcuts for long commands or common flags.
  • Structure: alias alias_name="command_to_alias arg1 arg2"

Alias Examples

alias ll="ls -lh"
alias gs="git status"
alias v="vim"
alias sl=ls
alias mv="mv -i"

Aliases Persistence

  • Aliases do not persist by default.
  • Add to startup files like .bashrc or .zshrc.



  • Plain-text configuration files.
  • Examples: .vimrc, .bashrc.
  • Shell, git, vim, ssh, and tmux are configured using dotfiles.

Organizing Dotfiles

  • Keep in a separate folder.
  • Use version control.
  • Symlink them using a script.

Benefits of Organizing Dotfiles

  • Easy installation on new machines.
  • Portability across systems.
  • Synchronization between machines.

Further Reading

  • Detailed resources for shell startup scripts, tmux, and screen.
  • Explore and customize your toolset!


A common pain with dotfiles is the configurations might not work across machines. Especially if they have different operating systems or shells.

Sometimes configurations should only apply to a specific machine. There are tricks to make this easier:

  1. Use if-statements for machine-specific customizations.
  2. Use includes for machine-specific settings.
  3. Share configurations across programs.

if [[ "$(uname)" == "Linux" ]]; then {do_something}; fi
if [[ "$SHELL" == "zsh" ]]; then {do_something}; fi
if [[ "$(hostname)" == "myServer" ]]; then {do_something}; fi

In a ~/.gitconfig:

    path = ~/.gitconfig_local

And ~/.gitconfig_local can have machine-specific settings.

For sharing configurations, such as aliases:

if [ -f ~/.aliases ]; then
    source ~/.aliases

Shells & Frameworks

While bash is popular, there are alternatives like zsh with enhanced features:

  • Smarter globbing
  • Spelling correction
  • Better tab completion

Frameworks improve shells:

Terminal Emulators

Choosing a terminal emulator is vital. Consider:

  • Font
  • Color Scheme
  • Shortcuts
  • Tabs/Panes
  • Scrollback

🆕 Warp. For Windows users: the new Terminal