Post

Linux CLI Notes

A growing reference of Linux CLI commands, concepts, and patterns picked up over time

Linux CLI Notes

Append and Overwrite Files

In Linux, the difference between overwriting and appending is just one extra character. > replaces the file entirely, while >> adds to the bottom of it.

CommandActionResult
echo "text" > fileOverwriteDeletes old content, writes “text”
echo "text" >> fileAppendKeeps old content, adds “text” at the bottom
tee -a fileAppend with sudoSafest way to append to system files like /etc/hosts

Using >>:

1
echo "10.10.10.0 lookup.thm" >> /etc/hosts

Using tee -a (the permission-safe way):

Editing /etc/hosts directly will give a “Permission denied” error for non-root users. Even sudo echo ... >> /etc/hosts fails because the redirect >> is handled by your shell, not by sudo. The correct approach is to pipe through tee with the -a flag:

1
echo "10.10.10.0 lookup.thm" | sudo tee -a /etc/hosts

Namespaces and cgroups

Namespaces isolate a process so it only sees its own version of system resources — its own process list, network stack, filesystem root, and so on. Normally all processes share the same global view of the system. Namespaces carve out a private “bubble” for a process or group of processes. This is the core technology that makes containers (like Docker) possible.

cgroups (control groups) limit how much of a resource a process is allowed to use — CPU time, RAM, disk I/O, network bandwidth.

The key distinction:

  • Namespaces → control what a process can see
  • cgroups → control what a process can consume

Together they are the foundation of Linux containers.

Namespace Types

NamespaceIsolates
PIDProcess IDs — processes only see their own PID tree
NetworkNetwork interfaces, IPs, routing tables, ports
MountFilesystem mount points
UTSHostname and domain name
IPCShared memory and semaphores
UserUID/GID mappings
Cgroupcgroup root directory visibility
TimeSystem clocks

Moving Around

1
2
3
4
5
6
7
8
9
pwd                        # print current directory
cd /etc                    # go to absolute path
cd ..                      # go up one level
cd ~                       # go to home directory
cd -                       # go back to previous directory
ls                         # list files
ls -la                     # long format, show hidden files
ls -lh                     # human-readable file sizes
ls -lt                     # sort by modification time (newest first)

Creating and Removing

1
2
3
4
5
6
7
8
9
mkdir projects             # create a directory
mkdir -p a/b/c             # create nested directories (no error if exists)
touch file.txt             # create empty file or update timestamp
cp file.txt backup.txt     # copy a file
cp -r dir/ dir_copy/       # copy a directory recursively
mv old.txt new.txt         # rename or move a file
rm file.txt                # delete a file
rm -r dir/                 # delete directory recursively
rm -rf dir/                # force delete without prompts (be careful)

Finding Files

1
2
3
4
5
6
7
find / -name "passwd"               # find by name
find /home -type f -name "*.log"    # files only, by pattern
find /var -size +100M               # files larger than 100MB
find . -mtime -1                    # modified in the last 24 hours
find . -perm 777                    # files with exact permissions
find / -user root -type f           # files owned by root
find . -name "*.conf" -exec cat {} \;   # find and run a command on results

Viewing Files

1
2
3
4
5
6
7
8
9
10
cat file.txt               # print entire file
cat -n file.txt            # print with line numbers
less file.txt              # scroll through file (q to quit)
head file.txt              # first 10 lines
head -n 20 file.txt        # first 20 lines
tail file.txt              # last 10 lines
tail -f file.txt           # follow (live updates — great for logs)
tail -n 50 file.txt        # last 50 lines
wc -l file.txt             # count lines
wc -w file.txt             # count words

File Permissions

Every file in Linux has three permission sets: owner, group, and others. Each set has three bits: read (r=4), write (w=2), execute (x=1).

1
2
3
4
-rwxr-xr--
 ^^^         owner:  rwx = 7
    ^^^      group:  r-x = 5
       ^^^   others: r-- = 4

chmod — change permissions

1
2
3
4
5
6
chmod 755 script.sh          # rwxr-xr-x (owner full, group/others read+execute)
chmod 644 file.txt           # rw-r--r-- (owner read+write, others read only)
chmod +x script.sh           # add execute for everyone
chmod -w file.txt            # remove write from everyone
chmod u+x,g-w file.txt       # add execute for owner, remove write from group
chmod -R 755 /var/www/html   # apply recursively

chown — change owner

1
2
3
chown user file.txt           # change owner
chown user:group file.txt     # change owner and group
chown -R user:group /data/    # change recursively

Special permissions

1
2
3
chmod u+s /usr/bin/prog     # setuid — runs as file owner, not caller
chmod g+s /shared/          # setgid — new files inherit the directory's group
chmod +t /tmp/              # sticky bit — only owner can delete their files

umask — default permissions

umask subtracts from the maximum permission (666 for files, 777 for directories). A umask of 022 means new files are 644 and new directories are 755.

1
2
umask            # show current umask
umask 027        # set new umask (files=640, dirs=750)

Text Processing

grep — search inside files

1
2
3
4
5
6
7
8
9
grep "error" logfile.txt             # search for pattern
grep -i "error" logfile.txt          # case-insensitive
grep -r "TODO" ./src/                # recursive search
grep -n "error" logfile.txt          # show line numbers
grep -v "debug" logfile.txt          # invert — lines that do NOT match
grep -c "error" logfile.txt          # count matching lines
grep -l "TODO" *.py                  # show only filenames that match
grep -E "error|warn|fail" log.txt    # extended regex (OR)
grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" file   # extract IPs

cut — extract columns

1
2
3
cut -d: -f1 /etc/passwd             # extract field 1, delimiter ":"
cut -d, -f2,4 data.csv              # fields 2 and 4 from CSV
cut -c1-10 file.txt                 # first 10 characters of each line

sort and uniq

1
2
3
4
5
6
7
sort file.txt                       # alphabetical sort
sort -n numbers.txt                 # numeric sort
sort -r file.txt                    # reverse sort
sort -k2 file.txt                   # sort by second column
sort file.txt | uniq                # remove duplicate lines
sort file.txt | uniq -c             # count occurrences of each line
sort file.txt | uniq -d             # show only duplicate lines

sed — stream editor

1
2
3
4
5
6
sed 's/old/new/' file.txt           # replace first match per line
sed 's/old/new/g' file.txt          # replace all matches per line
sed -i 's/old/new/g' file.txt       # in-place edit
sed '/pattern/d' file.txt           # delete matching lines
sed -n '10,20p' file.txt            # print lines 10 to 20
sed '5a\new line' file.txt          # append text after line 5

awk — column processing

1
2
3
4
5
6
awk '{print $1}' file.txt           # print first column
awk -F: '{print $1, $3}' /etc/passwd    # custom delimiter, print cols 1 and 3
awk '{sum += $1} END {print sum}' file  # sum a column
awk 'NR > 1' file.txt               # skip first line (header)
awk '$3 > 100' data.txt             # filter rows where column 3 > 100
awk '{print NR, $0}' file.txt       # print line numbers

Pipelines — chaining commands

The pipe | passes the output of one command as input to the next. You can chain as many commands as you need.

1
2
3
4
cat /etc/passwd | cut -d: -f1 | sort             # sorted list of usernames
ps aux | grep nginx | grep -v grep               # find nginx processes
cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10   # top IPs
ls -la | grep "^d"                               # list only directories

Process Management

Viewing processes

1
2
3
4
5
6
7
ps aux                              # all processes, BSD style
ps -ef                              # all processes, POSIX style
ps aux | grep nginx                 # find a process by name
pgrep nginx                         # get PID by name
pstree                              # visual process tree
top                                 # live process monitor (q to quit)
htop                                # better top (if installed)

Signals and killing

1
2
3
4
5
kill 1234                           # send SIGTERM (graceful stop) to PID
kill -9 1234                        # SIGKILL (force kill — no cleanup)
kill -HUP 1234                      # SIGHUP — reload config
killall nginx                       # kill all processes named nginx
pkill -f "python app.py"            # kill by matching command line
SignalNumberMeaning
SIGTERM15Polite stop — default kill
SIGKILL9Force kill — cannot be caught
SIGHUP1Hangup — reload config
SIGINT2Interrupt — same as Ctrl+C
SIGSTOP19Pause — cannot be caught
SIGCONT18Resume a paused process

Background jobs

1
2
3
4
5
6
command &                           # run in background immediately
Ctrl+Z                              # suspend current foreground process
bg                                  # resume suspended process in background
fg                                  # bring background process to foreground
jobs                                # list all background jobs
nohup command &                     # run in background, survive logout

Disk and Storage

1
2
3
4
5
6
7
8
9
10
df -h                               # filesystem disk usage, human-readable
df -hT                              # include filesystem type
du -sh /var/log                     # total size of a directory
du -sh *                            # size of each item in current dir
du -h --max-depth=1 /               # one level deep from root
lsblk                               # list block devices (disks and partitions)
fdisk -l                            # list partition tables (root only)
mount                               # show all mounted filesystems
mount /dev/sdb1 /mnt/data           # mount a device
umount /mnt/data                    # unmount

Networking

Interface and routing

1
2
3
4
5
ip addr                             # show all interfaces and IP addresses
ip addr show eth0                   # show specific interface
ip link set eth0 up                 # bring interface up
ip route                            # show routing table
ip route show default               # show default gateway

Connectivity and diagnostics

1
2
3
4
5
6
7
ping -c 4 8.8.8.8                   # send 4 ICMP packets
traceroute google.com               # trace route to host
mtr google.com                      # live traceroute
nslookup example.com                # DNS query
dig example.com                     # detailed DNS query
dig +short example.com              # just the IP
host example.com                    # quick DNS lookup

Ports and connections

1
2
3
4
5
ss -tlnp                            # listening TCP ports with PID
ss -tunap                           # all TCP/UDP connections
netstat -tlnp                       # same (older command)
lsof -i :80                         # what process is using port 80
lsof -i TCP                         # all open TCP connections

curl and wget

1
2
3
4
5
6
7
8
curl https://example.com                         # fetch a URL
curl -o file.html https://example.com            # save to file
curl -I https://example.com                      # headers only
curl -X POST -d '{"key":"val"}' -H "Content-Type: application/json" URL
curl -u user:pass https://api.example.com        # basic auth
curl -L https://example.com                      # follow redirects
wget https://example.com/file.zip                # download file
wget -r -np https://example.com/files/           # recursive download

SSH

SSH is the standard way to connect to remote Linux machines securely.

1
2
3
4
5
6
7
ssh user@host                       # connect to remote host
ssh -p 2222 user@host               # non-standard port
ssh -i ~/.ssh/id_rsa user@host      # use a specific key
ssh -L 8080:localhost:80 user@host  # local port forwarding
ssh -R 9090:localhost:22 user@host  # remote port forwarding
ssh -D 1080 user@host               # SOCKS proxy (dynamic forwarding)
ssh -J jumphost user@target         # connect via a jump host

Key management

1
2
3
4
ssh-keygen -t ed25519 -C "email@example.com"    # generate a key pair
ssh-copy-id user@host                            # copy public key to remote
ssh-add ~/.ssh/id_ed25519                        # add key to SSH agent
eval $(ssh-agent)                                # start SSH agent

SCP and rsync

1
2
3
4
5
6
7
scp file.txt user@host:/remote/path/            # copy file to remote
scp user@host:/remote/file.txt ./               # copy file from remote
scp -r dir/ user@host:/remote/                  # copy directory

rsync -av ./local/ user@host:/remote/           # sync local to remote
rsync -av --delete ./local/ user@host:/remote/  # mirror (delete missing)
rsync -avz -e ssh ./local/ user@host:/remote/   # compressed over SSH

User Management

1
2
3
4
5
6
7
8
9
whoami                              # current username
id                                  # UID, GID, and groups
groups username                     # groups a user belongs to
who                                 # logged-in users
w                                   # logged-in users + what they're running
last                                # login history
su - username                       # switch user (full login shell)
sudo command                        # run command as root
sudo -i                             # open root shell

Managing users and groups

1
2
3
4
5
6
7
useradd -m -s /bin/bash username    # create user with home dir and bash
passwd username                     # set password
usermod -aG sudo username           # add user to sudo group (keep -a!)
usermod -s /bin/zsh username        # change shell
userdel -r username                 # delete user and home directory
groupadd devteam                    # create group
groupdel devteam                    # delete group

Package Management

Debian / Ubuntu (apt)

1
2
3
4
5
6
7
8
9
10
apt update                          # refresh package index
apt upgrade                         # upgrade installed packages
apt install nginx                   # install a package
apt remove nginx                    # remove package (keep config)
apt purge nginx                     # remove package and config
apt autoremove                      # remove unused dependencies
apt search keyword                  # search for packages
apt show nginx                      # package info
dpkg -l                             # list all installed packages
dpkg -i package.deb                 # install a local .deb file

RHEL / CentOS / Fedora (dnf/yum)

1
2
3
4
5
6
7
dnf update                          # update all packages
dnf install nginx                   # install
dnf remove nginx                    # remove
dnf search keyword                  # search
dnf info nginx                      # package info
rpm -qa                             # list all installed packages
rpm -ivh package.rpm                # install a local .rpm file

Archives and Compression

tar

1
2
3
4
5
tar -czvf archive.tar.gz dir/       # create compressed archive
tar -xzvf archive.tar.gz            # extract compressed archive
tar -xzvf archive.tar.gz -C /dest/  # extract to a specific directory
tar -tzvf archive.tar.gz            # list contents without extracting
tar -cjvf archive.tar.bz2 dir/      # create bzip2 compressed archive

gzip and zip

1
2
3
4
5
6
7
8
gzip file.txt                       # compress (creates file.txt.gz, removes original)
gzip -d file.txt.gz                 # decompress
gzip -k file.txt                    # compress but keep original
zcat file.txt.gz                    # view compressed file without extracting

zip -r archive.zip dir/             # zip a directory
unzip archive.zip                   # extract
unzip -l archive.zip                # list contents

System Information

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
uname -a                            # kernel version, hostname, architecture
uname -r                            # kernel version only
hostname                            # machine hostname
hostname -I                         # all IP addresses
uptime                              # uptime and load averages
free -h                             # RAM usage
lscpu                               # CPU information
lsblk                               # disk layout
lspci                               # PCI devices (GPU, NIC, etc.)
lsusb                               # USB devices
dmesg | tail -20                    # recent kernel messages
dmesg -T | grep -i error            # kernel errors with timestamps
journalctl -b                       # all logs from current boot
journalctl -u nginx                 # logs for a specific service
journalctl --since "1 hour ago"     # recent logs

Environment and Shell

Variables

1
2
3
4
5
6
7
echo $PATH                          # print PATH variable
echo $HOME                          # print home directory
MY_VAR="hello"                      # set local variable
export MY_VAR="hello"               # export to child processes
env                                 # show all environment variables
unset MY_VAR                        # remove a variable
printenv PATH                       # print a specific env var

PATH management

1
2
3
4
5
export PATH="$HOME/.local/bin:$PATH"    # prepend to PATH
export PATH="$PATH:/opt/tool/bin"       # append to PATH
which python3                           # find where a command lives
whereis nginx                           # find binary, source, and man page
type ls                                 # show how a command is resolved

Aliases

1
2
3
4
alias ll='ls -la'                   # create alias
alias gs='git status'               # git shortcut
unalias ll                          # remove alias
alias                               # list all aliases

Put permanent aliases in ~/.bashrc or ~/.zshrc and run source ~/.bashrc to reload.

History

1
2
3
4
5
6
history                             # show command history
history | grep ssh                  # search history
!!                                  # repeat last command
!ssh                                # repeat last command starting with "ssh"
Ctrl+R                              # interactive reverse history search
history -c                          # clear history

Redirection

1
2
3
4
5
6
7
8
9
10
command > file.txt                  # redirect stdout to file (overwrite)
command >> file.txt                 # redirect stdout to file (append)
command < file.txt                  # read stdin from file
command 2> error.txt                # redirect stderr to file
command 2>&1                        # redirect stderr to stdout
command &> file.txt                 # redirect both stdout and stderr
command > /dev/null                 # discard stdout
command > /dev/null 2>&1            # discard all output
command | tee file.txt              # write to file AND show on screen
command | tee -a file.txt           # append to file AND show on screen

Scheduling with cron

1
2
3
crontab -e                          # edit cron jobs for current user
crontab -l                          # list cron jobs
crontab -r                          # remove all cron jobs

Crontab format:

1
2
MIN  HOUR  DOM  MON  DOW  COMMAND
 *    *     *    *    *   /path/to/script.sh

Examples:

1
2
3
4
0 2 * * *    /backup.sh            # daily at 2 AM
*/15 * * * * /check.sh             # every 15 minutes
0 9 * * MON  /report.sh            # every Monday at 9 AM
@reboot      /startup.sh           # once at boot

Useful One-Liners

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Find and kill a process by port
kill $(lsof -t -i:8080)

# Show top 10 largest files in current directory
du -ah . | sort -rh | head -10

# Watch disk usage in real time
watch -n 5 df -h

# Count lines in all Python files
find . -name "*.py" | xargs wc -l | tail -1

# Replace text in all files in a directory
grep -rl "old_text" . | xargs sed -i 's/old_text/new_text/g'

# Extract all IP addresses from a file
grep -oE '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' file.txt

# Show all open ports
ss -tlnp

# Test if a port is open
nc -zv host 443

# Generate a random password
openssl rand -base64 16

# Check certificate expiry
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

# Monitor a log file and highlight errors
tail -f /var/log/syslog | grep --line-buffered -i "error\|warn\|fail"

You can find me online at:

My signature image

This post is licensed under CC BY 4.0 by the author.