What Is a Shell?

The shell is your command-line interpreter. Bash (Bourne Again Shell) is the default on most Linux distros. It parses input, expands variables, runs external programs, and supports full scripting.

  echo $SHELL          # /bin/bash
echo $0              # bash (interactive session)
bash --version

# Alternative shells
cat /etc/shells
chsh -l              # list available
  

Prompt and Navigation

  cd /var/log
pwd                  # print working directory

cd -                 # previous directory (directory stack)
pushd /tmp && popd   # explicit stack

# Customize prompt (temporary)
export PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
  

Persist prompt changes in ~/.bashrc. Login shells may read ~/.bash_profile or ~/.profile first.

History and Completion

  history              # list past commands
history | grep apt   # search history file

!!                   # repeat last command
!grep                # last command starting with grep
!123                 # command number 123 from history

# Interactive search: Ctrl+R (reverse), Ctrl+S (forward)
# Accept match: Enter or Right arrow
  

Tab completion uses bash-completion package for flags and service names:

  systemctl sta<Tab>   # start, status, stop, ...
apt install ngi<Tab>
  

Enable programmable completion in ~/.bashrc:

  if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi
  

Pipes and Redirection

Operator Meaning
| Pipe stdout to stdin of next command
> Redirect stdout (overwrite)
>> Redirect stdout (append)
2> Redirect stderr
&> Redirect stdout and stderr
< Redirect stdin from file
2>&1 Merge stderr into stdout
  # Count error lines in nginx log
grep "error" /var/log/nginx/error.log | wc -l

# Save stdout and stderr separately
make > build.log 2> build-errors.log

# Append both streams
./deploy.sh &>> deploy.log

# Pipe stderr too
cmd 2>&1 | grep -i error
  

Order matters: cmd > file 2>&1 captures both streams; cmd 2>&1 > file only redirects stdout to file.

Environment Variables

  export EDITOR=vim
export PATH="$HOME/bin:$PATH"
export LANG=en_US.UTF-8

# View all exported
env | sort
printenv HOME

# Persist
echo 'export EDITOR=vim' >> ~/.bashrc
source ~/.bashrc
  

Common variables: HOME, USER, PATH, LANG, PS1, HISTSIZE, HISTFILESIZE.

  # Extend PATH safely (prepend user bin)
export PATH="$HOME/.local/bin:$PATH"
  

Quoting and Escaping

  echo "Hello $USER"     # variable expanded
echo 'Hello $USER'     # literal $USER
echo $'line1\nline2'   # ANSI-C quoting: escape sequences

# Command substitution
today=$(date +%Y-%m-%d)
files=$(ls *.md 2>/dev/null)
count=$(wc -l < access.log)

# Nested substitution
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
  

Always quote variables in scripts: "$var" prevents word splitting on spaces.

Job Control

  sleep 100 &
jobs                   # list background jobs
fg %1                  # bring job 1 to foreground
bg %1                  # resume stopped job in background
kill %1                # terminate job 1
wait                   # wait for all background jobs
  

Useful Shortcuts

Shortcut Action
Ctrl+C Interrupt current command (SIGINT)
Ctrl+Z Suspend current command
Ctrl+D End of input / logout
Ctrl+L Clear screen
Ctrl+A / Ctrl+E Beginning / end of line
Alt+. Insert last argument of previous command
Ctrl+R Reverse history search

Best Practices

Practice Reason
Quote variables in scripts Prevents word splitting and glob expansion
Use $(cmd) not backticks Readable nesting, no escape hell
Set HISTTIMEFORMAT Audit when commands ran
Avoid spaces in paths Or always quote paths
  export HISTTIMEFORMAT='%F %T '
export HISTCONTROL=ignoredups:erasedups
  

Common Mistakes

Mistake Consequence
Unquoted $var with spaces Breaks filenames, deletes wrong files
Piping to sh without review Executes untrusted remote scripts
source vs ./script confusion source runs in current shell; ./ in subshell
Forgetting export Child processes don’t see variable

Troubleshooting

Tab completion broken: Install bash-completion package and source it in ~/.bashrc.

History not saving: Check HISTFILE permissions and shopt histappend for concurrent sessions.

Wrong shell after login: Verify chsh -s /bin/bash and /etc/passwd shell field.

Production Scenario

An SRE debugs a failing deploy script over SSH:

  # Run with trace to see every command
bash -x ./deploy.sh 2>&1 | tee deploy-trace.log

# Check what the script inherited
env | grep -E '^(PATH|HOME|USER)='
  

Tracing reveals an unquoted $APP_DIR that breaks when the path contains spaces — fixed with "$APP_DIR" before the next production run.

Bash is the glue between you and every Linux tool — invest time in pipes, history, quoting, and job control before writing automation scripts.