Shell basics.

pwd                    # current dir
cd /etc                # absolute
cd ../parent           # relative
cd                     # home
cd -                   # previous
ls -la
ls -lah                # human sizes
ls -lat                # by time
ls -lhS                # by size

Files

cp source dest
cp -r dir1 dir2        # recursive
cp -a dir1 dir2        # archive (preserves perms, links, time)
mv old new
rm file
rm -rf dir             # CAREFUL
ln -s target link      # symlink
ln target hardlink     # hard link
touch file             # create / update timestamp
mkdir -p a/b/c         # create with parents
rmdir empty_dir        # only if empty

Reading

cat file
less file              # paged; q to quit, /search, n next
head -n 20 file
tail -n 20 file
tail -f file           # follow
wc -l file             # lines
file foo               # type
stat foo

Redirects

cmd > file             # stdout to file (overwrite)
cmd >> file            # append
cmd 2> err             # stderr
cmd > out 2>&1         # both
cmd &> all             # both (bash shortcut)
cmd < input            # stdin from file
cmd <<< "str"          # here string
cmd <<EOF              # here doc
line1
line2
EOF

Pipes

cmd1 | cmd2            # stdout to stdin
cmd1 |& cmd2           # both (stdout + stderr)
ls | grep foo
ps aux | grep nginx | grep -v grep

tee

cmd | tee file         # print + save
cmd | tee -a file      # append
cmd | tee >(grep err)  # process substitution

Background / jobs

cmd &                  # background
jobs                   # list
fg %1                  # foreground job 1
bg %1
kill %1
disown %1              # detach from shell
nohup cmd &            # survive shell exit

history

history
!42                    # run command 42
!!                     # run last
!ssh                   # last starting with ssh
^old^new               # quick fix
ctrl-r                 # reverse search

Quoting

echo 'literal $foo'    # no expansion
echo "expand $foo"     # variable expansion
echo `cmd`             # command substitution (old)
echo $(cmd)            # command substitution (preferred)

Variables

NAME=value             # no spaces around =
export NAME=value      # exported to subprocesses
echo $NAME
echo ${NAME}_suffix
echo ${NAME:-default}  # default if unset
echo ${NAME:?error msg} # error if unset
unset NAME

Globs

ls *.txt
ls a?.txt              # ? = one char
ls a[1-3].txt
ls **/*.txt            # recursive (shopt -s globstar)

Brace expansion

echo {1..10}                # 1 2 3 ... 10
echo {a,b,c}.txt            # a.txt b.txt c.txt
mkdir -p /var/{log,run,tmp}
cp file{,.bak}              # cp file file.bak

Loops

for f in *.txt; do
    echo $f
done

while read line; do
    echo $line
done < file

until [ -f /done ]; do
    sleep 1
done

Conditionals

if [ -f file ]; then echo exists; fi
if [[ $x -gt 10 ]]; then echo big; fi

[ -f file ]        # file exists
[ -d dir ]         # directory
[ -e path ]        # exists
[ -r file ]        # readable
[ -w file ]        # writable
[ -x file ]        # executable
[ -s file ]        # non-empty
[ -z "$str" ]      # empty
[ -n "$str" ]      # non-empty
[ "$a" = "$b" ]
[ "$a" != "$b" ]
[ "$a" -eq "$b" ]  # numeric ==
[ "$a" -lt "$b" ]

case

case "$x" in
    a|A) echo letter A;;
    [0-9]) echo digit;;
    *) echo other;;
esac

Functions

greet() {
    echo "Hi $1"
    return 0
}

greet "World"

Aliases

alias ll='ls -lah'
alias gst='git status'

In ~/.bashrc / ~/.zshrc.

set -e / set -u / set -o pipefail

#!/bin/bash
set -euo pipefail
  • -e: exit on error.
  • -u: error on undefined var.
  • -o pipefail: pipe fails if any stage fails.

Recommended for scripts.

Exit codes

cmd; echo $?     # 0 = success
true; echo $?    # 0
false; echo $?   # 1

ssh / scp

ssh user@host
ssh -i ~/.ssh/key user@host
ssh -p 2222 user@host
ssh user@host 'command'
scp file user@host:/path/
scp -r dir user@host:/path/

tar / zip

tar czf out.tar.gz dir/
tar xzf out.tar.gz
tar tzf out.tar.gz       # list

tar cJf out.tar.xz dir/  # xz (better compression)
tar cf - dir | gzip > out.tar.gz   # streamed

zip -r out.zip dir/
unzip out.zip

Common mistakes

  • rm -rf $VAR/ with empty $VAR → wipes root.
  • Missing quotes around $var → splits on whitespace.
  • [ -e "$x" ] vs [[ -e $x ]][[]] is bash-only but safer.
  • Using $1, $2 outside script — those are positional args.
  • Spaces around = in assignment → syntax error.

Read this next

If you want my shell setup (zsh, starship, fzf), it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .