Logo ka1.io
Cheat Sheet: Linux & Shell Source: Unsplash

Cheat Sheet: Linux & Shell

A quick reference guide for common Linux and shell commands

November 20, 2024
13 min read
Table of Contents

This cheat sheet provides a quick reference guide for common Linux and shell commands. Whether you’re a beginner or an experienced user, these commands will help you navigate the Linux environment more efficiently.

Services

# list systemd units
systemctl list-units --no-pager --type=service
 
# service status
systemctl status ufw.service
systemctl stop sshd
systemctl start sshd
systemctl status sshd
systemctl is-active sshd
systemctl is-failed sshd
systemctl restart sshd
systemctl reload sshd # re-reads the configuration of the service configs
systemctl daemon-reload sshd # re-reads the configuration of the systemd configs of this service
systemctl enable sshd
systemctl disable sshd
 
systemctl is-system-running # running, degraded, maintenance, initializing, starting, stopping
systemctl --failed
 
journalctl # show all journal
journalctl --no-pager # do not use less
journalctl -n 10 # only 10 lines
journalctl -S -1d # last 1 day
journalctl -xe # last few logs
journalctl -u ntp # only ntp unit
journalctl _PID=1234

Text filtering

# sort by filesize
ls -lS /path/to/folder/
 
# cat -n gives line numbers
ls | cat -n
 
# line numbering
nl test.txt
 
# split file in 10 lines
split -l 10 test.txt prefix_
 
# get back original file
cat filename* > originalfile
 
# tail logs
tail -f logs.txt
 
# split text into 1-2,4 parts with delimiter ' '
cut -d ' ' -f 1-2,4 test.txt
 
# shuffle lines
shuf test.txt > shuffled.txt
 
# sort
sort test.txt
 
# unique line filtering and count
sort test.txt | uniq -c
 
# replace chars
cat test.txt | tr 'o' 'O'
 
# count lines
wc -l test.txt
 
# count words in file
cat file.txt | grep -o -i example | wc -l
 
# sed regex
sed -r "s/(Z|R|J)/starts with ZRJ/" friends.txt 
 
# substitute (find and replace) "foo" with "bar" on each line
sed 's/foo/bar/'             # replaces only 1st instance in a line
sed 's/foo/bar/4'            # replaces only 4th instance in a line
sed 's/foo/bar/g'            # replaces ALL instances in a line
sed 's/\(.*\)foo\(.*foo\)/\1bar\2/' # replace the next-to-last case
sed 's/\(.*\)foo/\1bar/'            # replace only the last case
 
# substitute "foo" with "bar" ONLY for lines which contain "baz"
sed '/baz/s/foo/bar/g'

grep

# extended regex grep
grep -E "a|b" words

Disk Layout & Filesystem Hierarchy Standard (FHS)

fdisk /dev/sda
mount

Debugging boot loader (grub2)

cat /boot/efi/EFI/ubuntu/grub.cfg

Debian package management

# pkg sources
cat /etc/apt/sources.list
 
# check the files and directories a package installed
dpkg -L bzr
 
# fix broken pkgs
apt install -f
 
# show pkg info
apt info pkg
 
# search pkg
apt search pkg
 
# rm unneeded pkg deps
apt autoremove
 

Basic Shell Stuff

# what shell is used
readlink /bin/sh # or echo $SHELL
 
# find out stuff about bins
which ls
whatis ls
whereis ls
 
# current location
pwd
 
# info on system
uname -a
 
# add stuff to PATH
PATH=$PATH:~/opt/bin # persist in .profile
 
# run last cmd
!!

Basic Hashing

md5sum test.txt
sha256sum test.txt
sha512sum test.txt

File Management

# copy 3 letter files
cp ???.* /tmp
 
# move files containing _.
mv *[_.]* /tmp
 
# create nested dirs
mkdir -p test/test1/test2
 
# check file type
file test.txt
 
# list only files
ls -p | grep -v /
 
# find case insensitive files starting with a-c
find . f -iname "[a-c]*"
 
# find & exec on all files altered in the last hour
find . -mmin -60 -exec echo {} \;
 
# find & rename
find . -name "*.htm" -exec mv '{}' '{}l' \;

Compression

# zip
gzip test.txt
 
# unzip
gunzip test.txt
 
# tar & compress
tar cvzf file.tar.gz *.txt
 
# tar extract
tar xvzf file.tar.gz

Streams, Redirects, Pipes

Streams: 0 stdin, 1 stdout, 2 stderr

SymbolDescription
>STDOUT to file (overwrite)
>>STDOUT to file (append)
2>STDERR to file (overwrite)
2>>STDERR to file (append)
&>STDOUT & STDERR to file (overwrite)
&>>STDOUT & STDERR to file (append)
<STDIN from file
<>Redirect STDIN from the file and send the STDOUT to it
# example
$ ls
bob jack    jadi    linus   sara who_uses_what.txt
$ ls x*
ls: x*: No such file or directory
$ ls j*
jack    jadi
$ ls j* x* > output 2> errors
$ cat output
jack
jadi
$ cat errors
ls: x*: No such file or directory
 
# &1 and &2 and &0 to refer to the target of STDOUT, STDERR & STDIN
# example: redirect output to file1 and output stderr to same place as stdout (file1)
ls > file1 2>&1
 
# send errs into abyss
ls j* x* > file1 2>/dev/null
 
# pipes
cut -f2 -d, who_uses_what.txt | sed -e 's/ //g' | sort  | uniq -c | sort -nr

xargs & tee

# execute sth on lines
ls -1 | xargs -I HERE echo these HERE are files
 
# tee (2x stdout)
ls | tee file.txt

Managing Processes

# show processes
ps -aux | less
ps -A
ps -e | grep -E 'firefox|chrome'
pstree # tree like process view
 
# info on threads
ps -eLf
 
# lookup process by name
pgrep docker
 
# run binary in background
somebin &
 
# check jobs with process id
jobs -l
 
# bring job back to foreground 
fg %1
 
# run independent of shell
nohup script.sh > mynohup.out 2>&1 &
 
# kill process
kill 8733
kill -15 8733 # default (TERM)
kill -9 8733 # force kill (KILL)
 
# kill by name
pkill docker
 
# kill all ps with given name
killall sleep
 
uptime
# 13:51:49 up 161 days,  4:56,  1 user,  load average: 0.00, 0.05, 0.02

top

key during topfunctionality
hhelp
qquit
Msort based on memory usage
cshow full commands
kkill after asking pid and signal
Psort based on CPU usage

tmux

The default command prefix is Ctrl+B and after running the tmux new you can issue these:

KeyUsage
%Split current window vertically
Split current window horizontally
DDetach from the current window
&Kill current window
cnew window

You can list the tmux sessions using tmux ls and re-attach to one using tmux att to connect to the last one or tmux att -t session_name to attach to a specific one.

Filesystem Checking

# free & used space on file systems
df -h
 
# check used space on specific dirs
du -h .
du -h --max-dept 1 /home/
 
# show block devices
lsblk
 
# check filesystem
fsck /dev/sdb
 
# show auto mounts
cat /etc/fstab
 
# list mounted fs
mount
 
# mount & unmount
sudo mount -t ext4 /dev/sda3 /media/mydisk
sudo umount /dev/sda3
sudo umount /media/mydisk

File Permissions & Ownership

linux file permissions

SymbolicOctal
rwx7
rw-6
r-x5
r—4
-wx3
-w-2
—x1
---0
Generally: 755 for general executable files or 600 for personal files
# user
whoami
 
# groups membership
groups
 
# show user id, group id & groups
id
 
# change file ownership & permissions
chmod u=rxw,g=rw,o= test.txt
chown user:group test.txt

User & Group Management

# change password
passwd
passwd newuser
 
# add user
adduser newuser
 
# delete user
userdel newuser
 
# change groups
chgrp group test.txt
 
# add group
groupadd -g 1200 newgroup
groupdel newgroup
newgrp lxd
 
# add user to sudo group (addGroup)
usermod -aG sudo user
 
# check persisted users & groups
cat /etc/passwd
 
# hashed passwords
cat /etc/shadow
 
# change password
chage -l user
chage user
# symlink (soft)
ln -s file_a file_b
 
# hard link
ln new_file hard_link
 
# find links
find . -type l

Bash Scripting

# one-liner: check if file exists
[ ! -f foo.txt ] && echo "File not found!"
[ ! -f foo.txt ] && echo "File not found" || echo "file found"
 
# or: conditional
if [ ! -f /tmp/foo.txt ]; then
    echo "File not found!"
fi
 
# check for parameter
if [ $# -ne 1 ]
then
	echo "I need 1 parameter"
	exit 1
else
	echo "starting"
	cd /tmp
	touch $($date +'%Y%m%d-%H%m')-$1
	ls -ltrh | tail -3
	echo "done"
	exit 0
fi
 
# check last return code
echo $?

Conditionals

The command to check conditions is the test command but since it is used a lot, we have a shortcut for it. Instead of test condition you can write [ condition ].

conditionswhat is means
”a” = “b”if two strings are equal (here it will return False)
“a” != “b”string a is not equal to string b
4 -lt 40if 4 is lower than 40 (True)
5 -gt 15if 5 is greater than 15 (False)
5 -ge 5if 5 is greater or equal 5
5 -le 3if 5 is lower or equal to 3
9 -ne 29 is not equal with 2 (True)
-f FILENAMEif file FILENAME exists
-s FILENAMEif file exists and its size is more than 0 (Zero)
-x FILENAMEif file exists and is executable

Note that [[ is actually a command/program that returns either 0 (true) or 1 (false). Any program that obeys the same logic (like all base utils, such as grep(1) or ping(1)) can be used as condition, see examples.

conditionswhat is means
[[ -z STRING ]]Empty string
[[ -n STRING ]]Not empty string
[[ STRING == STRING ]]Equal
[[ STRING != STRING ]]Not Equal
[[ NUM -eq NUM ]]Equal
[[ NUM -ne NUM ]]Not equal
[[ NUM -lt NUM ]]Less than
[[ NUM -le NUM ]]Less than or equal
[[ NUM -gt NUM ]]Greater than
[[ NUM -ge NUM ]]Greater than or equal
[[ STRING =~ STRING ]]Regexp
(( NUM < NUM ))Numeric conditions
[[ -o noclobber ]]If OPTIONNAME is enabled
[[ ! EXPR ]]Not
[[ X && Y ]]And
[[ X | Y ]]Or

File conditions:

conditionswhat is means
[[ -e FILE ]]Exists
[[ -r FILE ]]Readable
[[ -h FILE ]]Symlink
[[ -d FILE ]]Directory
[[ -w FILE ]]Writable
[[ -s FILE ]]Size is > 0 bytes
[[ -f FILE ]]File
[[ -x FILE ]]Executable
[[ FILE1 -nt FILE2 ]]1 is more recent than 2
[[ FILE1 -ot FILE2 ]]2 is more recent than 1
[[ FILE1 -ef FILE2 ]]Same files

examples

# String
if [[ -z "$string" ]]; then
  echo "String is empty"
elif [[ -n "$string" ]]; then
  echo "String is not empty"
else
  echo "This never happens"
fi
 
# Combinations
if [[ X && Y ]]; then
  ...
fi
 
# Equal
if [[ "$A" == "$B" ]]
 
# Regex
if [[ "A" =~ . ]]
 
# smaller than
if (( $a < $b )); then
   echo "$a is smaller than $b"
fi
 
# if file exists
if [[ -e "file.txt" ]]; then
  echo "file exists"
fi

Loops

#!/bin/bash
for NUM in {1..5};
do
	echo $NUM
done

while

VAR=52
 
# while greater than
while [ $VAR -gt 42 ]
do
    echo VAR is $VAR and it is still greater than 42
    let VAR=VAR-1 # let for calc on vars
done

Arrays

# Define an array
$ Fruits=('Apple' 'Banana' 'Orange')
 
Fruits[0]="Apple"
Fruits[1]="Banana"
Fruits[2]="Orange"
 
# Working with arrays
echo "${Fruits[0]}"           # Element #0
echo "${Fruits[-1]}"          # Last element
echo "${Fruits[@]}"           # All elements, space-separated
echo "${#Fruits[@]}"          # Number of elements
echo "${#Fruits}"             # String length of the 1st element
echo "${#Fruits[3]}"          # String length of the Nth element
echo "${Fruits[@]:3:2}"       # Range (from position 3, length 2)
echo "${!Fruits[@]}"          # Keys of all elements, space-separated
 
# Operations
Fruits=("${Fruits[@]}" "Watermelon")    # Push
Fruits+=('Watermelon')                  # Also Push
Fruits=( "${Fruits[@]/Ap*/}" )          # Remove by regex match
unset Fruits[2]                         # Remove one item
Fruits=("${Fruits[@]}")                 # Duplicate
Fruits=("${Fruits[@]}" "${Veggies[@]}") # Concatenate
lines=(`cat "logfile"`)                 # Read from file
 
# Iteration
for i in "${arrayName[@]}"; do
  echo "$i"
done

Directories

# Declare a directory
declare -A sounds
 
sounds[dog]="bark"
sounds[cow]="moo"
sounds[bird]="tweet"
sounds[wolf]="howl"
 
# Working with dictionaries
echo "${sounds[dog]}" # Dog's sound
echo "${sounds[@]}"   # All values
echo "${!sounds[@]}"  # All keys
echo "${#sounds[@]}"  # Number of elements
unset sounds[dog]     # Delete dog
 
# Iteration: values
for val in "${sounds[@]}"; do
  echo "$val"
done
 
# Iteration: keys
for key in "${!sounds[@]}"; do
  echo "$key"
done

Command Substitution

TODAY=$(date +'%Y %m %d - %H:%m')
echo $TODAY
 
name="John"
echo "${name}"
echo "${name/J/j}"    #=> "john" (substitution)
echo "${name:0:2}"    #=> "Jo" (slicing)
echo "${name::2}"     #=> "Jo" (slicing)
echo "${name::-1}"    #=> "Joh" (slicing)
echo "${name:(-1)}"   #=> "n" (slicing from right)
echo "${name:(-2):1}" #=> "h" (slicing from right)
echo "${food:-Cake}"  #=> $food or "Cake"

Cron

# list cronjobs
crontab -l
 
# edit cronjobs
crontab -e
A    B    C    D    E    command and arguments
filedMeaningvalues
Aminute0-59
Bhour0-23
Cday of month1-31
Dmonth1-12 (or names, see below)
Eday of week0-7 (0 or 7 is Sunday, or use names)

If you replace a field with * it means “whatever” or “all” or “any”. Also if you have @reboot or @daily instead of time fields, the command will be run once after the reboot or daily. Lets see some examples:

5 0 * * *       $HOME/bin/daily.job >> $HOME/tmp/out 2>&1
 
# run at 2:15pm on the first of every month -- output mailed to paul
15 14 1 * *     $HOME/bin/monthly
 
# run at 10 pm on weekdays, annoy Joe
0 22 * * 1-5    mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
 
23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
5 4 * * sun     echo "run at 5 after 4 every sunday"
 
*/5 * * * *    echo "each 5 mintues"
 
42 8,18 * * 1-5    echo "8:42 and 18:42 and only on weekdays (monday till friday)"
 
@reboot        echo "runs after the reboot"

System & Boot Logs

# kernel ring buffer logs
dmesg
 
# check log rotation
cat /etc/logrotate.conf # usually in /etc/cron.daily
 
# system log management
systemctl status rsyslog
cat /etc/rsyslog.conf # config
 
journalctl # show all journal
journalctl -xe # last few logs
journalctl --no-pager # do not use less
journalctl -n 10 # only 10 lines
journalctl -S -1d # last 1 day
journalctl -u nginx.service --since today # only nginx unit
journalctl _PID=1234 # by process id

Network Troubleshooting

# show NICs
ip link show
ip addr show
ifconfig -a # old
 
# hostname
hostname
hostnamectl status
cat /etc/hostname
 
# remote host: return DNS records (& get ip)
host google.com
host -t TXT google.com
 
# routing
ip route
ip route add default via 172.31.1.1 # default gateway
ip route add 4.2.2.4 via 172.31.1.1 # static route
 
# trace
traceroute google.com
 
# netstat & ss: check open ports (LISTEN)
netstat -tulpen # old
ss -tulpen
 
# check which user & command is using port
sudo fuser 3000/tcp -v
 
# set DNS server
cat /etc/resolv.conf
 
# netcat: listen on port
nc -l 8080
 
# netcat: check if remote port is open
nc -zv localhost 8080
nc -zv localhost 1-9999
 
# dig: check dns
dig @8.8.8.8 google.com
 
# tcpflow & tcpdump
tcpflow -c port 80
tcpdump -i eth0

Administration & Security

# change to root with env vars
sudo su -
 
# change to user
su newuser -
 
# check system sessions
w
who
 
# last logins
last
last -f /var/log/btmp # failed logins
 
# suid & guid
find /usr/bin/ -perm -u+s
 
# show open files
lsof
sudo lsof -i # show open connection files

ssh

# generate ssh key pair in ~/.ssh
ssh-keygen -t ed25519
 
# ssh agent
ssh-agent /bin/bash
ssh-add # add all keys to agent
 
# ssh tunnel: enable processes running at foo to connect 
# to `localhost:8080` and actually speak to your home computer at port # 3000
ssh -R 8080:localhost:3000 foo.mycompany.com