Helpful Commands for Ubuntu
Helpful Commands for Ubuntu
A reference for commonly used Ubuntu terminal commands, written for beginners. Each command includes an explanation of what it does and what any flags mean.
Flags (also called options) are extra instructions you add to a command, always starting with - or --. For example, in ls -l, the -l flag tells ls to show a detailed (long) list instead of just filenames.
System Information
View OS version
lsb_release -a
lsb_releaseprints information about the Linux distribution.-ameans all — show every available detail (distributor, description, release number, codename).
View kernel version
uname -r
unameprints system information.-rmeans release — show only the kernel version number (e.g.6.8.0-45-generic).
View system uptime
uptime
Prints how long the system has been running, how many users are logged in, and the average CPU load over the last 1, 5, and 15 minutes. No flags needed.
View CPU info
lscpu
Lists detailed information about your CPU: architecture, number of cores, threads, speed, and more. No flags needed.
View memory (RAM) usage
free -h
freeshows how much RAM and swap space is used vs. available.-hmeans human-readable — displays sizes in MB/GB instead of raw bytes (e.g.3.8Ginstead of3981234).
View disk usage
df -h
dfstands for disk free — shows how much space is used and available on each mounted filesystem.-hmeans human-readable — displays sizes in MB/GB instead of raw bytes.
Package Management (APT)
APT is Ubuntu's built-in package manager. Use it to install, update, and remove software.
Update package lists
sudo apt update
Downloads the latest list of available packages from Ubuntu's software repositories. This does not install or upgrade anything — it only refreshes the list so Ubuntu knows what's available.
Always run apt update first so Ubuntu knows what's available.
Upgrade installed packages
sudo apt upgrade -y
Installs the newest versions of all currently installed packages.
-ymeans yes — automatically answers "yes" to any confirmation prompts so you don't have to type it manually.
Install a package
sudo apt install <package-name>
Downloads and installs the named package. Replace <package-name> with the actual name, e.g. sudo apt install curl.
Remove a package
sudo apt remove <package-name>
Uninstalls the named package but keeps its configuration files on disk (useful if you want to reinstall later and keep your settings).
Remove a package and its config files
sudo apt purge <package-name>
Uninstalls the named package and deletes its configuration files. Use this when you want a completely clean removal.
Remove unused dependencies
sudo apt autoremove -y
Removes packages that were installed automatically to support other software but are no longer needed.
-yautomatically confirms the removal.
Search for a package
apt search <keyword>
Searches the package list for packages matching the keyword. No sudo needed since this only reads data.
Show package details
apt show <package-name>
Displays information about a package: version, description, dependencies, and more. No sudo needed.
File & Directory
List files
ls -lah
lslists the contents of a directory.-lmeans long format — shows permissions, owner, size, and modification date for each file.-ameans all — includes hidden files (files whose names start with.).-hmeans human-readable — shows file sizes in KB/MB/GB instead of bytes.
You can combine these flags: -lah is the same as -l -a -h.
Change directory
cd /path/to/directory
Moves your terminal session into the specified directory. Replace /path/to/directory with the actual path, e.g. cd /home/john/Documents.
| Shortcut | Meaning |
|---|---|
cd ~ | Go to your home directory |
cd .. | Go up one level |
cd - | Go back to the previous directory |
Create a directory
mkdir -p /path/to/directory
mkdircreates a new directory.-pmeans parents — also creates any missing parent directories in the path. Without-p, the command fails if the parent directory doesn't exist.
Example: mkdir -p /home/john/projects/myapp creates all three folders at once if they don't exist.
Create an empty file
touch /path/to/file
- Creates the file if it does not exist.
- If the file already exists,
touchupdates its access and modification timestamps without changing its contents.
Useful for creating placeholder files or resetting timestamps for testing.
Print text or write to a file
echo "hello world"
Prints the string to standard output (your terminal).
Redirect to a file with > (overwrite) or >> (append):
# overwrite the file with new content
echo "config=true" > /path/to/file.txt
# append a line without erasing existing content
echo "another line" >> /path/to/file.txt
> overwrites without warning> silently replaces the entire file. Use >> when you want to add to an existing file.
Copy files
cp -r /source /destination
cpcopies files or directories.-rmeans recursive — required when copying a directory, so it copies the folder and everything inside it. Without-r,cpwill refuse to copy a directory.
Copy files with copy-on-write (reflink)
cp --reflink=auto /source /destination
Instead of duplicating the file's data on disk immediately, --reflink creates a shallow clone that shares the same underlying data blocks as the original. New blocks are only written when one of the two copies is modified (copy-on-write), so the initial copy is nearly instant and uses no extra space until changes are made.
--reflink=auto— use a reflink if the filesystem supports it (Btrfs, XFS, APFS); silently fall back to a normal copy if not.--reflink=always— fail with an error if a reflink is not possible, rather than falling back.
Reflinks require a filesystem that supports copy-on-write extents. On Ubuntu, Btrfs and XFS (with reflink=1 mount option) support this. The default ext4 filesystem does not.
Move or rename files
mv /source /destination
mvmoves a file or directory to a new location.- If the destination is in the same folder with a different name, it renames the file instead. No flags needed for basic usage.
Bulk rename files with rename
Ubuntu ships with two different rename tools with incompatible syntax:
| Package | Command syntax | Supports regex |
|---|---|---|
util-linux (default) | rename <from> <to> <files> | No — literal strings only |
rename (Perl) | rename 's/pattern/replacement/' <files> | Yes |
Check which version you have:
rename --version
If the output mentions util-linux, you have the basic version.
util-linux rename — literal string replacement:
# rename every .txt file to .bak
rename .txt .bak *.txt
Perl rename — regex-based (install first):
sudo apt install rename
# remove [video_id] suffixes from filenames, e.g. "Title [abc123].mkv" → "Title.mkv"
rename 's/ \[[^\]]*\]//' *.mkv
# replace spaces with underscores
rename 's/ /_/g' *.mkv
# dry run — preview changes without renaming
rename -n 's/ \[[^\]]*\]//' *.mkv
-n— dry run: print what would be renamed without making any changes.s/pattern/replacement/— Perl substitution expression;gat the end replaces all occurrences per filename.
If you can't install the Perl version, use a for loop with sed as a portable alternative:
for f in *.mkv; do mv "$f" "$(echo "$f" | sed 's/ \[[^]]*\]//')"; done
Create links between files
# symbolic (soft) link — like a shortcut
ln -s /path/to/original /path/to/link
# hard link — a second name for the same file data
ln /path/to/original /path/to/link
A symbolic link points to a path. If the original is moved or deleted, the symlink breaks. Works across filesystems and on directories.
A hard link points directly to the same inode (the underlying data) as the original. The file's data is only deleted when all hard links to it are removed. Cannot span filesystems or link directories.
| Symlink | Hard link | |
|---|---|---|
| Survives original deletion | No — becomes a dangling link | Yes — data stays until all links removed |
| Works across filesystems | Yes | No |
| Can link directories | Yes (with -s) | No |
| Shows as separate file | Yes | Yes |
Verify a symlink with ls -la — the -> arrow shows what it points to:
ls -la /path/to/link
Delete a file
rm /path/to/file
rmpermanently deletes a file. There is no recycle bin — deleted files cannot be recovered easily.
Delete a directory
rm -rf /path/to/directory
-rmeans recursive — delete the directory and everything inside it.-fmeans force — skip confirmation prompts and do not show errors for missing files.
rm -rf is permanent and irreversible. Double-check the path before running it.
Find a file by name
find / -name "filename" 2>/dev/null
findsearches for files and directories./is the starting directory — here it starts from the root, searching the entire system.-name "filename"filters results to only entries matching that name. You can use wildcards, e.g.-name "*.log"finds all.logfiles.2>/dev/nullredirects error messages (like "Permission denied") away from your screen so the output is clean.2>redirects stderr (error output) and/dev/nullis a special file that discards anything written to it.
Find large files and display their sizes
sudo find ./ -type f -size +30G -printf '%s %p\n' | sort -n | numfmt --field=1 --to=iec
Searches the current directory recursively for files larger than 30 GB, then sorts them by size and prints human-readable sizes (e.g. 14T).
./— start searching from the current directory.-type f— match only files (not directories).-size +30G— only include files larger than 30 GB. Change30Gto any size you need (e.g.1G,500M).-printf '%s %p\n'— print the file size in bytes (%s) followed by the full path (%p) on each line. This format is required for the next two commands to work correctly.sort -n— sort the lines numerically by the first column (the byte size), so the largest files appear last.numfmt --field=1 --to=iec— convert the first field (raw bytes) to a human-readable IEC unit (K,M,G,T), so15393162788864becomes14T.
Change +30G to a smaller threshold like +1G if you want to cast a wider net.
Find files by extension
find . -type f \( -iname "*.EXT1" -o -iname "*.EXT2" -o -iname "*.EXT3" \)
Searches the current directory recursively for files matching any of the listed extensions. Add or remove -o -iname "*.EXT" blocks to match more or fewer extensions.
.— start from the current directory.-type f— match only files.\( ... \)— groups the extension conditions together as a unit.-iname "*.EXT"— case-insensitive name match.*.EXTmatches any filename ending in.EXTregardless of upper/lowercase.-o— means or — the file only needs to match one of the extensions.
Example — find files with suspicious or unknown extensions:
find . -type f \( -iname "*.KDRSXS" -o -iname "*.ECJLLX" -o -iname "*.YFUINC" \)
Find and delete files by extension
find . -type f \( -iname "*.EXT1" -o -iname "*.EXT2" -o -iname "*.EXT3" \) -delete
Same as the search above but adds -delete at the end to permanently remove every matched file.
-delete— deletes each file that matches all the preceding conditions. It must come after the match conditions orfindwill behave unexpectedly.
Run the command without -delete first to review what will be removed before committing to the deletion.
Example — delete files with those extensions:
find . -type f \( -iname "*.KDRSXS" -o -iname "*.ECJLLX" -o -iname "*.YFUINC" \) -delete
Get detailed file metadata
stat /path/to/file
Displays detailed metadata about a file: size in bytes, block allocation, inode number, permissions, owner, and all three timestamps (access time, modify time, change time).
stat accepts multiple paths in a single call, which is useful for comparing several files at once:
sudo stat /path/to/file1 /path/to/file2 /path/to/file3
Useful for diagnosing files that are unexpectedly growing — run stat periodically and watch whether the Size and Modify time keep updating.
Hex dump the last N bytes of a file
sudo tail -c 1024 /path/to/file | xxd
tail -c 1024reads the last 1024 bytes of the file. Change1024to any byte count.xxdconverts the binary data to a hex dump for visual inspection.
Useful for checking whether a file has valid end-of-file data or is still being written. For example, a correctly finalised MKV will have recognisable EBML closing bytes; a file still in progress will show an incomplete block.
Check which process has a file open
sudo lsof /path/to/file
- Passing a file path to
lsofshows every process that currently has that file open, along with its PID, user, and access mode.
Useful when a file is growing unexpectedly, cannot be deleted, or you need to confirm whether a tool has finished writing before moving the file.
- Run
stat /path/to/fileto record the current size. - Run
sudo lsof /path/to/fileto see what has it open and in what mode (r= read,w= write,u= read+write). - Wait a few seconds, then
statagain. If the size increased andlsofshows a write handle, a process is still appending to it.
Watch a file's size in real time
watch -n 1 'stat -c "%s bytes %n" "/path/to/file"'
watch -n 1re-runs the quoted command every 1 second and refreshes the display in place.stat -c "%s bytes %n"prints only the size in bytes (%s) and the filename (%n) — much less noise than a fullstatoutput.
Useful for confirming a file has stopped growing after a transcoding or remux job finishes. Press Ctrl+C to exit watch.
Search file contents with grep
grep "pattern" /path/to/file
- Prints every line in the file that contains
pattern. The pattern can be plain text or a regular expression.
Common flags:
| Flag | Effect |
|---|---|
-r | Recurse into subdirectories |
-i | Case-insensitive match |
-n | Prefix each match with its line number |
-l | Print only the filenames that contain a match, not the lines |
-v | Invert — print lines that do not match |
-c | Print a count of matching lines per file |
--include='*.log' | Limit recursive search to files matching a glob |
Recursive search with line numbers (the most common real-world form):
grep -rn "pattern" /path/to/directory
Filter command output — pipe any command into grep to show only relevant lines:
journalctl -u tdarr | grep -i "error\|warn"
Edit text in files with sed
sed 's/search/replacement/' /path/to/file
sed (stream editor) reads a file line by line and applies an expression to each line. The substitution expression format is s/search/replacement/ — search is the text (or regex) to find, and replacement is what to put in its place.
Concrete example — change every http:// to https:// in a config file:
sed 's/http:\/\//https:\/\//' /etc/myapp/config.conf
Because sed uses / as the delimiter between s, search, and replacement, any / that appears in the search or replacement text must be escaped as \/ so sed doesn't mistake it for a delimiter.
Common expressions:
| Expression | Effect |
|---|---|
s/search/replacement/ | Replace first match per line |
s/search/replacement/g | Replace all matches per line (g = global) |
s/search/replacement/i | Case-insensitive replace |
/pattern/d | Delete lines that contain pattern |
/pattern/p | Print only lines that contain pattern (use with -n) |
By default sed prints to stdout without modifying the file. Use -i to edit in place:
# replace all occurrences directly in the file
sed -i 's/search/replacement/g' /path/to/file
# save a backup as file.bak before editing
sed -i.bak 's/search/replacement/g' /path/to/file
Print specific lines from a file
sed -n '45,55p' /path/to/file
Prints only lines 45 through 55 of a file without modifying it.
-n— suppress the default behavior of printing every line. Without this flag,sedprints all lines plus the matched ones.'45,55p'— the address range45,55selects lines 45 to 55;pprints each selected line.
Useful for inspecting a specific section of a large config file without opening it in an editor:
sudo sed -n '45,55p' /etc/sudoers
To print a single line, use the same number for both ends of the range, or just '<N>p':
sed -n '72p' /path/to/file
Compare two files line by line
diff file1 file2
Prints the lines that differ between two files. Lines prefixed with < are only in file1; lines prefixed with > are only in file2.
Common flags:
| Flag | Effect |
|---|---|
-u | Unified format — shows a few lines of context around each change (the format used by git diff) |
-i | Ignore case differences |
-w | Ignore all whitespace differences |
-r | Recurse into directories and compare all files |
-q | Quiet — only report whether files differ, not what differs |
Example — compare two JSON dumps side by side in unified format:
diff -u /tmp/before.json /tmp/after.json
Exit code 0 means the files are identical; 1 means they differ.
Compare two files byte by byte
cmp file1 file2
cmp does a binary comparison and reports the byte offset and line number of the first difference it finds, then stops. Unlike diff, it works on any file type (binary, compressed, media).
- With no flags, prints nothing if the files are identical and reports the first differing byte if not.
-l— list all differing bytes (offset and values in octal).-s— silent mode: produce no output, only set the exit code. Useful in scripts.-n <bytes>— compare only the first<bytes>bytes. Use this when the files have different sizes and you only want to check the region that exists in both.
Exit code 0 = identical, 1 = differ, 2 = error.
Use diff when you want to see what text changed line by line. Use cmp when you only need to know whether two files are byte-for-byte identical (e.g. verifying a copy or download).
Once cmp reports a differing byte offset, use dd + xxd + diff to see exactly what changed around that position:
# 1. Find where the files first differ (limit to the smaller file's size with -n)
cmp -n 2106826942 file-before.mkv file-after.mkv
# output: files differ: byte 2106824424, line 7876101
# 2. Extract ~4 KB around the differing offset from each file
dd if="file-before.mkv" bs=1 skip=2106824000 count=4000 2>/dev/null | xxd > /tmp/before.hex
dd if="file-after.mkv" bs=1 skip=2106824000 count=4000 2>/dev/null | xxd > /tmp/after.hex
# 3. Diff the two hex dumps to see exactly which bytes changed
diff -u /tmp/before.hex /tmp/after.hex
bs=1 skip=<offset>— seek to<offset>bytes into the file (bs=1means each skip unit is 1 byte).count=4000— read 4000 bytes (adjust to capture the full area of interest).2>/dev/null— suppressdd's progress line so only the data goes toxxd.
Browse disk usage interactively with ncdu
ncdu /path/to/directory
ncdu (NCurses Disk Usage) scans a directory tree and displays a sorted, interactive breakdown of what is consuming space.
Install it first if not present:
sudo apt install ncdu
Key bindings once inside ncdu:
| Key | Action |
|---|---|
↑ / ↓ | Move between entries |
Enter | Drill into a subdirectory |
d | Delete the selected file or directory (with confirmation) |
i | Show info about the selected item |
q | Quit |
Useful for quickly finding which folder is eating your disk before reaching for du -sh *.
Copy and convert data at block level
dd if=/dev/sda of=/path/to/image.img bs=4M status=progress
dd reads from an input file (if=) and writes to an output file (of=) block by block. Both if and of can be a regular file, a disk device, or a special file like /dev/zero or /dev/null.
if=— input file or device to read from.of=— output file or device to write to.bs=— block size; larger values (e.g.4M) are faster for bulk transfers.status=progress— print transfer speed and progress while running.
Common uses:
| Command | What it does |
|---|---|
dd if=/dev/sda of=disk.img bs=4M status=progress | Clone an entire disk to an image file |
dd if=disk.img of=/dev/sdb bs=4M status=progress | Restore an image file to a disk |
dd if=/dev/zero of=testfile bs=1M count=1024 status=progress | Create a 1 GB zero-filled file (useful for write speed testing) |
dd if=/dev/urandom of=testfile bs=1M count=100 | Fill a file with random data |
of= targets are overwritten silentlyWriting to a wrong of= target (e.g. of=/dev/sda instead of of=/dev/sdb) will destroy data with no confirmation prompt. Double-check the device name with lsblk before running.
User Management
Add a new user
sudo adduser <username>
Creates a new user account interactively — it will ask you to set a password and optional details. Replace <username> with the desired username.
Add a user to a group
sudo usermod -aG <group> <username>
usermodmodifies an existing user account.-ameans append — add the user to the group without removing them from other groups.-Gspecifies the group to add the user to.
Using -G alone without -a will remove the user from all other groups.
Example: sudo usermod -aG docker john gives the user john permission to run Docker commands without sudo.
Switch to another user
su - <username>
sustands for substitute user — switches to the specified user's account.-loads that user's full login environment (home directory, shell settings, etc.). Without-, you switch users but keep your current environment, which can cause unexpected behaviour.
Show current user
whoami
Prints the username of the currently logged-in user. Useful when switching between users to confirm who you are.
List groups for a user
groups <username>
Prints all groups the specified user belongs to. Leave out <username> to see groups for the current user.
Service Management (systemd)
Ubuntu uses systemd to manage background services (called units or daemons). Replace <service> with the service name, e.g. nginx, ssh, or docker.
Start a service
sudo systemctl start <service>
Starts the service immediately. This does not make it start automatically on reboot.
Stop a service
sudo systemctl stop <service>
Stops the service immediately.
Restart a service
sudo systemctl restart <service>
Stops and then starts the service. Use this to apply configuration changes.
Enable a service at boot
sudo systemctl enable <service>
Configures the service to start automatically every time the system boots. Does not start it right now.
Disable a service at boot
sudo systemctl disable <service>
Prevents the service from starting automatically on boot. Does not stop it right now.
Check service status
sudo systemctl status <service>
Shows whether the service is running or stopped, and displays the most recent log lines. Press q to exit.
View live service logs
journalctl -u <service> -f
journalctlreads logs managed by systemd.-u <service>means unit — filter logs to only show entries from the specified service.-fmeans follow — keep the output open and print new log lines in real time (liketail -f). PressCtrl+Cto stop.
Networking
Show IP addresses
ip a
ipis the modern Linux networking tool.ais short for address — lists all network interfaces and their assigned IP addresses (both IPv4 and IPv6).
Show routing table
ip route
Displays the system's routing table — which network interface handles traffic to which destinations, and what the default gateway is.
Test connectivity
ping -c 4 <host>
pingsends ICMP echo requests to a host to test if it is reachable.-c 4means count 4 — send exactly 4 packets then stop. Without-c, ping runs forever until you pressCtrl+C.
Example: ping -c 4 google.com
DNS lookup
nslookup <domain>
Queries DNS to find the IP address associated with a domain name. Example: nslookup google.com.
Show open ports
ss -tulnp
ssstands for socket statistics — shows network connections and listening ports.-tshows TCP connections.-ushows UDP connections.-lshows only listening sockets (ports waiting for connections).-nshows numeric addresses and port numbers instead of resolving hostnames and service names.-pshows the process (program name and PID) that owns each socket.
Find what is using a specific port
ss -tulnp | grep :<port>
Filters the socket list to only show the process bound to a specific port. Replace <port> with the port number.
Example — find what is using port 8080:
ss -tulnp | grep :8080
The output shows the process name and PID in the last column, e.g. users:(("nginx",pid=1234,fd=6)).
You can also use lsof for a more detailed view:
sudo lsof -i :<port>
lsofstands for list open files — on Linux, network sockets are treated as files.-i :<port>filters to only show processes with a socket open on that port.- The output includes the command, PID, user, and connection state.
Or use fuser to get just the PID instantly:
sudo fuser <port>/tcp
fuserprints the PID(s) of processes using the specified port. Combine with-vfor verbose output including the process name:
sudo fuser -v <port>/tcp
- Run
sudo lsof -i :<port>to identify the conflicting process and its PID. - Either stop the service (
sudo systemctl stop <service>) or kill the process (sudo kill -9 <pid>). - Then start your own service on that port.
Test if a port is reachable
nc -zv <host> <port>
nc(netcat) opens a TCP connection to<host>on<port>and immediately exits.-z— zero-I/O mode: connect and exit without sending data (port probe only).-v— verbose: print whether the connection succeeded or was refused.
Example — check if Jellyfin on another machine is reachable:
nc -zv 192.168.1.50 8096
Output when open: Connection to 192.168.1.50 8096 port [tcp/*] succeeded!
Output when blocked or closed: nc: connect to 192.168.1.50 port 8096 (tcp) failed: Connection refused
Connection refused means the host responded but nothing is listening on that port — the service is down or on a different port.
Connection timed out (no output for several seconds) means the traffic is being dropped by a firewall before it reaches the host — check UFW rules on the server and any network-level firewall between the two machines.
Check firewall status (UFW)
sudo ufw status verbose
ufwstands for Uncomplicated Firewall — Ubuntu's built-in firewall tool.statusshows whether the firewall is active and lists the current rules.verboseshows extra detail, including the default policies for incoming and outgoing traffic.
Allow a port through UFW
sudo ufw allow <port>/tcp
Creates a firewall rule that permits incoming TCP connections on the specified port. Replace <port> with the port number, e.g. sudo ufw allow 80/tcp opens port 80 for web traffic.
Allow a port with a comment
sudo ufw allow <port>/tcp comment '<description>'
Same as above but attaches a human-readable label to the rule so you can remember why it was added. The comment appears when you run ufw status.
Example:
sudo ufw allow 8096/tcp comment 'Jellyfin Web UI'
View firewall rules with rule numbers
sudo ufw status numbered
Lists all active firewall rules with a number next to each one. The numbers are useful for deleting a specific rule:
sudo ufw delete <number>
Example — to remove rule number 3:
sudo ufw delete 3
Process Management
List running processes
ps aux
psshows a snapshot of currently running processes.ashows processes from all users, not just your own.ushows output in a user-oriented format that includes the username, CPU%, and memory% columns.xincludes processes that are not attached to a terminal (background daemons).
Interactive process viewer
top
Opens a live, updating view of all running processes sorted by CPU usage. Useful for spotting what is using the most resources. Press q to quit, M to sort by memory, P to sort by CPU.
Interactive process viewer (enhanced)
htop
htop is a more readable alternative to top with color-coded bars for CPU and memory, mouse support, and easier process management. Install it first if not present:
sudo apt install htop
Key bindings:
| Key | Action |
|---|---|
F2 | Open settings |
F3 / / | Search for a process by name |
F5 | Toggle tree view (shows parent/child relationships) |
F6 | Change sort column |
F9 | Send a signal to the selected process (e.g. SIGKILL) |
q | Quit |
Kill a process by PID
kill -9 <pid>
killsends a signal to a process.-9is the signal number to send — signal 9 is called SIGKILL, which forces the process to terminate immediately and cannot be ignored or caught by the program. You can also write it as-SIGKILLfor the same effect. Use this only when a normalkill <pid>(which sends SIGTERM) has not worked.<pid>is the process ID — the target of the signal. You can find it withps auxorpgrep.
So in the example below, -9 is what to do and 8325 is who to do it to:
sudo kill -9 8325
Kill a process by name
pkill <process-name>
Sends a termination signal to all processes matching the given name. Easier than finding the PID first.
Find a process by name
pgrep <process-name>
Prints the PID(s) of all processes matching the given name. Example: pgrep nginx.
Find processes by full command line
pgrep -a -f <pattern>
-a— print the full command line alongside each PID, not just the PID.-f— match against the full command line (including arguments and flags) instead of just the executable name. Useful when multiple processes share the same binary (e.g. several concurrentffmpegjobs with different input files).
The pattern can be a regex, so you can match multiple programs at once using | alternation:
sudo pgrep -a -f 'mkvpropedit|tdarr|ffmpeg'
This returns all running processes whose command line contains mkvpropedit, tdarr, or ffmpeg. sudo is needed to see processes owned by other users (e.g. services running as root or a dedicated service account).
Find a process with ps and grep
sudo ps auxww | grep '[m]kvpropedit'
ps auxwwlists all processes for all users (a), with user-oriented format (u), including processes without a controlling terminal (x), with no column truncation (ww).- The bracket trick
[m]kvpropeditprevents thegrepprocess itself from appearing in results (the pattern doesn't match its own command line).
Alternative to pgrep when you want the full ps output columns (USER, PID, %CPU, %MEM, VSZ, RSS, START, TIME, COMMAND) without a separate lookup.
Inspect a specific process by PID
sudo ps -p <PID> -o pid,etime,pcpu,pmem,cmd
-p <PID>— target a single process by its PID.etime— elapsed time since the process started (format:[[DD-]HH:]MM:SS).pcpu/pmem— CPU and memory percentage.cmd— full command line.
Useful after finding a PID with pgrep or ps auxww to check how long a job has been running and how much CPU/memory it is consuming.
Trace file-write syscalls on a running process
sudo strace -p <PID> -e trace=write,pwrite64,truncate,ftruncate -c
-p <PID>— attach to an already-running process.-e trace=write,pwrite64,truncate,ftruncate— record only file-write related syscalls; filters out the noise of unrelated syscalls.-c— summary mode: instead of printing every call, accumulate counts and print a table of call frequency and time when you detach (Ctrl+C).
Useful for confirming whether a process is actively writing to disk. If write/pwrite64 counts climb while you watch, the process is still appending data. A near-zero count after a few seconds means it has stalled or finished.
Permissions
Linux file permissions control who can read, write, or execute a file. Every file has three sets of permissions: one for the owner, one for the group, and one for everyone else (others).
Understanding permission numbers
Each set is represented by a single digit from 0–7, calculated by adding up the values of the permissions granted:
| Value | Permission | Symbol |
|---|---|---|
| 4 | Read | r |
| 2 | Write | w |
| 1 | Execute | x |
| 0 | No permission | - |
You add these numbers together to get the digit for each set. For example, read + write = 4 + 2 = 6.
Permission reference chart
| Number | Permissions | Symbolic | Who can do what |
|---|---|---|---|
7 | Read + Write + Execute | rwx | Full access |
6 | Read + Write | rw- | Read and modify, but not execute |
5 | Read + Execute | r-x | Read and run, but not modify |
4 | Read only | r-- | View only |
3 | Write + Execute | -wx | Modify and run, but not read |
2 | Write only | -w- | Modify only |
1 | Execute only | --x | Run only |
0 | No permission | --- | No access |
Common permission combinations
| Mode | Owner | Group | Others | Typical use |
|---|---|---|---|---|
755 | rwx | r-x | r-x | Directories, executables — owner can edit; everyone else can read/run |
644 | rw- | r-- | r-- | Regular files — owner can edit; everyone else can only read |
600 | rw- | --- | --- | Private files (e.g. SSH keys) — only the owner can read/write |
777 | rwx | rwx | rwx | Full access for everyone — avoid unless necessary |
700 | rwx | --- | --- | Private executables — only the owner can read, write, or run |
750 | rwx | r-x | --- | Group-accessible executables — others have no access |
Change file permissions
chmod 755 /path/to/file
chmodstands for change mode — sets the permissions of a file or directory.- The three digits represent permissions for owner, group, and others respectively.
Example: chmod 644 config.txt makes config.txt readable by everyone but only writable by the owner.
To apply permissions recursively to a directory and all its contents, add -R:
chmod -R 755 /path/to/directory
Change file owner
sudo chown -R <user>:<group> /path
chownstands for change owner — changes who owns a file or directory.<user>:<group>sets both the owning user and the owning group. You can omit:<group>to change only the user.-Rmeans recursive — apply the change to the directory and everything inside it.
Example: sudo chown -R john:john /home/john/projects gives the user john ownership of all files in that directory.
SSH
SSH (Secure Shell) lets you securely connect to and control remote machines from your terminal.
Connect to a remote host
ssh <user>@<host>
Opens an encrypted terminal session on the remote machine. Replace <user> with the username on the remote machine and <host> with its IP address or hostname.
Example: ssh john@192.168.1.10
Copy files to a remote host
scp /local/file <user>@<host>:/remote/path
scpstands for secure copy — copies files over SSH.- The first argument is the source file on your local machine.
- The second argument is the destination in the format
user@host:/path.
To copy a directory, add -r (recursive):
scp -r /local/folder <user>@<host>:/remote/path
Copy files from Windows to Ubuntu (SCP)
scp -r "C:\path\to\folder" <user>@<host>:/remote/directory/
Run this command from a local Windows terminal (PowerShell or Command Prompt), not from inside your remote SSH session.
- Windows 10 and 11 include the OpenSSH client by default.
- Wrap paths containing spaces in double quotes.
- The remote path uses standard Linux forward slashes (
/).
Example:
scp -r "C:\Users\John\Documents\MEGA downloads\Season 01" server@192.168.1.10:/media/merged/Downloads/
If you are logged into your Ubuntu server via SSH and try to run scp to pull from Windows, Ubuntu tries to connect back to your Windows PC over port 22. Unless Windows has OpenSSH Server installed, running, and allowed through the firewall, the command will hang. Always push the files from a local Windows terminal instead.
Generate an SSH key pair
ssh-keygen -t ed25519 -C "your_email@example.com"
Creates a pair of cryptographic keys for passwordless SSH authentication.
-t ed25519specifies the key type — Ed25519 is modern and secure.-C "your_email@example.com"adds a comment to the key to help you identify it later.
This creates two files: a private key (~/.ssh/id_ed25519) that you keep secret, and a public key (~/.ssh/id_ed25519.pub) that you share with remote servers.
Copy your public key to a remote host
ssh-copy-id <user>@<host>
Appends your public key to the remote machine's ~/.ssh/authorized_keys file, enabling passwordless login. You only need to do this once per remote machine.
Rsync
rsync is a fast, versatile file copying tool that only transfers the parts of files that have changed, making it far more efficient than cp or scp for large transfers or regular backups.
Common flags
| Flag | Meaning |
|---|---|
-a | Archive — preserves permissions, timestamps, symlinks, owner, and group. Equivalent to -rlptgoD. Almost always used. |
-v | Verbose — prints the name of each file as it is transferred. |
-z | Compress — compresses data during transfer to reduce bandwidth. Useful over slow networks, unnecessary on a LAN. |
-h | Human-readable — shows transfer sizes in KB/MB/GB. |
-P | Progress + Partial — shorthand for --progress --partial. Shows a per-file progress bar and keeps partially transferred files so the transfer can be resumed. |
--progress | Progress — shows a per-file progress bar without enabling partial file resuming. |
--info=progress2 | Overall progress — shows a single progress bar for the entire transfer instead of one per file. Cleaner output for large jobs. |
-n | Dry run — simulates the transfer without actually copying anything. Use this first to verify what will be synced. |
--delete | Deletes files at the destination that no longer exist at the source, keeping the two locations in sync. |
--exclude | Skips files or directories matching a pattern. |
Copy a local directory to another local location
rsync -avh /source/directory/ /destination/directory/
-apreserves all file attributes.-vprints each file name as it copies.-hshows sizes in human-readable format.
/source/directory/ (with trailing slash) copies the contents of the directory into the destination.
/source/directory (no trailing slash) copies the directory itself into the destination, creating /destination/directory/directory/.
Preview what will be synced (dry run)
rsync -avhn /source/directory/ /destination/directory/
-nperforms a dry run — nothing is copied. Use this to verify the file list before committing.
Copy files to a remote host over SSH
rsync -avhP /local/directory/ <user>@<host>:/remote/directory/
-Pshows a per-file progress bar and enables resuming interrupted transfers.- rsync uses SSH by default for remote transfers.
Example:
rsync -avhP /home/john/videos/ john@192.168.1.10:/mnt/storage/videos/
Copy files from a remote host to local
rsync -avhP <user>@<host>:/remote/directory/ /local/directory/
Same as above but the source and destination are swapped — pulling files from the remote machine to your local machine.
Copy files from Windows to Ubuntu with Rsync (WSL or Git Bash)
To push files from Windows to an Ubuntu server using rsync with progress and resume support, run the command from WSL (Windows Subsystem for Linux) or Git Bash on your Windows machine:
From WSL (type bash or wsl in PowerShell):
In WSL, local Windows drives are mounted under /mnt/ (e.g. C:\ becomes /mnt/c/):
rsync -avhP "/mnt/c/Users/John/Documents/downloads/Season 01" <user>@<host>:/remote/directory/
From Git Bash (right-click in the folder → Open Git Bash here):
In Git Bash, local Windows drives are mounted directly under / (e.g. C:\ becomes /c/):
# If launched from outside the folder (using absolute path):
rsync -avhP "/c/Users/John/Documents/downloads/Season 01" <user>@<host>:/remote/directory/
# If launched using "Open Git Bash here" inside the folder (using relative path):
rsync -avhP "./Season 01" <user>@<host>:/remote/directory/
Add -n (rsync -avhnP ...) to simulate the transfer and verify file paths before copying data.
Sync and delete files removed from source
rsync -avh --delete /source/directory/ /destination/directory/
--deleteremoves files from the destination that no longer exist in the source, keeping the destination an exact mirror.
--delete permanently removes files from the destination. Always do a dry run with -n first.
Exclude files or directories
rsync -avh --exclude='*.tmp' --exclude='cache/' /source/ /destination/
--exclude='*.tmp'skips all files ending in.tmp.--exclude='cache/'skips thecachedirectory entirely.- You can stack multiple
--excludeflags.
Resume an interrupted transfer
rsync -avhP --append-verify /source/ /destination/
--append-verifyresumes partially transferred files and verifies the checksum of the appended data. Safer than--appendalone.
Media File Inspection
These commands require mkvtoolnix and ffmpeg. Install them with:
sudo apt install mkvtoolnix ffmpeg
Inspect MKV container structure
mkvinfo /path/to/file.mkv | head -100
mkvinfoparses an MKV file and prints its full container structure: EBML headers, tracks, codecs, timestamps, and flags.| head -100limits output to the first 100 lines — remove it to see everything (output can be thousands of lines for large files).
Useful for identifying the codec of each track (e.g. VC-1, H.264, AC-3) before remuxing or transcoding, and for diagnosing container-level issues such as a corrupt seek head.
To save the full output to a file for easier reading (e.g. in a text editor or with grep):
mkvinfo /path/to/file.mkv > output.txt
Dump MKV metadata as JSON
mkvmerge -J /path/to/file.mkv > /tmp/output.json
-Joutputs the file's full track, attachment, chapter, and container metadata as structured JSON instead of human-readable text.- Redirecting to a file (e.g.
/tmp/output.json) lets you open it in a JSON viewer, diff two files, or parse it withjq.
Useful for comparing a file before and after a remux or transcode to confirm track order, codec, language tags, and flags are unchanged:
mkvmerge -J before.mkv > /tmp/before.json
mkvmerge -J after.mkv > /tmp/after.json
diff /tmp/before.json /tmp/after.json
Add track statistics tags to an MKV
mkvpropedit /path/to/file.mkv --add-track-statistics-tags
- Reads the actual stream data and writes
BPS(bitrate),DURATION,NUMBER_OF_FRAMES, andNUMBER_OF_BYTEStags into the MKV container without re-encoding. - Tdarr and some media servers call this automatically after transcoding to populate statistics that the original mux may not have included.
- The file is modified in-place; no re-mux is required.
Files muxed with old versions of mkvmerge (e.g. v5.8.0 from 2012) often have a Seek Head with no void space reserved for future edits. When mkvpropedit needs to add or update Seek Head entries, if the existing Seek Head is too small to hold the new positions, versions before v71.0.0 entered an endless loop writing data to the end of the file — causing the file to grow indefinitely.
This was fixed in MKVToolNix v71.0.0 (issue #3338): the fix was to void the undersized Seek Head and write a new one with sufficient space instead. If you are running mkvpropedit v71.0.0 or newer, this bug does not affect you. Any codec muxed with that era of mkvmerge is susceptible, not just VC-1.
If you are on an older version, use mkvinfo to check the writing application and mkvmerge version in the file's segment info before running mkvpropedit, and remux the file first with a current mkvmerge to rebuild the Seek Head with proper void space.
Probe media file metadata
ffprobe -v error -show_entries format=filename,format_name,duration,size -of default=noprint_wrappers=1 /path/to/file
-v error— suppress all output except errors.-show_entries format=...— select which container-level fields to display. Common fields:filename,format_name,duration,size,bit_rate.-of default=noprint_wrappers=1— output as plainkey=valuepairs without section headers.
Example output:
filename=Supernatural - S02E15 - Tall Tales.mkv
format_name=matroska,webm
duration=2612.345678
size=34359738368
To also include per-stream info (codec, resolution, audio channels), add stream=codec_name,width,height,channels to -show_entries:
ffprobe -v error -show_entries format=size,duration:stream=codec_name,width,height -of default=noprint_wrappers=1 /path/to/file
Run ffprobe (or stat) twice a few seconds apart. If the size value changes between runs, a process is still writing to the file.
💬 Recent Comments