Linux commands explained from the ground up

Linux commands explained from the ground up

Linux commands remain the most direct way to understand, operate and troubleshoot Linux systems. They are best learned as practical task families rather than as isolated syntax to memorize.

Introduction: Why Linux commands still matter

Linux commands are not just shortcuts for people who do not want to use a graphical interface. They are the natural language of the Linux operating system. When you open a terminal, you are not opening an old or limited tool. You are opening the most direct control layer of the system.

A graphical desktop shows icons, windows and menus. The command line shows the real structure underneath those visual elements. Files become paths. Programs become processes. Background applications become services. Storage becomes mounted filesystems. Internet connections become interfaces, routes, ports and packets. Permissions become visible rules that decide who can read, write or execute something.

This is why the Linux command line still matters everywhere: on personal computers, servers, Raspberry Pi devices, cloud infrastructure, containers, cybersecurity labs, development machines, hosting environments, routers, embedded devices, automation platforms and production systems. A person who understands Linux commands does not only know how to type instructions. They understand how the operating system thinks.

The goal of this guide is to explain Linux commands deeply, practically and clearly. It is not a dry list of commands. A list can help you remember syntax, but it does not teach real competence. Real competence comes from understanding what each command does, what problem it solves, what can go wrong, how it combines with other commands and how it fits into the larger structure of Linux administration.

A beginner often tries to memorize commands one by one. That is understandable, but it is not the best approach. Linux becomes much easier when you understand that commands belong to families of tasks.

Task familyWhat you are trying to doCommands you will use often
OrientationUnderstand where you are in the filesystempwd, cd, ls, tree
File creationCreate folders and filesmkdir, touch, nano
File operationsCopy, move, rename and delete datacp, mv, rm
File readingDisplay and inspect text filescat, more, less, head, tail
SearchingFind text, files and patternsgrep, find
CompressionCreate and extract archivestar, zip, unzip
PermissionsControl access to files and folderschmod, chown
Package managementInstall, update and remove softwareapt, dpkg
System managementRestart, shut down and manage servicesreboot, shutdown, service, systemctl
Process controlInspect and stop running programsps, htop, kill, killall
Disk analysisCheck free space and folder sizedf, du, mount, umount
NetworkingInspect connections and communicate remotelyip, ping, wget, ssh, scp, rsync
AutomationRepeat commands and schedule workhistory, crontab, screen
Text processingTransform structured text and logsawk, sed, cut, wc
DiagnosticsInvestigate system activitylsof, watch, netstat, ss, dmesg

The command line becomes powerful because Linux commands are designed to be combined. One command produces output. Another command filters it. A third command sorts it. A fourth command saves it. A fifth command can run the whole workflow every night.

This is one of the deepest ideas in Linux: a command is useful by itself, but a command pipeline can become a custom tool.

Why Linux commands are still essential

Linux commands remain essential because many important systems do not have a graphical desktop at all. Most production servers are managed through SSH. Cloud instances often start as minimal systems. Containers usually run without a graphical interface. Network devices, Raspberry Pi projects and embedded systems may expose only a shell. Even when dashboards exist, they often show only part of the truth.

The command line is also important because it is precise. When you click a button in a graphical interface, you may not know exactly what happened. When you run a command, the instruction is explicit. You can copy it, document it, repeat it, automate it and audit it.

This makes Linux commands especially valuable in professional environments.

Professional situationWhy commands matter
Server administrationServers are often managed remotely through terminal sessions
Web hostingWebsites, logs, permissions, services and packages are controlled through shell tools
DevOpsDeployment, automation, containers and monitoring rely heavily on command-line workflows
CybersecurityLogs, network connections, permissions and processes must be inspected precisely
Software developmentGit, package managers, build tools and deployment scripts are command-line oriented
Data processingLarge text files, logs and exports can be filtered faster from the terminal
TroubleshootingReal errors are often visible in logs before they appear in dashboards
AutomationRepetitive work can be converted into scripts and scheduled jobs
RecoveryBroken systems may boot into a minimal shell where commands are the only option

A graphical interface is comfortable when everything works. The terminal is essential when something does not.

For example, a web application may show a generic error page. The real reason may be inside a log file. You might need to inspect the last lines of a log, search for a specific error, check whether the web server is running, verify disk space, restart a service and confirm that the port is listening.

That is not one command. It is a workflow.

tail -n 50 /var/log/syslog
grep -i "error" /var/log/syslog
df -h
systemctl status apache2
sudo systemctl restart apache2
sudo ss -tulpn

A person who only knows individual commands may see this as a collection of strange lines. A person who understands Linux sees a logical diagnostic sequence: read recent logs, search errors, check disk space, inspect service state, restart service, confirm network listening ports.

Why command combinations matter more than memorization

A single command answers a simple question. A combination answers a real operational question.

Simple question:

ls

What files are here?

Better question:

ls -lah

What files are here, including hidden files, with permissions and readable sizes?

Operational question:

find . -type f -name "*.log" -exec ls -lh {} \;

Which log files exist under this directory, and how large are they?

More operational:

find . -type f -name "*.log" -size +10M -exec ls -lh {} \;

Which log files are larger than 10 MB?

Even more useful:

find . -type f -name "*.log" -size +10M -exec gzip {} \;

Compress log files larger than 10 MB.

This progression shows how Linux thinking works. You begin by inspecting. Then you filter. Then you act.

Never skip directly to the action stage when using find, rm, chmod, chown or administrative commands.

Key takeaways

At this point, the foundation is clear. Linux commands operate inside a structured filesystem. Paths can be absolute or relative. Commands have options and arguments. Output can be displayed, filtered, redirected and combined. The safest workflow is to inspect before changing anything.

The core beginner commands are already enough to perform real work:

CommandEssential purpose
pwdKnow your location
cdMove through directories
lsList files and metadata
treeUnderstand structure visually
mkdirCreate directories
touchCreate empty files
nanoEdit text files
catDisplay short files
moreRead long files page by page
lessRead and search long files comfortably
headInspect the beginning of a file
tailInspect the end of a file and follow logs
grepSearch text patterns
cpCopy files and directories
mvMove and rename files
rmRemove files and directories
rmdirRemove empty directories
manRead command manuals

These commands are not “basic” in the sense of being unimportant. They are basic in the sense that everything else depends on them.

If you understand these commands deeply, then package management, permissions, services, networking, logs, processes, automation and scripting become much easier. Linux is not a collection of disconnected tools. It is a coherent environment built around files, processes, users, permissions and text streams.

How to think at the Linux command line

The command line becomes safer and more useful when it is approached with the right mental model: inspect first, understand the context, make controlled changes and verify the result.

The Linux command line mindset

Before learning syntax, it is important to understand the mindset. Linux does exactly what you tell it to do. It does not always ask whether you are sure. It does not always protect you from your own mistakes. It assumes that the user knows what they are doing, especially when administrative privileges are used.

This is both powerful and dangerous.

A careful Linux user follows a basic principle: inspect first, understand second, change third, delete last.

StagePurposeTypical commands
InspectSee where you are and what existspwd, ls, tree, df, du, ps
UnderstandRead files, logs and service statuscat, less, head, tail, grep, systemctl status
ChangeEdit, move, install, restart or reconfigurenano, mv, cp, apt install, systemctl restart
DeleteRemove only after verificationrm, apt remove, find -delete

A beginner often wants to jump directly to action. An expert first gathers context.

For example, before deleting a directory, do not immediately run this:

rm -rf old-project

A safer workflow is:

pwd
ls -lah
du -sh old-project
tree -L 2 old-project
rm -ri old-project

This workflow confirms your location, lists the current directory, checks the size of the target, previews its structure and then removes it interactively.

Linux rewards this kind of discipline.

A professional mental model for Linux commands

Linux command-line work is not about typing fast. It is about thinking accurately.

A professional mental model follows these questions:

QuestionCommand examples
Where am I?pwd
What is here?ls -lah, tree -L 2
How big is it?du -sh, df -h
What does it contain?cat, less, head, tail
Does it contain a pattern?grep
Where is the file?find
Who owns it?ls -l, stat
Can I access it?ls -l, chmod, chown
Is a process running?ps, htop
Is a service running?systemctl status
Is a port listening?ss -tulpn
What changed recently?ls -lt, find -mtime
What is failing?tail, grep, journalctl

A beginner memorizes commands. An expert asks better questions.

Practical workflow: build a command-line investigation habit

When something is wrong, do not jump to solutions. Collect facts.

For a service problem:

hostname
uptime
df -h
systemctl status service-name
journalctl -u service-name -n 100
sudo ss -tulpn

For a disk problem:

df -h
sudo du -h --max-depth=1 / | sort -h
sudo find /var/log -type f -size +100M -exec ls -lh {} \;
sudo lsof | grep deleted

For a network problem:

ip a
ip route
ping -c 4 8.8.8.8
getent hosts example.com
sudo ss -tulpn

For a permission problem:

whoami
pwd
ls -ld .
ls -l target
namei -l /full/path/to/target

The command namei -l shows permissions along each component of a path. It is very useful for permission troubleshooting.

Example:

namei -l /var/www/site/uploads/image.jpg

This can reveal that the file itself is readable, but one parent directory blocks access.

Practical workflow: write commands as documentation

A good Linux command is also documentation. It shows what was done.

Compare this vague note:

I cleaned the logs.

with this clear command record:

sudo find /var/log/myapp -type f -name "*.gz" -mtime +30 -delete

The command tells you:

DetailInformation
Location/var/log/myapp
TypeRegular files only
PatternCompressed .gz files
AgeOlder than 30 days
ActionDelete

This is why command-line work is reproducible. The exact action can be reviewed and repeated.

For important operations, save the command and output.

sudo find /var/log/myapp -type f -name "*.gz" -mtime +30 -exec ls -lh {} \; | tee cleanup-preview.txt

Then after deletion:

sudo find /var/log/myapp -type f -name "*.gz" -mtime +30 -delete

Save a maintenance log:

{
    date
    hostname
    uptime
    df -h
    systemctl --failed
} | tee maintenance-check.txt

This creates a simple record of system state.

How to think about advanced shell work

Advanced shell usage is not about writing unreadable one-liners. It is about building reliable, inspectable workflows.

A good shell workflow has these qualities:

QualityMeaning
ClearYou can understand it later
SafeIt previews or limits destructive actions
QuotedVariables and paths are protected
LoggedImportant output is saved
RepeatableIt can run again with predictable behavior
TestableIt can be run manually before scheduling
RecoverableIt creates backups before risky changes
MinimalIt changes only what must be changed

A bad shell workflow is clever but fragile. A good shell workflow is boring, explicit and safe.

For example, this is risky:

rm -rf $(find . -name "*.tmp")

This is better:

find . -type f -name "*.tmp" -print

Then:

find . -type f -name "*.tmp" -delete

Better still when learning:

find . -type f -name "*.tmp" -exec rm -i {} \;

The safest Linux users are not the slowest. They are the ones who build verification into their workflow.

Terminal, shell, commands and built-in help

Before individual commands make sense, the relationship between the terminal, the shell, command syntax and built-in documentation must be clear.

Understanding the terminal, shell and command

Many people use the words terminal, shell and command as if they were the same thing. They are related, but not identical.

TermMeaningPractical explanation
TerminalThe interface window where you typeThe visible program that accepts keyboard input
ShellThe command interpreterThe program that reads and executes your commands
CommandThe instruction you runA program, shell built-in or script
PromptThe text shown before your inputIt often shows user, host and current directory
ArgumentThe target of a commandA filename, directory, user, service or option value
OptionA modifier that changes behaviorUsually begins with - or --

When you type this:

ls -lah /home/pat

you are typing into a terminal. The shell interprets the line. The command is ls. The options are -lah. The argument is /home/pat.

The shell then runs the ls program and displays the result in the terminal.

A typical shell prompt may look like this:

pat@server:~/projects$

This can be understood as:

Prompt partMeaning
patCurrent user
serverHostname of the machine
~/projectsCurrent directory
$Normal user prompt

If the prompt ends with #, it often means you are acting as the root user.

root@server:/etc#

This deserves attention. A root shell can change or damage the entire system.

The basic structure of a Linux command

Most Linux commands follow a predictable structure.

command options arguments

A simple example:

ls

This runs the command ls without extra options or arguments.

A more specific example:

ls -lah /var/log

This command has three parts.

PartValueMeaning
CommandlsList directory contents
Options-lahLong format, show hidden files, human-readable sizes
Argument/var/logThe directory to list

Options change how a command behaves. Arguments tell the command what to work on.

Short options usually begin with one dash.

ls -l

Long options usually begin with two dashes.

ls --all

Several short options can often be combined.

ls -l -a -h

can usually be written as:

ls -lah

This is why Linux commands may look cryptic at first. They are compact, but the logic is consistent.

CommandExpanded meaning
ls -lList in long format
ls -aList all files including hidden files
ls -hShow human-readable sizes
ls -lahCombine long format, all files and readable sizes

Not every command supports the same options. You should not assume that -h, -r or -f always means the same thing in every command. Many common patterns exist, but the manual is the final authority.

Getting help from Linux itself

One of the most important commands is man, which opens the manual page for another command.

man ls

Inside a manual page, you can usually use these keys:

KeyAction
SpaceMove forward one page
bMove backward one page
/wordSearch for a word
nGo to next search result
qQuit

The manual page may seem dense, but it teaches you how Linux documents itself.

Most commands also support quick help.

ls --help

Another useful tool is type, which tells you what kind of command you are running.

type cd
type ls
type grep

Example output may show that cd is a shell built-in while ls is an external program.

cd is a shell builtin
ls is /usr/bin/ls
grep is /usr/bin/grep

This matters because some commands are built directly into the shell, while others are separate executable files.

You can also locate commands with:

command -v ls
which ls

A good learning habit is this:

command --help
man command
type command
command -v command

Replace command with the command you are learning.

type, command, which and whereis

Linux offers several ways to identify commands.

type ls

This tells whether ls is a shell built-in, alias, function or external command.

command -v ls

This prints the path or command resolution.

which ls

This often prints the path of the executable.

whereis ls

This can show binary, source and manual locations.

Comparison:

CommandBest use
type commandUnderstand how the shell interprets a command
command -v commandScript-friendly command lookup
which commandQuick executable path lookup
whereis commandLocate binary and related manual/source paths

Examples:

type cd
type ls
type grep
command -v bash
whereis bash

You may see that cd is a shell built-in, while grep is an external program.

This distinction matters because built-ins affect the current shell. For example, cd must be a shell built-in because it changes the current directory of the shell itself.

man pages are the built-in university of Linux

The command man opens the manual page for a command.

man find

Manual pages are not always beginner-friendly, but they are precise and complete. A serious Linux user should learn how to read them.

A typical manual page has sections such as:

SectionPurpose
NAMEShort command name and summary
SYNOPSISSyntax structure
DESCRIPTIONWhat the command does
OPTIONSAvailable options
EXAMPLESSometimes included
FILESRelated files
SEE ALSORelated commands
AUTHORAuthor information
BUGSKnown issues or reporting information

Inside man, use:

KeyAction
SpaceNext page
bPrevious page
/wordSearch for word
nNext search result
NPrevious search result
qQuit

Example workflow:

man chmod

Search inside manual:

/recursive

Press n to move to the next occurrence.

Read the synopsis carefully. For example, syntax like this:

chmod [OPTION]... MODE[,MODE]... FILE...

has meaning.

SymbolMeaning
[OPTION]Optional option
...Can be repeated
MODEPermission mode
FILETarget file or directory

Manual pages become easier once you understand their notation.

apropos searches manual descriptions

If you do not know the command name, use apropos.

apropos password

This searches manual page descriptions for the word password.

Another example:

apropos network

If apropos gives poor results, the manual database may need updating:

sudo mandb

The command apropos is useful when you know what you want to do but not which command does it.

Example:

apropos "disk usage"

You may discover commands such as du or related tools.

help for shell built-ins

Some commands are shell built-ins, not external programs. For Bash built-ins, use help.

help cd
help export
help history

You can also use:

type cd

If it says:

cd is a shell builtin

then help cd is often more relevant than searching for an external executable.

This matters for commands such as:

Built-inPurpose
cdChange shell directory
echoPrint text
exportExport variables to environment
historyShow shell history
aliasDefine command shortcuts
jobsShow shell jobs
fgBring job to foreground
bgResume job in background

The shell itself is a tool, and built-ins are part of that tool.

The Linux filesystem, paths and essential directories

Linux commands operate inside a structured filesystem. Paths, core directories and file-like system interfaces explain where data lives and how Linux exposes system state.

The Linux filesystem as a tree

The most important structural idea in Linux is that the filesystem is a tree. Everything starts at /, called the root directory. Every file, folder, device and mounted disk appears somewhere under this root.

This is different from Windows, where drives are commonly shown as C:, D: and so on. Linux does not organize the system around drive letters. It organizes everything under one unified tree.

The root directory is written as:

/

A full path may look like this:

/home/pat/Documents/report.txt

This path can be read from left to right.

Path partMeaning
/Start at the root directory
homeEnter the home area
patEnter the user folder named pat
DocumentsEnter the Documents directory
report.txtOpen or refer to the file

Linux paths are case-sensitive. This means:

Documents
documents
DOCUMENTS

are three different names.

This is a common source of beginner errors. If a folder is named Downloads, this command will fail:

cd downloads

The correct command is:

cd Downloads

Absolute paths and relative paths

A path tells Linux where something is. There are two main types: absolute paths and relative paths.

Path typeDescriptionExample
Absolute pathStarts from / and gives the full location/home/pat/Documents/file.txt
Relative pathStarts from the current directoryDocuments/file.txt

An absolute path always begins with /.

cd /home/pat/Documents

This command works no matter where you currently are, because it gives the full address.

A relative path does not begin with /.

cd Documents

This command depends on your current directory. If you are in /home/pat, it means /home/pat/Documents. If you are in /var/log, it means /var/log/Documents.

This is why pwd is so important. Before running commands that change files, always know your current location.

pwd

Example output:

/home/pat

A few special path symbols are used constantly.

SymbolMeaningExample
.Current directoryfind . -name "*.txt"
..Parent directorycd ..
~Current user’s home directorycd ~
/Root directorycd /
-Previous directory with cdcd -

Examples:

cd .

This technically means stay in the current directory.

cd ..

This moves one level up.

cd ~

This moves to your home directory.

cd /

This moves to the root directory.

cd -

This returns to the previous directory.

Essential Linux directories

Linux directories are not random. They follow a long-established structure. You do not need to memorize every directory immediately, but you should understand the major ones because they appear constantly in commands, logs, configuration and administration.

DirectoryPurposePractical importance
/Root of the entire filesystemEverything begins here
/homeHome directories of normal usersPersonal files, documents, scripts and user configuration
/rootHome directory of the root userAdministrator’s private home folder
/etcSystem configuration filesNetwork, services, users, package sources and system settings
/varVariable data that changes over timeLogs, caches, mail, databases and web data
/var/logLog filesOne of the most important troubleshooting locations
/tmpTemporary filesShort-lived files created by users and programs
/usrInstalled software and shared system resourcesApplications, libraries and documentation
/usr/binMany user commandsCommon executable programs
/usr/sbinMany administrative commandsSystem administration tools
/binEssential basic commandsCritical commands needed during boot and recovery
/sbinEssential system commandsAdministrative commands needed during boot and repair
/bootBootloader and kernel filesNeeded for system startup
/devDevice filesDisks, partitions, terminals and hardware interfaces
/procVirtual process and kernel informationLive system data exposed as files
/sysKernel and hardware informationDevice and driver information
/mediaMount point for removable mediaUSB drives and external disks may appear here
/mntTemporary manual mount pointCommon place for manually mounted filesystems
/optOptional third-party softwareSome manually installed applications live here

The most important practical distinction is between user space and system space.

Your home directory is usually safe for personal work.

/home/pat

System directories require caution.

/etc
/usr
/var
/boot
/dev

A useful rule is: inside your home directory you are usually managing your own data; outside your home directory you may be changing the operating system.

The root directory and the root user are not the same thing

Beginners often confuse / with the root user.

The root directory is the top of the filesystem.

/

The root user is the administrative superuser.

root

The root user’s home directory is:

/root

These are three related but different concepts.

TermMeaning
/Root directory of the filesystem
rootAdministrative superuser account
/rootHome directory of the root user

This distinction matters. When someone says “go to root,” they may mean the root directory /. When someone says “run as root,” they mean run with administrative privileges. When someone says “root’s home,” they mean /root.

The deeper structure behind Linux commands

At this point, the command line is no longer just a set of tools. It is a coherent model of the operating system.

Linux exposes system reality through:

System realityCommand-line representation
FilesPaths, permissions, ownership, timestamps
ProgramsProcesses, PIDs, services
UsersUID, GID, groups
StorageFilesystems, mounts, blocks, inodes
NetworkInterfaces, routes, ports, sockets
LogsText files or journal entries
ConfigurationMostly text files under /etc
AutomationScripts, cron jobs, services
SecurityPermissions, ownership, sudo, SSH keys

The same command patterns repeat everywhere.

To inspect:

ls
cat
less
systemctl status
journalctl

To search:

grep
find
awk

To count:

wc
uniq -c

To transform:

sed
awk
cut
sort

To act:

cp
mv
rm
chmod
chown
systemctl restart
apt install

To automate:

bash scripts
crontab
systemd timers

A beginner learns commands. An expert sees patterns.

Linux becomes powerful when you understand what is a file and what only looks like a file

One of the most important ideas in Linux is that many things are represented as files or file-like objects. This does not mean everything is a normal document stored on disk. It means the operating system exposes devices, processes, kernel information, terminals, sockets and system state through file paths.

This design gives the command line extraordinary power. You can inspect a process through /proc. You can inspect hardware through /sys. You can see devices in /dev. You can read logs in /var/log. You can configure services through text files under /etc. You can redirect output into files, read from files and connect commands through streams.

A beginner sees files as documents. A Linux administrator sees files as the interface of the operating system.

LocationWhat it representsPractical meaning
/etcConfiguration filesSystem and service behavior
/var/logLog filesEvidence of events and errors
/devDevice filesDisks, terminals, random generators, hardware interfaces
/procProcess and kernel informationLive runtime system state
/sysKernel device modelHardware, drivers and low-level system information
/runRuntime statePID files, sockets, temporary service state
/tmpTemporary filesShort-lived files used by users and programs
/var/tmpTemporary files that may persist longerTemporary data not always removed on reboot

The directories /proc and /sys are especially important because they are virtual filesystems. Their contents are not ordinary files stored on disk. They are generated by the kernel to expose live information.

For example:

cat /proc/cpuinfo

shows CPU information.

cat /proc/meminfo

shows memory information.

ls /proc

shows many numbered directories. Those numbers are process IDs.

If a process has PID 1234, then this directory may exist:

/proc/1234

Inside it, Linux exposes information about that running process.

ls -lah /proc/1234

This can show process command line, environment, file descriptors, current working directory and executable path.

This is why Linux troubleshooting often feels transparent. The system exposes itself through inspectable paths.

Understanding /proc through real examples

The /proc filesystem is one of the most useful places for understanding a running Linux system. It contains live information about processes and kernel state.

Show CPU information:

cat /proc/cpuinfo

Show memory information:

cat /proc/meminfo

Show kernel command line used at boot:

cat /proc/cmdline

Show mounted filesystems:

cat /proc/mounts

Show uptime directly from proc:

cat /proc/uptime

Show load average:

cat /proc/loadavg

Many normal commands read from /proc internally or present the same kind of information in a more readable way.

CommandRelated proc information
uptime/proc/uptime, /proc/loadavg
free/proc/meminfo
ps/proc/PID/ directories
mount/proc/mounts
topProcess and memory information from /proc

This means Linux tools often transform raw system information into readable output.

For example, compare:

cat /proc/meminfo

with:

free -h

The first shows detailed raw memory fields. The second summarizes memory in a more human-friendly way.

Both are useful. The command is easier for daily work. The proc file is useful for deeper understanding and scripts.

Inspecting a running process through /proc

Suppose a process has PID 1234.

Show the command line that started it:

tr '\0' ' ' < /proc/1234/cmdline

Show the executable path:

readlink -f /proc/1234/exe

Show the process working directory:

readlink -f /proc/1234/cwd

Show open file descriptors:

ls -lah /proc/1234/fd

Show environment variables:

sudo tr '\0' '\n' < /proc/1234/environ

The null character \0 is used internally as a separator in some proc files, so tr converts it into spaces or new lines for readability.

This process inspection is extremely useful when you need to answer questions such as:

QuestionCommand
What command started this process?tr '\0' ' ' < /proc/PID/cmdline
Which binary is running?readlink -f /proc/PID/exe
What directory is it running from?readlink -f /proc/PID/cwd
What files does it have open?ls -lah /proc/PID/fd
What environment does it have?tr '\0' '\n' < /proc/PID/environ

This is especially helpful when ps aux shows a process but not enough detail.

Example workflow:

ps aux | grep myapp

Find the PID, then:

readlink -f /proc/PID/exe
readlink -f /proc/PID/cwd
tr '\0' ' ' < /proc/PID/cmdline

Replace PID with the real process ID.

File descriptors explain open files and sockets

Every running process can have open file descriptors. A file descriptor is a numeric handle used by a process to read from or write to something.

Common file descriptors are:

DescriptorMeaning
0Standard input
1Standard output
2Standard error

But processes can have many more. They may point to files, pipes, sockets, devices or deleted files.

Inspect file descriptors for a process:

ls -lah /proc/PID/fd

You may see output like:

0 -> /dev/null
1 -> /var/log/myapp/output.log
2 -> /var/log/myapp/error.log
3 -> socket:[123456]
4 -> /var/lib/myapp/data.db

This tells you what the process is connected to.

A process writing to a deleted file may show something like:

1 -> /var/log/myapp/old.log (deleted)

This explains why disk space may remain used even after deleting a large file.

Use lsof for a more readable view:

sudo lsof -p PID

Find deleted open files:

sudo lsof | grep deleted

This is one of the most important advanced disk troubleshooting commands.

Understanding /dev and device files

The /dev directory contains device files. These are special files that represent devices or kernel interfaces.

List some devices:

ls -lah /dev | head

Common examples:

DeviceMeaning
/dev/sdaFirst detected disk in many systems
/dev/sda1First partition on that disk
/dev/sdbAnother disk
/dev/nullDiscards all data written to it
/dev/zeroProduces endless zero bytes
/dev/randomRandom data source
/dev/urandomNon-blocking random data source
/dev/ttyCurrent terminal
/dev/pts/0Pseudo-terminal session

The special file /dev/null is used constantly in shell work.

Discard normal output:

command > /dev/null

Discard error output:

command 2> /dev/null

Discard everything:

command > /dev/null 2>&1

This is useful in scripts when you intentionally do not need output. But it can also hide errors, so use it carefully.

Example:

tar -tzf backup.tar.gz > /dev/null 2>&1

This tests whether the archive can be read without printing the file list. The exit status tells whether it succeeded.

echo $?

Understanding /run and runtime state

The /run directory stores runtime data. This data is created after boot and usually does not persist across reboots.

Examples include:

Runtime dataPurpose
PID filesStore process IDs for services
SocketsLocal communication endpoints
Lock filesIndicate that a resource is in use
Service stateTemporary status files
User sessionsRuntime information about logged-in users

List /run:

ls -lah /run

Look for service-related runtime files:

ls -lah /run | head

Some services create sockets under /run.

Example:

find /run -type s 2> /dev/null | head

The -type s option in find searches for sockets.

Runtime files can explain how services communicate locally. For example, databases, PHP-FPM, system services and desktop sessions may use Unix sockets stored under /run.

A socket is not a normal text file. It is a communication endpoint.

Check file type:

ls -l /run/some-socket

You may see the first character s, meaning socket.

Understanding /etc as the configuration center

The /etc directory is where most system-wide configuration lives. It is one of the most important directories on a Linux system.

Examples:

PathPurpose
/etc/hostsLocal hostname mappings
/etc/hostnameStatic hostname on many systems
/etc/fstabPersistent filesystem mounts
/etc/passwdUser account information
/etc/groupGroup information
/etc/shadowProtected password hash information
/etc/ssh/sshd_configSSH server configuration
/etc/systemd/system/Custom systemd unit files
/etc/apt/sources.listAPT repository configuration
/etc/apt/sources.list.d/Additional APT source files
/etc/nginx/Nginx configuration
/etc/apache2/Apache configuration on Debian-based systems

Because /etc controls system behavior, editing it requires discipline.

A safe configuration editing workflow is:

sudo cp /etc/service/config.conf /etc/service/config.conf.$(date +%Y-%m-%d-%H-%M).backup
sudo nano /etc/service/config.conf

Then test if possible:

sudo service-name --test-config

Then reload or restart:

sudo systemctl reload service-name

Then verify:

systemctl status service-name
journalctl -u service-name -n 50

Never treat /etc as an ordinary personal notes folder. It is the control panel of the operating system.

The difference between configuration, state and data

Linux systems contain different kinds of information. Mixing them up causes bad backups, bad migrations and bad repairs.

TypeMeaningCommon location
ConfigurationDefines behavior/etc, application config directories
StateCurrent runtime condition/run, service memory, PID files
DataUser or application content/home, /var/lib, /var/www, databases
LogsRecords of events/var/log, journal
CacheRebuildable temporary data/var/cache, application cache folders
BinariesExecutable programs/bin, /usr/bin, /usr/sbin
LibrariesShared code used by programs/lib, /usr/lib

This matters for backups.

A website may require:

ComponentExample
Code files/var/www/site
Uploaded files/var/www/site/uploads
Configuration/etc/nginx, application .env file
DatabaseMySQL, PostgreSQL, SQLite or another database
Scheduled jobsUser crontab or systemd timers
Service definitions/etc/systemd/system
SSL certificatesOften under /etc/letsencrypt or service-specific paths

A backup of /var/www/site alone may not be enough.

A migration plan should identify all required components.

Understanding /var/lib as application state

The directory /var/lib often stores application state and persistent data managed by services.

Examples may include:

PathPossible purpose
/var/lib/mysqlMySQL or MariaDB data
/var/lib/postgresqlPostgreSQL data
/var/lib/dockerDocker data
/var/lib/aptAPT package state
/var/lib/systemdsystemd state
/var/lib/dpkgDebian package database

Do not casually delete content from /var/lib. It may contain databases, package metadata or service state.

Check size:

sudo du -h --max-depth=1 /var/lib | sort -h

If /var/lib/docker is huge, the answer is not simply:

sudo rm -rf /var/lib/docker

That can destroy containers, images and volumes.

Instead, use the appropriate application tools.

The same logic applies to databases. Do not delete database files manually unless you understand the database engine and recovery plan.

Understanding /var/cache

The directory /var/cache stores cache data. Cache is usually rebuildable, but it can still matter.

Check size:

sudo du -h --max-depth=1 /var/cache | sort -h

APT package cache:

sudo du -sh /var/cache/apt

Clean APT cache:

sudo apt clean

Application caches may live under /var/cache, but do not delete them blindly. Some services expect cache directories to exist with correct ownership.

A safe cache cleanup process is:

sudo du -h --max-depth=1 /var/cache | sort -h

Then identify the application. Read documentation or service status. Stop the service if needed. Clean only the correct cache. Restart or reload. Verify logs.

Cache is generally less critical than data, but uncontrolled deletion can still cause service disruption.

Understanding /var/log as evidence

The directory /var/log is not just storage. It is evidence.

Before deleting logs, consider whether you need them for troubleshooting, security analysis or compliance.

Check log size:

sudo du -h --max-depth=1 /var/log | sort -h

Find large logs:

sudo find /var/log -type f -size +100M -exec ls -lh {} \;

Search errors:

sudo grep -R -i "error" /var/log 2> /dev/null | head

Check recent logs:

journalctl -p warning -n 100

If logs are huge, ask why.

SymptomPossible cause
One log file grows rapidlyApplication error loop
Many compressed logs existRetention too long
Journal uses large spacesystemd journal retention not limited
Auth log grows quicklySSH brute force attempts
Web access log hugeHigh traffic or bot activity
Error log hugeMisconfiguration or application failure

Deleting logs may free space but hide the cause.

A safer approach is to archive, truncate if necessary and fix the underlying problem.

Working with journal and text logs together

Some systems use both traditional log files and systemd journal logs. You may need both.

For a service:

journalctl -u nginx -n 100

Traditional Nginx logs:

tail -n 100 /var/log/nginx/error.log
tail -n 100 /var/log/nginx/access.log

For SSH:

journalctl -u ssh -n 100

or:

sudo tail -n 100 /var/log/auth.log

For package operations:

cat /var/log/apt/history.log

and:

journalctl -u apt-daily.service

The exact logging location depends on the distribution, service and configuration.

A good habit is to check both service logs and application-specific logs.

Understanding system boot at a practical level

Boot is the process that starts the Linux system. You do not need to know every low-level detail at first, but you should understand the practical sequence.

A simplified boot flow:

StageMeaning
FirmwareHardware initializes and loads bootloader
BootloaderLoads Linux kernel and initial RAM disk
KernelInitializes hardware and core system
init systemStarts user space services
systemd targetBrings system to multi-user or graphical state
ServicesNetwork, SSH, web servers, databases and other daemons start

On many modern systems, systemd manages services during boot.

Check boot logs:

journalctl -b

Check previous boot:

journalctl -b -1

List boots:

journalctl --list-boots

Check failed services after boot:

systemctl --failed

Check boot time summary:

systemd-analyze

Show slow services:

systemd-analyze blame

Show critical chain:

systemd-analyze critical-chain

This helps diagnose slow boot or services delaying startup.

Safety principles before changing the system

Administrative power is useful only when it is controlled. The safest Linux work happens when every edit, deletion, restart or installation is preceded by inspection and followed by verification.

Normal user privileges and sudo

Linux is designed around users and permissions. A normal user should be able to manage personal files but should not accidentally damage system files. Administrative changes require elevated privileges.

The most common way to run a command with administrative privileges is sudo.

sudo apt update

This means: run apt update as a superuser, if the current user is allowed to use sudo.

Common tasks that usually require sudo include installing software, editing system configuration, restarting system services, changing ownership of system files and mounting disks.

TaskNeeds sudo?Example
List files in your home directoryUsually nols ~/Documents
Create a folder in your home directoryUsually nomkdir ~/projects
Edit your own text fileUsually nonano notes.txt
Install softwareYessudo apt install htop
Update package listsYessudo apt update
Edit system configurationYessudo nano /etc/hosts
Restart a serviceYessudo systemctl restart apache2
Change ownership of system filesYessudo chown user:group file
Mount a disk manuallyUsually yessudo mount /dev/sdb1 /mnt/usb

A dangerous beginner habit is using sudo for everything. That is not necessary and not safe. Use sudo only when the task requires it.

Compare these two commands:

rm notes.txt

This removes a file in the current directory if your user has permission.

sudo rm notes.txt

This removes it with elevated privileges. If you are in the wrong directory, the risk is higher.

The more power a command has, the more carefully it should be checked.

How to read command examples correctly

Many command examples use placeholders. A placeholder is not meant to be typed literally. It represents something you must replace.

Example:

cp  

You should not type and exactly. You replace them with real paths.

Correct example:

cp report.txt /home/pat/Documents/

Common placeholders include:

PlaceholderMeaningReal example
A file namenotes.txt
A directory name/home/pat/projects
A usernamepat
A hostname or IP address192.168.1.10
A package namehtop
A service nameapache2
A command to runls -lah

When you see:

ssh @

you should type something like:

ssh pat@192.168.1.10

Understanding placeholders prevents many beginner mistakes.

Your first safety workflow

Before learning many commands, learn this safety workflow:

pwd
ls -lah

This shows where you are and what is there.

Add one more command when working with directories:

tree -L 2

If tree is not installed, use:

find . -maxdepth 2

A safe inspection sequence is:

pwd
ls -lah
tree -L 2
du -sh .

This gives four layers of understanding.

CommandWhat it tells you
pwdCurrent location
ls -lahFiles, folders, permissions, owners, sizes and hidden entries
tree -L 2Structure two levels deep
du -sh .Total size of the current directory

This sequence does not modify anything. It is safe. It is also professional. Many serious mistakes happen because users act before inspecting.

The safest way to learn Linux commands

The safest way to learn Linux commands is to create a practice directory in your home folder and experiment there.

mkdir -p ~/linux-command-lab
cd ~/linux-command-lab
pwd

Inside this lab, create sample files:

mkdir documents logs scripts backups
touch documents/report.txt
touch logs/app.log
touch scripts/backup.sh

Display the structure:

tree

Expected structure:

.
├── backups
├── documents
│   └── report.txt
├── logs
│   └── app.log
└── scripts
    └── backup.sh

Now you can safely practice copying, moving, renaming, reading and deleting.

cp documents/report.txt backups/report-backup.txt
mv logs/app.log logs/application.log
ls -lah logs
tree

Remove practice files only after inspecting:

ls -lah backups
rm -i backups/report-backup.txt

This practice environment prevents damage to real files.

Remote administration safety habits

Remote Linux work requires extra caution because mistakes can affect systems you cannot physically access.

Use these habits:

HabitWhy it matters
Confirm hostname after SSH loginPrevents working on wrong server
Keep one SSH session open during critical changesMaintains recovery access
Use screen or tmux for long tasksSurvives connection loss
Back up config files before editingAllows quick rollback
Test configuration before reloadingPrevents service failure
Use --dry-run with rsyncPrevents accidental file deletion
Avoid rm -rf over SSH unless fully verifiedRemote deletion is hard to recover
Check disk space before upgradesFull disks can break package operations
Reload instead of restart when appropriateReduces disruption
Read logs before changing settingsAvoids blind troubleshooting

A safe remote maintenance start:

ssh pat@server
hostname
whoami
uptime
df -h
systemctl --failed

A safe config edit pattern:

sudo cp /etc/service/config.conf /etc/service/config.conf.backup
sudo nano /etc/service/config.conf
sudo service-name --test-config
sudo systemctl reload service-name

The exact test command depends on the service.

Security notes for remote commands

Remote commands are powerful. They also carry risk.

Be especially careful with commands like:

ssh server "rm -rf /path"

or:

rsync -av --delete source/ server:/important/path/

Before destructive remote operations, run inspection commands.

ssh server "pwd; hostname; ls -lah /important/path"

For rsync, run:

rsync -av --delete --dry-run source/ server:/important/path/

For remote deletion, list first:

ssh server "find /path -type f -name '*.tmp' -mtime +30 -print"

Then delete only if correct:

ssh server "find /path -type f -name '*.tmp' -mtime +30 -delete"

A remote command should be treated with more caution than a local command because recovery may be harder.

Least privilege in practice

Least privilege means giving only the access required, not more.

Bad habit:

sudo chmod -R 777 /var/www/site

Better:

sudo find /var/www/site -type d -exec chmod 755 {} \;
sudo find /var/www/site -type f -exec chmod 644 {} \;

Then grant write access only where needed.

sudo chown -R www-data:www-data /var/www/site/uploads

Bad habit:

sudo chown -R www-data:www-data /var/www/site

This may make the web server own everything, including code files. If the application is compromised, an attacker may be able to modify application code more easily.

A better model may be:

AreaOwnerPermission idea
Application codedeploy:www-dataWeb server can read, deploy user can write
Uploadswww-data:www-data or controlled groupWeb server can write
Cachewww-data:www-dataWeb server can write
Configuration secretsrestricted owner and groupOnly required users can read
Scriptsdeploy or rootExecutable only where needed

There is no universal permission model for every application, but the principle is universal: do not give write access where read access is enough.

Dangerous commands and why they are dangerous

Some commands are not bad, but they are dangerous when used without context.

Command patternRisk
rm -rf pathDeletes recursively without confirmation
chmod -R 777 pathGives everyone full access
chown -R user:group pathChanges ownership for many files
find / -exec rm {} \;Can delete across the system
rsync --deleteRemoves destination files not in source
dd if=... of=...Can overwrite disks
mkfsCreates filesystem and destroys existing data
kill -9Forces process termination without cleanup
sudo commandRuns with elevated privileges
> fileOverwrites file content
truncate -s 0 fileEmpties file content

Before running dangerous commands, use a safety checklist.

hostname
whoami
pwd
ls -lah

For file deletion:

find /target/path -type f -name "*.tmp" -print

Then:

find /target/path -type f -name "*.tmp" -delete

For rsync --delete:

rsync -av --delete --dry-run source/ destination/

Then:

rsync -av --delete source/ destination/

For recursive ownership changes:

ls -ld /target/path
find /target/path -maxdepth 2 -exec ls -ld {} \; | head

Then apply only if correct.

A dangerous command should never be the first command in a workflow.

Operational discipline: one change at a time

When fixing a Linux problem, make one meaningful change at a time.

Bad workflow:

sudo chmod -R 777 /var/www/site
sudo chown -R www-data:www-data /var/www/site
sudo systemctl restart nginx
sudo apt upgrade

After this, if the problem is fixed or worse, you do not know which change mattered.

Better workflow:

systemctl status nginx
journalctl -u nginx -n 100
namei -l /var/www/site/index.html

Then one change:

sudo chmod 755 /var/www/site

Verify:

curl -I http://localhost

Then another change only if needed.

One change at a time makes troubleshooting learnable and reversible.

Operational discipline: save the exact command

When a command solves a problem, save it.

Create notes:

mkdir -p ~/ops/notes
nano ~/ops/notes/fixes.md

Add:

Problem:
Nginx failed because port 80 was already used.

Diagnosis:
sudo ss -tulpn | grep ':80'
sudo lsof -i :80

Fix:
sudo systemctl stop old-service
sudo systemctl restart nginx

Verification:
curl -I http://localhost
systemctl status nginx

This creates institutional memory, even if you are the only administrator.

Search later:

grep -i "port 80" ~/ops/notes/fixes.md

Linux knowledge grows faster when commands are documented in context.

Operational discipline: build command templates

Many Linux tasks repeat with small changes. Templates reduce mistakes.

Find large files template:

sudo find /PATH -type f -size +SIZE -exec ls -lh {} \;

Example:

sudo find /var/log -type f -size +100M -exec ls -lh {} \;

Rsync preview template:

rsync -avz --delete --dry-run SOURCE/ USER@HOST:DESTINATION/

Service diagnosis template:

systemctl status SERVICE
journalctl -u SERVICE -n 100
sudo ss -tulpn | grep PORT

Permission diagnosis template:

whoami
id
ls -l FILE
namei -l FILE

Backup template:

tar -czf NAME-$(date +%Y-%m-%d-%H-%M).tar.gz SOURCE
tar -tzf NAME-$(date +%Y-%m-%d-%H-%M).tar.gz | head

Templates are safer than rewriting complex commands from memory every time.

Navigation and inspection commands

Navigation and inspection commands answer the first operational questions: where am I, what is here and what does it look like?

pwd: know your current location

The command pwd means print working directory.

pwd

Example output:

/home/pat/projects

This tells you that your terminal is currently working inside /home/pat/projects.

The current directory matters because many commands operate relative to it.

If you type:

rm test.txt

Linux looks for test.txt in the current directory.

If you type:

cp report.txt backup/

Linux looks for report.txt and backup/ relative to where you are now.

This is why pwd should become automatic before file operations.

Use pwd before:

OperationWhy
Removing filesTo avoid deleting from the wrong directory
Moving filesTo understand source and target
Copying filesTo avoid copying wrong data
Running scriptsTo know where relative paths resolve
Editing configurationTo avoid editing the wrong file
Creating archivesTo avoid archiving the wrong folder

Example:

pwd
ls -lah
rm -i old-notes.txt

This is much safer than running rm blindly.

cd: move through the filesystem

The command cd means change directory.

Go to a specific absolute path:

cd /home/pat/Documents

Go to a directory relative to your current location:

cd Documents

Go to your home directory:

cd

or:

cd ~

Go to the root directory:

cd /

Go one level up:

cd ..

Go two levels up:

cd ../..

Return to the previous directory:

cd -

This command is useful when switching between two directories.

Example:

cd /var/log
pwd
cd /etc
pwd
cd -
pwd

The last cd - returns you to /var/log.

Understanding cd .. is essential. If you are in:

/home/pat/projects/linux/scripts

and run:

cd ..

you move to:

/home/pat/projects/linux

Run it again:

cd ..

Now you are in:

/home/pat/projects

Linux path navigation is logical once you think in levels.

Common cd mistakes

The cd command is simple, but beginners often run into predictable problems.

MistakeExampleWhy it failsCorrect approach
Wrong letter casecd downloadsThe folder is Downloadscd Downloads
Spaces not quotedcd My FolderShell sees two argumentscd "My Folder"
Trying to enter a filecd notes.txtFiles are not directoriesUse cat, nano or less
Wrong current directorycd projectproject is not inside current directoryUse absolute path
Missing permissionscd /rootNormal user cannot enterUse appropriate privileges only when justified

Handling spaces:

cd "My Folder"

or:

cd My\ Folder

The backslash tells the shell that the space belongs to the folder name.

However, for command-line work, names without spaces are usually easier.

Better:

my-folder
my_folder
project-backup

Less convenient:

My Folder
Project Backup Final
New Documents Copy

Spaces are allowed, but they require more care.

ls: list files and directories

The command ls lists directory contents.

Basic use:

ls

List a specific directory:

ls /home/pat/Documents

Long format:

ls -l

Show hidden files:

ls -a

Human-readable sizes:

ls -h

Common combined form:

ls -lah

This is one of the most useful commands in Linux.

A typical ls -lah output may look like this:

drwxr-xr-x  5 pat pat 4.0K May 14 10:20 .
drwxr-xr-x 25 pat pat 4.0K May 14 09:55 ..
-rw-r--r--  1 pat pat 1.2K May 14 10:18 notes.txt
-rwxr-xr-x  1 pat pat  842 May 14 10:19 backup.sh
drwxr-xr-x  2 pat pat 4.0K May 14 10:20 logs

This output contains a lot of information.

ColumnExampleMeaning
Type and permissions-rw-r--r--File type and access rights
Link count1Number of hard links
OwnerpatUser owner
GrouppatGroup owner
Size1.2KFile size
Date and timeMay 14 10:18Last modification time
Namenotes.txtFile or directory name

The first character tells you the type.

First characterMeaning
-Regular file
dDirectory
lSymbolic link
bBlock device
cCharacter device
sSocket
pNamed pipe

This means:

-rw-r--r--

is a regular file.

drwxr-xr-x

is a directory.

lrwxrwxrwx

is a symbolic link.

Understanding the first column of ls -l is the beginning of understanding Linux permissions.

Hidden files in Linux

In Linux, hidden files are not hidden through a special property. They are hidden because their names begin with a dot.

Examples:

.bashrc
.profile
.ssh
.config
.cache

The normal ls command does not show them.

ls

To show hidden files, use:

ls -a

To show hidden files with details and readable sizes:

ls -lah

Hidden files often store user configuration.

Hidden file or directoryCommon purpose
.bashrcBash shell configuration
.profileLogin shell environment settings
.sshSSH keys and configuration
.configUser application configuration
.cacheUser cache files
.localUser-local applications and data

Do not delete hidden files casually. Some of them are important for login, shell behavior, SSH access or application settings.

Practical ls patterns

The ls command becomes more useful when you learn common patterns.

CommandPurpose
lsSimple list
ls -lDetailed list
ls -aInclude hidden files
ls -hHuman-readable sizes
ls -lahDetailed list with hidden files and readable sizes
ls -ltSort by modification time, newest first
ls -ltrSort by modification time, oldest first
ls -RList recursively
ls *.txtShow only files ending in .txt
ls /var/logList another directory
ls -ld folderShow information about the folder itself, not its contents

The command:

ls -ld /var/log

shows information about the directory /var/log itself.

The command:

ls -l /var/log

shows what is inside /var/log.

This difference matters when checking permissions on a directory.

tree: see the structure clearly

The command tree displays a directory structure visually.

tree

Example output:

.
├── documents
│   ├── report.txt
│   └── notes.txt
├── scripts
│   └── backup.sh
└── logs
    └── app.log

This is much easier to understand than a flat list when working with projects.

Show a specific directory:

tree /home/pat/projects

Limit depth:

tree -L 2

Show only directories:

tree -d

Show hidden files too:

tree -a

Show human-readable sizes:

tree -h

Combine options:

tree -a -h -L 2

If tree is not installed:

sudo apt update
sudo apt install tree

A useful alternative using find:

find . -maxdepth 2

This lists files and directories up to two levels below the current directory.

Creating, reading, copying, moving and deleting files

Most real Linux work begins with files. Creating, reading, editing, copying, moving, linking and deleting data should be done with enough context to avoid accidental damage.

mkdir: create directories

The command mkdir creates directories.

mkdir test

This creates a directory named test in the current location.

Create a directory using an absolute path:

mkdir /home/pat/test

Create multiple directories:

mkdir documents scripts backups

Create nested directories:

mkdir -p projects/linux/scripts

The -p option means create parent directories if they do not exist.

Without -p, this can fail:

mkdir projects/linux/scripts

if projects or projects/linux does not already exist.

With -p, Linux creates the full structure.

mkdir -p projects/linux/scripts

This is especially useful in scripts because it avoids errors when parent directories are missing.

Common mkdir examples:

CommandMeaning
mkdir logsCreate logs in current directory
mkdir ~/backupsCreate backups in home directory
mkdir -p ~/projects/app/logsCreate nested directory structure
mkdir dir1 dir2 dir3Create three directories
mkdir -m 755 publicCreate directory with specific permissions

The command mkdir -m sets permissions during creation.

mkdir -m 700 private

This creates a directory accessible only to the owner.

touch: create empty files and update timestamps

The command touch creates an empty file if the file does not exist.

touch notes.txt

If the file already exists, touch updates its modification timestamp.

Create multiple files:

touch file1.txt file2.txt file3.txt

Create a file in another directory:

touch /home/pat/Documents/notes.txt

Why use touch?

Use caseExplanation
Create an empty placeholder fileUseful before adding content
Test write permissionsIf touch fails, you may not have write access
Update modification timeUseful in scripts and build systems
Prepare a log fileA script can later append to it
Create files quicklyFaster than opening an editor

Example permission test:

touch /var/log/test-file

As a normal user, this will likely fail.

touch: cannot touch '/var/log/test-file': Permission denied

That tells you the directory is protected.

Inside your home directory, this should work:

touch ~/test-file

nano: edit text files from the terminal

The command nano opens a simple terminal text editor.

nano notes.txt

If notes.txt exists, nano opens it. If it does not exist, nano creates it when you save.

Open a file in another directory:

nano /home/pat/Documents/notes.txt

Edit a system file with administrative privileges:

sudo nano /etc/hosts

Important nano shortcuts:

ShortcutMeaning
Ctrl + OSave file
EnterConfirm filename after saving
Ctrl + XExit
Ctrl + WSearch
Ctrl + KCut current line
Ctrl + UPaste
Ctrl + CShow cursor position
Ctrl + GOpen help

A safe configuration editing workflow:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
sudo nano /etc/ssh/sshd_config

This creates a backup before editing.

That habit is extremely important. Many Linux problems are caused by editing configuration files without keeping a known-good copy.

A practical rule: before editing an important file under /etc, make a backup first.

cat: display and concatenate files

The command cat displays file content.

cat notes.txt

It can also concatenate multiple files.

cat part1.txt part2.txt part3.txt

Save combined output to a new file:

cat part1.txt part2.txt part3.txt > complete.txt

Display all text files matching a pattern:

cat *.txt

The * character is a wildcard. It means any characters.

PatternMeaning
*.txtAll files ending with .txt
log-*All files beginning with log-
file?.txtFiles like file1.txt, file2.txt, but not file10.txt

Use cat for short files. Do not use it blindly on huge logs because it can flood your terminal.

Good uses of cat:

SituationExample
Display a short notecat notes.txt
Check a small config filecat app.conf
Combine filescat a.txt b.txt > c.txt
Send content into a pipeline`cat file.txt

Although this works:

cat app.log | grep error

this is usually simpler:

grep error app.log

Still, cat remains useful because it is easy to understand and often appears in examples and scripts.

more and less: read long files safely

The command more displays long files page by page.

more long-file.txt

Basic controls:

KeyAction
SpaceNext page
EnterNext line
qQuit

A more powerful alternative is less.

less long-file.txt

Despite the name, less is more capable than more.

Useful controls inside less:

KeyAction
SpaceNext page
bPrevious page
Up arrowScroll up
Down arrowScroll down
/wordSearch for word
nNext search match
NPrevious search match
gGo to beginning
GGo to end
qQuit

Use less for logs, configuration files and command output that is too long for one screen.

Example:

less /var/log/syslog

Search inside it:

/error

Then press n to jump to the next match.

head: inspect the beginning of a file

The command head shows the first lines of a file.

head file.txt

By default, it shows the first 10 lines.

Show the first 20 lines:

head -n 20 file.txt

or:

head -20 file.txt

head is useful when you need to understand the structure of a file quickly.

Examples:

head /etc/passwd
head -n 5 data.csv
head -n 30 app.log

Common uses:

File typeWhy head helps
CSV filesSee column names and format
LogsSee initial format and source
ScriptsRead interpreter line and comments
Configuration filesRead introductory comments
Data exportsConfirm structure before processing

For example, before processing a CSV file with awk or cut, use:

head -n 3 data.csv

This helps you avoid wrong assumptions about delimiters and columns.

tail: inspect the end of a file

The command tail shows the last lines of a file.

tail file.txt

By default, it shows the last 10 lines.

Show the last 50 lines:

tail -n 50 file.txt

Follow a file in real time:

tail -f file.txt

This is one of the most important commands for Linux troubleshooting.

For example:

sudo tail -f /var/log/syslog

This shows new system log entries as they are written.

Another example:

sudo tail -f /var/log/auth.log

This can show authentication-related events on many Debian-based systems.

A practical service debugging workflow:

sudo systemctl restart apache2
sudo tail -f /var/log/apache2/error.log

This restarts Apache and then watches the error log.

Stop tail -f with:

Ctrl + C

Useful tail patterns:

CommandMeaning
tail file.txtShow last 10 lines
tail -n 100 file.txtShow last 100 lines
tail -f file.txtFollow new lines live
tail -n 50 -f file.txtShow last 50 lines and continue following

cp: copy files and directories

The command cp copies files.

Basic copy:

cp source.txt target.txt

Copy a file into a directory:

cp report.txt /home/pat/Documents/

Copy and rename at the same time:

cp report.txt /home/pat/Documents/final-report.txt

Copy multiple files into a directory:

cp file1.txt file2.txt file3.txt /home/pat/Documents/

Copy a directory recursively:

cp -r project project-backup

The -r option means recursive. It copies a directory and everything inside it.

Important cp options:

OptionMeaning
-rCopy directories recursively
-iAsk before overwriting
-vShow what is being copied
-uCopy only when the source is newer
-aArchive mode, preserving structure and metadata

Archive mode is often better for backups.

cp -a website website-backup

This preserves permissions, timestamps and symbolic links more carefully than a simple recursive copy.

A safe copy command:

cp -av project project-backup

This copies in archive mode and shows what is happening.

mv: move and rename files

The command mv moves or renames files and directories.

Rename a file:

mv oldname.txt newname.txt

Move a file:

mv report.txt /home/pat/Documents/

Move and rename at the same time:

mv report.txt /home/pat/Documents/final-report.txt

Rename a directory:

mv old-project new-project

Move a directory:

mv project /home/pat/backups/

Important options:

OptionMeaning
-iAsk before overwriting
-vShow what is being moved
-nDo not overwrite existing files

Safer move:

mv -iv draft.txt final.txt

Unlike cp, mv does not require -r for directories.

A practical difference:

CommandWhat happens
cp file backup/Original file remains
mv file backup/Original file is moved
mv old newFile or directory is renamed

Be careful when moving files across filesystems. Moving inside the same filesystem is usually very fast because Linux changes directory references. Moving across disks may require copying data and deleting the original.

rm: remove files and directories

The command rm removes files.

rm file.txt

Remove multiple files:

rm file1.txt file2.txt file3.txt

Ask before removing:

rm -i file.txt

Remove a directory recursively:

rm -r folder

Force deletion:

rm -f file.txt

Recursive forced deletion:

rm -rf folder

This is powerful and dangerous.

OptionMeaning
-rRecursive, remove directories and their contents
-fForce, do not ask
-iAsk before every removal
-IAsk once before removing many files

A safer beginner command is:

rm -ri folder

This removes recursively but asks for confirmation.

Before deleting a directory, inspect it:

pwd
ls -lah
du -sh folder
tree -L 2 folder

Then remove:

rm -ri folder

Do not run destructive commands copied from the internet unless you understand every part.

Especially dangerous patterns include:

rm -rf /
rm -rf *
rm -rf ./*
sudo rm -rf /path
find / -name "*.log" -exec rm {} \;

The command rm -rf * removes everything matching * in the current directory. If you are in the wrong place, the result can be disastrous.

A safer habit is to use ls first with the same pattern.

ls *.log
rm -i *.log

rmdir: remove empty directories

The command rmdir removes empty directories.

rmdir empty-folder

If the directory contains files, rmdir refuses to remove it.

rmdir: failed to remove 'folder': Directory not empty

This makes rmdir safer than rm -r, but less flexible.

Use rmdir when you specifically expect a directory to be empty. Use rm -r only when you intend to remove contents too.

Practical workflow: create, inspect, copy, move and remove files

The following workflow demonstrates basic file operations safely.

Create a practice directory:

mkdir -p ~/linux-practice
cd ~/linux-practice
pwd

Create files:

touch notes.txt tasks.txt log.txt
ls -lah

Write text into a file using redirection:

echo "Linux practice notes" > notes.txt
echo "First task" > tasks.txt
echo "Application started" > log.txt

Read files:

cat notes.txt
cat tasks.txt
cat log.txt

Copy a file:

cp notes.txt notes-copy.txt
ls -lah

Rename a file:

mv notes-copy.txt archived-notes.txt
ls -lah

Create a subdirectory:

mkdir archive

Move the archived file:

mv archived-notes.txt archive/
tree

Search text:

grep "Linux" notes.txt

Remove safely:

rm -i tasks.txt
rm -ri archive

This small exercise covers mkdir, cd, pwd, touch, ls, echo, redirection, cat, cp, mv, tree, grep and rm.

It is simple, but it mirrors real Linux work.

Practical workflow: safely clean a temporary directory

Temporary directories can grow. But cleaning them blindly can break running programs.

Inspect first:

du -sh /tmp
sudo find /tmp -type f -mtime +7 -exec ls -lh {} \;

If the list looks safe, remove files older than 7 days:

sudo find /tmp -type f -mtime +7 -delete

Remove empty directories:

sudo find /tmp -type d -empty -delete

This is more controlled than:

sudo rm -rf /tmp/*

The second command may remove files currently needed by applications.

A precise cleanup is better than a dramatic cleanup.

Practical workflow: use diff to compare files

The command diff compares files.

diff old.conf new.conf

Unified format:

diff -u old.conf new.conf

This is useful after configuration changes.

Workflow:

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.before
sudo nano /etc/nginx/nginx.conf
diff -u /etc/nginx/nginx.conf.before /etc/nginx/nginx.conf

The output shows what changed.

This is a professional habit because it prevents accidental edits from going unnoticed.

File timestamps help reconstruct what happened

Linux files have timestamps. The most commonly visible one in ls -l is modification time.

ls -l file.txt

Show detailed timestamps with stat:

stat file.txt

Example fields:

FieldMeaning
AccessLast time file was read
ModifyLast time file content changed
ChangeLast time metadata changed
BirthCreation time, if supported by filesystem

Modification time changes when file content changes.

Change time changes when metadata changes, such as permissions or ownership.

This is useful in investigations.

Find recently modified files:

find /var/www/site -type f -mtime -1

Find files modified in the last 30 minutes:

find /var/www/site -type f -mmin -30

Sort files by modification time:

ls -lt

Oldest last or reversed:

ls -ltr

This helps answer: what changed recently?

stat gives exact file metadata

The command stat displays detailed file information.

stat file.txt

Example output includes size, blocks, permissions, UID, GID and timestamps.

Use it when ls -l is not enough.

Example:

stat /var/www/site/index.php

This can help compare files before and after deployment.

You can format output:

stat -c "%n %U %G %a %s" file.txt

This prints:

FormatMeaning
%nFile name
%UOwner username
%GGroup name
%aPermissions in numeric form
%sSize in bytes

Example output:

file.txt pat pat 644 1200

This can be useful in scripts.

ln and symbolic links

A symbolic link is a file that points to another file or directory.

Create symbolic link:

ln -s /real/path/file.txt link-name

Example:

ln -s /var/www/releases/2026-05-14 /var/www/current

Now /var/www/current points to the release directory.

Show link:

ls -l /var/www/current

Output may look like:

current -> /var/www/releases/2026-05-14

Symbolic links are common in deployments, configuration management and shared paths.

Important distinction:

Link typeCommandMeaning
Symbolic linkln -s target linkPoints to a path
Hard linkln target linkPoints to the same inode

Symbolic links are easier to understand and more common for directories and deployments.

If a symbolic link breaks, it points to a target that no longer exists.

Check target:

readlink link-name

Resolve full path:

readlink -f link-name

Find symbolic links:

find . -type l

Find broken symbolic links:

find . -xtype l

Practical workflow: generate files from scripts

Create a simple configuration file:

cat > app.conf << 'EOF'
APP_ENV=production
APP_DEBUG=false
APP_PORT=8080
EOF

Create a protected file with sudo:

sudo tee /etc/myapp.conf > /dev/null << 'EOF'
APP_ENV=production
APP_DEBUG=false
APP_PORT=8080
EOF

Append a block:

cat >> notes.txt << 'EOF'
New section
More notes
EOF

This is useful for automation, but be careful. > overwrites. >> appends.

OperatorEffect
>Create or overwrite
>>Append
<Read from file
<< EOFHere-document input

Before overwriting an important file, back it up.

Safe deletion with trash alternatives

The terminal rm command usually does not move files to a graphical trash bin. It deletes directory entries directly.

For safer interactive work, use:

rm -i file.txt

For recursive interactive deletion:

rm -ri directory

For a safer manual approach, move files to a temporary review directory first.

mkdir -p ~/delete-review
mv old-files ~/delete-review/

Inspect later:

ls -lah ~/delete-review

Delete only after review:

rm -ri ~/delete-review/old-files

This is useful when you are not completely sure.

For servers, deletion safety comes from backups, review commands and precise paths, not from a trash feature.

Practical workflow: cleanup with review directory

Suppose you want to remove old generated files from a project.

Create review folder:

mkdir -p ~/cleanup-review

Find files:

find /var/www/site/cache -type f -mtime +30 -exec ls -lh {} \;

Move instead of delete:

find /var/www/site/cache -type f -mtime +30 -exec mv {} ~/cleanup-review/ \;

Check application behavior. Check disk:

df -h
du -sh ~/cleanup-review

If everything is fine, delete later:

rm -ri ~/cleanup-review

This approach is slower but safer when you are uncertain.

For huge numbers of files, moving all into one directory may cause name collisions or performance issues. In that case, use a structured cleanup or direct deletion after proper backups. But the review-directory concept is useful for small and medium cleanup tasks.

Understanding diff and patch

The command diff shows differences between files.

diff -u old.conf new.conf

The -u option produces unified diff format, widely used in development and administration.

Save patch:

diff -u old.conf new.conf > change.patch

Apply patch:

patch old.conf < change.patch

In system administration, you may not use patch every day, but diff -u is extremely useful for reviewing configuration changes.

Example:

sudo cp /etc/ssh/sshd_config /tmp/sshd_config.before
sudo nano /etc/ssh/sshd_config
diff -u /tmp/sshd_config.before /etc/ssh/sshd_config

This shows exactly what changed before you reload SSH.

Practical workflow: review configuration changes before reload

Backup:

sudo cp /etc/nginx/nginx.conf /tmp/nginx.conf.before

Edit:

sudo nano /etc/nginx/nginx.conf

Review:

diff -u /tmp/nginx.conf.before /etc/nginx/nginx.conf

Test:

sudo nginx -t

Reload:

sudo systemctl reload nginx

Verify:

systemctl status nginx
journalctl -u nginx -n 50

This workflow is simple and professional.

Searching files, filtering text and processing output

Searching and text processing turn the terminal into an analytical tool. These commands find files, filter logs and extract meaning from structured text.

grep: search text with precision

The command grep searches for text patterns in files or command output.

Basic search:

grep "error" app.log

This displays every line in app.log that contains error.

Case-insensitive search:

grep -i "error" app.log

Show line numbers:

grep -n "error" app.log

Search recursively in a directory:

grep -r "database" /var/www/html

Ignore case recursively and show line numbers:

grep -rin "database" /var/www/html

Invert the search:

grep -v "Notice" app.log

This shows lines that do not contain Notice.

Count matching lines:

grep -c "error" app.log

Show filenames containing matches:

grep -l "error" *.log

Show context around matches:

grep -A 2 -B 4 "Fatal error" app.log

This shows two lines after and four lines before each matching line.

OptionMeaning
-iIgnore case
-nShow line numbers
-rRecursive search
-vInvert match
-cCount matching lines
-lShow only filenames with matches
-AShow lines after match
-BShow lines before match
-CShow lines before and after match

A powerful log example:

grep -i "failed password" /var/log/auth.log

Count failed password entries:

grep -i "failed password" /var/log/auth.log | wc -l

Show context:

grep -i -C 3 "failed password" /var/log/auth.log

This is how grep becomes a diagnostic tool.

Finding files is not only searching by name

One of the most important differences between a casual Linux user and a confident Linux user is the ability to find things precisely. On a graphical desktop, searching often means typing part of a filename into a search box. In the Linux command line, searching can be much more powerful. You can search by name, extension, type, size, modification time, ownership, permissions and even execute another command on every result.

The main command for this task is find.

find   

A simple example:

find /home/pat -iname "report.txt"

This searches inside /home/pat for a file or directory named report.txt, ignoring uppercase and lowercase differences.

The structure is logical.

PartMeaning
findRun the search tool
/home/patStart searching inside this path
-inameMatch name case-insensitively
"report.txt"The name pattern to search for

The command find is not only useful when you have lost a file. It is also useful when auditing systems, cleaning old logs, locating large files, finding broken project structures, checking modified files after deployment and preparing backups.

A graphical search tool usually answers the question: “Where is this file?”

The find command can answer deeper questions:

QuestionExample command
Where is this file?find /home -iname "report.txt"
Where are all PHP files?find /var/www -type f -iname "*.php"
Which files are larger than 100 MB?find /home -type f -size +100M
Which files changed in the last two days?find /home -type f -mtime -2
Which empty directories exist?find . -type d -empty
Which log files can be compressed?find /var/log -type f -iname "*.log" -size +10M
Which files belong to a specific user?find /var/www -user www-data

The real value of find is not just that it searches. The real value is that it can search with conditions that matter to administrators.

Searching by filename with find

The most basic use of find is searching by filename.

find /home/pat -name "test.txt"

This searches inside /home/pat for an exact name match.

The -name option is case-sensitive. That means test.txt, Test.txt and TEST.txt are different.

To ignore case, use -iname.

find /home/pat -iname "test.txt"

This can match:

test.txt
Test.txt
TEST.txt

For beginners, -iname is often safer because real files are not always named consistently.

Search for all text files:

find /home/pat -iname "*.txt"

Search for all PHP files:

find /var/www -iname "*.php"

Search for all configuration files:

find /etc -iname "*.conf"

The * symbol is a wildcard. It means any characters.

PatternMeaning
"*.txt"Anything ending in .txt
"log-*"Anything starting with log-
"*.conf"Anything ending in .conf
"backup*.tar.gz"Anything starting with backup and ending in .tar.gz

Always quote patterns like "*.txt" when using find.

This is better:

find . -iname "*.txt"

This can behave unexpectedly:

find . -iname *.txt

The reason is that the shell may expand *.txt before find receives it. Quoting keeps the pattern intact.

Searching by file type

Linux directories can contain many kinds of filesystem objects: regular files, directories, symbolic links, devices, sockets and named pipes. When searching, you often want only one type.

Find only regular files:

find /home/pat -type f

Find only directories:

find /home/pat -type d

Find only symbolic links:

find /home/pat -type l

Combine type and name:

find /var/www -type f -iname "*.php"

This means: find only regular files under /var/www whose names end in .php.

Find directories named cache:

find /var/www -type d -iname "cache"

Find symbolic links:

find /usr/local/bin -type l

The -type filter is important because names alone can be misleading. A directory can be named backup.txt. A file can be named logs. Search by type when the distinction matters.

Type optionMeaning
-type fRegular file
-type dDirectory
-type lSymbolic link
-type bBlock device
-type cCharacter device
-type sSocket
-type pNamed pipe

For most everyday work, f, d and l are the most common.

Searching by size

Disk space problems are common on Linux servers. A log grows unexpectedly. A backup script creates repeated archives. A user uploads large files. A database dump remains forgotten in a project directory. The find command helps locate files by size.

Find files larger than 100 MB:

find /home -type f -size +100M

Find files smaller than 1 KB:

find /home -type f -size -1k

Find files exactly 10 MB in size is less common, but possible:

find /home -type f -size 10M

The symbols matter.

Size expressionMeaning
+100MLarger than 100 MB
-100MSmaller than 100 MB
100MExactly 100 MB unit match
+1GLarger than 1 GB
+500kLarger than 500 KB

A practical command for finding large files:

find /home -type f -size +500M -exec ls -lh {} \;

This finds files larger than 500 MB and displays them with readable sizes.

Explanation:

PartMeaning
find /homeSearch inside /home
-type fOnly regular files
-size +500MLarger than 500 MB
-exec ls -lh {} \;Run ls -lh on each result

A more advanced version:

find /home -type f -size +500M -printf "%s %p\n" | sort -nr | head -20

This prints file sizes and paths, sorts them by size and shows the largest 20.

The lesson is important: when disk space is low, do not delete randomly. First locate the largest files.

Searching by modification time

Time-based searching is essential for administration. You may need to know which files changed recently, which logs are old, which backups should be removed or which files were modified after a deployment.

Find files modified in the last two days:

find /home -type f -mtime -2

Find files modified more than 30 days ago:

find /var/log -type f -mtime +30

Find files modified exactly around 7 days ago:

find /home -type f -mtime 7

The signs matter.

ExpressionMeaning
-mtime -2Modified less than 2 days ago
-mtime +30Modified more than 30 days ago
-mtime 7Modified 7 days ago according to find’s day rounding

For minute-level precision, use -mmin.

Find files modified in the last 60 minutes:

find /home/pat -type f -mmin -60

Find files modified more than 120 minutes ago:

find /tmp -type f -mmin +120

This is very useful when troubleshooting.

Example: after updating a web application, find recently changed files:

find /var/www/html -type f -mmin -30

Example: find old compressed logs:

find /var/log -type f -iname "*.gz" -mtime +30

A safe cleanup workflow:

find /var/log -type f -iname "*.gz" -mtime +30

Review the output first. Then, only when you are sure:

sudo find /var/log -type f -iname "*.gz" -mtime +30 -delete

The order matters. Inspect first. Delete only after verification.

Running commands on find results

The find command becomes extremely powerful when combined with -exec. This allows you to run another command on every result.

Basic structure:

find   -exec  {} \;

The {} placeholder represents each found item.

Example:

find /var/log -iname "*.log.gz" -exec ls -lh {} \;

This lists each matching compressed log file.

Remove matching files:

find /var/log -iname "*.log.gz" -exec rm {} \;

This is powerful but dangerous.

A safer method is to print first:

find /var/log -iname "*.log.gz"

Then list with details:

find /var/log -iname "*.log.gz" -exec ls -lh {} \;

Then remove only if the result is correct:

sudo find /var/log -iname "*.log.gz" -exec rm {} \;

Another useful example: change permissions on all .sh scripts.

find ~/scripts -type f -iname "*.sh" -exec chmod +x {} \;

Compress old logs:

find /var/log/myapp -type f -iname "*.log" -mtime +7 -exec gzip {} \;

Copy all PDF files into one folder:

find ~/Documents -type f -iname "*.pdf" -exec cp {} ~/pdf-collection/ \;

The -exec feature can save hours, but it must be used carefully.

SymbolMeaning
{}Current found item
\;End of the command executed by find
-execRun a command on each result

A professional habit is to replace the action with echo first.

find /var/log -iname "*.gz" -mtime +30 -exec echo rm {} \;

This prints what would be removed without actually removing it.

find with maxdepth and mindepth

By default, find searches recursively through all subdirectories. Sometimes this is too much.

Limit search to the current directory only:

find . -maxdepth 1 -type f

Search two levels deep:

find . -maxdepth 2 -type f

Ignore the current directory itself and search below it:

find . -mindepth 1 -type d

Combine both:

find . -mindepth 1 -maxdepth 2 -type d

This finds directories at depth one or two, but not the current directory itself.

This is useful when working with large projects or system folders where a full recursive search would produce too much output.

Example:

find /var/www -maxdepth 2 -type d

This shows the upper directory structure of web projects without descending into every subfolder.

Practical workflow: collect all files of one type

Suppose you want to collect all .pdf files from a large directory tree.

Create destination:

mkdir -p ~/pdf-collection

Preview files:

find ~/Documents -type f -iname "*.pdf"

Copy files:

find ~/Documents -type f -iname "*.pdf" -exec cp {} ~/pdf-collection/ \;

Check result:

ls -lah ~/pdf-collection

Count copied files:

find ~/pdf-collection -type f -iname "*.pdf" | wc -l

This workflow uses mkdir, find, cp, ls and wc together.

That is real command-line productivity.

Key takeaways

At this point, the command line becomes more than navigation and file reading. You now have the tools to search deeply, archive safely, analyze disk usage, mount filesystems and control permissions.

The most important commands in this section are:

CommandEssential role
findSearch by name, type, size, time and execute actions
tarCreate and extract Linux archives
zipCreate ZIP archives
unzipExtract ZIP archives
dfShow free and used filesystem space
duShow file and directory disk usage
mountAttach a filesystem to the directory tree
umountDetach a mounted filesystem
chmodChange permissions
chownChange ownership
dateDisplay and format date and time
uptimeShow system runtime and load average

The deeper lesson is this: Linux administration is a sequence of careful questions.

Where is the file? Use find.

How large is it? Use du or ls -lh.

Which filesystem is full? Use df.

Who owns it? Use ls -l.

Who can access it? Read the permissions.

Can it be executed? Check x.

Should it be archived? Use tar.

Should it be deleted? Inspect first, then act.

The more carefully you ask, the safer and more powerful your command line work becomes.

wc: counting lines, words, characters and bytes

The command wc means word count, but it can count more than words.

Basic use:

wc file.txt

Example output:

  20  150  900 file.txt

The columns usually mean:

ColumnMeaning
FirstLines
SecondWords
ThirdBytes
LastFilename

Count lines only:

wc -l file.txt

Count words only:

wc -w file.txt

Count characters:

wc -m file.txt

Count bytes:

wc -c file.txt

wc is especially useful after pipes.

Count matching lines:

grep -i "error" app.log | wc -l

Count files found by find:

find /var/www -type f | wc -l

Count logged-in users:

who | wc -l

Count installed packages:

dpkg -l | wc -l

The command wc -l is one of the simplest ways to turn text output into a number.

cut: extracting columns from structured text

The command cut extracts parts of each line. It is useful when text is separated by delimiters such as colons, commas, tabs or spaces.

A classic example uses /etc/passwd.

cut -d : -f 1 /etc/passwd

This prints the first field of each line, using : as the delimiter.

Explanation:

PartMeaning
cutRun field extraction
-d :Use colon as delimiter
-f 1Print first field
/etc/passwdInput file

The file /etc/passwd contains user account records. The first field is the username.

Extract usernames and home directories:

cut -d : -f 1,6 /etc/passwd

Extract only characters 1 to 10:

cut -c 1-10 file.txt

Extract the second column from a CSV file:

cut -d ',' -f 2 data.csv

Common options:

OptionMeaning
-dDelimiter
-fField number
-cCharacter positions
--complementSelect everything except specified fields

Example:

cut -d ',' -f 1,3 data.csv

This prints fields 1 and 3 from a comma-separated file.

cut is simple and fast, but it is not a complete CSV parser. Real CSV files can contain quoted commas, line breaks inside fields and escaping rules. For simple delimiter-based text, cut is excellent. For complex CSV, use more suitable tools.

awk: a complete text processing language

The command awk is more powerful than cut. It can select fields, apply conditions, calculate values, format output and behave like a small programming language.

Basic structure:

awk 'pattern { action }' file

Print the first field:

awk '{print $1}' file.txt

By default, awk splits input on whitespace.

Use a colon as field separator:

awk -F ':' '{print $1}' /etc/passwd

This prints usernames, similar to:

cut -d : -f 1 /etc/passwd

Print username and home directory:

awk -F ':' '{print $1, $6}' /etc/passwd

Print with custom formatting:

awk -F ':' '{print "User:", $1, "Home:", $6}' /etc/passwd

Print lines where the third field is greater than or equal to 1000:

awk -F ':' '$3 >= 1000 {print $1, $3}' /etc/passwd

This is already more powerful than cut.

Important awk field variables:

VariableMeaning
$0Entire line
$1First field
$2Second field
$NFLast field
NFNumber of fields
NRCurrent line number

Print line numbers:

awk '{print NR, $0}' file.txt

Print last field:

awk '{print $NF}' file.txt

Print only lines with more than 5 fields:

awk 'NF > 5 {print $0}' file.txt

awk for log analysis

Suppose a web access log has lines where the first field is the client IP address. You can count requests by IP.

awk '{print $1}' access.log | sort | uniq -c | sort -nr | head

This means:

StagePurpose
awk '{print $1}' access.logExtract IP addresses
sortGroup identical IPs
uniq -cCount repeated IPs
sort -nrSort by count descending
headShow top results

Print the first and ninth fields from a web log:

awk '{print $1, $9}' access.log

If the ninth field is HTTP status code, this can show which IP produced which status.

Count status codes:

awk '{print $9}' access.log | sort | uniq -c | sort -nr

Find lines with status 500:

awk '$9 == 500 {print $0}' access.log

Find IPs causing 404 errors:

awk '$9 == 404 {print $1}' access.log | sort | uniq -c | sort -nr | head

These are real server investigation patterns. They show why text processing is central to Linux administration.

awk for calculations

awk can also calculate.

Suppose sizes.txt contains numbers:

10
25
30

Sum them:

awk '{sum += $1} END {print sum}' sizes.txt

Output:

65

Average:

awk '{sum += $1; count++} END {print sum / count}' sizes.txt

Print total size from a command:

du -sk * | awk '{sum += $1} END {print sum " KB"}'

This is where awk becomes more than a column extractor. It becomes a compact data processing tool.

sed: editing text streams

The command sed is a stream editor. It reads text, applies editing rules and prints the result.

Basic substitution:

sed 's/old/new/' file.txt

This replaces the first occurrence of old with new on each line in the output. It does not modify the file unless you use in-place editing.

Replace all occurrences on each line:

sed 's/old/new/g' file.txt

The g means global within each line.

Delete lines beginning with #:

sed '/^#/d' config.conf

This removes comment lines from the output.

Delete empty lines:

sed '/^$/d' file.txt

Print only a range of lines:

sed -n '10,20p' file.txt

This prints lines 10 through 20.

In-place editing:

sed -i 's/old/new/g' file.txt

In-place editing with backup:

sed -i.backup 's/old/new/g' file.txt

This creates file.txt.backup.

The backup form is much safer when learning.

sed examples for configuration cleanup

Show a configuration file without comments and empty lines:

sed '/^#/d; /^$/d' config.conf

This applies two commands:

sed ruleMeaning
/^#/dDelete lines beginning with #
/^$/dDelete empty lines

This is useful when reading long configuration files.

Example:

sed '/^#/d; /^$/d' /etc/ssh/sshd_config

Be careful: this prints a cleaned view. It does not show inline comments and it does not explain inherited defaults. Still, it can make large configuration files easier to inspect.

Replace a domain in a file:

sed -i.backup 's/old.example.com/new.example.com/g' config.conf

Then compare:

diff config.conf.backup config.conf

If wrong, restore:

mv config.conf.backup config.conf

A professional habit with sed -i is to make a backup first or use the built-in backup extension.

sort and uniq: organizing and counting text

The command sort sorts lines.

sort file.txt

Reverse sort:

sort -r file.txt

Numeric sort:

sort -n numbers.txt

Human-readable size sort:

sort -h sizes.txt

Sort by a specific column:

sort -k 2 file.txt

The command uniq removes adjacent duplicate lines.

uniq file.txt

Important detail: uniq only removes duplicates that are next to each other. This is why it is often used after sort.

sort file.txt | uniq

Count duplicates:

sort file.txt | uniq -c

Sort counts descending:

sort file.txt | uniq -c | sort -nr

This pattern is extremely useful.

Count repeated errors:

grep -i "error" app.log | sort | uniq -c | sort -nr

Count top IP addresses:

awk '{print $1}' access.log | sort | uniq -c | sort -nr | head

Count status codes:

awk '{print $9}' access.log | sort | uniq -c | sort -nr

The combination sort | uniq -c | sort -nr is one of the most practical Linux text-analysis patterns.

head and tail in pipelines

The commands head and tail are not only for reading files. They also limit pipeline output.

Show top 10 largest files from a du pipeline:

du -ak | sort -nr | head

Show top 20:

du -ak | sort -nr | head -20

Show the last 20 commands from history:

history | tail -n 20

Show the latest 50 matching log lines:

grep -i "error" app.log | tail -n 50

Show the first 5 users from /etc/passwd:

cut -d : -f 1 /etc/passwd | head -5

In real work, many commands produce too much output. head and tail help you inspect a manageable slice.

Practical workflow: analyze a large log file

Suppose you have a large application log named app.log.

Start by checking size:

ls -lh app.log

Inspect beginning:

head -n 20 app.log

Inspect end:

tail -n 50 app.log

Count total lines:

wc -l app.log

Count error lines:

grep -i "error" app.log | wc -l

Show most common error lines:

grep -i "error" app.log | sort | uniq -c | sort -nr | head -20

Save error summary:

grep -i "error" app.log | sort | uniq -c | sort -nr > error-summary.txt

Read summary:

less error-summary.txt

Follow new errors live:

tail -f app.log | grep -i "error"

This workflow turns a large log into useful information.

Practical workflow: count web requests by IP address

Assume access.log is a web access log where the first field is the client IP.

Top IP addresses:

awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -20

Count total requests:

wc -l access.log

Count unique IP addresses:

awk '{print $1}' access.log | sort -u | wc -l

Save top IP report:

awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -50 > top-ips.txt

This is useful for traffic analysis, abuse detection, debugging and understanding server load.

Practical workflow: count HTTP status codes

If the ninth field in an access log is the HTTP status code, count status codes:

awk '{print $9}' access.log | sort | uniq -c | sort -nr

Find 500 errors:

awk '$9 == 500 {print $0}' access.log

Find 404 errors:

awk '$9 == 404 {print $0}' access.log

Top IPs causing 404 errors:

awk '$9 == 404 {print $1}' access.log | sort | uniq -c | sort -nr | head -20

Save 500 errors:

awk '$9 == 500 {print $0}' access.log > http-500-errors.log

A few commands can answer questions that would be tedious in a graphical editor.

Practical workflow: prepare a clean configuration view

Many configuration files contain comments and blank lines. To read active lines more easily:

sed '/^#/d; /^$/d' config.conf

For SSH configuration:

sudo sed '/^#/d; /^$/d' /etc/ssh/sshd_config

For Apache configuration:

sed '/^#/d; /^$/d' /etc/apache2/apache2.conf

This does not edit the file. It prints a cleaned view.

Save cleaned view:

sed '/^#/d; /^$/d' config.conf > active-config-view.txt

This is useful for review, documentation or troubleshooting.

Practical workflow: batch rename with shell tools

Suppose you have files ending in .jpeg and want to rename them to .jpg.

Preview:

ls *.jpeg

A simple loop:

for file in *.jpeg; do
    mv "$file" "${file%.jpeg}.jpg"
done

Explanation:

PartMeaning
for file in *.jpegLoop through .jpeg files
"${file%.jpeg}"Remove .jpeg from the end
.jpgAdd new extension
mvRename file

Safer preview:

for file in *.jpeg; do
    echo mv "$file" "${file%.jpeg}.jpg"
done

This prints the planned commands without running them.

Only after review, run the real loop.

This preview-first method is important for batch operations.

Practical workflow: find and process files safely

Find all .log files:

find . -type f -name "*.log"

Show sizes:

find . -type f -name "*.log" -exec ls -lh {} \;

Count them:

find . -type f -name "*.log" | wc -l

Compress logs older than 7 days:

find . -type f -name "*.log" -mtime +7 -exec gzip {} \;

Preview deletion of compressed logs older than 30 days:

find . -type f -name "*.gz" -mtime +30 -exec echo rm {} \;

Delete after verifying:

find . -type f -name "*.gz" -mtime +30 -delete

The important pattern is: find, inspect, count, preview, act.

Practical workflow: use grep, awk and cut together

Extract usernames from /etc/passwd:

cut -d : -f 1 /etc/passwd

Show users with UID 1000 or higher:

awk -F ':' '$3 >= 1000 {print $1, $3, $6}' /etc/passwd

Search for a specific shell:

grep "/bin/bash" /etc/passwd

Extract usernames using Bash shell:

grep "/bin/bash" /etc/passwd | cut -d : -f 1

This demonstrates tool selection:

ToolBest use
grepFind lines
cutExtract simple fields
awkApply conditions and format output
sedEdit or transform lines
wcCount results

The tools overlap, but each has a natural strength.

Practical workflow: create a top error report from a web log

Assume access.log contains web requests.

Create report:

{
    echo "Top client IPs"
    awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -20

    echo
    echo "HTTP status code counts"
    awk '{print $9}' access.log | sort | uniq -c | sort -nr

    echo
    echo "Top 404 sources"
    awk '$9 == 404 {print $1}' access.log | sort | uniq -c | sort -nr | head -20

    echo
    echo "Recent 500 errors"
    awk '$9 == 500 {print $0}' access.log | tail -20
} > web-log-report.txt

Read it:

less web-log-report.txt

This is a compact reporting workflow using grouping, awk, sort, uniq, head, tail and redirection.

Time based log investigation

When investigating an incident, time matters.

Show logs since a specific time:

journalctl --since "2026-05-14 09:00"

Until a specific time:

journalctl --since "2026-05-14 09:00" --until "2026-05-14 10:00"

For a service:

journalctl -u nginx --since "2026-05-14 09:00" --until "2026-05-14 10:00"

For plain log files, use grep if timestamps are textual.

grep "2026-05-14 09:" app.log

Show files modified during the period:

find /var/www/site -type f -newermt "2026-05-14 09:00" ! -newermt "2026-05-14 10:00" -exec ls -lh {} \;

This command finds files modified between 09:00 and 10:00.

Time-based investigation is essential when a problem begins after a deployment, update, reboot or scheduled job.

Using find with newermt

The find command can search by human-readable modification time using -newermt.

Find files modified after a date:

find /var/www/site -type f -newermt "2026-05-14" -exec ls -lh {} \;

Find files modified after a specific time:

find /var/www/site -type f -newermt "2026-05-14 10:00" -exec ls -lh {} \;

Find files modified in a range:

find /var/www/site -type f -newermt "2026-05-14 10:00" ! -newermt "2026-05-14 11:00" -exec ls -lh {} \;

This is extremely useful after deployment incidents.

Example workflow:

find /etc -type f -newermt "2026-05-14 09:00" -exec ls -lh {} \;
find /var/www -type f -newermt "2026-05-14 09:00" -exec ls -lh {} \;
journalctl --since "2026-05-14 09:00"

This connects file changes and logs in the same time window.

Pipes, redirection and command composition

Pipes, redirection and shell interpretation explain why small commands can become complete workflows.

Understanding pipes

The pipe symbol | sends the output of one command into another command.

Example:

ls -lah | grep ".log"

This means:

StepAction
ls -lahList files with details
``
grep ".log"Show only lines containing .log

Another example:

history | tail -n 20

This shows only the last 20 commands from your command history.

A more advanced example:

du -ak | sort -nr | head -20

This shows large files or directories.

Command partPurpose
du -akShow disk usage in kilobytes
sort -nrSort numerically in reverse order
head -20Show only first 20 lines

Pipes are one of the most important concepts in Linux. They allow simple tools to become powerful workflows.

A command pipeline should be read from left to right. Each command transforms the previous output.

Output redirection

Redirection sends command output into files instead of showing it only on the screen.

Overwrite or create a file:

command > file.txt

Append to a file:

command >> file.txt

Example:

grep "error" app.log > errors.txt

This creates errors.txt with all matching lines. If the file already exists, it is overwritten.

Append instead:

grep "error" app.log >> errors.txt

This adds matching lines to the end of the file.

SymbolMeaningRisk
>Write output and overwrite fileCan erase previous content
>>Append output to fileSafer for accumulating logs
2>Redirect error outputUseful for separating errors
&>Redirect normal output and errorsUseful for full command logs

Example separating successful output from errors:

find /etc -name "*.conf" > found.txt 2> denied.txt

This saves found files into found.txt and permission errors into denied.txt.

Example saving both output and errors:

find /etc -name "*.conf" &> result.txt

Redirection is essential for logging, scripting and automation.

The shell is more than a place where commands are typed

The Linux shell is not only a command launcher. It is an environment that can remember commands, expand patterns, redirect output, connect programs, store variables, repeat work, run scripts and automate system behavior.

This is where Linux begins to feel different from a normal graphical operating system. In a graphical interface, you usually perform one action at a time. In the shell, you can describe a whole workflow as text. That workflow can be repeated, saved, scheduled, shared, inspected and improved.

A command such as this is useful:

grep -i "error" app.log

But the shell becomes much more powerful when commands are combined:

grep -i "error" app.log | sort | uniq -c | sort -nr > error-summary.txt

This single line searches for errors, sorts them, counts repeated lines, sorts by frequency and saves the result into a file.

That is not just command usage. That is text-based automation.

The shell gives you several major powers.

Shell capabilityWhat it meansExample
Command historyReuse previous commandshistory, !!, !123
ExpansionConvert patterns into filenames or values*.log, {a,b}, $HOME
PipesSend output from one command to another`ps aux
RedirectionSave output or errors to filescommand > output.txt
VariablesStore values temporarilyNAME="backup"
SubstitutionUse output of one command inside another$(date +%Y-%m-%d)
Job controlMove work between foreground and backgroundjobs, fg, bg
ScriptsSave commands into executable filesbackup.sh
SchedulingRun commands automatically latercrontab

A beginner sees the shell as a blank screen. An experienced Linux user sees it as a programmable control surface.

Shell expansion explains many surprising behaviors

The shell often modifies your command before the command itself runs. This process is called expansion.

For example:

ls *.txt

The ls command may never receive the literal text *.txt. The shell first expands *.txt into matching filenames.

If the directory contains:

notes.txt
report.txt
tasks.txt

then the command becomes:

ls notes.txt report.txt tasks.txt

This is why wildcard behavior can surprise beginners.

Common shell patterns:

PatternMeaning
*Any number of characters
?Exactly one character
[abc]One character from the set
[0-9]One digit
*.logFiles ending in .log
file?.txtfile1.txt, fileA.txt, but not file10.txt
backup-*Names beginning with backup-

Examples:

ls *.log
ls file?.txt
ls backup-*

Before removing files with a wildcard, always preview.

Do not start with:

rm *.log

Start with:

ls *.log

Then use safer deletion:

rm -i *.log

Wildcards are powerful, but they expand before the command runs. That means a mistake in the pattern can affect many files.

Quoting changes how the shell interprets text

Quotes control expansion and word splitting.

Without quotes:

echo Hello World

The shell sees two separate words: Hello and World.

With quotes:

echo "Hello World"

The shell treats the text as one argument.

This matters with filenames that contain spaces.

Wrong:

cd My Folder

The shell sees two arguments: My and Folder.

Correct:

cd "My Folder"

or:

cd My\ Folder

Double quotes allow variable expansion.

NAME="Linux"
echo "Hello $NAME"

Output:

Hello Linux

Single quotes prevent variable expansion.

NAME="Linux"
echo 'Hello $NAME'

Output:

Hello $NAME

Comparison:

FormBehavior
"text $VAR"Keeps text together and expands variables
'text $VAR'Keeps text together and does not expand variables
text\ with\ spacesEscapes individual spaces
Unquoted textSubject to splitting and expansion

A strong shell habit is to quote variables.

Better:

cp "$SOURCE" "$DESTINATION"

Riskier:

cp $SOURCE $DESTINATION

If a variable contains spaces, the unquoted version can break.

Variables make commands reusable

A shell variable stores a value.

PROJECT="website"

Use it with $.

echo "$PROJECT"

Output:

website

A practical example:

SOURCE="/var/www/site"
DESTINATION="/home/pat/backups"
DATE=$(date +%Y-%m-%d)

Now create a backup:

tar -czf "$DESTINATION/site-$DATE.tar.gz" "$SOURCE"

This is easier to read and safer to modify than a long command with repeated paths.

Variables are especially useful in scripts.

#!/bin/bash

SOURCE="/var/www/site"
DESTINATION="/home/pat/backups"
DATE=$(date +%Y-%m-%d)
ARCHIVE="$DESTINATION/site-$DATE.tar.gz"

mkdir -p "$DESTINATION"
tar -czf "$ARCHIVE" "$SOURCE"

echo "Backup created: $ARCHIVE"

This script is simple, but it already shows real automation.

Important syntax detail: do not place spaces around = when assigning variables.

Correct:

NAME="Linux"

Wrong:

NAME = "Linux"

The second form does not assign a variable. The shell interprets it differently.

Command substitution uses command output inside another command

Command substitution runs a command and inserts its output into another command.

Modern syntax:

$(command)

Example:

echo "Today is $(date +%Y-%m-%d)"

Output:

Today is 2026-05-14

Create a dated backup:

tar -czf "project-$(date +%Y-%m-%d).tar.gz" project/

Create a log line with timestamp:

echo "$(date +"%Y-%m-%d %H:%M:%S") backup started" >> backup.log

Store command output in a variable:

DATE=$(date +%Y-%m-%d)
HOST=$(hostname)

Use them:

echo "Running on $HOST at $DATE"

Command substitution is one of the bridges between one-time commands and shell scripts.

Pipes turn commands into workflows

A pipe sends the output of one command into the input of another command.

command1 | command2

Example:

ps aux | grep nginx

This runs ps aux, then filters the output through grep nginx.

Another example:

cat app.log | grep -i error

This works, but the shorter form is usually better:

grep -i error app.log

Pipes become valuable when several tools are connected.

grep -i "error" app.log | sort | uniq -c | sort -nr

This means:

StageCommandPurpose
1grep -i "error" app.logFind error lines
2sortSort identical lines together
3uniq -cCount repeated lines
4sort -nrSort counts from highest to lowest

A disk usage pipeline:

du -ak | sort -nr | head -20

This means:

StageCommandPurpose
1du -akShow disk usage in kilobytes
2sort -nrSort largest first
3head -20Show top 20 results

A process pipeline:

ps aux | sort -nrk 3 | head -10

This sorts processes by CPU usage and shows the top 10.

The pipe is central to Linux because it lets each command remain simple while allowing the workflow to be complex.

Redirection controls where output goes

Most commands have output. By default, normal output appears on the terminal. Errors also appear on the terminal, but technically they use a different stream.

Linux commonly uses three standard streams.

StreamNumberMeaning
Standard input0Input into a command
Standard output1Normal output
Standard error2Error output

Redirect standard output into a file:

command > output.txt

Append standard output to a file:

command >> output.txt

Redirect errors:

command 2> errors.txt

Redirect output and errors to separate files:

command > output.txt 2> errors.txt

Redirect both output and errors to one file:

command > all.txt 2>&1

Modern shorthand in many shells:

command &> all.txt

Example:

find /etc -name "*.conf" > found.txt 2> denied.txt

This stores successful results in found.txt and permission errors in denied.txt.

Append errors to a log file:

command 2>> errors.log

Discard output:

command > /dev/null

Discard errors:

command 2> /dev/null

Discard everything:

command > /dev/null 2>&1

The special file /dev/null is a data sink. Anything written to it disappears.

Use /dev/null carefully. It is useful in scripts, but hiding errors can make troubleshooting harder.

Redirection and sudo can be confusing

A common beginner problem appears when writing to protected files.

This often fails:

sudo echo "test" > /etc/example.conf

Why? Because sudo applies to echo, but the redirection > is handled by your current shell before sudo writes the file. The shell itself may not have permission to write into /etc.

Use tee instead:

echo "test" | sudo tee /etc/example.conf

Append with tee -a:

echo "another line" | sudo tee -a /etc/example.conf

Hide tee output if needed:

echo "test" | sudo tee /etc/example.conf > /dev/null

This pattern is important for writing into protected files from command pipelines.

Examples:

echo "127.0.0.1 localtest" | sudo tee -a /etc/hosts
printf "Hello\nWorld\n" | sudo tee /opt/example.txt

The core lesson: sudo does not automatically apply to shell redirection.

xargs converts input into command arguments

The command xargs takes input lines and turns them into arguments for another command.

A simple example:

find . -name "*.tmp" | xargs rm

This finds .tmp files and passes them to rm.

However, this can break when filenames contain spaces or unusual characters. A safer version uses null-separated output.

find . -name "*.tmp" -print0 | xargs -0 rm

Explanation:

PartMeaning
find . -name "*.tmp"Find matching files
-print0Separate results with null characters
xargs -0Read null-separated input safely
rmRemove files

Preview before deleting:

find . -name "*.tmp" -print0 | xargs -0 ls -lh

Then remove:

find . -name "*.tmp" -print0 | xargs -0 rm

Another example: count lines in all .log files.

find . -name "*.log" -print0 | xargs -0 wc -l

The command xargs is useful, but it should be handled carefully. For many tasks, find -exec is easier to read.

Compare:

find . -name "*.tmp" -exec rm {} \;

and:

find . -name "*.tmp" -print0 | xargs -0 rm

Both can work. xargs may be more efficient for large numbers of files because it can pass many files to one command invocation.

tee: display output and save it at the same time

The command tee reads input and writes it both to the screen and to a file.

command | tee output.txt

Example:

ls -lah | tee listing.txt

This displays the listing and saves it to listing.txt.

Append instead of overwrite:

command | tee -a output.txt

Use with protected files:

echo "example" | sudo tee /etc/example.conf

Use in logs:

sudo apt update | tee apt-update.log

Save both output and errors:

command 2>&1 | tee command.log

Example:

sudo apt upgrade 2>&1 | tee upgrade.log

This is useful during maintenance because you can watch output and keep a record.

Understanding standard input in practical commands

Standard input is the data a command reads. Many commands can read from files or from standard input.

Example:

cat file.txt

The file is an argument.

But this uses standard input:

cat < file.txt

Pipes provide standard input:

cat file.txt | grep error

Here, grep reads from standard input.

Equivalent:

grep error file.txt

Some commands are commonly used with standard input.

sort < names.txt

or:

cat names.txt | sort

A here-document sends standard input:

cat << 'EOF'
Line one
Line two
EOF

Understanding input makes pipes and scripts easier to reason about.

Understanding shell globbing versus find

Globbing is expansion performed by the shell.

ls *.log

This matches files in the current directory.

find searches recursively and with conditions.

find . -type f -name "*.log"

Comparison:

FeatureShell globfind
Current directory matchingExcellentYes
Recursive searchLimited unless using shell optionsExcellent
Search by sizeNoYes
Search by timeNoYes
Search by ownerNoYes
Execute action on resultsLimitedExcellent
Handles huge treesShell may hit argument limitsBetter

Use globbing for simple current-directory tasks.

ls *.txt
rm -i *.tmp

Use find for deeper controlled searches.

find /var/log -type f -name "*.gz" -mtime +30 -exec ls -lh {} \;

Argument list too long

Sometimes shell expansion creates too many arguments.

Example:

rm *.log

If there are too many .log files, you may see:

Argument list too long

This happens because the shell expands *.log into a huge list before running rm.

Use find instead:

find . -type f -name "*.log" -delete

Or interactive:

find . -type f -name "*.log" -exec rm -i {} \;

Or with xargs safely:

find . -type f -name "*.log" -print0 | xargs -0 rm

This is another reason find is essential for serious file operations.

Archives, compression and backup basics

Archives, compression and backups connect file operations with operational safety. A useful archive is not only created, but also inspected, moved, verified and restorable.

Archiving and compression in Linux

Linux systems often use archives for backups, transfers, deployments and log storage. The most important command is tar.

The name originally meant tape archive, but today it is used for packaging files and directories into archive files.

There is an important distinction:

ConceptMeaning
ArchivingCombining multiple files into one file
CompressionReducing the size of data
Archive fileOne file containing many files
Compressed archiveAn archive that is also compressed

The command tar can create an archive and optionally compress it.

Common archive extensions:

ExtensionMeaning
.tarTar archive, usually not compressed
.tar.gzTar archive compressed with gzip
.tgzShort form of .tar.gz
.tar.bz2Tar archive compressed with bzip2
.tar.xzTar archive compressed with xz
.zipZIP archive, common on Windows

A .tar.gz file is extremely common in Linux.

Creating tar archives

Create a gzip-compressed tar archive:

tar -czvf archive.tar.gz /home/pat/project

This command creates archive.tar.gz from /home/pat/project.

The options can be understood like this:

OptionMeaning
-cCreate an archive
-zCompress with gzip
-vVerbose output
-fUse the following filename

The -f option must be followed by the archive filename.

This is correct:

tar -czvf project-backup.tar.gz project/

This is wrong or confusing:

tar -czv project-backup.tar.gz project/

Without -f, tar does not know that project-backup.tar.gz is the archive file name in the intended way.

A quieter version without verbose output:

tar -czf project-backup.tar.gz project/

For scripts, less verbose output is often preferred.

Create an uncompressed tar archive:

tar -cf archive.tar project/

Create a bzip2-compressed archive:

tar -cjvf archive.tar.bz2 project/

Create an xz-compressed archive:

tar -cJvf archive.tar.xz project/
CompressionOptionCommon extensionGeneral note
gzip-z.tar.gzFast and widely used
bzip2-j.tar.bz2Often smaller than gzip, slower
xz-J.tar.xzStrong compression, often slower
noneno compression option.tarArchive only

For most practical use, .tar.gz is a safe default.

Extracting tar archives

Extract a .tar.gz archive:

tar -xzvf archive.tar.gz

Options:

OptionMeaning
-xExtract
-zUse gzip
-vVerbose output
-fArchive filename follows

A quieter version:

tar -xzf archive.tar.gz

Extract into a specific directory:

tar -xzf archive.tar.gz -C /home/pat/extracted

The destination directory must already exist.

mkdir -p /home/pat/extracted
tar -xzf archive.tar.gz -C /home/pat/extracted

List archive contents without extracting:

tar -tzf archive.tar.gz

This is a very important safety command.

Before extracting an archive from an unknown source, inspect its structure:

tar -tzf archive.tar.gz | head

Why this matters:

Some archives contain a clean folder like this:

project/
project/index.php
project/assets/style.css

Others may contain files directly:

index.php
style.css
config.php

If you extract the second type in the wrong directory, it can scatter files everywhere.

A safe extraction workflow:

mkdir -p ~/extract-test
tar -tzf archive.tar.gz | head -50
tar -xzf archive.tar.gz -C ~/extract-test

ZIP and unzip

ZIP files are common when exchanging files with Windows users, clients, designers, office workers or web platforms.

Create a ZIP archive:

zip archive.zip file1.txt file2.txt

Create a ZIP archive from a directory:

zip -r archive.zip project/

The -r option means recursive.

Extract a ZIP archive:

unzip archive.zip

Extract into a specific directory:

unzip archive.zip -d extracted/

List ZIP contents without extracting:

unzip -l archive.zip

This is the ZIP equivalent of inspecting before extracting.

Common ZIP workflow:

unzip -l website-files.zip
mkdir -p website-files
unzip website-files.zip -d website-files

Comparison between tar.gz and ZIP:

Feature.tar.gz.zip
Common on LinuxVery commonCommon
Common on WindowsLess native historicallyVery common
Preserves Unix permissions wellYesLess consistently
Good for Linux backupsYesSometimes
Good for sharing with non-Linux usersSometimesYes
Compression includedYes with gzipYes

For Linux system backups, prefer tar.gz. For general file sharing, ZIP is often more convenient.

Practical archive workflow for backups

A good backup archive should have a clear name, include the correct directory and be easy to inspect.

Create a timestamped backup:

tar -czf project-$(date +%Y-%m-%d).tar.gz project/

If today is 2026-05-14, this creates:

project-2026-05-14.tar.gz

The date command inside $() runs first and inserts the result into the filename.

A more detailed timestamp:

tar -czf project-$(date +%Y-%m-%d-%H-%M).tar.gz project/

This may create:

project-2026-05-14-10-30.tar.gz

Backup and verify:

tar -czf project-backup.tar.gz project/
tar -tzf project-backup.tar.gz | head -20
ls -lh project-backup.tar.gz

This creates the archive, lists the first 20 archive entries and shows the archive size.

A safer backup script pattern:

#!/bin/bash

SOURCE="/home/pat/project"
DESTINATION="/home/pat/backups"
DATE=$(date +%Y-%m-%d-%H-%M)
ARCHIVE="$DESTINATION/project-$DATE.tar.gz"

mkdir -p "$DESTINATION"
tar -czf "$ARCHIVE" "$SOURCE"
tar -tzf "$ARCHIVE" > /dev/null

echo "Backup created: $ARCHIVE"

This simple script introduces several important Linux ideas: variables, quoting, directory creation, archive creation and verification.

Practical workflow: prepare a clean project backup

Suppose you want to back up a project directory.

Go to the parent directory:

cd /home/pat/projects
pwd
ls -lah

Inspect the project:

du -sh myproject
tree -L 2 myproject

Create a backup directory:

mkdir -p /home/pat/backups

Create a dated archive:

tar -czf /home/pat/backups/myproject-$(date +%Y-%m-%d).tar.gz myproject/

Verify archive exists:

ls -lh /home/pat/backups

Inspect archive contents:

tar -tzf /home/pat/backups/myproject-$(date +%Y-%m-%d).tar.gz | head -30

This is much better than simply compressing files blindly.

A backup is not complete until you know it can be read.

Practical workflow: securely copy a backup from a server

Suppose you want to download a backup from a server.

First connect and inspect:

ssh pat@server
hostname
ls -lh /home/pat/backups

Exit remote session:

exit

Download with scp:

scp pat@server:/home/pat/backups/project-backup.tar.gz .

Verify local file:

ls -lh project-backup.tar.gz
tar -tzf project-backup.tar.gz | head -30

A better method for large or repeated backups:

rsync -avz --progress pat@server:/home/pat/backups/ ./backups/

This preserves metadata and is efficient if run repeatedly.

Downloading and verifying archives

When downloading files with wget, do not immediately extract them into important directories.

Use a controlled directory:

mkdir -p ~/downloads
cd ~/downloads

Download:

wget https://example.com/archive.tar.gz

Check size:

ls -lh archive.tar.gz

Inspect archive:

tar -tzf archive.tar.gz | head -50

Create extraction directory:

mkdir -p extracted

Extract there:

tar -xzf archive.tar.gz -C extracted

Inspect:

tree -L 2 extracted

This prevents messy extraction into the wrong location.

For ZIP:

unzip -l archive.zip
mkdir -p extracted
unzip archive.zip -d extracted

The principle is the same: inspect before extracting.

Practical cron workflow for a daily backup

Create directories:

mkdir -p /home/pat/scripts
mkdir -p /home/pat/backups
mkdir -p /home/pat/logs

Create script:

nano /home/pat/scripts/site-backup.sh

Script content:

#!/bin/bash

SOURCE="/var/www/site"
DESTINATION="/home/pat/backups"
LOG="/home/pat/logs/site-backup.log"
DATE=$(date +%Y-%m-%d-%H-%M)
ARCHIVE="$DESTINATION/site-$DATE.tar.gz"

echo "$(date +"%Y-%m-%d %H:%M:%S") Backup started" >> "$LOG"

mkdir -p "$DESTINATION"

tar -czf "$ARCHIVE" "$SOURCE" >> "$LOG" 2>&1

if tar -tzf "$ARCHIVE" > /dev/null 2>&1; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") Backup verified: $ARCHIVE" >> "$LOG"
else
    echo "$(date +"%Y-%m-%d %H:%M:%S") Backup verification failed: $ARCHIVE" >> "$LOG"
    exit 1
fi

echo "$(date +"%Y-%m-%d %H:%M:%S") Backup finished" >> "$LOG"

Make executable:

chmod +x /home/pat/scripts/site-backup.sh

Run manually:

/home/pat/scripts/site-backup.sh

Check log:

tail -n 50 /home/pat/logs/site-backup.log

Edit crontab:

crontab -e

Add daily schedule:

0 2 * * * /home/pat/scripts/site-backup.sh

Verify:

crontab -l

This is a complete beginner-friendly automation workflow.

Practical workflow: create a compressed report bundle

Suppose support asks you for logs and system state.

Create report directory:

mkdir -p ~/support-report

Collect system information:

hostname > ~/support-report/hostname.txt
uptime > ~/support-report/uptime.txt
df -h > ~/support-report/disk.txt
ip a > ~/support-report/ip-addresses.txt
ip route > ~/support-report/routes.txt
systemctl --failed > ~/support-report/failed-services.txt

Collect recent logs:

journalctl -n 300 > ~/support-report/journal-recent.txt

Create archive:

tar -czf support-report-$(date +%Y-%m-%d-%H-%M).tar.gz support-report/

Inspect archive:

tar -tzf support-report-$(date +%Y-%m-%d-%H-%M).tar.gz | head -50

This creates a clean diagnostic package without manually copying terminal output.

Be careful not to include secrets, private keys, tokens or sensitive customer data in support bundles.

Practical workflow: investigate a broken backup

A backup file exists, but is it usable?

Check size:

ls -lh backup.tar.gz

Test archive listing:

tar -tzf backup.tar.gz > /dev/null

Check exit status:

echo $?

Show first entries:

tar -tzf backup.tar.gz | head -30

Extract to a test directory:

mkdir -p /tmp/restore-test
tar -xzf backup.tar.gz -C /tmp/restore-test
tree -L 2 /tmp/restore-test

A backup is not proven by existing. It is proven by successful reading and preferably test restoration.

A better backup script verifies after creation:

if tar -tzf "$ARCHIVE" > /dev/null 2>&1; then
    echo "Backup verified"
else
    echo "Backup failed verification"
    exit 1
fi

Working with compressed logs

Linux logs are often compressed after rotation.

You may see files like:

syslog.1
syslog.2.gz
auth.log.1
auth.log.2.gz

To read a .gz file without extracting it, use zcat.

zcat /var/log/syslog.2.gz | less

Search compressed logs with zgrep.

zgrep -i "error" /var/log/syslog.2.gz

Count matches:

zgrep -i "failed password" /var/log/auth.log.*.gz | wc -l

List compressed log contents:

gzip -l /var/log/syslog.2.gz

These tools help investigate older logs without manually decompressing files.

Practical workflow: create a pre change snapshot using tar

Before making risky changes to a directory, create a local archive.

sudo tar -czf /root/site-before-change-$(date +%Y-%m-%d-%H-%M).tar.gz /var/www/site

Verify:

sudo tar -tzf /root/site-before-change-$(date +%Y-%m-%d-%H-%M).tar.gz | head

For configuration:

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%Y-%m-%d-%H-%M).backup

For whole config directory:

sudo tar -czf /root/nginx-config-before-change-$(date +%Y-%m-%d-%H-%M).tar.gz /etc/nginx

This provides rollback material before experiments.

A rollback archive is not a full backup strategy, but it is very useful before local changes.

Understanding file integrity checks

Sometimes you need to verify whether a file changed or whether two files are identical.

Use checksums.

sha256sum file.txt

Example output:

2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824  file.txt

Compare two files:

sha256sum file1.txt file2.txt

If the hash is the same, the content is the same with extremely high practical confidence.

Create checksum file:

sha256sum backup.tar.gz > backup.tar.gz.sha256

Verify later:

sha256sum -c backup.tar.gz.sha256

This is useful for backups, downloads and file transfer verification.

For a directory archive:

tar -czf site.tar.gz /var/www/site
sha256sum site.tar.gz > site.tar.gz.sha256

After transfer:

sha256sum -c site.tar.gz.sha256

This verifies that the archive did not change during transfer.

Practical workflow: verify transferred backup

On source server:

tar -czf site-backup.tar.gz /var/www/site
sha256sum site-backup.tar.gz > site-backup.tar.gz.sha256

Transfer:

scp site-backup.tar.gz site-backup.tar.gz.sha256 backup@backup-server:/backups/

On backup server:

cd /backups
sha256sum -c site-backup.tar.gz.sha256

Expected output:

site-backup.tar.gz: OK

Then test archive:

tar -tzf site-backup.tar.gz | head

This workflow verifies both transfer integrity and archive readability.

Understanding compression choices

Different compression tools have different tradeoffs.

FormatCommandGeneral characteristics
gzipgzip, tar -zFast, common, good default
bzip2bzip2, tar -jBetter compression than gzip in some cases, slower
xzxz, tar -JStrong compression, often slower
zipzipCommon for sharing with Windows users
plain tartar -cfArchive without compression

Create gzip tar:

tar -czf archive.tar.gz directory/

Create xz tar:

tar -cJf archive.tar.xz directory/

Create uncompressed tar:

tar -cf archive.tar directory/

If speed matters, gzip is often a good default. If smallest size matters and time is acceptable, xz may be useful.

For system backups, compatibility and restore speed often matter more than maximum compression.

Practical workflow: choose backup compression

Fast backup:

tar -czf site-fast-backup.tar.gz /var/www/site

Smaller backup:

tar -cJf site-small-backup.tar.xz /var/www/site

No compression, useful when storage is fast and compression is unnecessary:

tar -cf site-backup.tar /var/www/site

Check sizes:

ls -lh site-fast-backup.tar.gz site-small-backup.tar.xz site-backup.tar

Test readability:

tar -tf site-backup.tar | head
tar -tzf site-fast-backup.tar.gz | head
tar -tJf site-small-backup.tar.xz | head

Use the compression method that fits the operational need.

Practical workflow: restore configuration safely

Suppose you backed up /etc/nginx.

Archive:

nginx-config-backup.tar.gz

Inspect:

tar -tzf nginx-config-backup.tar.gz | head -50

Extract into test directory:

mkdir -p /tmp/nginx-config-restore
tar -xzf nginx-config-backup.tar.gz -C /tmp/nginx-config-restore
tree -L 3 /tmp/nginx-config-restore

Compare current and backup:

diff -ru /etc/nginx /tmp/nginx-config-restore/etc/nginx

Restore one file if needed:

sudo cp /tmp/nginx-config-restore/etc/nginx/nginx.conf /etc/nginx/nginx.conf

Test:

sudo nginx -t

Reload:

sudo systemctl reload nginx

This avoids blindly overwriting the whole configuration directory.

Practical workflow: compare cron and systemd timer for backups

Cron version:

0 2 * * * /home/pat/ops/scripts/site-backup >> /home/pat/ops/logs/site-backup-cron.log 2>&1

Systemd timer version:

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

Comparison:

FeatureCronsystemd timer
Simple syntaxYesMore files required
Integrated logsManual redirectionjournalctl
Missed run handlingNot by defaultPersistent=true
Dependency handlingLimitedStrong
Service statusLimitedsystemctl status
User familiarityVery commonModern systemd systems

Use cron for simple user tasks. Use systemd timers when you want service-style visibility, missed-run handling and better integration.

Permissions, ownership, users and groups

Permissions and ownership explain many Linux problems that look mysterious at first. Users, groups, modes, ACLs and sudo policy determine who can access what and under which conditions.

Understanding Linux permissions

Linux permissions control who can read, write and execute files. This is one of the most important security concepts in the system.

Run:

ls -l

Example:

-rw-r--r-- 1 pat pat 1200 May 14 10:18 notes.txt
-rwxr-xr-x 1 pat pat  842 May 14 10:19 backup.sh
drwxr-xr-x 2 pat pat 4096 May 14 10:20 scripts

The first column contains type and permissions.

Take this example:

-rwxr-xr--

Break it down:

PartMeaning
-Regular file
rwxOwner permissions
r-xGroup permissions
r--Others permissions

The permission letters mean:

LetterMeaning for filesMeaning for directories
rRead file contentList directory contents
wModify file contentCreate, delete or rename entries inside directory
xExecute file as a programEnter or traverse directory

The meaning of execute permission is different for files and directories.

For a file, execute means you can run it as a program or script.

For a directory, execute means you can enter it and access items inside it if you know their names.

This is why directory permissions can be confusing. A directory needs execute permission to be usable.

Permission groups: owner, group and others

Every file has three permission categories.

CategoryMeaning
OwnerThe user who owns the file
GroupThe group assigned to the file
OthersEveryone else

Example:

-rw-r--r-- 1 pat editors 1200 May 14 10:18 article.txt

This means:

FieldValue
Ownerpat
Groupeditors
Owner permissionsrw-
Group permissionsr--
Others permissionsr--

So pat can read and write. Members of editors can read. Everyone else can read.

A more restrictive example:

-rw------- 1 pat pat 1200 May 14 10:18 private.txt

Only pat can read and write this file.

A script example:

-rwxr-xr-x 1 pat pat 842 May 14 10:19 backup.sh

The owner can read, write and execute. Group and others can read and execute.

chmod with symbolic permissions

The command chmod changes permissions.

Make a script executable:

chmod +x backup.sh

This adds execute permission.

Remove execute permission:

chmod -x backup.sh

Give the owner execute permission only:

chmod u+x backup.sh

Remove write permission from others:

chmod o-w file.txt

Add read permission for group:

chmod g+r file.txt

The symbolic categories are:

SymbolMeaning
uUser owner
gGroup
oOthers
aAll

The operations are:

SymbolMeaning
+Add permission
-Remove permission
=Set exact permission

The permissions are:

SymbolMeaning
rRead
wWrite
xExecute

Examples:

chmod u+rw file.txt
chmod g-w file.txt
chmod o-r file.txt
chmod a+r public.txt
chmod u=rwx,g=rx,o= script.sh

Symbolic permissions are readable and good for learning.

chmod with numeric permissions

Numeric permissions are compact and common in administration.

Each permission has a number:

PermissionNumber
Read4
Write2
Execute1

Add the numbers together.

Permission setCalculationValue
r--44
rw-4 + 26
r-x4 + 15
rwx4 + 2 + 17
---00

A numeric permission has three digits.

Digit positionApplies to
First digitOwner
Second digitGroup
Third digitOthers

Examples:

PermissionMeaning
644Owner read/write, group read, others read
600Owner read/write, nobody else has access
755Owner full access, group and others read/execute
700Owner full access, nobody else has access
775Owner and group full access, others read/execute
777Everyone can read, write and execute

Set file to 644:

chmod 644 file.txt

Set script to 755:

chmod 755 script.sh

Set private key to 600:

chmod 600 ~/.ssh/id_rsa

Set private directory to 700:

chmod 700 ~/.ssh

Important warning: do not use chmod 777 as a universal fix. It gives everyone full access and can create serious security problems.

chmod on directories

Directory permissions deserve special attention.

For directories:

PermissionMeaning
ReadCan list directory contents
WriteCan create, delete or rename entries
ExecuteCan enter or traverse the directory

A common directory permission is 755.

chmod 755 public-directory

This means:

CategoryPermissionMeaning
OwnerrwxCan enter, list and modify
Groupr-xCan enter and list
Othersr-xCan enter and list

A private directory often uses 700.

chmod 700 private-directory

This means only the owner can access it.

For web directories, permissions must be chosen carefully. Giving write access to the wrong user can create security risks. Giving too little access can break uploads, cache generation or application updates.

A common safe starting pattern for many web projects is:

find /var/www/site -type d -exec chmod 755 {} \;
find /var/www/site -type f -exec chmod 644 {} \;

This sets directories to 755 and files to 644.

Do not apply this blindly to every application. Some applications need writable cache or upload directories.

chown: change owner and group

The command chown changes file owner and group.

Change owner:

sudo chown pat file.txt

Change owner and group:

sudo chown pat:www-data file.txt

Change ownership recursively:

sudo chown -R pat:www-data /var/www/site

The -R option means recursive. It changes ownership for the directory and everything inside it.

This is powerful and must be used carefully.

Common ownership examples:

CommandMeaning
sudo chown pat file.txtMake pat the owner
sudo chown pat:editors file.txtOwner pat, group editors
sudo chown :www-data file.txtChange group only
sudo chown -R pat:pat folderRecursively change owner and group

Check ownership:

ls -l file.txt

Check directory ownership:

ls -ld folder

The difference matters:

ls -l folder

shows the contents of the folder.

ls -ld folder

shows the folder itself.

Permission and ownership troubleshooting

Permission problems are common. The error messages usually look like this:

Permission denied

or:

Operation not permitted

A good troubleshooting workflow:

whoami
pwd
ls -ld .
ls -l target-file

This tells you who you are, where you are, the permissions of the current directory and the permissions of the target file.

If a script will not run:

ls -l script.sh
chmod +x script.sh
./script.sh

If a directory cannot be entered:

ls -ld directory

Check whether execute permission exists.

If a web application cannot write to a cache directory:

ls -ld cache
ls -l cache

You may need to adjust owner, group or permissions depending on which user the web server runs as.

For example:

sudo chown -R www-data:www-data cache

or:

sudo chmod -R 775 cache

But do not guess. First identify the correct service user.

ps aux | grep apache
ps aux | grep nginx

Permission fixes should be precise, not random.

The danger of recursive chmod and chown

Recursive permission changes can affect thousands of files.

This command:

sudo chmod -R 777 /var/www/site

may appear to “fix” a permission problem, but it creates a major security problem.

This command:

sudo chown -R pat:pat /

would be catastrophic because it would attempt to change ownership across the entire filesystem.

Before recursive changes, always verify the target.

pwd
ls -ld /var/www/site

Then use precise commands.

A safer web project example:

sudo find /var/www/site -type d -exec chmod 755 {} \;
sudo find /var/www/site -type f -exec chmod 644 {} \;

Writable upload directory only:

sudo chown -R www-data:www-data /var/www/site/uploads
sudo chmod -R 775 /var/www/site/uploads

This is better than making the entire website writable.

The principle is simple: change the smallest necessary area with the least necessary permission.

whoami, id and groups

Before changing permissions or debugging access, know who you are.

whoami

This prints the current username.

Show user and group IDs:

id

Example:

uid=1000(pat) gid=1000(pat) groups=1000(pat),27(sudo),33(www-data)

This tells you:

FieldMeaning
uidUser ID
gidPrimary group ID
groupsSupplementary groups

Show groups:

groups

Show groups for another user:

groups username

This matters because Linux permissions depend not only on the username but also on group membership.

If a file is owned by group www-data and has group write permission, a user must be in the www-data group to use that permission.

Example:

ls -l file.txt

Output:

-rw-rw-r-- 1 root www-data 1200 May 14 10:20 file.txt

A user in group www-data may write to this file if directory permissions also allow access.

Check:

id

If www-data is not listed, group permission will not apply to you.

su and sudo are different

The command sudo runs a command with elevated privileges, usually as root.

sudo apt update

The command su switches user.

su -

This tries to switch to the root user and start a login shell.

Switch to another user:

su - username

Run a command as another user with sudo:

sudo -u www-data whoami

Example:

sudo -u www-data php script.php

This runs the PHP script as the www-data user.

This is useful when debugging web application permissions. A file may be readable by your user but not by the web server user.

Test access as www-data:

sudo -u www-data ls -lah /var/www/site

Test writing:

sudo -u www-data touch /var/www/site/cache/test-file

If that fails, the web server may also fail to write cache files.

Use sudo -u as a diagnostic tool, not only as an administration shortcut.

Understanding users and groups in file access

Linux file access is decided by user, group and others permissions.

Example:

-rw-r----- 1 root www-data 1200 May 14 10:20 config.php

This means:

CategoryPermission
Owner rootRead and write
Group www-dataRead
OthersNo access

If the web server runs as www-data, it can read the file. Other users cannot.

Now consider:

drwxr-x--- 2 root www-data 4096 May 14 10:20 private

This directory allows:

CategoryAccess
Owner rootEnter, list, modify
Group www-dataEnter and list
OthersNo access

If a user is not root and not in www-data, they cannot enter.

To troubleshoot path access, use:

namei -l /var/www/site/private/config.php

This shows permissions for every path component.

Example output may show:

drwxr-xr-x root root /
drwxr-xr-x root root var
drwxr-xr-x root root www
drwxr-x--- root www-data site
-rw-r----- root www-data config.php

This helps reveal where access is blocked.

A file can have correct permissions, but if a parent directory blocks execute access, the file is still inaccessible.

passwd and changing passwords

The command passwd changes a user password.

Change your own password:

passwd

Change another user’s password as administrator:

sudo passwd username

Lock a password for an account:

sudo passwd -l username

Unlock:

sudo passwd -u username

On servers using SSH keys, password login may be disabled, but account passwords can still matter for local login, sudo policies or recovery workflows depending on configuration.

Password changes should be handled carefully, especially on production systems. Always know whether the account is used by humans, services or automation.

adduser, usermod and group membership

Create a user on Debian-based systems:

sudo adduser newuser

Add a user to a group:

sudo usermod -aG groupname username

Example: add user to sudo group:

sudo usermod -aG sudo pat

Example: add user to www-data group:

sudo usermod -aG www-data pat

The -aG combination is important.

OptionMeaning
-aAppend to supplementary groups
-GSpecify supplementary groups

Without -a, you may replace the user’s supplementary groups instead of adding to them. That can remove important access.

After group changes, the user usually needs to log out and log back in for the new group membership to appear.

Check:

id pat

or:

groups pat

Practical workflow: investigate permission denied

Suppose a user cannot read:

/var/www/site/uploads/image.jpg

Start with identity:

whoami
id

Check the file:

ls -l /var/www/site/uploads/image.jpg

Check the parent directory:

ls -ld /var/www/site/uploads

Check the whole path:

namei -l /var/www/site/uploads/image.jpg

Test as the service user if relevant:

sudo -u www-data ls -l /var/www/site/uploads/image.jpg

If the issue is missing directory execute permission, changing only the file will not help. One of the parent directories must allow traversal.

Example fix for a web upload directory:

sudo chown -R www-data:www-data /var/www/site/uploads
sudo find /var/www/site/uploads -type d -exec chmod 755 {} \;
sudo find /var/www/site/uploads -type f -exec chmod 644 {} \;

But this is only correct if www-data should own those uploads. Do not apply ownership changes blindly.

Process ownership and service users

Every process runs as a user. That user controls what the process can read and write.

Show processes:

ps aux

Find web server processes:

ps aux | grep nginx
ps aux | grep apache
ps aux | grep php

The first column is the process owner.

Example:

www-data  842  0.1  1.5 300000 65000 ?  S  10:20  0:01 nginx

This means the process runs as www-data.

If the process needs to write to:

/var/www/site/cache

then test:

sudo -u www-data touch /var/www/site/cache/test-file

If it fails, the application will likely fail too.

This is the connection between processes and permissions.

Advanced permissions explain many problems that basic chmod does not solve

Basic Linux permissions are built around three actions and three identity classes.

The actions are read, write and execute. The identity classes are owner, group and others. This model explains many everyday problems, but real Linux systems often need more detail. Web servers, shared directories, deployment users, backup users, scripts, SSH keys and service accounts all depend on permissions behaving predictably.

A beginner may know that chmod 755 gives executable access and chmod 644 is common for files. A professional user asks deeper questions.

Who owns the file?

Which group owns it?

Which user runs the process that needs access?

Does every parent directory allow traversal?

Is the execute bit missing on a directory?

Is the file controlled by ACL rules?

Is a special permission bit active?

Is the default creation mask causing new files to have unexpected permissions?

Is a service writing files as a different user than expected?

Linux permission problems often look simple from the outside, but the cause may be one level deeper than the file itself.

Review of standard permission logic

Run:

ls -l file.txt

Example output:

-rw-r----- 1 pat www-data 1200 May 14 10:20 file.txt

This line tells you the file type, permissions, owner, group, size, time and name.

The permission part is:

-rw-r-----

Break it down:

PartMeaning
-Regular file
rw-Owner can read and write
r--Group can read
---Others have no access

The owner is:

pat

The group is:

www-data

This means user pat can read and write. Members of group www-data can read. Everyone else has no access.

For directories, execute permission has a special meaning. It means the user can enter or traverse the directory.

Example:

ls -ld /var/www/site

Output:

drwxr-x--- 5 deploy www-data 4096 May 14 10:20 /var/www/site

This means:

CategoryPermissionPractical effect
Owner deployrwxCan enter, list and modify
Group www-datar-xCan enter and list
Others---Cannot access

If a web server runs as www-data, it can read files inside this directory only if the files and all parent directories allow it.

This is why the command below is extremely useful:

namei -l /var/www/site/index.html

It shows permissions for each path component, not only the final file.

umask controls default permissions for new files

When a user or process creates a new file, Linux does not usually create it with full open permissions. The final permissions are influenced by a value called umask.

Show current umask:

umask

Example output:

0022

The umask removes permissions from the default creation mode.

Typical defaults are:

Object typeBase permission before umask
New file666
New directory777

If the umask is 022, then:

ObjectBaseMinus umaskResult
File666022644
Directory777022755

That is why new files are often created as 644 and new directories as 755.

If the umask is 002, then:

ObjectBaseMinus umaskResult
File666002664
Directory777002775

This is common in collaborative group environments where group members should be able to write.

Set umask temporarily:

umask 002

Create a file and directory:

touch test-file
mkdir test-directory
ls -l
ls -ld test-directory

The permissions will reflect the active umask.

Why umask matters:

SituationWhy umask matters
Deployment user creates filesNew files may not be group-writable
Web app creates cache filesRuntime permissions may differ from expected
Shared foldersGroup collaboration may fail
Backup scriptsRestored or generated files may have different access
Cron jobsNon-interactive environment may use different umask

You can set umask inside a script.

#!/bin/bash

umask 002

mkdir -p /var/www/site/cache
touch /var/www/site/cache/example.cache

This ensures new files created by the script follow the intended permission pattern.

setgid directories keep group ownership consistent

A common problem in shared directories is inconsistent group ownership.

Suppose a project directory is owned by group www-data.

ls -ld /var/www/site

Output:

drwxrwxr-x 5 deploy www-data 4096 May 14 10:20 /var/www/site

If user deploy creates a new file, the file may be owned by the user’s primary group, not necessarily www-data.

The setgid bit on a directory helps solve this. When setgid is active on a directory, new files and subdirectories created inside it inherit the directory’s group.

Set setgid on a directory:

sudo chmod g+s /var/www/site

Check:

ls -ld /var/www/site

Output may show:

drwxrwsr-x 5 deploy www-data 4096 May 14 10:20 /var/www/site

The s in the group execute position indicates setgid.

Apply to directories recursively:

sudo find /var/www/site -type d -exec chmod g+s {} \;

A practical collaborative web directory setup may look like this:

sudo chown -R deploy:www-data /var/www/site
sudo find /var/www/site -type d -exec chmod 2775 {} \;
sudo find /var/www/site -type f -exec chmod 664 {} \;

The leading 2 in 2775 means setgid.

PermissionMeaning
775Owner and group can write, others can read and enter
2775Same as 775, plus setgid on directory

Use this carefully. It is useful for shared project directories, but it should not be applied blindly across the system.

Sticky bit protects shared directories

The sticky bit is commonly used on shared writable directories such as /tmp.

Check /tmp:

ls -ld /tmp

Typical output:

drwxrwxrwt 10 root root 4096 May 14 10:20 /tmp

The t at the end means sticky bit.

A directory with sticky bit allows multiple users to create files, but users cannot delete files owned by other users unless they have appropriate privileges.

This is important for shared temporary directories.

Set sticky bit:

sudo chmod +t shared-directory

Numeric form:

sudo chmod 1777 shared-directory

A permission of 1777 means:

PartMeaning
1Sticky bit
777Everyone can read, write and enter

This is appropriate for directories like /tmp, not for ordinary web application directories.

Do not use 1777 as a lazy fix for permission problems. It is for specific shared temporary use cases.

setuid is powerful and risky

The setuid bit allows an executable file to run with the permissions of the file owner, not the user who launched it.

A classic example is passwd.

ls -l /usr/bin/passwd

Output may look like:

-rwsr-xr-x 1 root root 68208 May 14 10:20 /usr/bin/passwd

The s in the owner execute position means setuid.

Why does passwd need this? A normal user must be able to change their password, but password data is stored in protected system files. The command needs controlled elevated privileges.

Set setuid:

sudo chmod u+s executable-file

Numeric form:

sudo chmod 4755 executable-file

The leading 4 means setuid.

Setuid is dangerous when applied incorrectly. A vulnerable setuid root program can become a serious security problem.

Find setuid files:

sudo find / -perm -4000 -type f -exec ls -lh {} \; 2> /dev/null

This command searches for files with setuid bit set.

You do not need to modify setuid files in normal administration unless you know exactly why.

ACLs provide permissions beyond owner group others

Standard permissions allow one owner, one group and others. Sometimes this is not flexible enough. Linux ACLs, access control lists, allow more detailed permission rules.

Check ACLs:

getfacl file.txt

Set ACL for a user:

setfacl -m u:alice:rw file.txt

This gives user alice read and write access to file.txt.

Set ACL for a group:

setfacl -m g:editors:rw file.txt

Remove ACL for a user:

setfacl -x u:alice file.txt

Set default ACL on a directory:

setfacl -m d:g:editors:rwx shared-directory

Default ACLs apply to newly created files and directories inside that directory.

Show ACLs:

getfacl shared-directory

If ls -l shows a plus sign after permissions, ACLs exist.

Example:

-rw-r-----+ 1 pat www-data 1200 May 14 10:20 file.txt

The + means extended ACLs are present.

ACLs are powerful, but they can also make permission troubleshooting more complex. If normal chmod and chown do not explain access behavior, check ACLs.

getfacl /path/to/file

sudo is controlled by policy

The sudo command does not magically give everyone root access. It checks policy. That policy is usually configured through the sudoers system.

The safest way to edit sudoers is:

sudo visudo

Do not edit the sudoers file with a normal editor unless you know exactly what you are doing. visudo checks syntax before saving, reducing the risk of locking out administrative access.

A common sudoers rule looks like:

%sudo   ALL=(ALL:ALL) ALL

This means members of group sudo can run commands as any user and group on any host, after authentication.

Check your groups:

id

If your user is in the sudo group, sudo access may be granted depending on configuration.

Add user to sudo group:

sudo usermod -aG sudo username

The user usually needs to log out and back in for group membership to apply.

Test sudo access:

sudo -v

Run a command:

sudo whoami

Expected output:

root

List allowed sudo commands:

sudo -l

This shows what the current user is allowed to run through sudo.

The sudoers.d directory

Many systems support additional sudo rules under:

/etc/sudoers.d/

List files:

sudo ls -lah /etc/sudoers.d/

Create a controlled rule with visudo:

sudo visudo -f /etc/sudoers.d/deploy

Example rule:

deploy ALL=(root) NOPASSWD: /usr/bin/systemctl reload nginx

This allows user deploy to reload Nginx without a password, but only that command.

This is much safer than giving full passwordless root access.

Bad rule:

deploy ALL=(ALL) NOPASSWD: ALL

This allows everything without a password. It may be too broad for many situations.

Better rules are specific.

UserAllowed commandReason
deployReload web serverNeeded after deployment
backupRun backup scriptNeeded for scheduled backups
monitorRead status commandsNeeded for monitoring

Least privilege applies to sudo too.

Understanding file ownership after extraction

When extracting archives, ownership can matter.

Extract as normal user:

tar -xzf archive.tar.gz

Files may be owned by the extracting user depending on archive and options.

Extract as root:

sudo tar -xzf archive.tar.gz -C /

This may preserve original numeric ownerships, which can be desired for system restores but dangerous if the archive is untrusted.

Inspect archive first:

tar -tzvf archive.tar.gz | head -30

The -v option shows details such as permissions and ownership.

Safer extraction into test directory:

mkdir -p /tmp/extract-test
tar -xzf archive.tar.gz -C /tmp/extract-test
ls -lah /tmp/extract-test

Never extract an unknown archive directly into /, /etc, /usr or a production directory without inspection.

Package management and software installation

Package management is the safest normal way to install, update, remove and investigate software on Debian-based Linux systems.

Package management is the safest way to install software on Linux

Installing software on Linux should usually be done through a package manager. A package manager is not only a download tool. It is a controlled system for finding software, installing it, updating it, verifying dependencies, removing it and keeping the operating system consistent.

On Debian-based systems such as Debian, Ubuntu, Linux Mint, Raspberry Pi OS and many server distributions derived from Debian, the most common package tool is apt.

When you install a program through apt, Linux does more than place one executable file somewhere on the disk. It checks repositories, reads package metadata, resolves dependencies, downloads the correct package versions, installs required libraries, registers the package in the local package database and often configures service files, documentation and default settings.

This matters because Linux software rarely exists as one isolated file. A web server, programming language, database system or desktop application may depend on many libraries and supporting packages.

For example, when you install a package such as apache2, the system may also install required dependencies. When you remove it later, the package manager knows what was installed and can manage it cleanly.

ConceptMeaning
PackageA software unit managed by the operating system
DependencyAnother package required by a package
RepositoryA trusted server or source containing packages
Package listLocal index of available packages
Package databaseLocal record of installed packages
UpgradeInstalling newer versions of installed packages
RemoveUninstalling a package
PurgeRemoving a package and its configuration files
AutoremoveRemoving dependencies no longer needed

A beginner may think installing software means downloading a random file from a website. On Linux, that should not be the first habit. The first habit should be: search the package manager.

apt search package-name

Then install using:

sudo apt install package-name

This approach is safer, easier to update and easier to undo.

Understanding repositories

A repository is a software source. It contains packages prepared for your distribution and version. Your system does not automatically know every software package in the world. It knows the repositories configured on that machine.

Repository configuration is commonly stored in files under:

/etc/apt/sources.list

and:

/etc/apt/sources.list.d/

You do not need to edit these files for normal package installation, but it is useful to know they exist.

When you run:

sudo apt update

your system contacts configured repositories and downloads fresh package lists. It does not upgrade your software yet. It only refreshes the local knowledge of what is available.

When you run:

sudo apt upgrade

your system installs newer versions of packages that are already installed, if upgrades are available.

This distinction is essential.

CommandWhat it doesWhat it does not do
sudo apt updateRefreshes package listsDoes not install upgrades
sudo apt upgradeUpgrades installed packagesDoes not refresh package lists by itself
sudo apt install packageInstalls a packageDoes not automatically know newest lists unless update was run
sudo apt remove packageRemoves a packageMay leave configuration files
sudo apt purge packageRemoves package and configurationDoes not remove all user data
sudo apt autoremoveRemoves unused dependenciesDoes not remove manually installed needed packages

A correct update workflow usually looks like this:

sudo apt update
sudo apt upgrade

This means: first refresh the list of available software versions, then upgrade installed packages.

apt update explained deeply

The command:

sudo apt update

updates the local package index. It asks the repositories: what packages are available, what versions exist and what dependencies are defined?

It does not install new package versions by itself.

This is why the name can be confusing for beginners. In everyday language, “update” often means making software newer. In apt, update means updating the package information database.

A typical workflow before installing software is:

sudo apt update
sudo apt install htop

This ensures that the package manager uses current repository metadata.

If you skip apt update, installation may still work, but your system may use outdated package information. On a server that has not been updated in a long time, this can lead to errors such as package not found, version conflicts or outdated dependency information.

A good habit:

sudo apt update

before:

sudo apt install package-name

and before:

sudo apt upgrade

Common output may include repository lines, package list downloads and information about packages that can be upgraded.

After apt update, the system may say that packages can be upgraded. That means you should decide whether to run:

sudo apt upgrade

or a more complete upgrade command depending on the system policy.

For a beginner or general server maintenance workflow, this is the standard safe starting point:

sudo apt update
sudo apt upgrade

apt upgrade explained deeply

The command:

sudo apt upgrade

upgrades installed packages to newer available versions from configured repositories.

It uses the package lists refreshed by apt update.

The command may show a list of packages to be upgraded and ask for confirmation. You can review the packages before accepting.

Automatic yes:

sudo apt upgrade -y

The -y option answers yes automatically. This can be useful in scripts, but it should not be used blindly on important production systems unless you understand the update policy.

Manual confirmation is safer when learning.

sudo apt upgrade

A good maintenance workflow:

sudo apt update
apt list --upgradable
sudo apt upgrade

The command:

apt list --upgradable

shows which packages can be upgraded before actually upgrading them.

This gives you more control.

CommandPurpose
sudo apt updateRefresh available package information
apt list --upgradableShow packages with available upgrades
sudo apt upgradeInstall available upgrades
sudo apt autoremoveClean dependencies no longer needed

A careful server maintenance sequence:

sudo apt update
apt list --upgradable
sudo apt upgrade
sudo apt autoremove

After kernel or critical system updates, a reboot may be required.

You can check whether a reboot is suggested on many Debian-based systems by looking for:

/var/run/reboot-required

Example:

ls /var/run/reboot-required

If the file exists, the system indicates that a reboot is recommended.

apt install explained deeply

The command:

sudo apt install package-name

installs a package.

Example:

sudo apt install htop

This installs htop, an interactive process viewer.

Install multiple packages:

sudo apt install htop tree curl wget unzip

This installs several packages in one command.

Before installing, you can search:

apt search htop

You can show package information:

apt show htop

The apt show command may display package version, description, dependencies, installed size, source repository and maintainer information.

This is useful when you do not know exactly what a package is.

CommandPurpose
apt search htopSearch package names and descriptions
apt show htopShow detailed package information
sudo apt install htopInstall the package
`dpkg -lgrep htop`

Install without recommended packages:

sudo apt install --no-install-recommends package-name

This can reduce installed dependencies, especially on minimal servers or containers. However, it may also omit useful supporting packages. Use it only when you understand the package.

Reinstall a package:

sudo apt install --reinstall package-name

This can help if files belonging to a package were accidentally removed or damaged.

apt search and finding the correct package name

Package names are not always obvious. The program name and package name may differ. This is why apt search is important.

Search for OpenJDK packages:

apt search openjdk

Filter search results:

apt search openjdk | grep jre

Search for Apache-related packages:

apt search apache2

Search for PHP packages:

apt search php

Search can produce many results. Filtering with grep makes it more useful.

apt search php | grep mysql

This searches packages related to PHP and filters lines containing mysql.

A practical pattern:

apt search keyword | grep second-keyword

Examples:

apt search python | grep venv
apt search nginx | grep module
apt search php | grep curl
apt search openjdk | grep jdk

This shows how package management connects to text filtering. apt search produces output. grep narrows it.

apt remove and apt purge

The command:

sudo apt remove package-name

removes a package, but usually leaves configuration files behind.

Example:

sudo apt remove vim

This removes the vim package.

If you want to remove the package and system-level configuration files, use:

sudo apt purge vim

The difference matters.

CommandRemoves program filesRemoves system configuration
apt removeYesUsually no
apt purgeYesYes

After removing packages, unused dependencies may remain. Clean them with:

sudo apt autoremove

A common cleanup workflow:

sudo apt remove package-name
sudo apt autoremove

A more complete removal workflow:

sudo apt purge package-name
sudo apt autoremove

Important detail: user-specific configuration files in home directories are usually not removed by apt purge.

For example, if an application created settings under:

/home/pat/.config/

those may remain because they belong to the user, not the system package database.

This is usually good because removing a package should not casually delete personal user data.

dpkg and manual package installation

The command dpkg is a lower-level Debian package tool. While apt manages repositories and dependencies, dpkg directly installs, removes and queries .deb packages.

Install a local .deb file:

sudo dpkg -i package.deb

If dependencies are missing, fix them with:

sudo apt -f install

The -f means fix broken dependencies.

A common manual installation workflow:

wget https://example.com/software.deb
sudo dpkg -i software.deb
sudo apt -f install

However, be careful with random .deb files. Installing packages outside official repositories can introduce compatibility, security and update problems.

Use manual .deb installation when:

SituationReason
The software vendor provides an official .deb packageCommon for some commercial tools
The package is not available in your repositoryManual installation may be necessary
You understand the source and trust itSecurity matters
You know how updates will be handledManual packages may not update automatically unless they add a repository

List installed packages:

dpkg -l

Filter installed packages:

dpkg -l | grep php

Show files installed by a package:

dpkg -L package-name

Find which package owns a file:

dpkg -S /path/to/file

Example:

dpkg -S /usr/bin/ls

This can tell you which package provides the ls command.

The package manager is also a system investigation tool.

Practical package workflow for a new server

When starting with a fresh Debian-based server, a common first workflow is:

sudo apt update
sudo apt upgrade
sudo apt install htop tree curl wget unzip zip rsync

This updates the system and installs useful administration tools.

A slightly more careful version:

sudo apt update
apt list --upgradable
sudo apt upgrade
sudo apt install htop tree curl wget unzip zip rsync

Then verify installed tools:

command -v htop
command -v tree
command -v curl
command -v wget
command -v rsync

This shows where the commands are located.

Example output:

/usr/bin/htop
/usr/bin/tree
/usr/bin/curl
/usr/bin/wget
/usr/bin/rsync

A good package maintenance routine:

sudo apt update
apt list --upgradable
sudo apt upgrade
sudo apt autoremove

This keeps the package database fresh, reviews upgrades, applies them and removes unused dependencies.

Practical workflow: install and start a web server

Install Apache:

sudo apt update
sudo apt install apache2

Start Apache:

sudo systemctl start apache2

Enable Apache at boot:

sudo systemctl enable apache2

Check status:

systemctl status apache2

Check listening ports:

sudo ss -tulpn | grep ':80'

Create a test file:

echo "Apache is working" | sudo tee /var/www/html/test.html

The command tee writes input to a file. With sudo, it can write to protected locations.

Why not simply use this?

sudo echo "Apache is working" > /var/www/html/test.html

Because redirection is handled by the shell before sudo applies to echo. The shell may not have permission to write into /var/www/html.

This works:

echo "Apache is working" | sudo tee /var/www/html/test.html

This is an important Linux lesson: sudo applies to the command, not automatically to shell redirection.

Practical workflow: install, inspect and remove a package

Install a tool:

sudo apt update
sudo apt install tree

Verify command path:

command -v tree

Use it:

tree -L 2

Check package status:

dpkg -l | grep tree

Show package information:

apt show tree

Show installed files:

dpkg -L tree

Remove it:

sudo apt remove tree

Remove unused dependencies:

sudo apt autoremove

This workflow teaches the full lifecycle: search, install, verify, inspect, use and remove.

Practical workflow: safe system update on a small server

A small server maintenance sequence can look like this:

who
uptime
df -h
systemctl --failed
sudo apt update
apt list --upgradable
sudo apt upgrade
sudo apt autoremove
systemctl --failed

Explanation:

CommandReason
whoSee logged-in users
uptimeCheck load and runtime
df -hEnsure enough disk space
systemctl --failedSee current service problems
apt updateRefresh package lists
apt list --upgradableReview available upgrades
apt upgradeApply upgrades
apt autoremoveRemove unused dependencies
systemctl --failedConfirm no new failed services

If a reboot is needed:

sudo reboot

After reconnecting:

uptime
systemctl --failed

This is controlled maintenance, not random updating.

Practical workflow: inspect a package and its files

Check whether a package is installed:

dpkg -l | grep nginx

Show package details:

apt show nginx

Show installed files:

dpkg -L nginx

Find which package owns a file:

dpkg -S /usr/sbin/nginx

Check service:

systemctl status nginx

This connects package management and service management.

If a configuration file is missing, dpkg -L package can show where it should be. If a binary exists but you do not know where it came from, dpkg -S can identify its package.

apt troubleshooting

Package management can fail for several reasons: network problems, repository issues, locks, broken dependencies, interrupted installations or insufficient disk space.

Start with disk space:

df -h

Update package lists:

sudo apt update

If update fails, read the error. It may be DNS, repository, GPG key, TLS, proxy or network related.

Check internet:

ping -c 4 8.8.8.8
getent hosts deb.debian.org

Fix broken dependencies:

sudo apt -f install

Reconfigure interrupted packages:

sudo dpkg --configure -a

Clean package cache:

sudo apt clean

Remove unused dependencies:

sudo apt autoremove

Check apt logs:

ls -lah /var/log/apt
cat /var/log/apt/history.log

A package lock error may look like another apt process is running. Check processes:

ps aux | grep apt
ps aux | grep dpkg

Do not delete lock files casually. First check whether a real package process is active. Killing or interrupting package operations can damage package state.

A safe recovery sequence after interrupted package work:

sudo dpkg --configure -a
sudo apt -f install
sudo apt update
sudo apt upgrade

This attempts to finish configuration, repair dependencies, refresh package lists and continue upgrades.

Understanding apt remove purge autoremove and clean

These apt commands remove different things.

CommandPurpose
sudo apt remove packageRemove installed package files
sudo apt purge packageRemove package and system configuration files
sudo apt autoremoveRemove unused dependency packages
sudo apt cleanClear downloaded package cache
sudo apt autocleanRemove obsolete package files from cache

Example:

sudo apt remove nginx

This removes Nginx package files, but may leave configuration.

sudo apt purge nginx

This removes Nginx and its system configuration files.

sudo apt autoremove

This removes packages installed as dependencies that are no longer needed.

sudo apt clean

This frees space used by cached .deb files.

Check package cache size:

sudo du -sh /var/cache/apt

Clean it:

sudo apt clean

Check again:

sudo du -sh /var/cache/apt

This can help on small systems with limited disk space.

dpkg database investigation

List installed packages:

dpkg -l

Search installed packages:

dpkg -l | grep nginx

Show files installed by a package:

dpkg -L nginx

Find which package owns a file:

dpkg -S /usr/sbin/nginx

Package file lists help answer questions like:

Where did this binary come from?

Which package installed this configuration file?

Which files belong to this package?

Is this command installed by the package I think it is?

Example:

command -v nginx
dpkg -S "$(command -v nginx)"

This finds the executable path and then asks which package owns it.

Processes, services and system control

Processes, services and system control commands show what is running, what failed, which programs own resources and how long-running system components are managed.

date: working with system time in commands

The command date displays the current date and time.

date

Custom format:

date +%Y-%m-%d

Example output:

2026-05-14

Useful date formats:

CommandExample output
date +%Y-%m-%d2026-05-14
date +%H:%M:%S10:30:45
date +%Y-%m-%d-%H-%M2026-05-14-10-30
date +"%Y-%m-%d %H:%M:%S"2026-05-14 10:30:45

The date command becomes powerful when used in filenames.

tar -czf backup-$(date +%Y-%m-%d).tar.gz project/

This creates a backup with the date in its name.

For logs:

echo "$(date +"%Y-%m-%d %H:%M:%S") Backup started" >> backup.log

This appends a timestamped line into backup.log.

uptime: checking how long the system has been running

The command uptime shows how long the system has been running and gives load average information.

uptime

Example output:

10:42:11 up 5 days,  3:21,  2 users,  load average: 0.18, 0.22, 0.20

This output contains:

PartMeaning
10:42:11Current system time
up 5 days, 3:21System has been running for 5 days and 3 hours 21 minutes
2 usersNumber of logged-in users
load averageSystem load over 1, 5 and 15 minutes

Show boot time:

uptime -s

Example:

2026-05-09 07:21:14

Uptime is useful because some problems appear after restarts, while others appear after long runtime.

If a server rebooted unexpectedly, uptime -s can help confirm when.

System management begins with understanding services

A Linux system runs many background programs. These programs may provide networking, logging, scheduling, databases, web servers, SSH access, printing, monitoring or other functionality.

A background program of this kind is often called a daemon. The managed unit used to start, stop, restart or inspect it is commonly called a service.

Examples of services:

ServiceTypical purpose
sshRemote shell access
apache2Apache web server
nginxNginx web server
mysqlMySQL or MariaDB database service
cronScheduled task service
rsyslogSystem logging service
dockerContainer engine
php-fpmPHP FastCGI process manager

On many modern Linux distributions, services are managed by systemd using the systemctl command. Older or compatibility commands may use service.

Both forms are still seen in documentation.

Traditional style:

sudo service apache2 restart

Modern systemd style:

sudo systemctl restart apache2

Both may work on many systems, but systemctl gives more detailed control and status information on systemd-based systems.

service command

The service command is a traditional way to manage services.

Start a service:

sudo service apache2 start

Stop a service:

sudo service apache2 stop

Restart a service:

sudo service apache2 restart

Reload configuration:

sudo service apache2 reload

Check status:

sudo service apache2 status

The difference between restart and reload matters.

ActionMeaning
StartStart a stopped service
StopStop a running service
RestartStop and start again
ReloadReload configuration without full restart, if supported
StatusShow current service state

Reload is usually less disruptive than restart, but not every service supports reload in the same way.

For example, after changing a web server configuration, you may try:

sudo service apache2 reload

If a full restart is needed:

sudo service apache2 restart

A safe configuration workflow is:

sudo apache2ctl configtest
sudo service apache2 reload

The first command tests Apache configuration before applying changes.

systemctl command

The systemctl command is the primary management tool for systemd services.

Start a service:

sudo systemctl start apache2

Stop a service:

sudo systemctl stop apache2

Restart a service:

sudo systemctl restart apache2

Reload configuration:

sudo systemctl reload apache2

Check status:

systemctl status apache2

Enable service at boot:

sudo systemctl enable apache2

Disable service at boot:

sudo systemctl disable apache2

Check whether service is enabled:

systemctl is-enabled apache2

Check whether service is active:

systemctl is-active apache2

Show failed services:

systemctl --failed

This is extremely useful after boot problems or service failures.

CommandPurpose
systemctl status serviceShow service state and recent logs
systemctl start serviceStart now
systemctl stop serviceStop now
systemctl restart serviceRestart now
systemctl reload serviceReload configuration
systemctl enable serviceStart automatically at boot
systemctl disable serviceDo not start automatically at boot
systemctl --failedShow failed units

The word enable does not mean start immediately. It means configure the service to start automatically during boot.

The word start means start now.

This distinction matters.

sudo systemctl enable nginx

makes Nginx start at boot.

sudo systemctl start nginx

starts Nginx immediately.

Often you want both:

sudo systemctl enable nginx
sudo systemctl start nginx

or:

sudo systemctl enable --now nginx

The --now option enables and starts in one command.

update-rc.d and service startup on older systems

The original cheat sheet includes update-rc.d, which is used on older Debian-style init systems and compatibility layers.

Enable SSH at boot:

sudo update-rc.d ssh enable

Disable SSH at boot:

sudo update-rc.d -f ssh remove

On modern systemd systems, the equivalent is usually:

sudo systemctl enable ssh

and:

sudo systemctl disable ssh

Understanding this helps when reading older tutorials. Many Linux guides remain useful, but commands evolve.

Older commandModern equivalent
sudo service apache2 startsudo systemctl start apache2
sudo service apache2 stopsudo systemctl stop apache2
sudo service apache2 restartsudo systemctl restart apache2
sudo service apache2 reloadsudo systemctl reload apache2
sudo update-rc.d ssh enablesudo systemctl enable ssh
sudo update-rc.d -f ssh removesudo systemctl disable ssh

A serious Linux user should recognize both styles.

Checking service status properly

When a service is not working, do not restart it blindly forever. First inspect its status.

systemctl status apache2

This may show:

InformationMeaning
LoadedWhether the service unit file exists and is loaded
ActiveWhether the service is running, stopped or failed
Main PIDMain process ID
TasksNumber of related processes
MemoryMemory used by the service
LogsRecent service log messages

If status shows failed, look at the log lines at the bottom. They often contain the real reason.

For deeper logs, use:

journalctl -u apache2

Follow logs live:

journalctl -u apache2 -f

Show recent logs:

journalctl -u apache2 -n 50

Although journalctl was not one of the central commands in the PDF cheat sheet, it is essential on modern systemd systems because it reads the systemd journal.

A professional service troubleshooting workflow:

systemctl status apache2
journalctl -u apache2 -n 50
sudo apache2ctl configtest
sudo systemctl restart apache2
systemctl status apache2

This reads status, checks logs, tests configuration, restarts and verifies.

Rebooting Linux safely

The command:

sudo reboot

restarts the system.

It is simple, but it should not be used casually on production machines. Rebooting disconnects users, stops services and interrupts running tasks.

Before rebooting a server, consider checking:

who
uptime
systemctl --failed
df -h

These commands show logged-in users, system runtime, failed services and disk space.

A more careful reboot workflow:

who
uptime
sudo reboot

If you are connected over SSH, your session will disconnect. Wait for the server to come back, then reconnect.

ssh user@server

After reconnecting:

uptime
systemctl --failed

This confirms the system booted and shows whether any services failed.

shutdown command

The command shutdown stops or restarts the system at a specific time.

Shut down immediately:

sudo shutdown -h now

Shut down at 20:00:

sudo shutdown -h 20:00

Reboot after one minute:

sudo shutdown -r +1

Cancel a scheduled shutdown:

sudo shutdown -c

Options:

OptionMeaning
-hHalt or power off
-rReboot
nowImmediately
+10In 10 minutes
20:00At 20:00 system time
-cCancel scheduled shutdown

A useful maintenance message:

sudo shutdown -r +10 "System will reboot for maintenance in 10 minutes"

This warns logged-in users.

On personal machines, immediate reboot is usually fine. On servers, scheduled shutdown is more professional.

Process management: every running program has a process

A process is a running instance of a program. When you start a shell, open an editor, run a web server or execute a script, Linux represents that activity as one or more processes.

Processes have process IDs, owners, states, memory usage, CPU usage and parent-child relationships.

The main commands for basic process management are:

CommandPurpose
psShow process list
ps auxShow detailed process list
topInteractive real-time process viewer
htopMore user-friendly process viewer
killSend a signal to a process by PID
killallSend a signal to processes by name
pgrepFind process IDs by name
pkillKill processes by name or pattern

The PDF cheat sheet includes ps, kill, killall and htop. These are core commands for understanding what is running on a Linux system.

ps aux explained

The command:

ps aux

shows running processes.

A simplified output may look like this:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.2 167000 12000 ?        Ss   May14   0:03 /sbin/init
www-data  842  0.1  1.5 300000 65000 ?        S    May14   1:20 apache2
pat      2510  0.0  0.1  12000  5000 pts/0    Ss   10:20   0:00 bash
pat      2601  0.0  0.1  15000  4000 pts/0    R+   10:30   0:00 ps aux

Important columns:

ColumnMeaning
USERUser owning the process
PIDProcess ID
%CPUCPU usage percentage
%MEMMemory usage percentage
VSZVirtual memory size
RSSPhysical memory currently used
TTYTerminal associated with process
STATProcess state
STARTStart time
TIMECPU time used
COMMANDCommand that started the process

Find processes related to Apache:

ps aux | grep apache

Find PHP processes:

ps aux | grep php

Find Nginx processes:

ps aux | grep nginx

A common beginner question is why grep itself appears in results.

Example:

pat  3001  0.0  0.0  grep apache

This happens because the grep apache command itself contains the word apache.

A common workaround:

ps aux | grep '[a]pache'

This searches for apache without matching the grep command line in the same way.

Another modern tool:

pgrep -a apache

This shows process IDs and command lines matching apache.

Process states

The STAT column in ps aux tells you the process state.

Common process states:

StateMeaning
RRunning or runnable
SSleeping, waiting for an event
DUninterruptible sleep, often waiting on I/O
TStopped
ZZombie process
sSession leader
+Foreground process group

A sleeping process is not necessarily a problem. Many services spend most of their time waiting for requests.

A zombie process is a process that has finished but still has an entry in the process table because its parent has not collected its exit status. Occasional zombies may appear briefly. Persistent zombies may indicate a parent process problem.

A process in uninterruptible sleep can be more serious, especially if related to disk or network filesystem issues.

For everyday administration, you do not need to memorize every process state immediately, but you should know that ps gives more than a list. It gives clues.

top and htop

The command top shows real-time system activity.

top

It displays CPU usage, memory usage, load average and active processes.

The command htop is a more user-friendly alternative.

htop

If it is not installed:

sudo apt update
sudo apt install htop

Why many administrators prefer htop:

FeatureBenefit
Color displayEasier to read
Interactive scrollingEasier navigation
Process tree viewBetter understanding of relationships
Search functionQuickly locate processes
Kill from interfaceStop processes interactively
CPU and memory barsFast visual overview

Inside htop, common keys include:

KeyAction
Arrow keysMove through process list
F3Search
F4Filter
F5Tree view
F6Sort
F9Kill selected process
F10Quit

You should not kill processes randomly from htop. First identify what they are and why they are running.

A good process investigation workflow:

uptime
htop
ps aux | grep process-name
systemctl status service-name

This connects system load, process view, specific process search and service status.

kill: stopping a process by PID

The command kill sends a signal to a process. Despite the name, it does not always mean immediate destruction. By default, it sends a termination signal asking the process to stop.

Basic syntax:

kill PID

Example:

kill 12345

This sends the default TERM signal.

Force kill:

kill -9 12345

The -9 signal is SIGKILL. It forces the kernel to stop the process. The process cannot clean up, save state or close files gracefully.

Use kill -9 only when normal termination fails.

A better sequence:

kill 12345
sleep 2
ps -p 12345
kill -9 12345

This first asks the process to stop normally, checks whether it is still running and only then forces termination if needed.

Common signals:

SignalNumberMeaning
SIGTERM15Ask process to terminate gracefully
SIGKILL9Force process to stop immediately
SIGHUP1Hangup, often used to reload configuration
SIGINT2Interrupt, similar to Ctrl + C

Send a named signal:

kill -TERM 12345

Force kill:

kill -KILL 12345

Reload-like signal for some processes:

kill -HUP 12345

Whether HUP reloads configuration depends on the program.

killall: stopping processes by name

The command killall sends a signal to processes by name.

Example:

killall php

This sends the default termination signal to processes named php.

Force kill:

killall -9 php

Use this carefully. It may stop more processes than intended.

A safer approach is to inspect first:

pgrep -a php

Then decide whether to use:

killall php

or kill a specific PID:

kill 12345

Comparison:

CommandTarget
kill 12345One process by PID
killall phpAll processes with the name php
pkill patternProcesses matching a pattern

A common beginner mistake is using killall without realizing how broad it can be.

On a shared or production server, prefer precise process IDs unless you are certain.

Process control with Ctrl + C, Ctrl + Z, jobs, fg and bg

Not every process needs to be killed with kill. Some are controlled directly from the terminal.

Stop a running foreground command:

Ctrl + C

This sends an interrupt signal.

Suspend a foreground command:

Ctrl + Z

This pauses it and returns you to the shell.

Show background and stopped jobs:

jobs

Resume a stopped job in the foreground:

fg

Resume a stopped job in the background:

bg

Example:

ping 8.8.8.8

Press:

Ctrl + Z

Then:

jobs
bg

The command continues in the background.

Bring it back:

fg

Stop it:

Ctrl + C

This is useful, but for long-running remote work, tools like screen or tmux are safer because they survive SSH disconnections.

Understanding logs in service management

Services often fail for reasons visible in logs. Linux logs may be stored in different places depending on the service and distribution.

Common locations:

LocationPurpose
/var/log/syslogGeneral system log on many Debian-based systems
/var/log/auth.logAuthentication logs
/var/log/apache2/Apache logs
/var/log/nginx/Nginx logs
/var/log/mysql/MySQL or MariaDB logs on some systems
journalctlSystemd journal logs

Read recent system logs:

tail -n 100 /var/log/syslog

Follow system logs:

sudo tail -f /var/log/syslog

Search errors:

grep -i "error" /var/log/syslog

Read service logs with journalctl:

journalctl -u service-name -n 100

Follow service logs live:

journalctl -u service-name -f

A practical restart and watch workflow:

sudo systemctl restart nginx
journalctl -u nginx -f

Stop following with:

Ctrl + C

Logs are often the difference between guessing and knowing.

The relationship between packages, services and processes

A strong Linux user understands that packages, services and processes are related but different.

LayerExampleMeaning
Packageapache2 packageInstalled software files managed by package manager
Serviceapache2.serviceManaged background unit
Process/usr/sbin/apache2 processCurrently running program instance
Port:80 or :443Network endpoint used by service
Log/var/log/apache2/error.logRecord of events and errors

Installing a package does not always mean the service is running.

A service being enabled does not always mean it is currently active.

A process running does not always mean it is listening on the expected port.

A port listening does not always mean the application is healthy.

You need commands for each layer.

QuestionCommand
Is the package installed?`dpkg -l
Is the service active?systemctl is-active apache2
Is the service enabled at boot?systemctl is-enabled apache2
What processes are running?`ps aux
Is the port listening?`sudo ss -tulpn
What do logs say?journalctl -u apache2 -n 50

This multi-layer thinking is essential for real troubleshooting.

Understanding foreground and background commands

When you run a command normally, it occupies the terminal until it finishes.

Example:

sleep 60

The terminal waits for 60 seconds.

Run it in the background:

sleep 60 &

The & symbol starts the command in the background.

Show jobs:

jobs

Bring a job to foreground:

fg

Background execution is useful for simple tasks, but it is not enough for important long-running remote tasks. If your SSH connection closes, background jobs may still end depending on how they were started.

For reliable long sessions, use:

screen

or:

tmux

The command screen is included in the original command set, and it remains useful for long-running administration work.

nohup for simple persistent commands

Another tool for keeping commands running after logout is nohup.

Example:

nohup ./long-script.sh > script.log 2>&1 &

This runs the script in the background and redirects output into script.log.

Breakdown:

PartMeaning
nohupIgnore hangup signal after logout
./long-script.shCommand to run
>Redirect standard output
script.logOutput file
2>&1Redirect errors to the same place as output
&Run in background

For beginners, screen is often easier because you can reattach and see the session interactively.

For scripts and automation, nohup can be useful.

watch: repeat a command automatically

The command watch repeatedly runs another command and displays the output.

Basic usage:

watch date

This refreshes every 2 seconds by default.

Run every 10 seconds:

watch -n 10 date

Watch disk space:

watch -n 5 df -h

Watch memory:

watch -n 5 free -h

Watch a directory:

watch -n 2 ls -lah

Watch listening ports:

watch -n 2 "ss -tulpn"

Use quotes when the watched command contains spaces, pipes or complex syntax.

Example:

watch -n 2 "ps aux | grep apache"

This repeats the full pipeline.

The watch command is useful during deployments, file transfers, log growth, service restarts and disk cleanup.

lsof: list open files

The command lsof means list open files.

lsof

This can produce a lot of output because Linux treats many things as files: regular files, directories, sockets, devices and network connections.

Find processes using a file:

lsof /path/to/file

Find what uses a port:

sudo lsof -i :80

Find what uses port 443:

sudo lsof -i :443

Find open deleted files:

sudo lsof | grep deleted

This is useful when disk space remains used after deleting large files.

Example workflow:

df -h
sudo lsof | grep deleted

If a large deleted file is still open by a process, restarting that process may release disk space.

Find network connections:

sudo lsof -i

The command lsof is advanced, but extremely valuable in troubleshooting.

netstat and ss

The command netstat appears in many older guides and cheat sheets. It shows network connections, routing tables and listening ports.

Show listening ports:

netstat -l

Show listening ports with process information:

sudo netstat -lp

Show continuously:

netstat -lpc

On many modern systems, ss is preferred.

Show listening TCP and UDP ports with process names:

sudo ss -tulpn

Breakdown:

OptionMeaning
-tTCP
-uUDP
-lListening sockets
-pShow process
-nNumeric addresses and ports

Check whether port 80 is listening:

sudo ss -tulpn | grep ':80'

Check SSH port:

sudo ss -tulpn | grep ':22'

netstat is still useful to recognize, but ss is usually the modern default.

dmesg: kernel messages

The command dmesg displays kernel ring buffer messages.

dmesg

It is useful for hardware, drivers, boot messages, disks, USB devices and kernel-level errors.

Search for errors:

dmesg | grep -i error

Search for USB events:

dmesg | grep -i usb

Follow kernel messages live:

sudo dmesg -w

A practical use case: plug in a USB drive, then run:

dmesg | tail -n 30

This may show which device name was assigned, such as /dev/sdb.

Another use case: disk problems.

dmesg | grep -i "I/O error"

Kernel messages are not everyday reading for beginners, but they are essential when diagnosing hardware or low-level system problems.

Key takeaways

At this point, the guide moves from file-level work into system-level administration. The command families now cover software installation, system updates, services, processes, long-running sessions and active server diagnosis.

The key commands in this section are:

CommandEssential role
apt updateRefresh package lists
apt upgradeUpgrade installed packages
apt installInstall packages
apt removeRemove packages
apt purgeRemove packages and configuration
apt searchFind packages
apt showDisplay package details
dpkg -iInstall local .deb packages
dpkg -lList installed packages
dpkg -LShow files installed by a package
dpkg -SFind which package owns a file
serviceTraditional service management
systemctlModern service management
rebootRestart the system
shutdownShut down or schedule restart
ps auxList running processes
htopInteractive process monitoring
killStop process by PID
killallStop processes by name
screenKeep terminal sessions alive
historyShow command history
watchRepeat commands automatically
lsofList open files and ports
netstatOlder network status tool
ssModern socket and port inspection
dmesgKernel and hardware messages

The deeper lesson is that Linux system administration is layered.

A package installs software. A service manages background behavior. A process is the running instance. A port exposes network access. A log explains what happened. A permission controls access. A filesystem stores the data. A command lets you inspect each layer.

Once you see those layers clearly, troubleshooting becomes much more precise. You no longer ask only “Why does it not work?” You ask better questions.

Is the package installed?

Is the service enabled?

Is it active?

Did it fail?

What do the logs say?

Is the process running?

Is the port listening?

Is the disk full?

Are permissions correct?

Was a configuration file changed recently?

Every one of those questions has a command. That is the real power of Linux.

Practical workflow: monitor a command repeatedly

Use watch to repeat commands.

Watch disk usage:

watch -n 5 df -h

Watch a directory during file transfer:

watch -n 2 "ls -lh /home/pat/downloads"

Watch memory:

watch -n 5 free -h

Watch top error count:

watch -n 10 "grep -i error app.log | wc -l"

Watch listening ports:

watch -n 2 "ss -tulpn"

The command must be quoted when it contains pipes or multiple words.

Without quotes, the shell may interpret only part of the command as the argument to watch.

Correct:

watch -n 10 "ps aux | grep nginx"

Risky or wrong:

watch -n 10 ps aux | grep nginx

The second form pipes the output of watch, not the intended repeated command.

Practical workflow: use lsof to solve file and port mysteries

Find what is using port 80:

sudo lsof -i :80

Find what is using port 443:

sudo lsof -i :443

Find processes using a mounted directory before unmounting:

sudo lsof +D /mnt/usb

This can help when umount says the target is busy.

Find deleted files still open:

sudo lsof | grep deleted

If disk space is not freed after deleting a large log, this may reveal the process still holding the file open.

Example workflow:

df -h
sudo lsof | grep deleted
sudo systemctl restart service-name
df -h

This is a real-world troubleshooting pattern.

Practical workflow: use dmesg for hardware events

View kernel messages:

dmesg

Show recent messages:

dmesg | tail -n 50

Search USB events:

dmesg | grep -i usb

Search disk errors:

dmesg | grep -i "error"

Follow live kernel messages:

sudo dmesg -w

Practical USB workflow:

sudo dmesg -w

Then plug in a USB drive and observe messages. Stop with:

Ctrl + C

Then check block devices:

lsblk

This helps identify whether the USB device appeared as /dev/sdb, /dev/sdc or another name.

Practical workflow: combine dmesg, lsblk and mount

Plug in a USB drive. Then run:

dmesg | tail -n 30
lsblk

Create mount point:

sudo mkdir -p /mnt/usb

Mount the partition:

sudo mount /dev/sdb1 /mnt/usb

Check:

df -h /mnt/usb
ls -lah /mnt/usb

Unmount safely:

sudo umount /mnt/usb

If unmount fails because the device is busy:

sudo lsof +D /mnt/usb

Close processes using it, change out of the directory if your shell is inside it, then try again.

cd ~
sudo umount /mnt/usb

This is a complete hardware-to-filesystem workflow.

Practical workflow: inspect a systemd service file

Show service file:

systemctl cat nginx

Show properties:

systemctl show nginx

Show selected property:

systemctl show nginx -p ExecStart

Show dependencies:

systemctl list-dependencies nginx

This helps explain how a service starts and what it depends on.

If you edit or add systemd unit files, reload systemd:

sudo systemctl daemon-reload

Then restart the service:

sudo systemctl restart service-name

Do not forget daemon-reload after changing unit files. Otherwise, systemd may continue using old unit information.

The difference between reload and restart

Many services support both reload and restart.

Reload usually means: read configuration again without fully stopping the service.

Restart means: stop and start the service.

ActionEffectRisk
ReloadApply configuration with less interruptionMay not apply all changes
RestartFully restarts serviceMore disruptive
StopStops serviceCauses downtime
StartStarts stopped serviceUsed after stop or failure

Examples:

sudo systemctl reload nginx
sudo systemctl restart nginx

Before either one, test configuration if possible.

sudo nginx -t

For Apache:

sudo apache2ctl configtest

For SSH:

sudo sshd -t

Prefer reload when supported and appropriate. Use restart when the service needs a full restart or reload is not enough.

Understanding system load

The uptime command shows load averages.

uptime

Example:

10:42:11 up 5 days, 3:21, 2 users, load average: 0.18, 0.22, 0.20

The three load numbers represent 1-minute, 5-minute and 15-minute averages.

Load is not exactly CPU percentage. It represents processes running or waiting for CPU and sometimes uninterruptible I/O.

Interpreting load depends on CPU core count.

Check CPU count:

nproc

If a system has 1 CPU core, a load of 1.00 may mean it is fully loaded. If it has 8 cores, a load of 1.00 is usually light.

Basic interpretation:

Load compared with CPU coresMeaning
Much lower than core countUsually fine
Around core countBusy but possibly normal
Much higher than core countPotential overload
High load with low CPUPossible I/O wait problem

Use htop or top to see more.

htop

If load is high, check CPU consumers:

ps aux --sort=-%cpu | head -15

Check memory:

free -h

Check disk I/O symptoms through logs:

dmesg | grep -i error

Load is a clue, not a conclusion.

Memory and swap basics

Check memory:

free -h

Example output:

               total        used        free      shared  buff/cache   available
Mem:           7.7Gi       2.1Gi       1.0Gi       120Mi       4.6Gi       5.2Gi
Swap:          2.0Gi       0.0Gi       2.0Gi

Important fields:

FieldMeaning
totalTotal memory
usedUsed memory
freeCompletely unused memory
buff/cacheMemory used for buffers and cache
availableEstimated memory available for applications
SwapDisk-based memory extension

Linux uses free memory for cache. This is normal. Do not panic just because free memory looks low. The available column is usually more useful.

Check swap devices:

swapon --show

High swap usage may indicate memory pressure, but some swap usage is not always a problem.

Find memory-heavy processes:

ps aux --sort=-%mem | head -15

Use htop for interactive inspection.

htop

Memory troubleshooting should ask whether usage is expected. Databases, search engines, Java applications and caches may use large amounts of memory by design.

journalctl is the modern log reader for systemd systems

Many modern Linux systems use systemd. The logs managed by systemd are read with journalctl.

Show recent logs:

journalctl -n 100

Follow logs live:

journalctl -f

Show logs for one service:

journalctl -u nginx

Show recent service logs:

journalctl -u nginx -n 100

Follow service logs:

journalctl -u nginx -f

Show logs since today:

journalctl --since today

Show logs since a specific time:

journalctl --since "2026-05-14 10:00"

Show logs in a time range:

journalctl --since "2026-05-14 10:00" --until "2026-05-14 11:00"

Show only errors:

journalctl -p err -n 100

Priority levels include:

PriorityMeaning
emergSystem is unusable
alertImmediate action required
critCritical condition
errError
warningWarning
noticeNormal but significant
infoInformational
debugDebug messages

For troubleshooting, -p err and -p warning are very useful.

journalctl -p warning -n 100

This shows warning-level and more severe messages.

journalctl for boot analysis

Show logs from the current boot:

journalctl -b

Show logs from the previous boot:

journalctl -b -1

List boots:

journalctl --list-boots

This is useful after unexpected reboots or startup failures.

Example workflow after a server rebooted unexpectedly:

uptime
journalctl --list-boots
journalctl -b -1 -p warning

This checks current uptime, lists boot history and shows warnings or errors from the previous boot.

If a service failed during boot:

systemctl --failed
journalctl -b -u service-name

This reads logs for that service from the current boot.

journal disk usage

The systemd journal can consume disk space.

Check journal size:

journalctl --disk-usage

Vacuum old journal logs by time:

sudo journalctl --vacuum-time=14d

Vacuum by size:

sudo journalctl --vacuum-size=1G

Use carefully. Logs are evidence. Do not remove them during an active investigation unless necessary.

Persistent journal configuration is often controlled under:

/etc/systemd/journald.conf

After changing journald configuration:

sudo systemctl restart systemd-journald

A practical disk cleanup workflow may include:

journalctl --disk-usage
sudo journalctl --vacuum-time=14d
journalctl --disk-usage

This checks size before and after cleanup.

systemctl is more than start and stop

Many users learn only these commands:

sudo systemctl start service
sudo systemctl stop service
sudo systemctl restart service

But systemctl can do much more.

Show status:

systemctl status nginx

Show whether active:

systemctl is-active nginx

Show whether enabled:

systemctl is-enabled nginx

Enable and start immediately:

sudo systemctl enable --now nginx

Disable and stop immediately:

sudo systemctl disable --now nginx

Show failed units:

systemctl --failed

Reload systemd after unit changes:

sudo systemctl daemon-reload

Show a service unit file:

systemctl cat nginx

Show service properties:

systemctl show nginx

Show dependencies:

systemctl list-dependencies nginx

List running services:

systemctl list-units --type=service --state=running

List all service unit files:

systemctl list-unit-files --type=service

The difference between a unit being active and enabled is important.

StateMeaning
ActiveRunning now
EnabledConfigured to start at boot
DisabledNot configured to start at boot
FailedTried to run but failed
MaskedPrevented from being started

Mask a service:

sudo systemctl mask service-name

Unmask:

sudo systemctl unmask service-name

Masking is stronger than disabling. A masked service cannot be started until unmasked.

Creating a simple systemd service

Cron is useful for scheduled jobs. But for long-running background programs, a systemd service is often better.

Suppose you have a script:

/home/pat/scripts/worker.sh

Make it executable:

chmod +x /home/pat/scripts/worker.sh

Create a service file:

sudo nano /etc/systemd/system/myworker.service

Content:

[Unit]
Description=My custom worker
After=network.target

[Service]
Type=simple
User=pat
WorkingDirectory=/home/pat/scripts
ExecStart=/home/pat/scripts/worker.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target

Reload systemd:

sudo systemctl daemon-reload

Start service:

sudo systemctl start myworker

Check status:

systemctl status myworker

Enable at boot:

sudo systemctl enable myworker

View logs:

journalctl -u myworker -f

This converts a script into a managed background service.

Important service fields:

FieldMeaning
DescriptionHuman-readable service description
AfterStart ordering
UserUser account running the process
WorkingDirectoryDirectory where process starts
ExecStartCommand to run
RestartRestart policy
WantedByBoot target for enabling

Systemd services are more appropriate than cron for programs that should stay running continuously.

systemd targets explain system states

Systemd uses targets to group system states.

List targets:

systemctl list-units --type=target

Common targets:

TargetMeaning
multi-user.targetNormal non-graphical multi-user mode
graphical.targetGraphical mode
rescue.targetSingle-user rescue mode
emergency.targetMinimal emergency shell
network.targetBasic network target
timers.targetTimer units active

Check default target:

systemctl get-default

Set default target to multi-user:

sudo systemctl set-default multi-user.target

Set default target to graphical:

sudo systemctl set-default graphical.target

Switch target temporarily:

sudo systemctl isolate multi-user.target

Be careful with isolate. It can stop services not part of the target.

For normal administration, you mostly need to know that targets define boot states and service grouping.

uname and kernel information

The command uname shows system and kernel information.

uname

Show all information:

uname -a

Show kernel release:

uname -r

Show machine architecture:

uname -m

Examples:

CommandPurpose
unameKernel name
uname -aAll available uname information
uname -rKernel release
uname -mMachine architecture

Kernel version matters for drivers, modules, containers, security updates and compatibility.

After kernel updates, a reboot may be needed before the new kernel is active.

Check running kernel:

uname -r

Check whether reboot is recommended on many Debian-based systems:

ls /var/run/reboot-required

If the file exists, plan a reboot.

lsmod and kernel modules

Kernel modules are pieces of code loaded into the kernel, often for drivers or filesystems.

List loaded modules:

lsmod

Search for a module:

lsmod | grep module-name

Show module information:

modinfo module-name

Load a module:

sudo modprobe module-name

Unload a module:

sudo modprobe -r module-name

These commands are more advanced and should be used carefully. Removing the wrong module can affect hardware or network functionality.

Practical example: checking whether a virtualization or filesystem module is loaded.

lsmod | grep overlay

This may matter for container systems.

Most users do not manually manage modules often, but knowing how to inspect them helps with hardware and container troubleshooting.

sysctl and kernel parameters

The sysctl command reads and changes kernel parameters at runtime.

Show all parameters:

sysctl -a

Show one parameter:

sysctl net.ipv4.ip_forward

Enable IP forwarding temporarily:

sudo sysctl -w net.ipv4.ip_forward=1

This runtime change may not survive reboot.

Persistent sysctl settings are usually placed under:

/etc/sysctl.conf
/etc/sysctl.d/

Example:

sudo nano /etc/sysctl.d/99-custom.conf

Content:

net.ipv4.ip_forward=1

Apply:

sudo sysctl --system

Be careful. Kernel parameters can affect networking, memory, security and performance.

A safe workflow:

sysctl parameter.name
sudo sysctl -w parameter.name=value
sysctl parameter.name

For persistent changes, document why the parameter is needed.

Environment files for services

Systemd services can use environment files. These files define variables used by the service.

Show a service file:

systemctl cat service-name

Look for lines like:

EnvironmentFile=/etc/default/service-name

or:

Environment="NAME=value"

Inspect environment file:

cat /etc/default/service-name

Edit carefully:

sudo cp /etc/default/service-name /etc/default/service-name.$(date +%Y-%m-%d-%H-%M).backup
sudo nano /etc/default/service-name

Restart service:

sudo systemctl restart service-name

Check logs:

journalctl -u service-name -n 100

Environment variables are often used to configure applications without changing code. They may include ports, paths, runtime modes or feature flags.

Be careful with secrets. Environment variables can sometimes be visible through process inspection depending on permissions and system configuration.

Working directory matters in services and scripts

A script may work when you run it from one directory and fail from another.

Example script:

#!/bin/bash

cat config.txt

If you run it from the directory containing config.txt, it works. If cron or systemd runs it from another directory, it fails.

Better:

#!/bin/bash

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cat "$SCRIPT_DIR/config.txt"

Or use absolute paths:

cat /home/pat/myapp/config.txt

In systemd service files, set:

WorkingDirectory=/home/pat/myapp

Then relative paths inside the application start from that directory.

In cron, avoid relative paths unless the script explicitly changes directory.

cd /home/pat/myapp || exit 1

Then run commands.

The current directory is an invisible dependency. Make it explicit.

Understanding signals beyond kill -9

The kill command sends signals. The default signal is usually SIGTERM, which asks a process to terminate gracefully.

Show available signals:

kill -l

Common signals:

SignalNumberMeaning
SIGHUP1Hangup, often reload configuration
SIGINT2Interrupt, like Ctrl + C
SIGTERM15Graceful termination request
SIGKILL9Immediate forced termination
SIGSTOP19 or system-dependentStop process
SIGCONT18 or system-dependentContinue stopped process

Graceful stop:

kill PID

Explicit graceful stop:

kill -TERM PID

Force stop:

kill -KILL PID

or:

kill -9 PID

Do not use kill -9 as the first option. It prevents cleanup. Files may remain incomplete. Locks may remain. Temporary state may not be cleaned.

For managed services, prefer:

sudo systemctl stop service-name

or:

sudo systemctl restart service-name

Systemd understands the service better than a random PID kill.

Process trees explain parent and child relationships

Processes can start other processes. This creates a process tree.

Show process tree with ps:

ps auxf

Install and use pstree if available:

sudo apt install psmisc
pstree -p

The -p option shows PIDs.

A web server may have a master process and worker processes. A shell may start scripts. A service manager may start a daemon.

Why process trees matter:

SituationWhy tree helps
Killing parent may stop childrenUseful or dangerous depending on context
Worker processes belong to masterRestart service instead of killing workers
Script started many child commandsNeed to understand full activity
Zombie process existsParent relationship matters
High CPU child processNeed to know what started it

Example:

ps auxf | grep nginx

This may show a master Nginx process and worker processes.

Do not kill worker processes randomly if the service manager should handle them.

Nice and process priority

Linux processes have scheduling priority. The nice value influences CPU scheduling.

Show nice values:

ps -eo pid,ni,comm | head

Run a command with lower priority:

nice -n 10 tar -czf backup.tar.gz /large/source

Higher nice value means lower priority.

Renice a running process:

sudo renice 10 -p PID

This can be useful for CPU-heavy tasks such as compression or batch processing.

Do not use priority changes as a substitute for proper capacity planning, but they can reduce impact of background jobs.

Example backup with lower CPU priority:

nice -n 10 tar -czf backup.tar.gz /var/www/site

Combine with I/O priority if ionice is available:

ionice -c2 -n7 nice -n 10 tar -czf backup.tar.gz /var/www/site

This tries to make the backup less disruptive.

Understanding PID files

A PID file contains a process ID. Services sometimes use PID files to record which process is running.

Common locations:

/run/service-name.pid
/var/run/service-name.pid

/var/run is often a link to /run.

Read PID file:

cat /run/service-name.pid

Check process:

ps -p "$(cat /run/service-name.pid)" -f

If the PID file points to a process that no longer exists, it may be stale.

Systemd often manages processes without requiring traditional PID files, but many services and scripts still use them.

Storage, disks, mounts and filesystem usage

Storage troubleshooting starts with free space, directory usage, mounts, persistent mount configuration and temporary data.

Disk space with df

The command df shows free and used space on mounted filesystems.

Basic command:

df

Human-readable output:

df -h

The -h option means human-readable. It shows sizes in KB, MB, GB or TB instead of raw blocks.

Example output:

Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   31G   17G  65% /
/dev/sdb1       200G  120G   80G  60% /mnt/data

Important columns:

ColumnMeaning
FilesystemDevice or filesystem source
SizeTotal size
UsedUsed space
AvailAvailable space
Use%Percentage used
Mounted onWhere it appears in the filesystem

Check a specific path:

df -h /var

Check the filesystem containing your current directory:

df -h .

The command df answers this question: how full is the filesystem?

It does not tell you which folder is responsible. For that, use du.

Disk usage with du

The command du shows how much space files and directories use.

Basic command:

du

This can produce a lot of output.

Human-readable summary of current directory:

du -sh .

Human-readable summary of a specific directory:

du -sh /home/pat

Show sizes of immediate items inside a directory:

du -h --max-depth=1 /home/pat

Sort by size:

du -h --max-depth=1 /home/pat | sort -h

Show largest items at the bottom:

du -h --max-depth=1 /home/pat | sort -h

Show largest items at the top with numeric kilobyte sorting:

du -ak /home/pat | sort -nr | head -20

The command from the cheat sheet style is especially useful:

du -ak | sort -nr | head -20

This finds the largest items under the current directory.

Command partPurpose
du -akShow disk usage in kilobytes for all items
sort -nrSort numerically from largest to smallest
head -20Show only the first 20 lines

A common disk investigation workflow:

df -h
du -sh /*
du -h --max-depth=1 /var | sort -h
du -h --max-depth=1 /var/log | sort -h

This starts broad and narrows down.

The difference between df and du is important.

CommandAnswers
df -hWhich filesystem is full?
du -sh folderHow much space does this folder use?
du -h --max-depth=1Which subfolder is large?

Use df first to identify the full filesystem. Use du next to find what is using space.

Why df and du may disagree

Sometimes df says a filesystem is full, but du does not show enough files to explain the usage. This can happen when a deleted file is still held open by a running process.

Linux allows a process to keep writing to a file even after the file name has been removed from the directory. The file disappears from normal listings, but the disk space is not released until the process closes it.

You can investigate this with lsof.

sudo lsof | grep deleted

If a huge deleted log file is still open, restarting the related service may release the space.

Example workflow:

df -h
sudo lsof | grep deleted
sudo systemctl restart service-name
df -h

This is an advanced but very real Linux troubleshooting situation.

Mounting and unmounting filesystems

Linux does not use drive letters like C: or D:. A disk or partition becomes accessible by being mounted somewhere in the filesystem tree.

The command mount attaches a filesystem to a directory.

The command umount detaches it.

Mount a partition:

sudo mount /dev/sda1 /mnt/usb

Unmount it:

sudo umount /mnt/usb

The command is umount, not unmount.

The directory /mnt/usb is called a mount point. It must exist before mounting.

sudo mkdir -p /mnt/usb
sudo mount /dev/sda1 /mnt/usb

Check mounted filesystems:

mount

More readable disk overview:

lsblk

Example output:

NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda      8:0    0   50G  0 disk
└─sda1   8:1    0   50G  0 part /
sdb      8:16   1   32G  0 disk
└─sdb1   8:17   1   32G  0 part /mnt/usb

The command lsblk is very useful before mounting because it shows available block devices.

A safe USB mounting workflow:

lsblk
sudo mkdir -p /mnt/usb
sudo mount /dev/sdb1 /mnt/usb
df -h /mnt/usb
ls -lah /mnt/usb

Before unplugging or removing a mounted device:

sudo umount /mnt/usb

Unmounting ensures pending writes are completed and the filesystem is detached safely.

Practical workflow: investigate a full disk

A real Linux administrator often starts with a warning: disk usage is high. The goal is not to delete something quickly. The goal is to find the cause safely.

Start with filesystems:

df -h

Find which filesystem is full.

If / is full, inspect top-level directories:

sudo du -h --max-depth=1 / | sort -h

If /var is large:

sudo du -h --max-depth=1 /var | sort -h

If /var/log is large:

sudo du -h --max-depth=1 /var/log | sort -h

Find large log files:

sudo find /var/log -type f -size +100M -exec ls -lh {} \;

Check compressed old logs:

sudo find /var/log -type f -iname "*.gz" -mtime +30 -exec ls -lh {} \;

Only after review, remove old compressed logs:

sudo find /var/log -type f -iname "*.gz" -mtime +30 -delete

Check space again:

df -h

If space is still not freed, check deleted open files:

sudo lsof | grep deleted

This workflow shows professional Linux thinking: identify, narrow down, verify, act, verify again.

Disk usage and inode usage

Disk space has two important dimensions: blocks and inodes.

Check block usage:

df -h

Check inode usage:

df -i

A filesystem can have free space but no free inodes. This happens when there are too many small files.

If inodes are full, commands may fail with:

No space left on device

even if df -h shows available space.

Find directories with many files:

sudo find /var -xdev -type f | cut -d / -f 2,3 | sort | uniq -c | sort -nr | head -20

This estimates where many files are located under /var.

Find many small session files, cache files or temporary files.

sudo find /var -type f -size -4k | wc -l

Do not delete randomly. Identify the application creating excessive files, then fix retention, cache cleanup or application behavior.

Practical workflow: inspect mounted filesystems deeply

Show block devices:

lsblk

Show filesystems:

lsblk -f

Show mounted filesystems:

findmnt

Show one mount:

findmnt /mnt/usb

Check disk free:

df -h

Check filesystem type:

df -Th

Example output:

Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/sda1      ext4   50G   20G   28G  42% /

The filesystem type matters. Permissions, ownership, symlinks and special features behave differently across filesystems such as ext4, xfs, btrfs, nfs, cifs, vfat or exfat.

For example, FAT-based filesystems do not support Unix permissions in the same way as ext4.

If permissions behave strangely on a mounted drive, check filesystem type.

lsblk -f
df -Th
mount | grep /mnt/usb

fstab controls persistent mounts

The file:

/etc/fstab

defines filesystems that should mount automatically.

View it:

cat /etc/fstab

Before editing, back it up:

sudo cp /etc/fstab /etc/fstab.$(date +%Y-%m-%d-%H-%M).backup

Edit:

sudo nano /etc/fstab

Test without rebooting:

sudo mount -a

If mount -a returns errors, fix them before rebooting. A broken fstab can cause boot problems.

A typical line may look like:

UUID=xxxx-xxxx /mnt/data ext4 defaults 0 2

Fields:

FieldMeaning
Device or UUIDWhat to mount
Mount pointWhere to mount
Filesystem typeext4, xfs, nfs, etc.
OptionsMount options
DumpBackup flag, often 0
PassFilesystem check order

Use UUIDs instead of device names when possible because /dev/sdb1 can change between boots.

Show UUIDs:

blkid

Persistent mounts are powerful, but mistakes can affect boot. Always test with mount -a.

Practical workflow: safe external disk setup

Plug in disk.

Inspect:

lsblk
lsblk -f
dmesg | tail -n 30

Create mount point:

sudo mkdir -p /mnt/data

Mount manually:

sudo mount /dev/sdb1 /mnt/data

Check:

df -h /mnt/data
ls -lah /mnt/data

Find UUID:

sudo blkid /dev/sdb1

Back up fstab:

sudo cp /etc/fstab /etc/fstab.backup

Edit fstab:

sudo nano /etc/fstab

Add carefully:

UUID=your-uuid-here /mnt/data ext4 defaults,nofail 0 2

Test:

sudo umount /mnt/data
sudo mount -a
df -h /mnt/data

The nofail option can prevent boot failure if an external disk is missing, depending on the use case.

Understanding temporary directories

Linux has multiple temporary locations.

DirectoryTypical behavior
/tmpTemporary files, often cleaned on reboot or by policy
/var/tmpTemporary files that may persist longer
/runRuntime files, cleared on reboot
User cacheUsually under ~/.cache

Check /tmp:

du -sh /tmp

Find old files:

sudo find /tmp -type f -mtime +7 -exec ls -lh {} \;

Do not blindly run:

sudo rm -rf /tmp/*

Some running programs may be using files there.

A safer cleanup:

sudo find /tmp -type f -mtime +7 -delete
sudo find /tmp -type d -empty -delete

Still use caution. Temporary does not always mean safe to delete right now.

Networking, SSH and remote file transfer

Networking, SSH and remote transfer commands make Linux useful across servers, hosting environments and production systems.

Networking in Linux begins with understanding interfaces

Networking in Linux starts with a simple question: how does this machine connect to the outside world?

A Linux system can have one network interface or many. A laptop may have Wi-Fi, Ethernet, Bluetooth networking and virtual interfaces created by VPNs or containers. A server may have one public interface, one private interface, loopback, bridge interfaces, Docker networks, VLANs or bonded interfaces. A Raspberry Pi may have Ethernet, Wi-Fi and USB networking. The command line gives you a precise way to see all of them.

A network interface is the system’s connection point to a network. It may be physical, such as an Ethernet card, or virtual, such as a bridge used by containers.

Common interface names include:

Interface nameTypical meaning
loLoopback interface used by the system to talk to itself
eth0Traditional name for the first Ethernet interface
wlan0Traditional name for the first Wi-Fi interface
enp0s3Predictable modern Ethernet interface name
ens33Another common modern Ethernet interface name
wlp2s0Predictable modern Wi-Fi interface name
docker0Docker bridge interface
br0Bridge interface
tun0Tunnel interface, often used by VPNs

The loopback interface lo is always important. It usually uses the IP address:

127.0.0.1

and the hostname:

localhost

This means the machine is communicating with itself. Many local services listen on loopback when they should be available only locally.

The first practical networking skill is learning how to inspect interfaces and addresses.

ip: the modern command for network inspection

The modern Linux command for network information is ip.

Show all network addresses:

ip a

or the longer form:

ip address

Typical output may include interface names, MAC addresses, IPv4 addresses, IPv6 addresses and interface states.

A simplified example:

2: enp0s3:  mtu 1500
    link/ether 08:00:27:12:34:56 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.50/24 brd 192.168.1.255 scope global dynamic enp0s3
    inet6 fe80::a00:27ff:fe12:3456/64 scope link

This output contains several important pieces of information.

FieldMeaning
enp0s3Interface name
UPInterface is enabled
LOWER_UPPhysical or link-layer connection is active
link/etherMAC address line
inetIPv4 address
192.168.1.50/24IPv4 address with subnet prefix
brdBroadcast address
dynamicAddress was likely assigned by DHCP
inet6IPv6 address

The /24 part is CIDR notation. It describes the subnet size. In many home and office networks, /24 corresponds to a subnet mask of:

255.255.255.0

This means addresses such as:

192.168.1.1
192.168.1.50
192.168.1.200

are usually in the same local network if they share the same /24 network.

Show only IPv4 addresses:

ip -4 a

Show only IPv6 addresses:

ip -6 a

Show a specific interface:

ip a show enp0s3

Bring an interface up:

sudo ip link set enp0s3 up

Bring an interface down:

sudo ip link set enp0s3 down

Show routing table:

ip route

Example output:

default via 192.168.1.1 dev enp0s3
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.50

This tells you two important things.

RouteMeaning
default via 192.168.1.1Traffic to other networks goes through gateway 192.168.1.1
192.168.1.0/24 dev enp0s3Local network is reachable through interface enp0s3

The default gateway is essential. If your IP address is correct but there is no default route, the machine may communicate locally but not reach the internet.

ifconfig: the older network command

The command ifconfig is older and may not be installed by default on many modern distributions. It is still common in older tutorials, embedded systems and some minimal environments.

Basic use:

ifconfig

Show a specific interface:

ifconfig eth0

If the command is missing, the system may show:

ifconfig: command not found

On Debian-based systems, it can often be installed with:

sudo apt update
sudo apt install net-tools

However, the modern replacement is usually:

ip a

Comparison:

Older commandModern equivalent
ifconfigip a
ifconfig eth0ip a show eth0
route -nip route
netstat -tulpnss -tulpn

A serious Linux user should recognize ifconfig, but should become comfortable with ip.

Understanding private and public IP addresses

When inspecting network configuration, you will often see private IP addresses.

Common private IPv4 ranges are:

RangeTypical use
10.0.0.0/8Large private networks
172.16.0.0/12Medium private networks
192.168.0.0/16Home and small office networks

Examples:

192.168.1.50
10.0.0.25
172.16.5.10

These addresses are not directly reachable from the public internet. They are used inside private networks.

A server may also have a public IP address if it is directly reachable from the internet. In cloud environments, the public IP may be assigned externally by the provider, while the operating system sees only a private address. That depends on the infrastructure.

You can inspect local addresses with:

ip a

You can inspect routes with:

ip route

Do not confuse local IP configuration with public internet identity. They may be different, especially behind NAT, routers, cloud load balancers or VPNs.

ping: testing basic connectivity

The command ping tests whether another host responds to ICMP echo requests.

Basic use:

ping 192.168.1.1

This sends packets continuously until stopped with:

Ctrl + C

Send only four packets:

ping -c 4 192.168.1.1

Test a domain:

ping example.com

Test a public IP address:

ping -c 4 8.8.8.8

The output may look like this:

64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=1.25 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=1.10 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=1.18 ms

Important fields:

FieldMeaning
64 bytesSize of response
from 192.168.1.1Host that replied
icmp_seqPacket sequence number
ttlTime to live
timeRound-trip latency

At the end, ping prints statistics.

4 packets transmitted, 4 received, 0% packet loss

Packet loss is important. High packet loss indicates network instability.

ResultMeaning
0% packet lossGood basic connectivity
50% packet lossUnstable connection
100% packet lossNo ICMP response or blocked ICMP
Very high latencySlow or distant connection
Unknown hostDNS resolution problem
Network unreachableRouting or interface problem

However, ping is not a complete test. Some servers block ICMP. A failed ping does not always mean the server is down. It may only mean ICMP is blocked.

A better diagnostic approach uses several tests.

ip a
ip route
ping -c 4 192.168.1.1
ping -c 4 8.8.8.8
ping -c 4 example.com

This sequence checks local configuration, route, gateway reachability, internet IP reachability and DNS resolution.

Diagnosing internet connectivity step by step

When internet connectivity fails, do not guess. Test in layers.

First, check whether the system has an IP address:

ip a

Then check whether it has a default route:

ip route

Then ping the gateway:

ping -c 4 192.168.1.1

Replace 192.168.1.1 with your actual gateway from ip route.

Then ping an external IP:

ping -c 4 8.8.8.8

Then ping a domain:

ping -c 4 example.com

Interpretation:

What worksWhat failsLikely issue
No IP addressEverythingDHCP, interface or cable/Wi-Fi problem
IP exists, no default routeInternet accessRouting problem
Gateway ping failsExternal accessLocal network problem
Gateway works, external IP failsInternet routing, firewall or ISP problem
External IP works, domain failsDNS problem
Domain worksBasic internet connectivity is working

Check DNS configuration:

cat /etc/resolv.conf

On many modern systems, DNS may be managed by systemd-resolved, NetworkManager or another service, so /etc/resolv.conf may point to a local stub resolver. Still, it is often useful for inspection.

A practical DNS test tool is getent.

getent hosts example.com

If this returns an IP address, name resolution is working through the system resolver.

hostname: identifying the machine

The command hostname displays the system hostname.

hostname

Example output:

webserver01

The hostname is the system’s local name. It may appear in prompts, logs, monitoring systems and network identification.

Set hostname temporarily:

sudo hostname webserver01

On modern systems, use:

sudo hostnamectl set-hostname webserver01

Show detailed hostname information:

hostnamectl

Example output may include static hostname, operating system, kernel and architecture.

A good hostname should be meaningful.

Poor hostnameBetter hostname
serverweb-prod-01
ubuntudb-staging-01
testbackup-lab-01
raspberrypisensor-garage-01

Naming matters because logs and monitoring become much easier to understand when machines have clear names.

A hostname should usually indicate function, environment and number if there are multiple machines.

Examples:

web-prod-01
web-prod-02
db-prod-01
web-staging-01
backup-office-01

iwconfig and wireless inspection

The command iwconfig shows wireless interface information. It is older, but still useful on systems where wireless tools are available.

Basic use:

iwconfig

Show one interface:

iwconfig wlan0

The output may include SSID, mode, frequency, access point, bit rate and signal quality.

Important fields:

FieldMeaning
ESSIDWi-Fi network name
ModeManaged, monitor or other wireless mode
FrequencyWireless frequency
Access PointMAC address of the access point
Bit RateLink speed
Signal levelWireless signal strength

On many modern systems, Wi-Fi is managed through tools such as NetworkManager, nmcli, iw or desktop network managers. Still, iwconfig appears in many Linux learning materials and remains useful to recognize.

A practical wireless troubleshooting sequence:

ip a
iwconfig
ip route
ping -c 4 192.168.1.1

This checks whether the wireless interface exists, whether it has wireless association information, whether routing exists and whether the gateway responds.

ifup and ifdown

The commands ifup and ifdown enable or disable network interfaces using traditional network configuration systems.

Enable an interface:

sudo ifup eth0

Disable an interface:

sudo ifdown eth0

These commands are most relevant on systems using /etc/network/interfaces style configuration. On systems using NetworkManager, systemd-networkd or cloud network tools, they may not apply or may not behave as expected.

Modern alternatives may include:

sudo ip link set eth0 up
sudo ip link set eth0 down

or NetworkManager commands such as:

nmcli connection show

The key principle is that network management depends on the distribution and configuration stack. The command line helps inspect what is present.

If ifup and ifdown fail, do not assume the interface is broken. The system may be managed by a different network service.

wget: downloading files from the terminal

The command wget downloads files from URLs.

Basic use:

wget http://example.com/file.txt

Download and save with a different filename:

wget http://example.com/file.txt -O target.txt

The -O option means write output to a specific file.

Download into the current directory using the remote filename:

wget https://example.com/archive.tar.gz

Continue an interrupted download:

wget -c https://example.com/large-file.iso

Download quietly:

wget -q https://example.com/file.txt

Download with visible progress but less output:

wget -q --show-progress https://example.com/file.txt

Useful wget options:

OptionMeaning
-O fileSave as a specific filename
-cContinue interrupted download
-qQuiet mode
--show-progressShow progress in quiet mode
-P directorySave into directory
--limit-rate=1mLimit download speed

Save into a directory:

wget -P downloads https://example.com/file.zip

Limit download speed:

wget --limit-rate=1m https://example.com/large-file.iso

This can be useful on slow connections or shared servers.

A safe download workflow:

mkdir -p ~/downloads
cd ~/downloads
wget https://example.com/archive.tar.gz
ls -lh
tar -tzf archive.tar.gz | head

This downloads into a controlled directory, checks the file size and inspects archive contents before extraction.

curl compared with wget

Although the original command list focuses on wget, many Linux systems also use curl.

Basic curl use:

curl https://example.com

Save to file:

curl -o file.txt https://example.com/file.txt

Follow redirects:

curl -L -o file.txt https://example.com/file.txt

Show only HTTP headers:

curl -I https://example.com

Comparison:

Taskwgetcurl
Download a file simplyVery convenientPossible
Save remote file with same nameDefault behaviorNeeds option in many cases
Test HTTP APIsLess commonVery common
Show headersPossibleVery convenient
Use in scriptsGoodExcellent
Resume downloadswget -ccurl -C -

For downloading files, wget is very comfortable. For API testing and HTTP inspection, curl is often preferred.

A Linux user should know both, but wget remains one of the easiest download tools.

ssh: remote login to Linux systems

The command ssh connects to another system securely over the network.

Basic syntax:

ssh user@host

Example:

ssh pat@192.168.1.10

This means: connect to host 192.168.1.10 as user pat.

Connect to a hostname:

ssh pat@webserver01

Connect using a specific port:

ssh -p 2222 pat@192.168.1.10

The default SSH port is 22, but servers may use a different port.

When connecting for the first time, SSH may ask whether you trust the host key.

Are you sure you want to continue connecting?

This protects against connecting to an unexpected machine. In professional environments, host keys should be verified carefully.

After successful connection, you receive a shell on the remote machine. Commands then run on that remote system, not your local computer.

This distinction is critical.

If you SSH into a server and run:

rm file.txt

you are deleting file.txt on the server, not on your local machine.

A safe habit after logging in:

hostname
whoami
pwd

This confirms where you are, which machine you are on and which user you are using.

SSH identity and who you are on the remote system

After logging in through SSH, verify identity.

whoami

Show hostname:

hostname

Show current directory:

pwd

Show logged-in users:

who

Show recent login information:

last | head

This matters because administrators often manage multiple servers. Accidentally running a command on production instead of staging can cause serious damage.

A helpful prompt or clear hostname reduces risk. If hostnames are unclear, fix them.

sudo hostnamectl set-hostname web-staging-01

A professional SSH habit:

hostname
whoami
uptime

This immediately tells you where you are, who you are and how long the system has been running.

SSH keys

SSH can authenticate with passwords or keys. SSH keys are usually safer and more convenient when managed properly.

A key pair contains:

PartPurpose
Private keyStays on your local machine and must be protected
Public keyCan be placed on servers you want to access

Generate an SSH key:

ssh-keygen

A common modern form:

ssh-keygen -t ed25519

This creates keys usually under:

~/.ssh/

Common files:

FileMeaning
~/.ssh/id_ed25519Private key
~/.ssh/id_ed25519.pubPublic key
~/.ssh/authorized_keysPublic keys allowed to log into this account
~/.ssh/known_hostsKnown server host keys
~/.ssh/configOptional client configuration

The private key must be protected.

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519

If permissions are too open, SSH may refuse to use the key.

Copy a public key to a server:

ssh-copy-id pat@192.168.1.10

Then connect:

ssh pat@192.168.1.10

If ssh-copy-id is not available, you can manually append the public key to the remote user’s authorized_keys file, but that requires care.

SSH client configuration

If you connect to servers often, create an SSH config file.

Open:

nano ~/.ssh/config

Example:

Host webprod
    HostName 192.168.1.10
    User pat
    Port 22
    IdentityFile ~/.ssh/id_ed25519

Then connect using:

ssh webprod

This is easier than typing the full command every time.

More examples:

Host staging
    HostName staging.example.local
    User deploy
    Port 2222

Host backup
    HostName 10.0.0.50
    User backupuser
    IdentityFile ~/.ssh/backup_key

Set secure permissions:

chmod 600 ~/.ssh/config

SSH config improves productivity and reduces mistakes.

Running one remote command with ssh

SSH can run one command on a remote server without opening an interactive shell.

ssh pat@192.168.1.10 "uptime"

Check disk space remotely:

ssh pat@192.168.1.10 "df -h"

Check failed services:

ssh pat@192.168.1.10 "systemctl --failed"

Run multiple commands:

ssh pat@192.168.1.10 "hostname; uptime; df -h"

This is useful for quick administration and scripting.

Example for multiple servers:

for server in web1 web2 web3; do
    echo "Checking $server"
    ssh "$server" "hostname; uptime; df -h /"
done

This shows how SSH becomes an automation tool.

scp: copying files over SSH

The command scp copies files between machines using SSH.

Copy a local file to a remote server:

scp test.txt pat@192.168.1.10:/home/pat/

Copy a remote file to the local machine:

scp pat@192.168.1.10:/home/pat/test.txt .

The dot . means current local directory.

Copy and rename:

scp test.txt pat@192.168.1.10:/home/pat/remote-test.txt

Copy a directory recursively:

scp -r project pat@192.168.1.10:/home/pat/

Use a specific SSH port:

scp -P 2222 test.txt pat@192.168.1.10:/home/pat/

Important detail: ssh uses lowercase -p for port, but scp uses uppercase -P.

CommandPort option
ssh-p
scp-P

This difference is a common source of mistakes.

rsync: efficient synchronization

The command rsync copies and synchronizes files. It is often better than scp for repeated transfers, backups and large directories because it can transfer only changed parts.

Basic local synchronization:

rsync -av source/ destination/

Copy local directory to remote server:

rsync -avz project/ pat@192.168.1.10:/home/pat/project/

Copy remote directory to local machine:

rsync -avz pat@192.168.1.10:/home/pat/project/ ./project/

Common options:

OptionMeaning
-aArchive mode, preserves permissions, timestamps and structure
-vVerbose output
-zCompress data during transfer
-rRecursive
-uSkip files newer on destination
--deleteDelete destination files not present in source
--dry-runShow what would happen without changing anything
--progressShow transfer progress

A safe rsync preview:

rsync -avz --dry-run project/ pat@192.168.1.10:/home/pat/project/

If the preview looks correct:

rsync -avz project/ pat@192.168.1.10:/home/pat/project/

This is a professional habit. Use --dry-run before major synchronization.

The trailing slash in rsync matters

One of the most important rsync details is the trailing slash.

Compare:

rsync -av project destination/

and:

rsync -av project/ destination/

They are different.

CommandResult
rsync -av project destination/Copies the directory project into destination
rsync -av project/ destination/Copies the contents of project into destination

Example:

rsync -av project backup/

Result:

backup/project/file.txt

Example:

rsync -av project/ backup/

Result:

backup/file.txt

This distinction is critical when deploying websites, synchronizing backups or updating server directories.

When unsure, use:

rsync -av --dry-run source/ destination/

Inspect the output before running the real command.

rsync with delete

The --delete option makes the destination match the source by deleting files from the destination that no longer exist in the source.

Example:

rsync -av --delete source/ destination/

This is powerful and dangerous.

Use dry run first:

rsync -av --delete --dry-run source/ destination/

Only if the planned deletions are correct:

rsync -av --delete source/ destination/

A deployment example:

rsync -avz --delete --dry-run ./site/ deploy@server:/var/www/site/

Then:

rsync -avz --delete ./site/ deploy@server:/var/www/site/

The --delete option is useful when the destination should be an exact mirror. It is dangerous when the destination contains files that are not present in the source but should be preserved.

Choosing between scp and rsync

Both scp and rsync copy files over SSH, but they serve different practical needs.

SituationBetter tool
Copy one small file quicklyscp
Copy a directory oncescp or rsync
Synchronize a directory repeatedlyrsync
Back up changed filesrsync
Preserve permissions and timestampsrsync -a
Preview changes before transferrsync --dry-run
Delete destination files not in sourcersync --delete
Transfer over a custom SSH portBoth can do it

Use scp for simple transfers. Use rsync for serious synchronization.

Example simple file upload:

scp index.html deploy@server:/var/www/site/

Example serious deployment:

rsync -avz --delete --dry-run ./site/ deploy@server:/var/www/site/
rsync -avz --delete ./site/ deploy@server:/var/www/site/

The second workflow is safer because you can preview the result.

Practical workflow: diagnose a server that cannot reach the internet

Suppose you are logged into a Linux server and it cannot download updates.

Start with IP addresses:

ip a

Check default route:

ip route

Try the gateway:

ping -c 4 192.168.1.1

Use the actual gateway from ip route.

Try external IP:

ping -c 4 8.8.8.8

Try domain resolution:

ping -c 4 deb.debian.org

Check DNS:

getent hosts deb.debian.org
cat /etc/resolv.conf

Try apt update:

sudo apt update

Interpretation:

ResultLikely area
No interface IPDHCP or interface problem
No default routeRouting problem
Gateway unreachableLocal network problem
External IP unreachableUpstream network or firewall
Domain fails but IP worksDNS problem
Only apt failsRepository, proxy, TLS or package source issue

This sequence prevents random changes. It identifies the failing layer.

Practical workflow: deploy a static website with rsync

Assume your local website build is in:

./public/

and the remote web directory is:

/var/www/example.com/

Preview deployment:

rsync -avz --delete --dry-run ./public/ deploy@server:/var/www/example.com/

If the preview is correct:

rsync -avz --delete ./public/ deploy@server:/var/www/example.com/

Then check remote files:

ssh deploy@server "ls -lah /var/www/example.com | head"

If the service needs reload:

ssh deploy@server "sudo systemctl reload nginx"

This workflow is fast, repeatable and safer than manual FTP-style copying.

Important details:

DetailWhy it matters
./public/ has trailing slashCopies contents of public, not the folder itself
--delete mirrors destinationRemoves old files no longer present locally
--dry-run previews changesPrevents accidental deletion
SSH command reloads serverKeeps workflow scriptable

Practical workflow: copy logs from a remote server for analysis

Create a local directory:

mkdir -p ~/server-logs

Copy logs with scp:

scp pat@server:/var/log/syslog ~/server-logs/

If permission is denied, you may need to read logs remotely with sudo and save them to a location your user can access.

On the server:

sudo cp /var/log/syslog /home/pat/syslog-copy
sudo chown pat:pat /home/pat/syslog-copy

Then locally:

scp pat@server:/home/pat/syslog-copy ~/server-logs/

Analyze locally:

grep -i "error" ~/server-logs/syslog-copy
grep -i "failed" ~/server-logs/syslog-copy
tail -n 100 ~/server-logs/syslog-copy

A more direct approach:

ssh pat@server "sudo tail -n 200 /var/log/syslog"

For longer analysis, copying logs locally can be more convenient.

Practical workflow: monitor a remote service

Check status:

ssh pat@server "systemctl status nginx"

Show recent logs:

ssh pat@server "journalctl -u nginx -n 50"

Follow logs interactively:

ssh pat@server "journalctl -u nginx -f"

Stop with:

Ctrl + C

Watch remote disk space:

watch -n 10 'ssh pat@server "df -h /"'

This runs the remote check every 10 seconds.

For multiple servers:

for server in web1 web2 web3; do
    echo "$server"
    ssh "$server" "hostname; uptime; df -h /"
done

This kind of loop is a simple but powerful administration tool.

Practical workflow: check whether a port is open locally

Suppose a web server should listen on port 80.

Check listening ports:

sudo ss -tulpn

Filter port 80:

sudo ss -tulpn | grep ':80'

Filter port 443:

sudo ss -tulpn | grep ':443'

Example output:

tcp   LISTEN 0 511 0.0.0.0:80   0.0.0.0:*   users:(("nginx",pid=842,fd=6))

This tells you:

FieldMeaning
tcpTCP socket
LISTENWaiting for incoming connections
0.0.0.0:80Listening on all IPv4 addresses, port 80
nginxProcess name
pid=842Process ID

If a service is running but not listening, check its configuration and logs.

systemctl status nginx
journalctl -u nginx -n 50

If another process is using the port:

sudo lsof -i :80

Then decide whether the conflict is expected or needs correction.

Practical workflow: check whether a remote port is reachable

From your local machine or another server, you can test TCP connectivity with tools such as nc if installed.

nc -vz server 80

Check HTTPS:

nc -vz server 443

If nc is not installed:

sudo apt install netcat-openbsd

You can also use curl for HTTP or HTTPS services.

curl -I http://server

For HTTPS:

curl -I https://server

Interpretation:

TestWhat it proves
ss -tulpn on serverService is listening locally
curl -I localhost on serverLocal HTTP response works
curl -I http://server from another machineNetwork path and service work externally
nc -vz server 80TCP port is reachable
ping serverICMP responds, but does not prove port availability

A common mistake is relying only on ping. A server can respond to ping while the web port is closed. A server can also block ping while the web port is open.

Practical workflow: troubleshoot SSH connection failure

If SSH fails, read the error carefully.

Try verbose mode:

ssh -v pat@server

More verbose:

ssh -vvv pat@server

Common errors:

ErrorPossible cause
Connection refusedSSH service not running or wrong port
Connection timed outFirewall, routing or host unreachable
Permission deniedWrong user, password or key
Host key verification failedHost key mismatch
Could not resolve hostnameDNS or hostname problem

Check whether server is reachable:

ping -c 4 server

Check port:

nc -vz server 22

Try correct port:

ssh -p 2222 pat@server

On the server, if you have another access method, check SSH service:

systemctl status ssh
sudo ss -tulpn | grep ':22'
journalctl -u ssh -n 50

On some distributions, the service may be named sshd instead of ssh.

systemctl status sshd

Check SSH configuration:

sudo sshd -t

If sshd -t returns no output, the configuration syntax is usually valid.

Practical workflow: safely edit SSH configuration

Editing SSH configuration on a remote server is risky because a mistake can lock you out.

First, keep your current SSH session open.

Back up configuration:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

Edit:

sudo nano /etc/ssh/sshd_config

Test syntax:

sudo sshd -t

If valid, reload rather than restart when possible:

sudo systemctl reload ssh

or:

sudo systemctl reload sshd

Open a second terminal and test a new SSH login before closing the original session.

ssh pat@server

If the new login works, the change is safe. If not, restore from the still-open original session.

sudo cp /etc/ssh/sshd_config.backup /etc/ssh/sshd_config
sudo sshd -t
sudo systemctl reload ssh

This workflow is professional because it preserves a recovery path.

Practical network checklist

When a Linux machine has network problems, use this checklist:

hostname
ip a
ip route
ping -c 4 127.0.0.1
ping -c 4 
ping -c 4 8.8.8.8
getent hosts example.com
ping -c 4 example.com

Replace with the actual gateway from:

ip route

Then inspect listening services if the problem is inbound access:

sudo ss -tulpn

Check firewall rules if relevant:

sudo ufw status

On systems using UFW, this shows whether the firewall is active and which ports are allowed.

For service logs:

journalctl -u service-name -n 100

This checklist is not random. It moves from local identity to interface, route, local stack, gateway, internet, DNS, inbound ports and logs.

Basic firewall awareness with ufw

Many Debian and Ubuntu systems may use UFW, the uncomplicated firewall. It is not part of the original command set, but it is directly relevant to network troubleshooting.

Check status:

sudo ufw status

Verbose status:

sudo ufw status verbose

Allow SSH:

sudo ufw allow ssh

Allow HTTP:

sudo ufw allow 80/tcp

Allow HTTPS:

sudo ufw allow 443/tcp

Enable firewall:

sudo ufw enable

Important warning: before enabling a firewall on a remote server, make sure SSH is allowed.

sudo ufw allow ssh
sudo ufw enable

Otherwise, you may lock yourself out.

Check numbered rules:

sudo ufw status numbered

Delete a rule by number:

sudo ufw delete 3

Firewall troubleshooting must be careful because blocking access can make remote administration impossible.

Name resolution and /etc/hosts

Linux can resolve names through DNS and local files.

The file:

/etc/hosts

can define local hostname mappings.

View it:

cat /etc/hosts

Example:

127.0.0.1 localhost
192.168.1.10 webserver01
192.168.1.20 dbserver01

This means the system can resolve webserver01 to 192.168.1.10 locally.

Edit carefully:

sudo nano /etc/hosts

Test resolution:

getent hosts webserver01

The /etc/hosts file is useful for small labs, local development, temporary migrations and internal names. For larger environments, DNS is usually better.

A practical local lab setup:

192.168.56.10 web-lab
192.168.56.11 db-lab
192.168.56.12 backup-lab

Then:

ssh pat@web-lab

This is easier than remembering IP addresses.

Network file transfer safety

Network file transfer can damage systems if source and destination are confused. Always verify direction.

The structure of scp is:

scp source destination

Upload local to remote:

scp local.txt user@server:/remote/path/

Download remote to local:

scp user@server:/remote/path/file.txt .

The structure of rsync is similar:

rsync options source destination

Upload:

rsync -av local-folder/ user@server:/remote/folder/

Download:

rsync -av user@server:/remote/folder/ local-folder/

Before large transfers:

rsync -av --dry-run source destination

Check these before pressing Enter:

CheckWhy
Source pathPrevents copying wrong data
Destination pathPrevents overwriting wrong location
Trailing slashChanges rsync behavior
--deleteCan remove destination files
User and hostPrevents deploying to wrong server
Current directoryImportant when using relative paths

A precise command is better than a fast command.

Practical workflow: complete remote maintenance session

Start local terminal:

ssh pat@server

Confirm identity:

hostname
whoami
uptime

Start screen:

screen -S maintenance

Check system:

df -h
free -h
systemctl --failed

Update package lists:

sudo apt update

Review upgrades:

apt list --upgradable

Upgrade:

sudo apt upgrade

Clean unused dependencies:

sudo apt autoremove

Check services:

systemctl --failed

Check whether reboot is recommended:

ls /var/run/reboot-required

If reboot is needed and acceptable:

sudo reboot

After reconnecting:

ssh pat@server
uptime
systemctl --failed

This workflow is structured, recoverable and safer than running updates casually.

Practical workflow: migrate files between two servers

If your local machine has access to both servers, you can copy from server A to local, then local to server B.

Download from source:

rsync -avz source-user@source-server:/var/www/site/ ./site-copy/

Upload to destination:

rsync -avz --dry-run ./site-copy/ dest-user@dest-server:/var/www/site/

If preview is correct:

rsync -avz ./site-copy/ dest-user@dest-server:/var/www/site/

Verify destination:

ssh dest-user@dest-server "du -sh /var/www/site; find /var/www/site -maxdepth 2 -type f | head"

If permissions need adjustment:

ssh dest-user@dest-server "sudo find /var/www/site -type d -exec chmod 755 {} \;"
ssh dest-user@dest-server "sudo find /var/www/site -type f -exec chmod 644 {} \;"

This is a basic migration pattern. For databases, services and live applications, additional steps are required, but the file transfer logic remains fundamental.

Practical workflow: backup a remote directory with rsync

Create local backup directory:

mkdir -p ~/server-backups/site

Preview backup:

rsync -avz --dry-run pat@server:/var/www/site/ ~/server-backups/site/

Run backup:

rsync -avz pat@server:/var/www/site/ ~/server-backups/site/

Create a compressed archive of the local backup:

tar -czf ~/server-backups/site-$(date +%Y-%m-%d).tar.gz -C ~/server-backups site

Verify archive:

tar -tzf ~/server-backups/site-$(date +%Y-%m-%d).tar.gz | head -30

This combines SSH, rsync, date, tar and verification.

Practical workflow: synchronize only changed files

Suppose you have a large directory that changes daily. scp -r would copy everything again. rsync copies only what changed.

rsync -avz /home/pat/Documents/ pat@backup-server:/backups/pat/Documents/

Run it again tomorrow. Only changed files need to be transferred.

Add progress:

rsync -avz --progress /home/pat/Documents/ pat@backup-server:/backups/pat/Documents/

Add deletion if the backup should mirror the source exactly:

rsync -avz --delete --dry-run /home/pat/Documents/ pat@backup-server:/backups/pat/Documents/

Then:

rsync -avz --delete /home/pat/Documents/ pat@backup-server:/backups/pat/Documents/

Use --delete only when mirror behavior is intended.

Practical workflow: identify which service owns a port

Suppose port 8080 is in use.

Check with ss:

sudo ss -tulpn | grep ':8080'

Check with lsof:

sudo lsof -i :8080

Example output may show a process name and PID.

Then inspect process:

ps -p 12345 -f

If it is a systemd service, try:

systemctl status service-name

If you do not know the service, inspect the command path:

readlink -f /proc/12345/exe

Show process working directory:

readlink -f /proc/12345/cwd

Show environment carefully:

sudo tr '\0' '\n' < /proc/12345/environ

This is more advanced, but it shows how Linux exposes process information through /proc.

Practical workflow: server cannot be reached from outside

If a service works locally but not externally, test in layers.

On the server:

ip a
ip route
systemctl status nginx
sudo ss -tulpn | grep ':80'
curl -I http://localhost
sudo ufw status

From another machine:

ping -c 4 server-ip
nc -vz server-ip 80
curl -I http://server-ip

Interpretation:

Local resultRemote resultLikely issue
Service not listening locallyRemote failsService or configuration problem
Service listens on 127.0.0.1 onlyRemote failsBinding problem
Service listens on 0.0.0.0:80, local curl worksRemote failsFirewall, router, cloud security group or network path
Remote port works, browser fails by domainDNS or virtual host problem
IP works but HTTPS failsTLS, certificate or port 443 configuration

A listening address matters.

Listening addressMeaning
127.0.0.1:80Only local machine can connect
0.0.0.0:80All IPv4 interfaces
[::]:80IPv6 all interfaces, may also accept IPv4 depending on configuration
192.168.1.50:80Only that specific interface address

If a service listens only on 127.0.0.1, external clients cannot reach it.

Practical workflow: check download speed and stability with wget

Download a test file:

wget -O /tmp/test-download.bin https://example.com/large-file.bin

Remove after testing:

rm -i /tmp/test-download.bin

If the connection drops, test resume:

wget -c -O /tmp/test-download.bin https://example.com/large-file.bin

Limit rate:

wget --limit-rate=500k -O /tmp/test-download.bin https://example.com/large-file.bin

This is useful when downloads consume too much bandwidth on a shared server.

Practical workflow: use SSH and screen for safe long transfers

Connect:

ssh pat@server

Start screen:

screen -S transfer

Run rsync or tar:

rsync -avz --progress /large/source/ backup@backup-server:/backups/source/

Detach:

Ctrl + A
Ctrl + D

Later, reconnect:

ssh pat@server
screen -r transfer

This prevents losing visibility if your SSH connection drops.

Key takeaways

The command-line foundation for Linux networking and remote administration is now in place.

The key commands are:

CommandEssential role
ip aShow network interfaces and addresses
ip routeShow routing table
ifconfigOlder interface inspection command
iwconfigOlder wireless inspection command
ifupBring interface up using traditional configuration
ifdownBring interface down using traditional configuration
pingTest basic reachability
hostnameShow or set system name
hostnamectlModern hostname and system identity tool
wgetDownload files from the terminal
curlTest URLs, APIs and HTTP headers
sshSecure remote login
scpSimple file copy over SSH
rsyncEfficient file synchronization
ssInspect listening ports and sockets
lsof -iFind processes using network ports
getent hostsTest system name resolution
ufwManage simple firewall rules on systems using UFW

The deeper lesson is that networking must be diagnosed in layers.

First, check whether the machine has an interface and IP address. Then check whether it has a route. Then check whether the gateway responds. Then test external IP connectivity. Then test DNS. Then check whether the local service is listening. Then check whether remote clients can reach it. Then inspect firewall rules, logs and service configuration.

Remote administration adds another layer of responsibility. With SSH, scp and rsync, you can manage systems from anywhere. That power requires careful habits: verify the host, verify the user, preview destructive actions, keep backups, use screen for long tasks and test before restarting critical services.

A Linux system becomes much easier to manage when you understand how files, services, processes and networks connect. The terminal gives you visibility into every layer.

Practical workflow: check open network ports after deployment

After deploying a service, check listening ports:

sudo ss -tulpn

Filter expected port:

sudo ss -tulpn | grep ':8080'

Check process:

sudo lsof -i :8080

Check local response:

curl -I http://localhost:8080

Check service status:

systemctl status service-name

Check logs:

journalctl -u service-name -n 100

If the service listens on 127.0.0.1:8080, it is local-only. If it listens on 0.0.0.0:8080, it accepts connections on all IPv4 interfaces.

This distinction is critical for remote access.

Practical workflow: check SSH key permissions

SSH is strict about private key permissions.

Check .ssh directory:

ls -ld ~/.ssh

Check private key:

ls -l ~/.ssh/id_ed25519

Recommended permissions:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub

Check authorized keys on server:

ls -l ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

If SSH refuses a key, run verbose mode:

ssh -v user@server

Look for lines about which keys are offered and why authentication fails.

Practical workflow: secure file transfer for backups

Create a backup user on the backup server.

sudo adduser backup

Create backup directory.

sudo mkdir -p /backups/server1
sudo chown backup:backup /backups/server1

From the source server, generate key if needed.

ssh-keygen -t ed25519

Copy key.

ssh-copy-id backup@backup-server

Test.

ssh backup@backup-server "hostname; pwd"

Run rsync backup.

rsync -avz --delete /var/www/site/ backup@backup-server:/backups/server1/site/

Preview first:

rsync -avz --delete --dry-run /var/www/site/ backup@backup-server:/backups/server1/site/

Use a dedicated backup user rather than full administrative root login where possible. Limit access according to the backup design.

Practical workflow: restore from rsync backup

Preview backup contents:

rsync -avz --dry-run backup@backup-server:/backups/server1/site/ /tmp/site-restore/

Restore to test directory first:

mkdir -p /tmp/site-restore
rsync -avz backup@backup-server:/backups/server1/site/ /tmp/site-restore/

Inspect:

tree -L 2 /tmp/site-restore
du -sh /tmp/site-restore

Restore to real location only when sure:

sudo rsync -avz /tmp/site-restore/ /var/www/site/

Fix ownership and permissions if needed:

sudo find /var/www/site -type d -exec chmod 755 {} \;
sudo find /var/www/site -type f -exec chmod 644 {} \;

Then verify service:

sudo nginx -t
sudo systemctl reload nginx
curl -I http://localhost

Restoration should be tested in a safe directory before touching production paths.

Automation, shell scripting and scheduled tasks

Automation turns tested command sequences into repeatable tools. History, cron, scripts, aliases, loops and timers help convert one-time work into reliable procedures.

screen: keeping terminal sessions alive

The command screen creates a virtual terminal session that can continue running even if you disconnect.

Install screen:

sudo apt update
sudo apt install screen

Start a named session:

screen -S backup

Now run a long command:

tar -czf big-backup.tar.gz /home/pat/project

Detach from the session:

Ctrl + A
Ctrl + D

List screen sessions:

screen -ls

Resume session:

screen -r backup

Exit a screen session after the work is done:

Ctrl + D

or type:

exit

Why screen matters:

SituationWhy screen helps
Long backupsContinue after SSH disconnect
Large file transfersAvoid losing process when connection drops
Remote updatesKeep session stable
Monitoring logsLeave a live session running
Slow scriptsDetach and return later

A practical remote workflow:

ssh pat@server
screen -S maintenance
sudo apt update
sudo apt upgrade

If the SSH connection drops, reconnect and run:

screen -r maintenance

This is much safer than running critical long tasks in a normal SSH session.

Command history

The shell stores commands you have typed. The history command displays them.

history

Show the last 20 commands:

history | tail -n 20

Search history:

history | grep apt

Run the previous command again:

!!

A very common use:

apt update

If you forgot sudo, run:

sudo !!

This becomes:

sudo apt update

Run a command by history number:

!123

Be careful with this because history numbers change as new commands are added.

Delete one history entry:

history -d 123

Clear history:

history -c

History is useful for productivity, auditing your own work and repeating complex commands. It is also sensitive because commands may contain paths, server names or accidentally typed secrets.

Avoid typing passwords directly into commands because they may be stored in shell history.

Command history is your memory in the terminal

The command history shows commands previously typed in the shell.

history

The output usually shows numbered commands.

1001  pwd
1002  ls -lah
1003  sudo apt update
1004  grep -i "error" /var/log/syslog

You can show the last 20 commands:

history | tail -n 20

You can search your command history:

history | grep apt

You can search for previous SSH commands:

history | grep ssh

You can search for previous rsync operations:

history | grep rsync

This is useful because many real commands are long. Instead of retyping them, you can find and reuse them.

The shell also supports command repetition shortcuts.

ShortcutMeaning
!!Run the previous command again
sudo !!Run the previous command again with sudo
!123Run command number 123 from history
!grepRun the most recent command beginning with grep
!?errorRun the most recent command containing error

The most famous example is forgetting sudo.

You type:

apt update

The system refuses because administrative privileges are required. Then you run:

sudo !!

The shell expands it to:

sudo apt update

This is convenient, but it must be used carefully. Repeating commands blindly can be dangerous, especially after deletion, permission or remote commands.

Before using history expansion on destructive commands, inspect the command first.

history | tail -n 10

Then decide whether it is safe to repeat.

History can also be a security risk

Shell history is useful, but it can accidentally store sensitive information.

Bad practice:

mysql -u root -pMySecretPassword

This places the password directly in shell history.

Better practice:

mysql -u root -p

This prompts for the password without storing it in the command line.

Another bad practice:

curl -H "Authorization: Bearer secret-token-value" https://api.example.com

This may store a token in history.

If sensitive data was typed accidentally, you can delete a specific history line.

First find it:

history | grep secret

Then delete by number:

history -d 1234

Clear all history:

history -c

However, clearing history does not solve every security problem. The command may already have been written to disk, captured by terminal logging, stored in process lists or recorded elsewhere. The better habit is to avoid placing secrets directly in command lines.

Sensitive values should be entered through prompts, protected files, environment mechanisms or secret management systems appropriate to the environment.

crontab schedules commands automatically

The command crontab manages scheduled tasks for a user.

List current cron jobs:

crontab -l

Edit cron jobs:

crontab -e

A cron line has five time fields followed by a command.

* * * * * command

The fields are:

FieldMeaningValues
MinuteMinute of the hour0-59
HourHour of the day0-23
Day of monthDay number1-31
MonthMonth number1-12
Day of weekWeekday0-7

Both 0 and 7 can mean Sunday on many systems.

Examples:

Cron expressionMeaning
* * * * *Every minute
*/5 * * * *Every 5 minutes
0 * * * *Every hour at minute 0
0 2 * * *Every day at 02:00
30 3 * * 1Every Monday at 03:30
0 0 1 * *At midnight on the first day of each month
0 4 * * 0Every Sunday at 04:00

A daily backup at 02:00:

0 2 * * * /usr/bin/bash /home/pat/scripts/backup.sh

Cron runs commands in a limited environment. This is very important. A command that works in your interactive shell may fail in cron because environment variables, working directory or PATH are different.

Use absolute paths in cron.

Better:

0 2 * * * /usr/bin/bash /home/pat/scripts/backup.sh

Riskier:

0 2 * * * bash backup.sh

The second version depends on the current directory and PATH.

Cron environment and logging

Cron jobs should write logs. Otherwise, failures may be invisible.

Example cron line:

0 2 * * * /usr/bin/bash /home/pat/scripts/backup.sh >> /home/pat/logs/backup.log 2>&1

This appends both output and errors to backup.log.

Breakdown:

PartMeaning
0 2 * * *Run daily at 02:00
/usr/bin/bashUse Bash explicitly
/home/pat/scripts/backup.shScript path
>> /home/pat/logs/backup.logAppend normal output
2>&1Send errors to the same log

Make sure the log directory exists:

mkdir -p /home/pat/logs

A script can also log internally.

#!/bin/bash

LOG="/home/pat/logs/backup.log"

echo "$(date +"%Y-%m-%d %H:%M:%S") Backup started" >> "$LOG"

tar -czf /home/pat/backups/site-$(date +%Y-%m-%d).tar.gz /var/www/site >> "$LOG" 2>&1

echo "$(date +"%Y-%m-%d %H:%M:%S") Backup finished" >> "$LOG"

This makes cron behavior easier to audit.

Testing cron jobs safely

Do not put a complex script into cron without testing it manually.

Step one: run the script manually.

/usr/bin/bash /home/pat/scripts/backup.sh

Step two: check exit status.

echo $?

Exit status 0 usually means success. Nonzero usually means failure.

Step three: check logs.

tail -n 50 /home/pat/logs/backup.log

Step four: test with a near-time cron schedule.

For example, run every minute temporarily:

* * * * * /usr/bin/bash /home/pat/scripts/backup.sh >> /home/pat/logs/backup.log 2>&1

After confirming it works, change to the real schedule.

A common mistake is leaving a test cron job running every minute. Always check:

crontab -l

System cron directories

Besides user crontabs, Linux systems may have system-wide cron locations.

Common locations:

LocationPurpose
/etc/crontabSystem-wide crontab
/etc/cron.d/Drop-in cron files
/etc/cron.daily/Scripts run daily
/etc/cron.hourly/Scripts run hourly
/etc/cron.weekly/Scripts run weekly
/etc/cron.monthly/Scripts run monthly

System crontab format can include a user field.

Example from a system cron style:

0 2 * * * root /usr/bin/bash /root/scripts/system-backup.sh

User crontab does not include the user field.

User crontab:

0 2 * * * /usr/bin/bash /home/pat/scripts/backup.sh

System crontab:

0 2 * * * pat /usr/bin/bash /home/pat/scripts/backup.sh

This difference is important. Putting the wrong format in the wrong place can break scheduling.

screen keeps sessions alive

The command screen creates detachable terminal sessions. This is useful over SSH because a normal command may stop if your connection drops.

Start a named screen session:

screen -S maintenance

Run a long command:

sudo apt upgrade

Detach:

Ctrl + A
Ctrl + D

List sessions:

screen -ls

Reattach:

screen -r maintenance

Exit a screen session:

exit

or press:

Ctrl + D

Use cases:

Use caseWhy screen helps
System upgradesAvoid interruption during SSH disconnect
Long backupsKeep process running
Large rsync transfersReconnect later
Log monitoringLeave session open
Slow scriptsDetach and return

A safe remote update pattern:

ssh pat@server
screen -S update
sudo apt update
sudo apt upgrade

If the connection drops:

ssh pat@server
screen -r update

This is much safer than running long maintenance in an ordinary SSH session.

Basic shell scripting turns workflows into tools

A shell script is a file containing commands.

Create a script:

nano hello.sh

Content:

#!/bin/bash

echo "Hello from Linux"

Make it executable:

chmod +x hello.sh

Run it:

./hello.sh

The first line:

#!/bin/bash

is called a shebang. It tells Linux which interpreter should run the file.

Without execute permission, this may fail:

Permission denied

Fix:

chmod +x hello.sh

A script does not need to be executable if you run it explicitly with Bash:

bash hello.sh

But executable scripts are more convenient.

Script safety basics

At the beginning of many scripts, you may see:

set -e

This tells the script to stop if a command fails.

A stricter pattern:

set -euo pipefail

Meaning:

OptionMeaning
-eExit if a command fails
-uTreat unset variables as errors
-o pipefailFail pipeline if any command in it fails

Example:

#!/bin/bash
set -euo pipefail

SOURCE="/var/www/site"
DESTINATION="/home/pat/backups"

mkdir -p "$DESTINATION"
tar -czf "$DESTINATION/site.tar.gz" "$SOURCE"

echo "Backup completed"

This makes scripts safer, but it also requires more careful writing. A command that returns a nonzero status intentionally may stop the script unless handled.

For beginner scripts, start simple. As scripts become important, add safety options and logging.

Exit status explains success and failure

Every Linux command returns an exit status.

Check the last command’s exit status:

echo $?

Usually:

Exit statusMeaning
0Success
NonzeroFailure or special condition

Example:

ls /home
echo $?

If successful, output is likely:

0

Now try a missing path:

ls /path/that/does/not/exist
echo $?

The exit status will be nonzero.

This is essential in scripts.

if tar -tzf backup.tar.gz > /dev/null 2>&1; then
    echo "Archive is readable"
else
    echo "Archive verification failed"
fi

The if statement checks the command’s exit status.

if statements in shell scripts

A basic if statement:

if command; then
    echo "Command succeeded"
else
    echo "Command failed"
fi

Check whether a file exists:

if [ -f "/etc/hosts" ]; then
    echo "File exists"
else
    echo "File does not exist"
fi

Check whether a directory exists:

if [ -d "/var/www/site" ]; then
    echo "Directory exists"
else
    echo "Directory does not exist"
fi

Common test operators:

TestMeaning
-f fileRegular file exists
-d directoryDirectory exists
-e pathPath exists
-r fileFile is readable
-w fileFile is writable
-x fileFile is executable
-s fileFile exists and is not empty

Example backup check:

if [ ! -d "$SOURCE" ]; then
    echo "Source directory does not exist: $SOURCE"
    exit 1
fi

The ! means not.

for loops repeat actions

A for loop runs commands for multiple values.

for file in *.log; do
    echo "$file"
done

Compress old-style log files:

for file in *.log; do
    gzip "$file"
done

Loop through servers:

for server in web1 web2 web3; do
    echo "Checking $server"
    ssh "$server" "hostname; uptime; df -h /"
done

Loop through users:

for user in alice bob charlie; do
    echo "User: $user"
done

Always quote variables unless you intentionally want word splitting.

Better:

echo "$file"

Riskier:

echo $file

For loops are the foundation of simple automation.

while loops process input line by line

A while loop can read a file line by line.

while read -r line; do
    echo "$line"
done < file.txt

The -r option prevents backslash interpretation.

Read server names from a file:

while read -r server; do
    echo "Checking $server"
    ssh "$server" "uptime"
done < servers.txt

If servers.txt contains:

web1
web2
web3

the script checks each server.

This is a simple but powerful administration pattern.

aliases make frequent commands shorter

An alias creates a shortcut.

alias ll='ls -lah'

Now you can run:

ll

Show aliases:

alias

Remove an alias:

unalias ll

To make aliases permanent, add them to your shell configuration file, often:

~/.bashrc

Edit:

nano ~/.bashrc

Add:

alias ll='ls -lah'
alias gs='git status'
alias update='sudo apt update && sudo apt upgrade'

Reload:

source ~/.bashrc

Aliases are useful, but do not make destructive aliases too casual. For example, aliasing rm to rm -rf would be dangerous. A safer alias is:

alias rm='rm -i'

This asks before deletion, but it can also affect scripts or expectations in interactive use. Use aliases thoughtfully.

Practical workflow: create a reusable maintenance script

Create script:

nano ~/scripts/server-check.sh

Script content:

#!/bin/bash
set -euo pipefail

echo "Hostname:"
hostname

echo
echo "Uptime:"
uptime

echo
echo "Disk usage:"
df -h

echo
echo "Failed services:"
systemctl --failed || true

echo
echo "Top memory processes:"
ps aux --sort=-%mem | head -10

echo
echo "Top CPU processes:"
ps aux --sort=-%cpu | head -10

Make executable:

chmod +x ~/scripts/server-check.sh

Run:

~/scripts/server-check.sh

Why || true after systemctl --failed?

Some commands can return nonzero status even when the output is still useful. Since the script uses set -e, a nonzero status could stop the script. The || true prevents that specific command from stopping the script.

This script combines system identity, uptime, disk usage, failed services and top processes into one repeatable check.

Practical workflow: remote health check for multiple servers

Create servers.txt:

nano servers.txt

Example content:

web1
web2
db1
backup1

Create script:

nano check-servers.sh

Script:

#!/bin/bash

while read -r server; do
    echo "Checking $server"
    ssh "$server" "hostname; uptime; df -h /; systemctl --failed"
    echo
done < servers.txt

Make executable:

chmod +x check-servers.sh

Run:

./check-servers.sh

This is a simple example of how shell scripting and SSH combine into real administration.

Practical workflow: build a daily report from logs

Suppose you want a daily error report from app.log.

Create script:

nano ~/scripts/error-report.sh

Script:

#!/bin/bash
set -euo pipefail

LOG_FILE="/var/log/myapp/app.log"
REPORT_DIR="/home/pat/reports"
DATE=$(date +%Y-%m-%d)
REPORT="$REPORT_DIR/error-report-$DATE.txt"

mkdir -p "$REPORT_DIR"

{
    echo "Error report for $DATE"
    echo
    echo "Total log lines:"
    wc -l "$LOG_FILE"
    echo
    echo "Total error lines:"
    grep -i "error" "$LOG_FILE" | wc -l
    echo
    echo "Most common error lines:"
    grep -i "error" "$LOG_FILE" | sort | uniq -c | sort -nr | head -20
} > "$REPORT"

echo "Report created: $REPORT"

Make executable:

chmod +x ~/scripts/error-report.sh

Run manually:

~/scripts/error-report.sh

Schedule daily at 06:00:

crontab -e

Add:

0 6 * * * /home/pat/scripts/error-report.sh >> /home/pat/reports/error-report-cron.log 2>&1

This turns log analysis into scheduled reporting.

Practical workflow: build a safe cleanup script

Create script:

nano ~/scripts/cleanup-old-logs.sh

Script:

#!/bin/bash
set -euo pipefail

LOG_DIR="/var/log/myapp"
DAYS="30"
REPORT="/home/pat/logs/cleanup-old-logs-$(date +%Y-%m-%d).log"

mkdir -p "$(dirname "$REPORT")"

echo "$(date +"%Y-%m-%d %H:%M:%S") Cleanup preview started" | tee -a "$REPORT"

find "$LOG_DIR" -type f -name "*.gz" -mtime +"$DAYS" -exec ls -lh {} \; | tee -a "$REPORT"

echo "$(date +"%Y-%m-%d %H:%M:%S") Cleanup deletion started" | tee -a "$REPORT"

find "$LOG_DIR" -type f -name "*.gz" -mtime +"$DAYS" -delete

echo "$(date +"%Y-%m-%d %H:%M:%S") Cleanup finished" | tee -a "$REPORT"

Make executable:

chmod +x ~/scripts/cleanup-old-logs.sh

Run manually:

~/scripts/cleanup-old-logs.sh

Schedule weekly:

crontab -e

Add:

0 3 * * 0 /home/pat/scripts/cleanup-old-logs.sh >> /home/pat/logs/cleanup-cron.log 2>&1

This script logs what it is doing and limits cleanup to a precise directory and file pattern.

Practical workflow: combine cron and reports

Create script:

nano ~/scripts/web-log-report.sh

Script:

#!/bin/bash
set -euo pipefail

ACCESS_LOG="/var/log/nginx/access.log"
REPORT_DIR="/home/pat/reports"
DATE=$(date +%Y-%m-%d)
REPORT="$REPORT_DIR/web-log-report-$DATE.txt"

mkdir -p "$REPORT_DIR"

{
    echo "Web log report for $DATE"
    echo
    echo "Top client IPs"
    awk '{print $1}' "$ACCESS_LOG" | sort | uniq -c | sort -nr | head -20

    echo
    echo "HTTP status code counts"
    awk '{print $9}' "$ACCESS_LOG" | sort | uniq -c | sort -nr

    echo
    echo "Top 404 sources"
    awk '$9 == 404 {print $1}' "$ACCESS_LOG" | sort | uniq -c | sort -nr | head -20

    echo
    echo "Recent 500 errors"
    awk '$9 == 500 {print $0}' "$ACCESS_LOG" | tail -20
} > "$REPORT"

echo "Report created: $REPORT"

Make executable:

chmod +x ~/scripts/web-log-report.sh

Run manually:

~/scripts/web-log-report.sh

Schedule daily:

crontab -e

Add:

5 6 * * * /home/pat/scripts/web-log-report.sh >> /home/pat/reports/web-log-report-cron.log 2>&1

This is how Linux text tools become automated operations.

Practical workflow: check command paths in scripts

Cron and scripts may not have the same PATH as your interactive shell.

Find command paths:

command -v bash
command -v tar
command -v awk
command -v sort
command -v uniq
command -v head

Example output:

/usr/bin/bash
/usr/bin/tar
/usr/bin/awk
/usr/bin/sort
/usr/bin/uniq
/usr/bin/head

In important scripts, you can either use absolute command paths or define PATH explicitly.

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

Example:

#!/bin/bash
set -euo pipefail

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

tar -czf /home/pat/backups/site.tar.gz /var/www/site

This reduces differences between interactive and scheduled execution.

Practical workflow: use shellcheck for better scripts

A very useful tool for checking shell scripts is shellcheck.

Install:

sudo apt update
sudo apt install shellcheck

Check a script:

shellcheck backup.sh

shellcheck can detect quoting issues, unsafe patterns, unused variables and many common scripting mistakes.

Example:

shellcheck ~/scripts/site-backup.sh

This is not part of the original beginner cheat sheet, but it is one of the best practical tools for writing safer shell scripts.

Practical workflow: build a personal Linux command library

As you learn, create your own command notes.

mkdir -p ~/linux-notes
nano ~/linux-notes/useful-commands.md

Add commands with comments.

Check disk:
df -h

Largest folders:
du -h --max-depth=1 /var | sort -h

Find large files:
find /var -type f -size +100M -exec ls -lh {} \;

Check failed services:
systemctl --failed

Follow Nginx logs:
journalctl -u nginx -f

This becomes your personal operational knowledge base.

You can search it:

grep -i "disk" ~/linux-notes/useful-commands.md

You can version it with Git later if needed.

Key takeaways

The focus now shifts from individual commands to workflows, scripts and scheduled automation.

The key commands and concepts are:

Tool or conceptEssential role
historyReuse and inspect previous commands
!!Repeat the previous command
!123Run a command from history by number
WildcardsMatch groups of files
QuotesControl shell interpretation
VariablesStore reusable values
$(command)Insert command output into another command
``
>Redirect output and overwrite
>>Redirect output and append
2>Redirect errors
2>&1Merge errors with output
teeDisplay and save output
xargsConvert input into command arguments
wcCount lines, words, characters and bytes
cutExtract simple fields
awkProcess structured text and apply logic
sedEdit and transform text streams
sortSort lines
uniqRemove or count repeated adjacent lines
crontabSchedule commands
screenKeep terminal sessions alive
Shell scriptsSave workflows as reusable tools
Exit statusDetect success or failure
ifAdd decisions to scripts
forRepeat actions over a list
while readProcess files line by line
watchRepeat a command visually
lsofIdentify open files and port usage
dmesgInspect kernel and hardware messages

The deeper lesson is that Linux is built around text streams. Logs are text. Configuration files are text. Command output is text. Scripts are text. Reports can be generated from text. Automation is often just carefully structured text moving through commands.

Once you understand pipes, redirection, quoting, variables, text processing and cron, the terminal stops being a manual interface only. It becomes a system for building your own tools.

Exit status tells whether a command succeeded

Every Linux command returns an exit status. This is a small numeric result that tells the shell whether the command succeeded or failed.

Check the exit status of the previous command:

echo $?

The general convention is:

Exit statusMeaning
0Success
NonzeroFailure, warning or special condition

Example:

ls /home
echo $?

If /home exists and is readable, the exit status is likely:

0

Now try:

ls /directory/that/does/not/exist
echo $?

The exit status will be nonzero.

This is important in scripts because scripts use exit status to decide what to do next.

Example:

if tar -tzf backup.tar.gz > /dev/null 2>&1; then
    echo "Archive is valid"
else
    echo "Archive is damaged or unreadable"
fi

The script does not need to parse text output. It checks whether tar succeeded.

This is a clean Linux pattern: let commands report success or failure through exit status.

Practical workflow: create a safe update script

Create script:

nano ~/scripts/safe-update.sh

Script:

#!/bin/bash
set -euo pipefail

LOG_DIR="/home/pat/maintenance-logs"
DATE=$(date +%Y-%m-%d-%H-%M)
LOG="$LOG_DIR/update-$DATE.log"

mkdir -p "$LOG_DIR"

{
    echo "Maintenance started at $(date +"%Y-%m-%d %H:%M:%S")"
    echo
    echo "Host:"
    hostname
    echo
    echo "Uptime before:"
    uptime
    echo
    echo "Disk before:"
    df -h
    echo
    echo "Failed services before:"
    systemctl --failed || true
    echo
    echo "Updating package lists:"
    sudo apt update
    echo
    echo "Upgradable packages:"
    apt list --upgradable
    echo
    echo "Applying upgrades:"
    sudo apt upgrade
    echo
    echo "Removing unused dependencies:"
    sudo apt autoremove
    echo
    echo "Failed services after:"
    systemctl --failed || true
    echo
    echo "Disk after:"
    df -h
    echo
    echo "Maintenance finished at $(date +"%Y-%m-%d %H:%M:%S")"
} 2>&1 | tee "$LOG"

Make executable:

chmod +x ~/scripts/safe-update.sh

Run:

~/scripts/safe-update.sh

This script records maintenance output. It is still interactive because apt upgrade may ask for confirmation. That is often desirable for manual maintenance.

For fully automated updates, more policy decisions are needed. Automation should not blindly upgrade critical production systems without testing and rollback planning.

Practical workflow: use aliases for safer inspection

Useful aliases can make inspection faster.

Open:

nano ~/.bashrc

Add:

alias ll='ls -lah'
alias la='ls -la'
alias lt='ls -lahtr'
alias disk='df -h'
alias ports='sudo ss -tulpn'
alias failed='systemctl --failed'

Reload:

source ~/.bashrc

Now:

ll
disk
failed
ports

Aliases should make safe inspection easier. Avoid aliases that hide dangerous behavior.

A dangerous alias would be:

alias cleanup='rm -rf *'

A safer alias:

alias rm='rm -i'

Even this should be used thoughtfully. Some experienced users prefer not to alias core commands because it can create surprises on other systems.

Practical workflow: create reusable functions

Shell functions are more flexible than aliases.

Add to ~/.bashrc:

servercheck() {
    hostname
    uptime
    df -h
    systemctl --failed
}

Reload:

source ~/.bashrc

Run:

servercheck

Function with argument:

portcheck() {
    sudo ss -tulpn | grep ":$1"
}

Use:

portcheck 80

Function for log search:

logerrors() {
    grep -i "error" "$1" | tail -n 50
}

Use:

logerrors /var/log/syslog

Functions can turn frequent diagnostic patterns into personal tools.

Practical workflow: make personal scripts portable

If you create scripts in:

~/scripts

Add this directory to PATH.

echo 'export PATH="$PATH:$HOME/scripts"' >> ~/.bashrc
source ~/.bashrc

Create a script:

nano ~/scripts/servercheck

Content:

#!/bin/bash

hostname
uptime
df -h
systemctl --failed || true

Make executable:

chmod +x ~/scripts/servercheck

Run from anywhere:

servercheck

This is how personal command-line workflows become reusable tools.

Here-documents for writing multi-line files

A here-document lets you send multiple lines into a command.

Example:

cat > notes.txt << 'EOF'
This is line one.
This is line two.
This is line three.
EOF

This writes three lines into notes.txt.

Use with sudo tee for protected files:

sudo tee /etc/example.conf > /dev/null << 'EOF'
setting_one=yes
setting_two=no
EOF

The quoted 'EOF' prevents variable expansion inside the block.

Without quotes:

cat > file.txt << EOF
Home is $HOME
EOF

The variable expands.

With quotes:

cat > file.txt << 'EOF'
Home is $HOME
EOF

The literal text $HOME is written.

Here-documents are useful for scripts, configuration templates, test files and documentation generation.

systemd timers as an alternative to cron

Cron is classic and simple. Systemd timers are a modern alternative on systemd systems. They integrate with system logs and service units.

A timer usually has two files: a service and a timer.

Create service:

sudo nano /etc/systemd/system/site-backup.service

Content:

[Unit]
Description=Run site backup

[Service]
Type=oneshot
User=pat
ExecStart=/home/pat/ops/scripts/site-backup

Create timer:

sudo nano /etc/systemd/system/site-backup.timer

Content:

[Unit]
Description=Run site backup daily

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

Reload systemd:

sudo systemctl daemon-reload

Enable and start timer:

sudo systemctl enable --now site-backup.timer

List timers:

systemctl list-timers

Check timer status:

systemctl status site-backup.timer

Check service logs:

journalctl -u site-backup.service

Systemd timer advantages:

FeatureBenefit
Integrated loggingUse journalctl
Persistent timersMissed runs can execute after boot
Dependency managementCan depend on services or targets
Service isolationRuns as defined unit
Status visibilitysystemctl status and list-timers

Cron is still excellent. Systemd timers are better when you want deeper integration with systemd.

Understanding lock files

Some programs create lock files to prevent multiple instances from running at the same time.

A lock file may live under:

/run
/var/lock
/tmp
application-specific directories

If a script says another instance is running, it may be using a lock file.

Find lock files:

find /run /var/lock /tmp -iname "*lock*" 2> /dev/null | head

Do not delete lock files blindly. First check whether the related process is still running.

Example:

ps aux | grep process-name

If a program crashed and left a stale lock, removing it may be appropriate after verification.

Lock files exist to prevent data corruption. Treat them as warning signs.

Practical workflow: prevent duplicate script runs with flock

If a cron job might overlap with itself, use flock.

Example cron line:

0 * * * * /usr/bin/flock -n /tmp/myjob.lock /home/pat/scripts/myjob.sh >> /home/pat/logs/myjob.log 2>&1

This means the job runs only if it can acquire the lock.

If the previous run is still active, the new run exits.

Manual example:

flock -n /tmp/backup.lock /home/pat/scripts/backup.sh

This is useful for backups, imports, synchronizations and cleanup tasks.

Without locking, a slow job scheduled every hour may still be running when the next hour begins. Two copies may run at once and cause problems.

Understanding grep exit status

grep returns different exit statuses depending on whether it found a match.

grep "error" app.log
echo $?

Typical behavior:

Exit statusMeaning
0Match found
1No match found
2Error occurred

This matters in scripts using set -e.

Example:

grep -i "error" app.log | wc -l

If no error exists, this still prints 0 because wc runs. But in some script structures, a no-match grep may stop the script if set -e is active.

Safer in reports:

grep -i "error" app.log || true

or:

ERROR_COUNT=$(grep -i "error" app.log | wc -l)

When writing strict scripts, understand which commands return nonzero for normal conditions.

Understanding return codes in maintenance scripts

A maintenance script should exit with a meaningful status.

Successful end:

exit 0

Failure:

exit 1

Example:

if [ ! -d "$SOURCE" ]; then
    echo "Source directory missing: $SOURCE"
    exit 1
fi

This tells cron, systemd or another calling process that the script failed.

For systemd services of type oneshot, exit status matters. A nonzero exit means the unit failed.

Check:

systemctl status site-backup.service

Read logs:

journalctl -u site-backup.service

Good scripts communicate failure clearly.

Practical workflow: turn a script into a monitored systemd job

Create backup script:

nano /home/pat/ops/scripts/site-backup

Make executable:

chmod +x /home/pat/ops/scripts/site-backup

Create service:

sudo nano /etc/systemd/system/site-backup.service

Content:

[Unit]
Description=Site backup job

[Service]
Type=oneshot
User=pat
ExecStart=/home/pat/ops/scripts/site-backup

Create timer:

sudo nano /etc/systemd/system/site-backup.timer

Content:

[Unit]
Description=Run site backup every day

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

Reload:

sudo systemctl daemon-reload

Test service:

sudo systemctl start site-backup.service

Check:

systemctl status site-backup.service
journalctl -u site-backup.service -n 100

Enable timer:

sudo systemctl enable --now site-backup.timer

List timers:

systemctl list-timers

This gives scheduled execution with systemd visibility.

Understanding persistent timers

In a systemd timer, this line is important:

Persistent=true

It means that if the system was powered off when the timer should have run, systemd can run the missed job after boot.

This is useful for laptops, small servers and machines that are not always on.

Cron does not behave exactly the same by default. If a cron job is missed because the machine is off, it may simply not run.

This makes systemd timers attractive for some scheduled maintenance tasks.

Practical workflow: inspect what a timer will run

List timers:

systemctl list-timers

Show timer:

systemctl status site-backup.timer

Show related service:

systemctl cat site-backup.service

Show logs:

journalctl -u site-backup.service

Run manually:

sudo systemctl start site-backup.service

Check result:

systemctl status site-backup.service

This workflow makes scheduled jobs easier to audit than hidden cron entries.

Troubleshooting Linux methodically

Troubleshooting Linux is a method. Good diagnosis follows evidence, error messages, logs, exit status, layered checks and reproducible verification.

Practical workflow: fix a script that will not run

Suppose you have a script named backup.sh.

Try to run it:

./backup.sh

If you see:

Permission denied

inspect permissions:

ls -l backup.sh

If it looks like this:

-rw-r--r-- 1 pat pat 500 May 14 10:20 backup.sh

it does not have execute permission.

Add execute permission:

chmod +x backup.sh

Check again:

ls -l backup.sh

Now it may look like:

-rwxr-xr-x 1 pat pat 500 May 14 10:20 backup.sh

Run again:

./backup.sh

If it still fails, check the first line of the script:

head -n 1 backup.sh

A Bash script should often begin with:

#!/bin/bash

or:

#!/usr/bin/env bash

This first line is called the shebang. It tells Linux which interpreter should run the script.

Practical workflow: investigate high CPU usage

Suppose a server feels slow. The goal is to identify whether CPU load is high and which process is responsible.

Start with uptime:

uptime

Look at load average.

Then open htop:

htop

If htop is not available:

top

Find the process consuming CPU. Note its PID and command.

Inspect it with ps:

ps -p 12345 -f

Show more detail:

ps aux | grep process-name

If it belongs to a service:

systemctl status service-name

Check logs:

journalctl -u service-name -n 50

Only then decide whether to restart:

sudo systemctl restart service-name

If a single runaway process does not stop gracefully:

kill 12345

If still running:

kill -9 12345

Professional sequence:

StepCommandPurpose
Check system loaduptimeConfirm load pressure
Inspect processeshtopIdentify heavy process
Verify processps -p PID -fUnderstand what it is
Check servicesystemctl status serviceSee managed service state
Read logsjournalctl -u service -n 50Find cause
Restart servicesystemctl restart serviceControlled recovery
Kill only if neededkill PIDStop unmanaged process

Do not start with kill -9. Start with diagnosis.

Practical workflow: investigate a failed service

Suppose Apache is not working.

Check service status:

systemctl status apache2

Read recent logs:

journalctl -u apache2 -n 80

Test configuration:

sudo apache2ctl configtest

If configuration is valid, restart:

sudo systemctl restart apache2

Check status again:

systemctl status apache2

Check listening ports:

sudo ss -tulpn | grep apache

or:

sudo ss -tulpn | grep ':80'

If Apache fails after a configuration edit, restore backup:

sudo cp /etc/apache2/apache2.conf.backup /etc/apache2/apache2.conf
sudo systemctl restart apache2

This shows why configuration backups matter.

A good service troubleshooting pattern:

systemctl status service-name
journalctl -u service-name -n 50
sudo systemctl restart service-name
systemctl status service-name

For web servers, add configuration test commands where available.

Practical workflow: why a website is down

Suppose a website is not responding. A beginner may restart everything. A better workflow is systematic.

Check whether the server is reachable:

ping server-ip

Log in:

ssh user@server-ip

Check disk space:

df -h

Check web service:

systemctl status nginx

or:

systemctl status apache2

Check listening ports:

sudo ss -tulpn | grep ':80'
sudo ss -tulpn | grep ':443'

Check logs:

journalctl -u nginx -n 80

or:

journalctl -u apache2 -n 80

Check web root permissions:

ls -ld /var/www
ls -lah /var/www/html

Check recent changes:

find /var/www/html -type f -mmin -60

Restart only after diagnosis:

sudo systemctl restart nginx

or:

sudo systemctl restart apache2

Then verify:

systemctl status nginx
sudo ss -tulpn | grep ':80'

This workflow connects networking, services, ports, logs, files and permissions.

Practical workflow: recover from a broken configuration change

Before editing a configuration file, make a backup.

Example:

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
sudo nano /etc/nginx/nginx.conf

Test configuration:

sudo nginx -t

If valid, reload:

sudo systemctl reload nginx

If broken, restore backup:

sudo cp /etc/nginx/nginx.conf.backup /etc/nginx/nginx.conf
sudo nginx -t
sudo systemctl reload nginx

The same logic applies to many services.

ServiceTest command example
Apachesudo apache2ctl configtest
Nginxsudo nginx -t
SSHsudo sshd -t
Systemd service filesudo systemd-analyze verify file.service

Testing before restarting is a professional habit.

This is especially important for SSH configuration. If you break SSH and restart it on a remote server, you may lock yourself out.

A safer SSH configuration workflow:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
sudo nano /etc/ssh/sshd_config
sudo sshd -t
sudo systemctl reload ssh

Keep an existing SSH session open while testing a new one.

Network troubleshooting as layered thinking

Network troubleshooting should be done in layers. Each layer answers a different question.

LayerQuestionCommands
InterfaceDoes the machine have a network interface and IP?ip a
LinkIs the interface up?ip link, ip a
RouteDoes traffic know where to go?ip route
GatewayCan the local router be reached?ping gateway
Internet IPCan external IPs be reached?ping 8.8.8.8
DNSCan names be resolved?getent hosts domain, ping domain
Local serviceIs the service listening?ss -tulpn, lsof -i :port
Remote serviceCan another host reach the port?curl, nc, browser
LogsWhat does the service report?journalctl, /var/log

This method avoids confusion. For example, if DNS fails, restarting the web server will not help. If the service is not listening, changing DNS will not help. If the interface has no IP, editing application configuration will not help.

A strong Linux user does not guess the layer. They test it.

Practical workflow: understand command failure with set -x

In shell scripts, set -x prints commands as they are executed. This is useful for debugging.

Example:

#!/bin/bash
set -x

SOURCE="/var/www/site"
DESTINATION="/home/pat/backups"

mkdir -p "$DESTINATION"
tar -czf "$DESTINATION/site.tar.gz" "$SOURCE"

Run the script and observe each expanded command.

You can enable debugging only for part of a script.

set -x
tar -czf "$ARCHIVE" "$SOURCE"
set +x

Do not use set -x around secrets because it may print sensitive values.

Troubleshooting Linux is a method, not a panic reaction

Linux troubleshooting is not about randomly restarting services, deleting files, changing permissions or copying commands from forums. Good troubleshooting is a method. It begins with observation, continues with narrowing the problem, then moves to controlled action and ends with verification.

A beginner often reacts to an error by immediately looking for a command that “fixes” it. An experienced Linux user first asks what layer is failing.

Is the problem in the filesystem?

Is the disk full?

Is the service stopped?

Is the process running but not responding?

Is the network interface down?

Is DNS failing?

Is a firewall blocking access?

Is a configuration file invalid?

Is a permission missing?

Is the command being run as the wrong user?

Is the script using the wrong working directory?

Is cron running with a different environment?

The terminal gives you tools to answer all of these questions. The real skill is choosing the right question first.

A professional Linux troubleshooting process usually follows this structure.

StagePurposeTypical commands
IdentifyConfirm what system, user and location you are working withhostname, whoami, pwd, id
ObserveCheck visible system stateuptime, df -h, free -h, systemctl --failed
InspectRead logs, files and service statustail, grep, journalctl, systemctl status
Narrow downTest one layer at a timeip a, ip route, ping, ss, lsof, find
ActMake the smallest necessary changenano, systemctl reload, chmod, chown, apt install
VerifyConfirm the result after actionsystemctl status, curl, df -h, tail, grep
DocumentSave what was donehistory, tee, notes, scripts

The most dangerous troubleshooting pattern is this:

sudo chmod -R 777 /var/www
sudo systemctl restart apache2
sudo rm -rf cache

This may appear to solve a symptom temporarily, but it creates security problems, removes evidence and may damage the system.

A better approach is:

hostname
whoami
pwd
df -h
systemctl status apache2
journalctl -u apache2 -n 100
ls -ld /var/www
ls -lah /var/www

This sequence gathers facts before making changes.

The deepest Linux troubleshooting principle is simple: do not destroy information before you understand it. Logs, permissions, timestamps, process states and configuration files are evidence. If you delete or overwrite them too early, you make the real cause harder to find.

Read the error message before searching for the solution

Many Linux errors already contain the answer, but beginners often ignore them because they look technical.

Consider this error:

Permission denied

This usually points to permissions, ownership, execution rights or user identity.

Start with:

whoami
pwd
ls -ld .
ls -l target-file

Another error:

No such file or directory

This does not always mean the file never existed. It may mean the path is wrong, the current directory is different, the filename case is wrong, a script interpreter path is invalid or a symbolic link points to a missing target.

Start with:

pwd
ls -lah
ls -l /full/path/to/file

Another error:

command not found

This may mean the package is not installed, the command name is wrong or the command is not in your PATH.

Start with:

type command-name
command -v command-name
echo "$PATH"

Another error:

Address already in use

This means a service tried to bind to a port that is already occupied.

Start with:

sudo ss -tulpn | grep ':80'
sudo lsof -i :80

Another error:

No space left on device

This may mean the filesystem is full, inodes are exhausted or a deleted file is still held open.

Start with:

df -h
df -i
sudo du -h --max-depth=1 / | sort -h
sudo lsof | grep deleted

A Linux error message is not an obstacle. It is a diagnostic clue.

Command not found means more than missing software

When you see:

command not found

do not immediately assume Linux is broken. This error has several possible causes.

CauseExampleDiagnostic command
Command is not installedhtop missingcommand -v htop
Command name is misspelledifconfgCheck spelling
Command exists but is not in PATHCustom scriptecho "$PATH"
Script is in current directory but not called with ./myscript.sh./myscript.sh
File is not executableScript exists but cannot runls -l script.sh
Wrong shell or environmentCron cannot find commandUse absolute paths

Check whether a command exists:

command -v htop

Check command type:

type htop

Find possible package:

apt search htop

Install if needed:

sudo apt update
sudo apt install htop

If you created a script in the current directory, this may fail:

backup.sh

The current directory is usually not searched automatically for security reasons. Use:

./backup.sh

If permission is missing:

chmod +x backup.sh
./backup.sh

If a script works interactively but fails in cron, use absolute paths.

Find command path:

command -v tar
command -v bash
command -v rsync

Then use full paths in cron or define PATH.

Understanding PATH

PATH is an environment variable that tells the shell where to look for commands.

Show it:

echo "$PATH"

Example output:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

The directories are separated by colons.

When you type:

ls

the shell searches directories in PATH until it finds an executable named ls.

Check where ls is found:

command -v ls

Example:

/usr/bin/ls

If your own script is in:

/home/pat/scripts

and that directory is not in PATH, you cannot run the script by name alone unless you use the full path or ./.

Run by full path:

/home/pat/scripts/backup.sh

Run from inside the script directory:

./backup.sh

Add a directory to PATH temporarily:

export PATH="$PATH:/home/pat/scripts"

To make it persistent, add it to ~/.bashrc:

nano ~/.bashrc

Add:

export PATH="$PATH:/home/pat/scripts"

Reload:

source ~/.bashrc

Be careful with PATH. Do not add untrusted writable directories to the beginning of PATH, especially on shared systems. If a malicious executable appears there with the same name as a common command, it may be run accidentally.

Environment variables shape command behavior

Environment variables are named values available to programs.

Show all environment variables:

env

Show a specific variable:

echo "$HOME"

Common variables:

VariableMeaning
HOMECurrent user’s home directory
USERCurrent username
SHELLCurrent user’s shell
PATHDirectories searched for commands
PWDCurrent working directory
LANGLocale and language setting
TERMTerminal type
EDITORPreferred text editor

Examples:

echo "$HOME"
echo "$USER"
echo "$SHELL"
echo "$PWD"

Set a variable for the current shell:

PROJECT="linux-guide"

Export it so child processes can see it:

export PROJECT

Or in one line:

export PROJECT="linux-guide"

Run one command with a temporary environment variable:

LANG=C sort file.txt

This sets LANG only for that command.

Environment variables are important in scripts, cron jobs, development tools, build systems and deployment workflows.

Practical workflow: investigate command not found in cron

A script works manually but fails in cron. This is common.

First inspect cron:

crontab -l

Check script permissions:

ls -l /home/pat/scripts/backup.sh

Run with full path:

/usr/bin/bash /home/pat/scripts/backup.sh

Add logging to cron:

0 2 * * * /usr/bin/bash /home/pat/scripts/backup.sh >> /home/pat/logs/backup.log 2>&1

Inside the script, define PATH:

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

Find command paths:

command -v tar
command -v rsync
command -v date

Use absolute paths for important commands if necessary.

A debugging script can temporarily include:

env > /home/pat/logs/cron-env.log
pwd >> /home/pat/logs/cron-env.log

This shows the environment cron provides.

Cron failures are often environment failures, not command failures.

Practical workflow: investigate disk full correctly

When a disk is full, start with filesystems.

df -h

Also check inodes:

df -i

A filesystem can be full because of data blocks or because it has run out of inodes. Inodes represent filesystem entries. A huge number of tiny files can exhaust inodes even when space remains.

If normal space is full, inspect directories:

sudo du -h --max-depth=1 / | sort -h

If /var is large:

sudo du -h --max-depth=1 /var | sort -h

If logs are large:

sudo du -h --max-depth=1 /var/log | sort -h

Find large files:

sudo find /var -type f -size +500M -exec ls -lh {} \;

If inodes are full, count files by directory:

sudo find /var -xdev -type f | cut -d / -f 2,3 | sort | uniq -c | sort -nr | head -20

This helps identify where too many files exist.

If disk usage remains high after deletion:

sudo lsof | grep deleted

Restart the process holding deleted files if appropriate.

This is professional disk troubleshooting: check blocks, check inodes, locate large files, locate too many files, check deleted open files.

Practical workflow: investigate high memory usage

Check memory:

free -h

Check processes by memory:

ps aux --sort=-%mem | head -15

Use htop:

htop

Check service status if a known service is consuming memory:

systemctl status service-name

Read logs:

journalctl -u service-name -n 100

Do not kill the largest process without understanding what it is. It may be the database, web server, backup process or monitoring agent.

If a process is part of a service, prefer restarting the service:

sudo systemctl restart service-name

rather than killing random PIDs.

If the system is swapping heavily, check:

swapon --show
free -h

Memory troubleshooting is not just “what uses the most RAM?” It is also “is this expected for the workload?”

A database may use memory as cache. That can be normal. A runaway script consuming memory endlessly is different.

Practical workflow: diagnose CPU-heavy processes

Check load:

uptime

Open interactive process viewer:

htop

Or use ps:

ps aux --sort=-%cpu | head -15

Inspect a specific process:

ps -p PID -f

Replace PID with the real process ID.

Show process tree:

ps auxf

If the process belongs to a service:

systemctl status service-name
journalctl -u service-name -n 100

If it is a script, inspect where it runs from:

readlink -f /proc/PID/cwd
readlink -f /proc/PID/exe

Replace PID with the real process ID.

If appropriate, terminate gracefully:

kill PID

Force only if necessary:

kill -9 PID

High CPU is a symptom. The cause may be traffic, a bug, a loop, compression, backup, attack, indexing, database query or scheduled task.

Practical workflow: investigate service starts and immediately fails

Check status:

systemctl status service-name

Read logs:

journalctl -u service-name -n 100

Try starting:

sudo systemctl start service-name

Check again:

systemctl status service-name

If it fails because of configuration, test configuration if the service provides a test command.

Examples:

sudo nginx -t
sudo apache2ctl configtest
sudo sshd -t

If it fails because a port is occupied:

sudo ss -tulpn | grep ':PORT'
sudo lsof -i :PORT

If it fails because of permissions:

ls -ld /path
ls -l /path/file
namei -l /path/file

If it fails because of missing files:

ls -l /expected/path

The logs usually contain the strongest clue. Read them before editing configuration.

Practical workflow: investigate why a script behaves differently under sudo

A script may work as a normal user but behave differently under sudo.

Check user:

whoami
sudo whoami

Check environment:

env | sort
sudo env | sort

Check home:

echo "$HOME"
sudo sh -c 'echo "$HOME"'

When using sudo, environment variables may be reset or changed. The working directory may remain the same, but home and PATH may differ depending on sudo policy.

If a script depends on user-specific files like:

~/.ssh/config
~/.aws/credentials
~/.config/app/settings

then running it with sudo may look in root’s home instead of the user’s home.

A safer script uses explicit paths and avoids relying blindly on ~ when privilege changes are involved.

Practical workflow: investigate symbolic link deployment

Suppose a website uses this layout:

/var/www/releases/2026-05-14
/var/www/releases/2026-05-15
/var/www/current -> /var/www/releases/2026-05-15

Check link:

ls -l /var/www/current

Resolve:

readlink -f /var/www/current

Check current release:

ls -lah /var/www/current

Switch to a new release:

sudo ln -sfn /var/www/releases/2026-05-16 /var/www/current

Options:

OptionMeaning
-sCreate symbolic link
-fForce replacement
-nTreat destination symlink as normal file

Then reload service if needed:

sudo systemctl reload nginx

Rollback:

sudo ln -sfn /var/www/releases/2026-05-15 /var/www/current
sudo systemctl reload nginx

Symbolic links make deployments fast, but they require careful path management.

Practical workflow: recover from accidental config edit

Suppose you edited:

/etc/nginx/nginx.conf

and now Nginx fails.

Check status:

systemctl status nginx

Test configuration:

sudo nginx -t

If you made a backup:

sudo cp /etc/nginx/nginx.conf.backup /etc/nginx/nginx.conf
sudo nginx -t
sudo systemctl reload nginx

If you did not make a backup, check package default examples or reinstall package configuration carefully. Do not immediately purge the package unless you understand consequences.

If using version control for /etc, restore from Git. Some administrators manage /etc with tools such as etckeeper, but even without that, the habit is clear: configuration should be backed up before editing.

A safer future workflow:

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%Y-%m-%d-%H-%M).backup
sudo nano /etc/nginx/nginx.conf
sudo nginx -t
sudo systemctl reload nginx

Practical workflow: compare before and after system state

Before maintenance:

mkdir -p ~/maintenance-logs
{
    date
    hostname
    uptime
    df -h
    systemctl --failed
    apt list --upgradable
} > ~/maintenance-logs/before.txt

After maintenance:

{
    date
    hostname
    uptime
    df -h
    systemctl --failed
} > ~/maintenance-logs/after.txt

Compare:

diff -u ~/maintenance-logs/before.txt ~/maintenance-logs/after.txt

This creates a record of system state before and after work.

For important servers, this habit is valuable because it separates real changes from assumptions.

Practical workflow: check what changed in the last hour

Find files modified in the last hour under a project:

find /var/www/site -type f -mmin -60 -exec ls -lh {} \;

Find configuration files modified recently:

sudo find /etc -type f -mmin -60 -exec ls -lh {} \;

Find logs updated recently:

sudo find /var/log -type f -mmin -60 -exec ls -lh {} \;

Sort current directory by time:

ls -lt

This is useful after unexpected behavior. If something broke recently, ask what changed recently.

Do not assume. Search timestamps.

Practical workflow: detect and inspect failed login attempts

On many Debian-based systems, authentication logs are stored in:

/var/log/auth.log

Search failed password attempts:

sudo grep -i "failed password" /var/log/auth.log

Count them:

sudo grep -i "failed password" /var/log/auth.log | wc -l

Top source IPs:

sudo grep -i "failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head

Log formats can vary, so the field position may need adjustment. Always inspect a few lines first:

sudo grep -i "failed password" /var/log/auth.log | head

For systemd journal:

journalctl -u ssh -n 200

or depending on service name:

journalctl -u sshd -n 200

Security analysis starts with logs, not assumptions.

Practical workflow: create a minimal diagnostic script

Create:

nano ~/scripts/diagnostic-summary.sh

Script:

#!/bin/bash

echo "System diagnostic summary"
echo
echo "Hostname:"
hostname
echo
echo "User:"
whoami
id
echo
echo "Current directory:"
pwd
echo
echo "Uptime:"
uptime
echo
echo "Disk usage:"
df -h
echo
echo "Memory:"
free -h
echo
echo "Failed services:"
systemctl --failed || true
echo
echo "Listening ports:"
sudo ss -tulpn
echo
echo "Recent system logs:"
journalctl -n 50

Make executable:

chmod +x ~/scripts/diagnostic-summary.sh

Run:

~/scripts/diagnostic-summary.sh

Save output:

~/scripts/diagnostic-summary.sh 2>&1 | tee diagnostic-summary.txt

This script is not a replacement for real diagnosis, but it collects a useful first snapshot.

Practical workflow: use watch during repair

When fixing a problem, you may want to monitor state repeatedly.

Watch disk:

watch -n 5 df -h

Watch service status:

watch -n 3 "systemctl is-active nginx"

Watch a port:

watch -n 2 "ss -tulpn | grep ':80'"

Watch log error count:

watch -n 10 "grep -i error /var/log/syslog | wc -l"

Watch file growth:

watch -n 2 "ls -lh app.log"

Use quotes around complex watched commands. Without quotes, pipes may be interpreted outside watch.

Practical workflow: stop guessing with a checklist

When a Linux service fails, use a checklist.

hostname
whoami
uptime
df -h
systemctl status service-name
journalctl -u service-name -n 100
sudo ss -tulpn
ps aux | grep service-name

If configuration was changed:

find /etc -type f -mmin -60 -exec ls -lh {} \;

If files were deployed:

find /var/www/site -type f -mmin -60 -exec ls -lh {} \;

If permissions may be wrong:

namei -l /path/to/problem/file

If disk may be full:

df -h
df -i

This checklist does not fix everything. It prevents blind troubleshooting.

Practical workflow: document a repair session

Start a log file:

LOG="repair-$(date +%Y-%m-%d-%H-%M).log"

Record basic state:

{
    date
    hostname
    whoami
    uptime
    df -h
    systemctl --failed
} | tee "$LOG"

Append commands manually as you work:

echo "Checked nginx status" | tee -a "$LOG"
systemctl status nginx 2>&1 | tee -a "$LOG"

Append logs:

journalctl -u nginx -n 100 2>&1 | tee -a "$LOG"

At the end:

echo "Repair finished at $(date)" | tee -a "$LOG"

This creates a trace of what you observed and changed. On professional systems, this is valuable for post-incident review.

Practical workflow: safely run a risky command

A risky command is any command that deletes, overwrites, recursively changes permissions, changes ownership, restarts critical services or synchronizes with deletion.

Before a risky command, ask:

QuestionVerification command
Am I on the right host?hostname
Am I the right user?whoami, id
Am I in the right directory?pwd
What will this affect?ls, find, tree, du
Can I preview it?echo, --dry-run, -print
Do I have a backup?ls -lh backup
Can I rollback?Backup config, previous release, service reload
Is this production?Hostname, prompt, deployment context

Example risky rsync:

rsync -av --delete site/ server:/var/www/site/

Safer:

hostname
pwd
rsync -av --delete --dry-run site/ server:/var/www/site/

Only after verifying:

rsync -av --delete site/ server:/var/www/site/

Example risky deletion:

find /var/log/myapp -type f -name "*.gz" -mtime +30 -delete

Safer:

find /var/log/myapp -type f -name "*.gz" -mtime +30 -exec ls -lh {} \;

Then delete.

Practical workflow: build a learning lab for troubleshooting

Create a safe lab:

mkdir -p ~/linux-lab/{logs,scripts,data,backups}
cd ~/linux-lab

Create sample log:

cat > logs/app.log << 'EOF'
2026-05-14 10:00:01 INFO Application started
2026-05-14 10:01:15 ERROR Database connection failed
2026-05-14 10:02:10 INFO Retrying connection
2026-05-14 10:03:44 ERROR Timeout while connecting
2026-05-14 10:04:01 INFO Application stopped
EOF

Analyze:

cat logs/app.log
grep -i error logs/app.log
grep -i error logs/app.log | wc -l
tail -n 2 logs/app.log

Create script:

cat > scripts/analyze-log.sh << 'EOF'
#!/bin/bash

LOG_FILE="$1"

echo "Total lines:"
wc -l "$LOG_FILE"

echo "Error lines:"
grep -i "error" "$LOG_FILE" || true

echo "Error count:"
grep -i "error" "$LOG_FILE" | wc -l
EOF

Make executable:

chmod +x scripts/analyze-log.sh

Run:

scripts/analyze-log.sh logs/app.log

This small lab teaches files, redirection, here-documents, grep, wc, scripts and arguments.

Practical workflow: log rotation awareness

Logs should not grow forever. Many Linux systems use logrotate to rotate, compress and remove old logs.

Configuration is commonly found in:

/etc/logrotate.conf
/etc/logrotate.d/

List logrotate configurations:

ls -lah /etc/logrotate.d/

View one:

cat /etc/logrotate.d/nginx

Force debug mode without rotating:

sudo logrotate -d /etc/logrotate.conf

The -d option runs in debug mode and does not make changes.

This is useful when logs are growing too large. Instead of manually deleting active logs, check whether log rotation is configured correctly.

If an application writes huge logs, the solution may be:

ProblemBetter direction
Logs never rotateConfigure logrotate
Logs are too verboseAdjust application log level
Logs grow during errorsFix root cause
Deleted log does not free spaceRestart process or use log rotation properly

Manual deletion is not a complete log management strategy.

Practical workflow: truncate a log safely

Sometimes you need to reduce a huge active log without deleting the file. Deleting an active log can leave disk space held by a running process.

Truncate a file to zero size:

sudo truncate -s 0 /var/log/myapp/app.log

Or:

: | sudo tee /var/log/myapp/app.log > /dev/null

Check size:

ls -lh /var/log/myapp/app.log

This keeps the same file path, which may be important if a process is still writing to it.

Do this only when you understand the operational impact. Logs are evidence. If needed, archive first:

sudo cp /var/log/myapp/app.log /var/log/myapp/app.log.$(date +%Y-%m-%d-%H-%M).backup
sudo truncate -s 0 /var/log/myapp/app.log

Practical workflow: find configuration files for a service

If you do not know where a service stores configuration, use several methods.

Check package files:

dpkg -L nginx | grep conf

Check common directories:

find /etc -iname "*nginx*"

Check service definition:

systemctl cat nginx

Check process command line:

ps aux | grep nginx

Check manual:

man nginx

The command:

systemctl cat service-name

shows the systemd unit file content and can reveal startup commands and environment files.

This connects package data, filesystem search, service management and process inspection.

Practical workflow: detect recently failed commands in a script

Use set -e to stop on failure and add logging.

Example:

#!/bin/bash
set -euo pipefail

LOG="/home/pat/logs/script.log"
mkdir -p "$(dirname "$LOG")"

echo "$(date +"%Y-%m-%d %H:%M:%S") Script started" | tee -a "$LOG"

echo "Running backup" | tee -a "$LOG"
tar -czf /home/pat/backups/site.tar.gz /var/www/site 2>&1 | tee -a "$LOG"

echo "$(date +"%Y-%m-%d %H:%M:%S") Script finished" | tee -a "$LOG"

If the script fails, the log shows the last successful step.

For deeper debugging, temporarily add:

set -x

But avoid set -x around secrets.

Practical workflow: create a command review habit

Before pressing Enter on a serious command, read it aloud logically.

Example:

sudo find /var/log/myapp -type f -name "*.gz" -mtime +30 -delete

Read it as:

Find inside /var/log/myapp, only regular files, named *.gz, older than 30 days, and delete them.

If any part is not what you intend, do not run it.

For rsync:

rsync -avz --delete ./public/ deploy@server:/var/www/site/

Read it as:

Synchronize contents of local public into remote /var/www/site, preserve metadata, compress transfer, and delete files on destination that are not in source.

That last part is critical. If you are not sure, use:

rsync -avz --delete --dry-run ./public/ deploy@server:/var/www/site/

This habit prevents many disasters.

Key takeaways

Individual Linux commands become more valuable when they are connected into professional diagnostic thinking.

The key tools and concepts are:

Tool or conceptEssential role
Error messagesFirst diagnostic clue
Exit statusMachine-readable success or failure
echo $?Show previous command result
PATHCommand search locations
typeShow how shell interprets a command
command -vLocate command reliably
whichQuick command path lookup
whereisLocate binary and manual paths
manFull command documentation
aproposSearch manual descriptions
helpHelp for shell built-ins
envShow environment variables
exportMake variables available to child processes
whoamiShow current user
idShow user and group IDs
groupsShow group membership
sudoRun command with elevated privileges
suSwitch user
sudo -uRun command as a specific user
passwdChange password
adduserCreate user on Debian-style systems
usermod -aGAdd user to group
statShow detailed file metadata
namei -lShow permissions along a path
ln -sCreate symbolic links
readlinkResolve symbolic links
diffCompare files
truncateReduce file size without deleting file
systemctl catShow service unit definition
systemctl showShow service properties
logrotateManage log rotation
teeSave and display command output

The deeper lesson is that Linux troubleshooting should be evidence-based.

A problem is not solved by force. It is solved by understanding which layer failed and applying the smallest correct change.

If a command is missing, inspect PATH and packages.

If access is denied, inspect user, groups, file permissions and every parent directory.

If a disk is full, check filesystems, inodes, large directories and deleted open files.

If a service fails, read status, logs, configuration tests, ports and recent changes.

If a script fails in cron, inspect environment, paths, permissions and logs.

If remote access fails, test interface, route, DNS, port, firewall and service state.

This is how Linux becomes predictable. The terminal does not merely let you control the system. It lets you prove what is happening.

Practical workflow: investigate a problem after deployment

Suppose a website broke after a deployment around 14:30.

Check service:

systemctl status nginx

Check web server config:

sudo nginx -t

Check logs since deployment:

journalctl -u nginx --since "2026-05-14 14:30"

Check application files modified since deployment:

find /var/www/site -type f -newermt "2026-05-14 14:30" -exec ls -lh {} \;

Check permissions of changed files:

find /var/www/site -type f -newermt "2026-05-14 14:30" -exec ls -l {} \;

Check recent error logs:

tail -n 100 /var/log/nginx/error.log

If using a symlink release structure:

ls -l /var/www/current
readlink -f /var/www/current

Rollback if needed:

sudo ln -sfn /var/www/releases/previous-release /var/www/current
sudo systemctl reload nginx

Then verify:

curl -I http://localhost
systemctl status nginx

This workflow focuses on the exact time when the problem began.

Practical workflow: investigate a cron job that did not run

Check crontab:

crontab -l

Check system cron service:

systemctl status cron

or on some systems:

systemctl status crond

Check cron logs. On Debian-based systems, cron entries may appear in syslog.

grep CRON /var/log/syslog

Check script path:

ls -l /home/pat/scripts/job.sh

Run manually with full path:

/usr/bin/bash /home/pat/scripts/job.sh

Check log redirection in cron:

0 2 * * * /usr/bin/bash /home/pat/scripts/job.sh >> /home/pat/logs/job.log 2>&1

If no log exists, create log directory:

mkdir -p /home/pat/logs

Add environment debugging temporarily:

env > /home/pat/logs/cron-env.log
pwd >> /home/pat/logs/cron-env.log

Common cron problems:

ProblemCause
Script works manually but not in cronPATH or environment differs
Relative paths failCron starts from a different directory
Permission deniedScript not executable or user lacks access
No output visibleOutput not redirected
Job runs as wrong userSystem crontab format misunderstood
Command not foundUse absolute command paths
Time wrongServer timezone or cron expression wrong

Cron troubleshooting is mostly environment troubleshooting.

Practical workflow: check timezone and time synchronization

Show date:

date

Show timedate status:

timedatectl

Example output includes local time, universal time, timezone and NTP synchronization status.

Set timezone:

sudo timedatectl set-timezone Europe/Bratislava

List timezones:

timedatectl list-timezones

Search:

timedatectl list-timezones | grep Europe

Time matters for logs, cron jobs, certificates, backups and distributed systems.

If logs appear to have the wrong time, check:

date
timedatectl

A wrong timezone can make troubleshooting confusing because event order becomes unclear.

Practical workflow: check certificates and date related failures

TLS certificates depend on correct time. If system time is wrong, HTTPS connections can fail.

Check time:

date
timedatectl

Test HTTPS headers:

curl -I https://example.com

Verbose TLS connection:

curl -Iv https://example.com

Certificate tools may vary, but time correctness is always a first check.

If package updates fail with certificate validity errors, check time before changing repositories.

date
timedatectl
sudo apt update

Time is a hidden dependency in many Linux operations.

Configuration files should be changed with a rollback plan

A configuration change should always have a rollback path.

For a single file:

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%Y-%m-%d-%H-%M).backup

For a whole directory:

sudo tar -czf /root/nginx-config-backup-$(date +%Y-%m-%d-%H-%M).tar.gz /etc/nginx

Verify archive:

sudo tar -tzf /root/nginx-config-backup-$(date +%Y-%m-%d-%H-%M).tar.gz | head

Edit:

sudo nano /etc/nginx/nginx.conf

Test:

sudo nginx -t

Reload:

sudo systemctl reload nginx

If broken, restore:

sudo cp /etc/nginx/nginx.conf.backup /etc/nginx/nginx.conf
sudo nginx -t
sudo systemctl reload nginx

A rollback plan does not mean you expect failure. It means you respect production systems.

Rescue thinking before disaster happens

A good Linux administrator thinks about recovery before the system breaks.

Questions to answer:

Recovery questionWhy it matters
Can I access the server if SSH breaks?Need console, provider panel or physical access
Do I have a recent backup?Recovery depends on data availability
Can I restore the backup?Untested backups are uncertain
Do I know critical service names?Needed for repair
Do I know where configuration lives?Needed for rollback
Do I know disk layout?Needed for mount and recovery
Are important commands installed?Recovery environment may be minimal
Are credentials available securely?Recovery may need access keys or passwords

Collect basic system information before disaster:

hostname
lsblk -f
df -h
ip a
ip route
systemctl list-units --type=service --state=running
crontab -l

Save it:

mkdir -p ~/ops/reports
{
    date
    hostname
    lsblk -f
    df -h
    ip a
    ip route
    systemctl list-units --type=service --state=running
    crontab -l
} > ~/ops/reports/system-baseline-$(date +%Y-%m-%d).txt

A baseline report helps when comparing future system state.

Creating a system baseline report

A system baseline is a snapshot of important system facts. It helps you understand what changed later.

Create script:

nano ~/ops/scripts/system-baseline

Script:

#!/bin/bash
set -euo pipefail

REPORT_DIR="$HOME/ops/reports"
DATE=$(date +%Y-%m-%d-%H-%M)
REPORT="$REPORT_DIR/system-baseline-$DATE.txt"

mkdir -p "$REPORT_DIR"

{
    echo "System baseline"
    echo "Generated at: $(date)"
    echo

    echo "Hostname"
    hostname
    echo

    echo "User"
    whoami
    id
    echo

    echo "Kernel"
    uname -a
    echo

    echo "Uptime"
    uptime
    echo

    echo "Block devices"
    lsblk -f
    echo

    echo "Filesystems"
    df -h
    echo

    echo "Inodes"
    df -i
    echo

    echo "Network addresses"
    ip a
    echo

    echo "Routes"
    ip route
    echo

    echo "Listening ports"
    sudo ss -tulpn
    echo

    echo "Failed services"
    systemctl --failed || true
    echo

    echo "Running services"
    systemctl list-units --type=service --state=running
    echo

    echo "Timers"
    systemctl list-timers || true
    echo

    echo "User crontab"
    crontab -l || true
} > "$REPORT"

echo "Baseline saved to: $REPORT"

Make executable:

chmod +x ~/ops/scripts/system-baseline

Run:

~/ops/scripts/system-baseline

This gives you a dated record of system state.

The difference between shell variables and service environment variables

A shell variable exists in your current shell.

APP_ENV=production

An exported variable is passed to child processes.

export APP_ENV=production

But a systemd service does not automatically inherit your interactive shell environment. If you run:

export APP_ENV=production
sudo systemctl restart myapp

that does not necessarily set APP_ENV for the service.

Service environment must be configured in the service unit, an environment file or application-specific configuration.

Check service environment in the unit:

systemctl cat myapp

Check process environment carefully:

sudo tr '\0' '\n' < /proc/PID/environ

Replace PID with the service process ID.

This distinction explains many problems where an application works manually but fails as a service.

Practical workflow: script works manually but fails as service

Check script permissions:

ls -l /home/pat/scripts/myapp.sh

Check shebang:

head -n 1 /home/pat/scripts/myapp.sh

Run manually as the service user:

sudo -u pat /home/pat/scripts/myapp.sh

Check service file:

systemctl cat myapp

Check working directory:

systemctl show myapp -p WorkingDirectory

Check logs:

journalctl -u myapp -n 100

Check environment:

systemctl show myapp -p Environment

Inspect process if running:

ps aux | grep myapp
readlink -f /proc/PID/cwd
tr '\0' '\n' < /proc/PID/environ

Common causes:

SymptomLikely cause
File not foundWrong working directory or relative path
Permission deniedService user lacks access
Command not foundPATH differs in service
Environment missingVariables set only in shell
Port already in useAnother process is listening
Immediate exitScript ends or fails quickly
Restart loopService restart policy keeps retrying

A service is a controlled environment. Treat it differently from an interactive shell.

Practical workflow: robust log report with no match handling

Script fragment:

ERROR_COUNT=$(grep -i "error" "$LOG_FILE" | wc -l || true)

Better structure:

ERROR_COUNT=$(grep -i "error" "$LOG_FILE" | wc -l)

This usually works because wc completes, but with pipefail enabled, the pipeline may fail if grep finds no match.

With set -o pipefail, use:

ERROR_COUNT=$(grep -i "error" "$LOG_FILE" || true)

But that stores lines, not count.

A clear version:

if grep -qi "error" "$LOG_FILE"; then
    grep -i "error" "$LOG_FILE" | wc -l
else
    echo 0
fi

This is longer but explicit.

In scripts, clarity is better than cleverness.

Real-world Linux administration workflows

Real administration depends on repeatable workflows. Maintenance, backups, web server checks, SSH changes, incident response and server preparation all benefit from structured command sequences.

Linux administration is built from repeatable workflows

A Linux command becomes truly valuable when it becomes part of a repeatable workflow. Knowing that df -h shows disk space is useful. Knowing when to run it, how to interpret it, how to combine it with du, how to investigate a full filesystem and how to document the result is professional administration.

The same applies to almost every Linux command. A command is the smallest unit. A workflow is the real skill.

A workflow has a beginning, a purpose, a safe sequence and a verification step.

For example, this is only a command:

df -h

This is a workflow:

hostname
uptime
df -h
sudo du -h --max-depth=1 /var | sort -h
sudo find /var/log -type f -size +100M -exec ls -lh {} \;
sudo lsof | grep deleted

The workflow answers several connected questions.

QuestionCommand
Which machine am I on?hostname
How long has it been running?uptime
Which filesystem is full?df -h
Which folder is using space?du -h --max-depth=1
Which large files exist?find -size +100M
Is deleted data still held open?`lsof

This is the difference between command memory and operational understanding.

A Linux system is predictable when you approach it in layers. Files belong to users and groups. Services create processes. Processes open files and ports. Logs record events. Package managers install software. Cron schedules commands. SSH connects systems. The shell connects all these pieces.

Professional Linux work is not based on improvisation. It is based on repeatable inspection, careful change and verification.

A daily Linux server check

A daily server check does not need to be complicated. The purpose is to quickly detect obvious problems before they become serious incidents.

A practical daily check may include identity, uptime, disk space, memory, failed services, listening ports and recent critical logs.

hostname
uptime
df -h
free -h
systemctl --failed
sudo ss -tulpn
journalctl -p warning -n 50

Each command has a clear purpose.

CommandWhat it checks
hostnameConfirms the machine identity
uptimeShows runtime and load average
df -hShows filesystem usage
free -hShows memory and swap usage
systemctl --failedShows failed systemd units
ss -tulpnShows listening network ports
journalctl -p warning -n 50Shows recent warning-level and higher logs

This does not replace monitoring. It gives a human-readable snapshot.

A more structured version can be saved as a script.

nano ~/scripts/daily-server-check.sh

Script content:

#!/bin/bash

echo "Daily Linux server check"
echo

echo "Hostname"
hostname
echo

echo "Current user"
whoami
echo

echo "Uptime and load"
uptime
echo

echo "Disk usage"
df -h
echo

echo "Memory usage"
free -h
echo

echo "Failed services"
systemctl --failed || true
echo

echo "Listening ports"
sudo ss -tulpn
echo

echo "Recent warnings"
journalctl -p warning -n 50

Make it executable:

chmod +x ~/scripts/daily-server-check.sh

Run it:

~/scripts/daily-server-check.sh

Save output:

~/scripts/daily-server-check.sh 2>&1 | tee ~/daily-server-check.txt

This is a simple but serious administrative habit. It creates awareness of the machine before problems become urgent.

A weekly Linux maintenance workflow

Weekly maintenance is deeper than a daily check. It should review updates, disk usage, logs, backups, services and security-sensitive access.

A safe weekly maintenance workflow begins with observation.

hostname
who
uptime
df -h
free -h
systemctl --failed

Then check package updates.

sudo apt update
apt list --upgradable

Then upgrade if appropriate.

sudo apt upgrade
sudo apt autoremove

Then verify service state.

systemctl --failed
journalctl -p err -n 100

Then check disk usage more deeply.

sudo du -h --max-depth=1 /var | sort -h
sudo du -h --max-depth=1 /home | sort -h

Then check large logs.

sudo find /var/log -type f -size +100M -exec ls -lh {} \;

Then verify backup location.

ls -lah /home/pat/backups
find /home/pat/backups -type f -mtime -7 -exec ls -lh {} \;

A weekly maintenance table may look like this.

AreaCommandPurpose
UserswhoSee who is logged in
RuntimeuptimeCheck load and uptime
Diskdf -hDetect full filesystems
Memoryfree -hCheck RAM and swap
Servicessystemctl --failedDetect failed services
Updatesapt list --upgradableReview available updates
Logsjournalctl -p err -n 100Review recent errors
Large filesfind /var/log -size +100MDetect oversized logs
Backupsfind backups -mtime -7Confirm recent backups exist

The important point is that maintenance must be repeatable. A checklist prevents omissions.

Safe package update policy

Updating Linux packages is important, but updates should still be done thoughtfully. A personal laptop, a lab Raspberry Pi and a production web server do not have the same risk profile.

For a personal machine, this may be acceptable:

sudo apt update
sudo apt upgrade

For a production server, it is better to inspect first.

hostname
uptime
df -h
systemctl --failed
sudo apt update
apt list --upgradable

Then decide whether to continue.

sudo apt upgrade

After the upgrade:

systemctl --failed
journalctl -p err -n 100

If a reboot is recommended:

ls /var/run/reboot-required

If that file exists, plan a reboot window.

sudo reboot

After reconnecting:

uptime
systemctl --failed

The correct update policy depends on the environment.

EnvironmentRecommended attitude
Personal computerRegular updates are usually straightforward
Development VMUpdate often, snapshots are useful
Raspberry Pi projectUpdate carefully if it controls hardware
Small web serverInspect before and after updates
Production serverUse maintenance windows and rollback planning
Critical infrastructureTest updates before production deployment

The package manager is safe compared with random manual installation, but any system change can have side effects. Good administrators verify before and after.

Building a backup strategy with Linux commands

A backup is not a backup until it can be restored. Many users create archives. Fewer users verify them. Even fewer test restoration.

A serious Linux backup strategy answers five questions.

QuestionWhy it matters
What is being backed up?Avoid missing important data
Where is the backup stored?Avoid storing backup only on the same failing disk
How often is it created?Define acceptable data loss
How is it verified?Detect broken archives
How is it restored?Ensure recovery is possible

A basic local backup command:

tar -czf /home/pat/backups/site-$(date +%Y-%m-%d).tar.gz /var/www/site

This creates a compressed archive of /var/www/site.

But a better workflow creates the destination, logs the process and verifies the archive.

mkdir -p /home/pat/backups
tar -czf /home/pat/backups/site-$(date +%Y-%m-%d).tar.gz /var/www/site
tar -tzf /home/pat/backups/site-$(date +%Y-%m-%d).tar.gz > /dev/null
ls -lh /home/pat/backups/site-$(date +%Y-%m-%d).tar.gz

This confirms the archive can be listed.

A better backup script:

#!/bin/bash
set -euo pipefail

SOURCE="/var/www/site"
BACKUP_DIR="/home/pat/backups"
LOG_DIR="/home/pat/logs"
DATE=$(date +%Y-%m-%d-%H-%M)
ARCHIVE="$BACKUP_DIR/site-$DATE.tar.gz"
LOG="$LOG_DIR/site-backup-$DATE.log"

mkdir -p "$BACKUP_DIR"
mkdir -p "$LOG_DIR"

echo "$(date +"%Y-%m-%d %H:%M:%S") Backup started" | tee -a "$LOG"
echo "Source: $SOURCE" | tee -a "$LOG"
echo "Archive: $ARCHIVE" | tee -a "$LOG"

tar -czf "$ARCHIVE" "$SOURCE" 2>&1 | tee -a "$LOG"

if tar -tzf "$ARCHIVE" > /dev/null 2>&1; then
    echo "$(date +"%Y-%m-%d %H:%M:%S") Backup verified" | tee -a "$LOG"
else
    echo "$(date +"%Y-%m-%d %H:%M:%S") Backup verification failed" | tee -a "$LOG"
    exit 1
fi

ls -lh "$ARCHIVE" | tee -a "$LOG"

echo "$(date +"%Y-%m-%d %H:%M:%S") Backup finished" | tee -a "$LOG"

This script is still simple, but it includes destination creation, timestamping, logging and verification.

Local backups and remote backups are different

A local backup protects against accidental deletion, failed configuration changes or application-level mistakes. It does not protect well against disk failure, server destruction, theft or ransomware.

A remote backup sends data to another machine.

Using rsync:

rsync -avz /var/www/site/ backupuser@backup-server:/backups/site/

For repeated backups, rsync is efficient because it copies only changed files.

A safer preview:

rsync -avz --dry-run /var/www/site/ backupuser@backup-server:/backups/site/

Then run the real command:

rsync -avz /var/www/site/ backupuser@backup-server:/backups/site/

If the remote directory should exactly mirror the source:

rsync -avz --delete --dry-run /var/www/site/ backupuser@backup-server:/backups/site/

Then:

rsync -avz --delete /var/www/site/ backupuser@backup-server:/backups/site/

Use --delete only when you really want destination files removed if they no longer exist in the source.

Backup strategy comparison:

Backup typeCommand exampleProtects againstWeakness
Local archivetar -czf backup.tar.gz sourceAccidental file changesSame-disk failure
Local syncrsync -av source/ backup/Fast local copySame-machine risk
Remote syncrsync -avz source/ server:/backup/Server data lossNeeds remote access
Remote archivetar plus scp or rsyncPortable restore pointLarger transfers
SnapshotFilesystem or provider toolFast rollbackPlatform-specific

The best backup plan often combines more than one method.

Testing restoration

A backup must be tested. The simplest test is listing archive contents.

tar -tzf backup.tar.gz | head -30

A stronger test is extraction into a temporary directory.

mkdir -p /tmp/restore-test
tar -xzf backup.tar.gz -C /tmp/restore-test
tree -L 2 /tmp/restore-test

Check size:

du -sh /tmp/restore-test

If the archive contains a project, inspect key files.

find /tmp/restore-test -maxdepth 3 -type f | head -50

For a website backup, you may need to verify:

ComponentVerification
Web filesArchive contains expected project files
UploadsUser-uploaded data exists
ConfigurationRequired config files exist
PermissionsOwnership and permissions can be restored
DatabaseDatabase dump exists and can be imported
Cron jobsScheduled tasks are documented
ServicesRequired packages and service names are known

A file backup alone may not be enough. Many applications need both files and databases.

A typical website backup may require:

tar -czf site-files.tar.gz /var/www/site
mysqldump database_name > database.sql
tar -czf full-site-backup.tar.gz site-files.tar.gz database.sql

Database backup commands depend on the database system and authentication setup, but the principle is universal: back up both application files and application data.

Retention: how many backups should be kept

If backups are never removed, they eventually fill the disk. If too few backups are kept, recovery options are limited.

A simple retention policy might keep daily backups for 7 days.

Find backups older than 7 days:

find /home/pat/backups -type f -name "site-*.tar.gz" -mtime +7 -exec ls -lh {} \;

Delete only after verifying:

find /home/pat/backups -type f -name "site-*.tar.gz" -mtime +7 -delete

A safer cleanup script logs what it removes.

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/home/pat/backups"
LOG="/home/pat/logs/backup-cleanup.log"

mkdir -p "$(dirname "$LOG")"

echo "$(date +"%Y-%m-%d %H:%M:%S") Backup cleanup started" | tee -a "$LOG"

find "$BACKUP_DIR" -type f -name "site-*.tar.gz" -mtime +7 -exec ls -lh {} \; | tee -a "$LOG"

find "$BACKUP_DIR" -type f -name "site-*.tar.gz" -mtime +7 -delete

echo "$(date +"%Y-%m-%d %H:%M:%S") Backup cleanup finished" | tee -a "$LOG"

Schedule weekly:

crontab -e

Cron line:

0 4 * * 0 /home/pat/scripts/backup-cleanup.sh >> /home/pat/logs/backup-cleanup-cron.log 2>&1

Retention should be intentional, not accidental.

Log management is system memory management

Logs are the memory of a Linux system. They explain what happened, when it happened and often why it happened. But logs can also grow until they fill a disk.

The most important log locations on many Linux systems are:

LocationPurpose
/var/log/syslogGeneral system logs on many Debian-based systems
/var/log/auth.logAuthentication events
/var/log/kern.logKernel messages on some systems
/var/log/apache2/Apache logs
/var/log/nginx/Nginx logs
/var/log/mysql/MySQL or MariaDB logs on some systems
journalctlsystemd journal access
/var/log/apt/Package management logs

Basic log inspection:

tail -n 100 /var/log/syslog

Follow live:

sudo tail -f /var/log/syslog

Search errors:

grep -i "error" /var/log/syslog

Read systemd journal:

journalctl -n 100

Show errors only:

journalctl -p err -n 100

Follow journal live:

journalctl -f

Show logs for one service:

journalctl -u nginx -n 100

Follow service logs:

journalctl -u nginx -f

Logs are useful only when you know how to filter them. A system may produce thousands of lines. The goal is not to read everything. The goal is to locate relevant evidence.

A practical log analysis workflow

Suppose an application log is located at:

/var/log/myapp/app.log

Start by checking size and timestamp.

ls -lh /var/log/myapp/app.log

Read the last lines.

tail -n 100 /var/log/myapp/app.log

Search errors.

grep -i "error" /var/log/myapp/app.log

Count errors.

grep -i "error" /var/log/myapp/app.log | wc -l

Show most common error lines.

grep -i "error" /var/log/myapp/app.log | sort | uniq -c | sort -nr | head -20

Follow only new errors.

tail -f /var/log/myapp/app.log | grep -i "error"

Create a report.

{
    echo "Log report generated at $(date)"
    echo
    echo "File size"
    ls -lh /var/log/myapp/app.log
    echo
    echo "Total lines"
    wc -l /var/log/myapp/app.log
    echo
    echo "Error count"
    grep -i "error" /var/log/myapp/app.log | wc -l
    echo
    echo "Most common errors"
    grep -i "error" /var/log/myapp/app.log | sort | uniq -c | sort -nr | head -20
} > myapp-log-report.txt

This workflow changes logs from noise into structured information.

Log rotation prevents uncontrolled growth

Log rotation means old logs are renamed, compressed and eventually removed according to policy. On many Linux systems, logrotate manages this.

Main configuration:

/etc/logrotate.conf

Service-specific configurations:

/etc/logrotate.d/

List configurations:

ls -lah /etc/logrotate.d/

Inspect one:

cat /etc/logrotate.d/nginx

Debug logrotate without changing anything:

sudo logrotate -d /etc/logrotate.conf

Force logrotate:

sudo logrotate -f /etc/logrotate.conf

Use force carefully. Debug mode is safer for inspection.

A typical logrotate configuration may define:

DirectiveMeaning
dailyRotate daily
weeklyRotate weekly
rotate 7Keep seven rotated logs
compressCompress old logs
missingokDo not fail if log is missing
notifemptyDo not rotate empty logs
createCreate a new log file after rotation
postrotateRun commands after rotation

If logs grow too large, do not only delete them. Ask why rotation did not manage them.

Possible causes:

CauseExplanation
Application writes outside expected log pathlogrotate config does not cover it
Rotation frequency is too lowLogs grow faster than policy
Compression disabledOld logs use more space
Service keeps old file handleService may need reload after rotation
Application log level too verboseToo much unnecessary logging
Error loopApplication repeatedly logs the same failure

Log growth is often a symptom, not the root cause.

Truncating active logs safely

If a log file is huge and active, deleting it may not immediately free space if the process still holds the file open. Truncating keeps the same file but reduces its size.

First archive if needed:

sudo cp /var/log/myapp/app.log /var/log/myapp/app.log.$(date +%Y-%m-%d-%H-%M).backup

Then truncate:

sudo truncate -s 0 /var/log/myapp/app.log

Check:

ls -lh /var/log/myapp/app.log

If disk space still does not return after deletion or truncation, check deleted open files.

sudo lsof | grep deleted

A process may need restart or reload.

sudo systemctl restart myapp

Only restart after understanding the operational impact.

Web server administration with Linux commands

A Linux web server is a combination of packages, configuration files, services, processes, ports, logs, permissions and application files.

For Apache, common commands include:

systemctl status apache2
sudo systemctl restart apache2
sudo apache2ctl configtest
journalctl -u apache2 -n 100

For Nginx:

systemctl status nginx
sudo systemctl restart nginx
sudo nginx -t
journalctl -u nginx -n 100

A web server also needs listening ports.

sudo ss -tulpn | grep ':80'
sudo ss -tulpn | grep ':443'

And logs.

tail -n 100 /var/log/nginx/access.log
tail -n 100 /var/log/nginx/error.log

or:

tail -n 100 /var/log/apache2/access.log
tail -n 100 /var/log/apache2/error.log

And file permissions.

ls -ld /var/www
ls -lah /var/www/site
namei -l /var/www/site/index.html

A web server problem is rarely “just one thing.” It may be a service problem, port problem, permission problem, configuration problem, DNS problem, firewall problem or application problem.

A complete web server down workflow

If a website is down, avoid random restarts. Use a layered workflow.

Check system identity and load.

hostname
uptime
df -h
free -h

Check service.

For Nginx:

systemctl status nginx

For Apache:

systemctl status apache2

Check configuration.

sudo nginx -t

or:

sudo apache2ctl configtest

Check ports.

sudo ss -tulpn | grep ':80'
sudo ss -tulpn | grep ':443'

Check local HTTP response.

curl -I http://localhost

Check logs.

journalctl -u nginx -n 100

or:

journalctl -u apache2 -n 100

Check web root.

ls -lah /var/www
find /var/www -maxdepth 3 -type f -mmin -60 -exec ls -lh {} \;

Check permissions.

namei -l /var/www/site/index.html

Only after diagnosis, restart or reload.

sudo systemctl reload nginx

or:

sudo systemctl restart nginx

Then verify.

systemctl status nginx
curl -I http://localhost
sudo ss -tulpn | grep ':80'

The workflow moves from system health to service state, configuration, ports, response, logs, files and permissions.

Web deployment with rsync

A simple deployment often means copying local build files to a remote web root.

Preview first:

rsync -avz --delete --dry-run ./public/ deploy@server:/var/www/site/

If correct:

rsync -avz --delete ./public/ deploy@server:/var/www/site/

Then verify remotely:

ssh deploy@server "ls -lah /var/www/site | head"

Reload web server if needed:

ssh deploy@server "sudo systemctl reload nginx"

The trailing slash is critical.

SourceMeaning
./publicCopy the directory itself
./public/Copy the contents of the directory

Deployment should be previewed because --delete can remove destination files.

A safer deployment script:

#!/bin/bash
set -euo pipefail

SOURCE="./public/"
DESTINATION="deploy@server:/var/www/site/"

echo "Previewing deployment"
rsync -avz --delete --dry-run "$SOURCE" "$DESTINATION"

echo "If the preview is correct, run:"
echo "rsync -avz --delete \"$SOURCE\" \"$DESTINATION\""

For real automation, you can add a confirmation prompt.

read -r -p "Deploy now? Type yes to continue: " ANSWER

if [ "$ANSWER" = "yes" ]; then
    rsync -avz --delete "$SOURCE" "$DESTINATION"
else
    echo "Deployment cancelled"
fi

This prevents accidental deployment.

Permissions for web projects

Web permissions are one of the most common Linux problems. Too strict, and the application cannot read or write. Too open, and the server becomes insecure.

A common baseline for static files:

sudo find /var/www/site -type d -exec chmod 755 {} \;
sudo find /var/www/site -type f -exec chmod 644 {} \;

This means directories are enterable and listable, files are readable, and only owners can write.

For upload or cache directories, the web server may need write access.

Example:

sudo chown -R www-data:www-data /var/www/site/uploads
sudo chmod -R 755 /var/www/site/uploads

Depending on the application, group-based access may be better.

sudo chown -R deploy:www-data /var/www/site
sudo find /var/www/site -type d -exec chmod 755 {} \;
sudo find /var/www/site -type f -exec chmod 644 {} \;
sudo chmod -R 775 /var/www/site/storage

The exact setup depends on the application.

Key questions:

QuestionWhy it matters
Which user deploys files?Determines owner
Which user runs the web server?Determines read/write needs
Which directories need writing?Cache, uploads, sessions, generated files
Which files contain secrets?Must not be world-readable if unnecessary
Does the application require executable files?Most web files do not need execute permission

Avoid the lazy fix:

sudo chmod -R 777 /var/www/site

This grants everyone full access and is almost never the correct solution.

Diagnosing web permission errors

If a web app cannot write to a directory, identify the web server user.

For Apache on many Debian-based systems:

ps aux | grep apache

For Nginx:

ps aux | grep nginx

For PHP-FPM:

ps aux | grep php-fpm

Common web users include:

UserCommon context
www-dataDebian and Ubuntu web services
nginxSome Nginx-based systems
apacheSome Apache-based distributions
deployDeployment user, not necessarily runtime user

Test as the web user.

sudo -u www-data ls -lah /var/www/site

Test writing to a cache directory.

sudo -u www-data touch /var/www/site/cache/test-file

If this fails, inspect path permissions.

namei -l /var/www/site/cache/test-file

Then fix the specific directory, not the whole server.

sudo chown -R www-data:www-data /var/www/site/cache
sudo chmod -R 755 /var/www/site/cache

Or if group write is intended:

sudo chown -R deploy:www-data /var/www/site/cache
sudo chmod -R 775 /var/www/site/cache

The correct fix depends on the ownership model.

SSH hardening begins with visibility

SSH is one of the most important services on a Linux server because it controls remote administrative access.

Check SSH status.

systemctl status ssh

or:

systemctl status sshd

Check listening port.

sudo ss -tulpn | grep ':22'

Check recent SSH logs.

journalctl -u ssh -n 100

or:

journalctl -u sshd -n 100

On many Debian-based systems:

sudo tail -n 100 /var/log/auth.log

Search failed logins.

sudo grep -i "failed password" /var/log/auth.log | tail -50

Count failed logins.

sudo grep -i "failed password" /var/log/auth.log | wc -l

Top sources may require log-format-specific parsing, but a common starting point is:

sudo grep -i "failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head

Always inspect sample lines first because log formats vary.

sudo grep -i "failed password" /var/log/auth.log | head

Security begins with knowing what is happening.

Safe SSH configuration editing

Before editing SSH configuration, keep an existing SSH session open.

Back up the file.

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +%Y-%m-%d-%H-%M).backup

Edit.

sudo nano /etc/ssh/sshd_config

Test syntax.

sudo sshd -t

If the test returns no output, syntax is usually valid.

Reload SSH.

sudo systemctl reload ssh

or:

sudo systemctl reload sshd

Open a second terminal and test login.

ssh user@server

Only close the original session after confirming the new login works.

If the new login fails, restore from backup in the still-open original session.

sudo cp /etc/ssh/sshd_config.backup /etc/ssh/sshd_config
sudo sshd -t
sudo systemctl reload ssh

SSH configuration mistakes can lock you out. The safe workflow preserves recovery access.

Firewall changes must protect your current access

A firewall can protect a server, but it can also block your own SSH session if configured carelessly.

If using UFW, always allow SSH before enabling.

sudo ufw allow ssh
sudo ufw status
sudo ufw enable

If SSH uses a custom port:

sudo ufw allow 2222/tcp
sudo ufw enable

Allow web traffic:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Check status:

sudo ufw status verbose

Show numbered rules:

sudo ufw status numbered

Delete a rule:

sudo ufw delete 3

Firewall troubleshooting must include both server-side and external tests.

On the server:

sudo ss -tulpn
sudo ufw status

From another machine:

nc -vz server 22
nc -vz server 80
curl -I http://server

A service can be listening locally but blocked externally by firewall, router, cloud security group or network policy.

Security baseline for a small Linux server

A simple security baseline is not a complete security program, but it improves basic posture.

Start with updates.

sudo apt update
sudo apt upgrade

Create a normal user with sudo access if needed.

sudo adduser adminuser
sudo usermod -aG sudo adminuser

Use SSH keys.

ssh-keygen -t ed25519
ssh-copy-id adminuser@server

Check SSH login.

ssh adminuser@server

Configure firewall carefully.

sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Check running services.

systemctl --type=service --state=running
sudo ss -tulpn

Disable services that are not needed.

sudo systemctl disable --now service-name

Check failed services.

systemctl --failed

Review logs.

journalctl -p warning -n 100

Set up backups.

mkdir -p ~/backups

Create and test a backup script.

Security is not one command. It is a collection of habits: least privilege, updates, key-based access, firewall rules, minimal services, logs and backups.

Practical incident workflow

When something breaks, use a structured incident workflow.

First snapshot:

date
hostname
whoami
uptime
df -h
free -h
systemctl --failed

Then define the symptom.

SymptomFirst commands
Website downsystemctl status nginx, curl -I localhost, ss -tulpn
SSH failingsystemctl status ssh, `ss -tulpn
Disk fulldf -h, du, find, lsof deleted
High CPUuptime, htop, ps --sort=-%cpu
High memoryfree -h, ps --sort=-%mem, htop
Package failureapt update, apt logs, disk space
Permission errorwhoami, id, ls -l, namei -l
Cron failurecrontab -l, logs, absolute paths, environment

Collect evidence:

journalctl -n 200

or service-specific:

journalctl -u service-name -n 200

Make one change at a time.

Verify after each change.

Document what worked.

This is slower than guessing at first, but much faster when problems are serious.

Building a personal Linux operations folder

A useful professional habit is keeping your own operational scripts and notes.

Create structure:

mkdir -p ~/ops/{scripts,logs,reports,notes}

Create notes:

nano ~/ops/notes/linux-commands.md

Add commonly used commands.

Disk check:
df -h
du -h --max-depth=1 /var | sort -h

Service check:
systemctl status nginx
journalctl -u nginx -n 100

Ports:
sudo ss -tulpn

Large files:
find /var -type f -size +100M -exec ls -lh {} \;

Failed SSH logins:
grep -i "failed password" /var/log/auth.log

Search notes:

grep -i "disk" ~/ops/notes/linux-commands.md

Create scripts:

nano ~/ops/scripts/server-summary.sh

Make scripts executable:

chmod +x ~/ops/scripts/server-summary.sh

Add scripts to PATH if desired.

echo 'export PATH="$PATH:$HOME/ops/scripts"' >> ~/.bashrc
source ~/.bashrc

This turns learning into a personal toolkit.

A complete server summary script

Create:

nano ~/ops/scripts/server-summary

Script:

#!/bin/bash

echo "Server summary"
echo

echo "Date"
date
echo

echo "Hostname"
hostname
echo

echo "User"
whoami
id
echo

echo "Uptime"
uptime
echo

echo "Disk usage"
df -h
echo

echo "Inode usage"
df -i
echo

echo "Memory"
free -h
echo

echo "Failed services"
systemctl --failed || true
echo

echo "Listening ports"
sudo ss -tulpn
echo

echo "Top CPU processes"
ps aux --sort=-%cpu | head -10
echo

echo "Top memory processes"
ps aux --sort=-%mem | head -10
echo

echo "Recent errors"
journalctl -p err -n 50 || true

Make executable:

chmod +x ~/ops/scripts/server-summary

Run:

server-summary

Save report:

server-summary 2>&1 | tee ~/ops/reports/server-summary-$(date +%Y-%m-%d-%H-%M).txt

This script uses many Linux fundamentals in one place: identity, users, disk, inodes, memory, services, ports, processes and logs.

A complete backup and cleanup script

Create:

nano ~/ops/scripts/site-backup

Script:

#!/bin/bash
set -euo pipefail

SOURCE="/var/www/site"
BACKUP_DIR="/home/pat/backups/site"
LOG_DIR="/home/pat/ops/logs"
RETENTION_DAYS="14"
DATE=$(date +%Y-%m-%d-%H-%M)
ARCHIVE="$BACKUP_DIR/site-$DATE.tar.gz"
LOG="$LOG_DIR/site-backup-$DATE.log"

mkdir -p "$BACKUP_DIR"
mkdir -p "$LOG_DIR"

{
    echo "Backup started at $(date +"%Y-%m-%d %H:%M:%S")"
    echo "Source: $SOURCE"
    echo "Archive: $ARCHIVE"
    echo

    if [ ! -d "$SOURCE" ]; then
        echo "Source directory does not exist"
        exit 1
    fi

    echo "Creating archive"
    tar -czf "$ARCHIVE" "$SOURCE"

    echo "Verifying archive"
    tar -tzf "$ARCHIVE" > /dev/null

    echo "Archive size"
    ls -lh "$ARCHIVE"

    echo
    echo "Removing backups older than $RETENTION_DAYS days"
    find "$BACKUP_DIR" -type f -name "site-*.tar.gz" -mtime +"$RETENTION_DAYS" -exec ls -lh {} \;
    find "$BACKUP_DIR" -type f -name "site-*.tar.gz" -mtime +"$RETENTION_DAYS" -delete

    echo
    echo "Backup finished at $(date +"%Y-%m-%d %H:%M:%S")"
} 2>&1 | tee "$LOG"

Make executable:

chmod +x ~/ops/scripts/site-backup

Run:

site-backup

Schedule:

crontab -e

Add:

0 2 * * * /home/pat/ops/scripts/site-backup >> /home/pat/ops/logs/site-backup-cron.log 2>&1

This script includes backup creation, verification, retention cleanup and logging.

A complete log report script

Create:

nano ~/ops/scripts/log-report

Script:

#!/bin/bash
set -euo pipefail

LOG_FILE="${1:-/var/log/syslog}"
REPORT_DIR="/home/pat/ops/reports"
DATE=$(date +%Y-%m-%d-%H-%M)
REPORT="$REPORT_DIR/log-report-$DATE.txt"

mkdir -p "$REPORT_DIR"

if [ ! -f "$LOG_FILE" ]; then
    echo "Log file does not exist: $LOG_FILE"
    exit 1
fi

{
    echo "Log report"
    echo "Generated at: $(date)"
    echo "Log file: $LOG_FILE"
    echo

    echo "File size"
    ls -lh "$LOG_FILE"
    echo

    echo "Total lines"
    wc -l "$LOG_FILE"
    echo

    echo "Error count"
    grep -i "error" "$LOG_FILE" | wc -l || true
    echo

    echo "Warning count"
    grep -i "warning" "$LOG_FILE" | wc -l || true
    echo

    echo "Most common error lines"
    grep -i "error" "$LOG_FILE" | sort | uniq -c | sort -nr | head -20 || true
    echo

    echo "Last 50 lines"
    tail -n 50 "$LOG_FILE"
} > "$REPORT"

echo "Report created: $REPORT"

Make executable:

chmod +x ~/ops/scripts/log-report

Run with default log:

log-report

Run with specific log:

log-report /var/log/nginx/error.log

This is a reusable log analysis tool.

A complete port investigation workflow

When a port conflict appears, use this sequence.

Suppose port 8080 is already in use.

sudo ss -tulpn | grep ':8080'

Then:

sudo lsof -i :8080

Find process details:

ps -p PID -f

Replace PID with the actual process ID.

Find executable:

readlink -f /proc/PID/exe

Find working directory:

readlink -f /proc/PID/cwd

Check whether it belongs to a service:

systemctl status service-name

If unknown, inspect process tree:

ps auxf | grep PID

Only then decide whether to stop it.

kill PID

or, if it is a service:

sudo systemctl stop service-name

Prefer stopping the service rather than killing its process if it is managed by systemd.

A complete disk cleanup workflow

Disk cleanup must be careful because deleting the wrong files can break applications or remove evidence.

Start:

df -h
df -i

Find large top-level directories:

sudo du -h --max-depth=1 / | sort -h

If /var is large:

sudo du -h --max-depth=1 /var | sort -h

If /var/log is large:

sudo du -h --max-depth=1 /var/log | sort -h

Find large files:

sudo find /var/log -type f -size +100M -exec ls -lh {} \;

Check old compressed logs:

sudo find /var/log -type f -name "*.gz" -mtime +30 -exec ls -lh {} \;

Remove only if safe:

sudo find /var/log -type f -name "*.gz" -mtime +30 -delete

Check deleted open files:

sudo lsof | grep deleted

Check again:

df -h

This workflow avoids deleting random files from /usr, /bin, /etc or application directories.

A complete permission repair workflow

Permission repair should begin with diagnosis.

Suppose the problematic path is:

/var/www/site/storage/cache/file.txt

Check identity:

whoami
id

Check file:

ls -l /var/www/site/storage/cache/file.txt

Check directory:

ls -ld /var/www/site/storage/cache

Check full path:

namei -l /var/www/site/storage/cache/file.txt

Check runtime user:

ps aux | grep php
ps aux | grep nginx
ps aux | grep apache

Test as runtime user:

sudo -u www-data ls -l /var/www/site/storage/cache/file.txt

Test write if needed:

sudo -u www-data touch /var/www/site/storage/cache/test-file

Apply minimal fix.

sudo chown -R www-data:www-data /var/www/site/storage/cache

or group-based:

sudo chown -R deploy:www-data /var/www/site/storage/cache
sudo chmod -R 775 /var/www/site/storage/cache

Verify:

sudo -u www-data touch /var/www/site/storage/cache/test-file
ls -l /var/www/site/storage/cache/test-file

Remove test file:

sudo rm /var/www/site/storage/cache/test-file

The repair is complete only after verification.

A complete SSH access workflow

Before changing SSH settings, document current access.

whoami
hostname
systemctl status ssh
sudo ss -tulpn | grep ':22'

Check current SSH config syntax.

sudo sshd -t

Back up config.

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +%Y-%m-%d-%H-%M).backup

Edit.

sudo nano /etc/ssh/sshd_config

Test.

sudo sshd -t

Reload.

sudo systemctl reload ssh

Test new login from a second terminal.

ssh user@server

If login works, close old session later. If not, restore.

This workflow prevents lockout.

A complete new server preparation workflow

A fresh Debian-based server can be prepared with a structured sequence.

Update package information.

sudo apt update
sudo apt upgrade

Install basic tools.

sudo apt install htop tree curl wget unzip zip rsync screen

Create administrative user if needed.

sudo adduser adminuser
sudo usermod -aG sudo adminuser

Set hostname.

sudo hostnamectl set-hostname web-prod-01

Configure firewall carefully.

sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Check services.

systemctl --failed
sudo ss -tulpn

Create operations folders.

mkdir -p ~/ops/{scripts,logs,reports,notes}

Create first server summary.

hostname
uptime
df -h
free -h
systemctl --failed

Set up backups before deploying important data.

This is not a complete hardening guide, but it creates a controlled starting point.

A complete learning roadmap for Linux commands

Linux should be learned in layers.

StageFocusCommands
OrientationWhere am I and what is here?pwd, cd, ls, tree
File basicsCreate, copy, move, removemkdir, touch, cp, mv, rm
Reading filesInspect textcat, less, head, tail
SearchingFind text and filesgrep, find
PermissionsUnderstand accesschmod, chown, id, namei
PackagesManage softwareapt, dpkg
ServicesManage daemonssystemctl, service, journalctl
ProcessesInspect running programsps, htop, kill
DiskManage spacedf, du, mount, umount
NetworkingDiagnose connectivityip, ping, ssh, ss, rsync
Text processingAnalyze logsawk, sed, cut, wc, sort, uniq
AutomationRepeat workcron, scripts, screen, watch
TroubleshootingThink in layersall of the above

Do not try to learn everything at once. Learn workflows. Use a practice directory. Build small scripts. Read logs. Break problems into layers.

Key takeaways

Linux command knowledge becomes operational practice when it is organized into repeatable checks, backups, deployment steps and incident workflows.

The central lessons are:

LessonMeaning
Commands become valuable inside workflowsOne command is useful, a repeatable process is stronger
Maintenance should be structuredCheck identity, load, disk, memory, services, logs and updates
Backups must be verifiedAn archive that cannot be restored is not a backup
Logs must be managedLogs are evidence, but uncontrolled logs can fill disks
Web servers are layered systemsFiles, permissions, services, ports, logs and configuration interact
SSH must be handled carefullyRemote access mistakes can lock you out
Firewalls require access planningAlways allow SSH before enabling remote firewall rules
Permissions should follow least privilegeAvoid 777 and fix only what needs fixing
Dangerous commands need previewsUse --dry-run, find -print, ls, backups and confirmation
Troubleshooting should be evidence-basedInspect first, change second, verify third

Linux expertise is not measured by how many commands someone can type from memory. It is measured by how safely and accurately they can move from symptom to cause to solution.

A strong Linux user does not simply know grep, find, chmod, systemctl, rsync or tar. A strong Linux user knows when to use them, how to combine them, how to avoid damage and how to prove that the result is correct.

Conclusion: building lasting Linux command competence

Linux command competence is not built by memorizing hundreds of isolated commands. It is built by understanding how Linux represents files, users, processes, services, storage, network connections, permissions and logs, and then using commands to inspect those structures before changing them.

A strong Linux workflow always starts with context. Confirm the current directory, inspect the target, read the relevant status or log, make the smallest safe change and verify the result. This habit matters more than knowing a long list of options by memory.

The commands in this guide form a practical operating language. Navigation commands show where you are. File commands change data. Search commands reveal patterns. Permission commands explain access. Package commands manage software. System commands control services. Network commands connect machines. Automation commands turn repeated work into reliable procedures.

When these layers come together, the command line stops feeling like a collection of cryptic instructions. It becomes a precise, observable and repeatable way to understand Linux systems.

The best long-term approach is simple: practice in a safe directory, read manual pages, build small workflows, keep notes, test backups, document commands that worked, and troubleshoot from evidence rather than from panic. That is how Linux commands become durable system knowledge.

Questions that turn Linux commands into real working knowledge

What are Linux commands?

Linux commands are text-based instructions used to interact with a Linux operating system through a terminal and a shell. A command can list files, move between directories, install software, inspect running processes, read logs, check disk space, manage permissions, connect to remote servers or automate repeated tasks. Linux commands are important because they expose the operating system in a precise and repeatable way. Instead of relying on a graphical interface, a user can run a clear instruction, copy it into documentation, place it in a script or repeat it on another server. This is why Linux commands are essential for system administration, web hosting, DevOps, cybersecurity, software development, cloud infrastructure and troubleshooting.

Why are Linux commands still important today?

Linux commands remain important because Linux powers servers, cloud instances, containers, routers, embedded devices, development environments and many production systems that do not use a graphical desktop. In these environments, the terminal is often the main control interface. Commands are also faster to repeat, easier to document and more precise than graphical actions. A command such as systemctl status nginx clearly checks the state of a service, while tail -f /var/log/syslog lets an administrator observe system events in real time. Linux command-line knowledge is not outdated. It is one of the core skills behind modern infrastructure, automation, hosting and technical troubleshooting.

What is the difference between a terminal, a shell and a command?

A terminal is the interface where you type commands and see output. A shell is the command interpreter that reads what you type, expands variables or wildcards, handles pipes and redirection, and starts programs. A command is the actual instruction being executed. For example, in ls -lah /var/log, the terminal is where you enter the line, the shell interprets it, ls is the command, -lah are options and /var/log is the argument. This distinction matters because many behaviors users experience are caused by the shell, not by the command itself. Quoting, wildcard expansion, environment variables and pipes are shell features that shape how commands run.

What is the best way to start learning Linux commands?

The best way to learn Linux commands is to start with context before memorization. A beginner should first understand the current directory, absolute paths, relative paths, command options, arguments and permissions. Then it makes sense to learn safe inspection commands such as pwd, ls, cd, cat, less, head, tail, man and tree. These commands teach how to move through the system and read information without changing anything. After that, file operations such as cp, mv, mkdir, touch and rm become easier to understand. Linux should be learned as a set of practical workflows, not as a random list of commands.

What does pwd do in Linux?

The pwd command means print working directory. It shows the full path of the directory where the current shell session is located. This matters because many Linux commands operate relative to the current directory. If you run rm notes.txt, Linux looks for notes.txt in the current location. If you run cp report.txt backup/, both paths may be interpreted relative to where you are. Running pwd before editing, moving, copying or deleting files is a simple but professional safety habit. It prevents many beginner mistakes because it confirms the context before any action is taken.

What does cd do in Linux?

The cd command changes the current directory. It is one of the most frequently used Linux commands because it lets users move through the filesystem. For example, cd /var/log moves to the system log directory, while cd Documents moves into a directory named Documents relative to the current location. Running cd without arguments usually returns the user to their home directory. cd .. moves one level up, and cd – returns to the previous directory. Since cd changes the context for later commands, it should often be followed by pwd and ls -lah before making changes.

What does ls do in Linux?

The ls command lists files and directories. By itself, it shows visible entries in the current directory. With options, it becomes much more informative. ls -l shows a long listing with permissions, ownership, size and modification time. ls -a includes hidden files that begin with a dot. ls -h shows human-readable sizes when combined with long format. A common practical form is ls -lah, which gives a clear overview of files, hidden entries, owners, permissions and sizes. ls is one of the first commands to run before copying, deleting, editing or troubleshooting files because it shows what actually exists.

What does tree do in Linux?

The tree command displays files and directories in a visual tree structure. It helps users understand how a directory is organized below the current level. For example, tree -L 2 shows two levels of structure, which is often enough to understand a project, backup folder or website directory without overwhelming output. tree is useful before deleting, archiving or moving a directory because it lets you inspect the structure first. It may not be installed by default on minimal systems. If it is unavailable, find . -maxdepth 2 can provide a similar overview, although the output is less visually organized.

What is an absolute path in Linux?

An absolute path is a full path that starts at the root directory /. For example, /home/pat/Documents/report.txt is an absolute path because it describes the complete location from the top of the filesystem tree. Absolute paths work no matter where the current shell is located. This makes them especially useful in scripts, system administration, documentation and scheduled tasks. If a script uses an absolute path, it does not depend on the current directory from which the script was started. Absolute paths reduce ambiguity and are safer when working with configuration files, backups, services, logs and system directories.

What is a relative path in Linux?

A relative path describes a location starting from the current working directory. For example, if the current directory is /home/pat, the relative path Documents/report.txt refers to /home/pat/Documents/report.txt. Relative paths are convenient because they are shorter, but they depend entirely on context. The same command can affect different files if it is run from different directories. This is why pwd is so important. Before using relative paths with commands such as rm, cp, mv, tar or rsync, users should confirm where they are. Relative paths are efficient for daily work, but they require awareness.

Why is the Linux filesystem described as a tree?

The Linux filesystem is described as a tree because everything begins at a single root directory written as /, and all files, directories, devices and mounted filesystems appear somewhere below it. Unlike systems that organize storage primarily by drive letters, Linux uses one unified hierarchy. A user’s home folder may be under /home, system configuration under /etc, logs under /var/log, programs under /usr/bin and devices under /dev. Additional disks and USB drives can be mounted into this same tree. Understanding the tree structure is essential because nearly every Linux command works with paths inside this hierarchy.

What is the root directory in Linux?

The root directory is the top-level directory of the Linux filesystem and is written as /. Every absolute path begins there. Directories such as /home, /etc, /var, /usr, /boot, /dev and /tmp are located under the root directory. The root directory should not be confused with the root user. The root directory is a filesystem location, while the root user is the administrative superuser account. This distinction is important because “go to root” may mean changing to /, while “run as root” means using administrative privileges. The two concepts are related but not the same.

What is the root user in Linux?

The root user is the administrative superuser account in Linux. It has the highest level of authority and can modify system files, install software, manage users, change ownership, restart services and remove protected data. This power is necessary for system administration, but it is also dangerous when used carelessly. A mistake made as root can damage the entire operating system. Modern Linux workflows often avoid direct root login and use sudo for specific administrative commands instead. This gives users elevated privileges only when needed and makes it easier to control and audit administrative actions.

What does sudo do in Linux?

The sudo command runs another command with elevated privileges, usually as the root user. For example, sudo apt update refreshes package lists with administrative rights. sudo is required for many system-level tasks, including installing software, editing files under /etc, restarting services, mounting filesystems and changing ownership of protected files. However, sudo should not be used automatically for every command. If a task can be done as a normal user, it is usually safer to do it that way. Using sudo unnecessarily increases the risk of damaging system files or hiding the real cause of permission errors.

Why should beginners avoid using sudo for everything?

Beginners should avoid using sudo for everything because it bypasses normal Linux permission protections. Those protections exist to prevent accidental damage to system files and other users’ data. When a command fails with “permission denied,” the correct response is not always to add sudo. The better response is to understand why permission was denied. The user may be in the wrong directory, targeting the wrong file, using the wrong account or trying to perform an action that should not be performed. sudo is powerful, but it should be used deliberately. A safe Linux user understands the task before elevating privileges.

What does man do in Linux?

The man command opens the manual page for another command. For example, man ls shows official documentation for the ls command, including its syntax, options and behavior. Manual pages are one of the most reliable sources of Linux command information because they are installed with the system and correspond to the tools available on that machine. Inside many manual pages, Space moves forward, b moves backward, /word searches and q exits. Although manual pages can be dense at first, learning to read them is one of the best ways to become independent on Linux. Good users do not memorize everything. They know how to find accurate information.

What does –help do in Linux commands?

Many Linux commands support the –help option, which prints a quick usage summary in the terminal. For example, ls –help shows common options and syntax for ls. This is useful when you need a fast reminder and do not want to open a full manual page. The output is usually shorter and less detailed than man, but it is often enough for basic usage. A practical learning workflow is to use command –help for quick reference, man command for deeper documentation and safe test files for experimentation. Not every command behaves identically, but –help is a widely used convention.

What does type do in Linux?

The type command shows how the shell interprets a command name. It can reveal whether a command is a shell built-in, alias, function, keyword or external executable. For example, type cd may show that cd is a shell built-in, while type grep may show that grep is located at /usr/bin/grep. This matters because built-ins affect the current shell directly, while external commands run as separate programs. type is also useful when a command behaves unexpectedly. An alias may be changing the default behavior, or a different executable may be found earlier in the PATH.

What does command -v do in Linux?

The command -v command shows how a command name will be resolved by the shell. For example, command -v python3 may return /usr/bin/python3. It is useful for checking whether a command exists, where it is located and whether the shell can find it through the PATH. In scripts, command -v is often preferred over which because it is more reliable in POSIX-style shell logic. If command -v nginx returns nothing, the shell cannot find an executable named nginx in the current command search path. This helps diagnose “command not found” errors.

What does mkdir do in Linux?

The mkdir command creates directories. For example, mkdir projects creates a directory named projects in the current location. With an absolute path, mkdir /home/pat/projects creates the directory at that exact location if the user has permission. The -p option is especially useful because it creates parent directories if they do not already exist. For example, mkdir -p projects/linux/scripts creates the full nested structure. mkdir is usually safe, but users should still understand where they are creating directories. Creating folders inside system locations such as /etc, /usr, /var or /opt may require administrative privileges and should be intentional.

What does touch do in Linux?

The touch command creates an empty file if it does not exist or updates the timestamp of an existing file. For example, touch notes.txt creates an empty file named notes.txt in the current directory. It is useful for placeholders, test files, scripts and timestamp-based workflows. However, touch does not open an editor and does not add content. If a user wants to write text immediately, an editor such as nano may be more practical. In scripts, touch is often used to ensure that a file exists before another command writes to it or checks its modification time.

What does nano do in Linux?

nano is a terminal-based text editor used to create and edit text files. It is popular with beginners because its basic keyboard shortcuts are visible at the bottom of the screen. For example, nano notes.txt opens notes.txt for editing or creates it if it does not exist. nano is often used for quick notes, shell scripts and configuration files. When editing protected system files, it may need sudo, such as sudo nano /etc/hosts. The main safety rule is to understand what file you are editing before saving. This is especially important under /etc, where configuration mistakes can affect services or networking.

What does cat do in Linux?

The cat command displays file contents in the terminal and can concatenate multiple files. For example, cat notes.txt prints the entire file to standard output. It is useful for short files, quick checks and simple content inspection. However, cat is not ideal for long files because it prints everything at once and can flood the terminal. For large files, logs or configuration files, less is usually better because it allows scrolling and searching. cat is also commonly used in pipelines, although many commands can read files directly. Use cat when you want fast complete output from a manageable text file.

What does less do in Linux?

The less command opens a file or command output in an interactive pager. It lets users scroll, search and inspect long text without dumping everything into the terminal at once. For example, less /var/log/syslog opens the system log for controlled reading. Inside less, /pattern searches, n moves to the next match and q exits. less is especially useful for logs, documentation, configuration files and long command output. It is safer and more practical than cat for large files because it does not overwhelm the terminal. Many manual pages and command outputs are displayed through a pager like less.

What does head do in Linux?

The head command displays the beginning of a file. By default, it usually shows the first ten lines. For example, head file.txt shows the start of the file, while head -n 20 file.txt shows the first twenty lines. head is useful when inspecting structured files because headers, column names or format examples often appear near the top. It is also useful for quickly checking whether a file contains the expected kind of data. Since head only reads data and does not modify files, it is a safe inspection command. It is commonly used before deeper filtering, parsing or processing.

What does tail do in Linux?

The tail command displays the end of a file. By default, it usually shows the last ten lines, which makes it especially useful for log files because the newest entries are commonly written at the bottom. For example, tail -n 50 /var/log/syslog shows the last fifty lines of the system log. The option -f follows a file as it grows, so tail -f /var/log/syslog displays new log entries in real time. This is one of the most practical Linux troubleshooting commands because it allows a user to restart a service, reproduce an error or trigger an application action and immediately watch what the system records.

What does cp do in Linux?

The cp command copies files and directories. For example, cp report.txt backup/ copies the file report.txt into the backup directory. To copy a directory and its contents, the recursive option is usually required, such as cp -r project project-backup. For more careful copying, cp -i asks before overwriting existing files, while cp -a preserves attributes such as permissions, timestamps and symbolic links more completely. cp is often used before editing configuration files because a backup copy gives the user a way to restore the previous version. The main safety rule is to verify both the source and the destination before running the command.

What does mv do in Linux?

The mv command moves or renames files and directories. For example, mv oldname.txt newname.txt renames a file, while mv report.txt archive/ moves the file into the archive directory. Unlike cp, mv does not leave the original file in place. This makes it efficient but also more risky when used without checking paths. If the destination already exists, the command may overwrite or replace data depending on the situation and options. The interactive form mv -i can reduce risk by asking before overwriting. mv is also commonly used in deployment and configuration workflows where a prepared file is moved into its final location.

What does rm do in Linux?

The rm command removes files. For example, rm old.txt deletes the file named old.txt from the current directory. To remove directories, users often add recursive options, but this should be done carefully because command-line deletion usually does not move files to a trash folder. Once data is removed with rm, recovery may be difficult or impossible. Safer habits include running pwd to confirm the current location, using ls -lah to inspect the target, checking directory size with du -sh and using rm -i for confirmation. rm is a normal Linux command, but it should be treated as a final action after inspection.

Why is rm -rf dangerous?

rm -rf is dangerous because it combines recursive deletion with forced deletion. The -r option removes directories and everything inside them, while -f suppresses many warnings and ignores missing files. If the target path is wrong, too broad or unexpectedly expanded by the shell, the command can remove a large amount of data very quickly. The risk becomes much greater when used with sudo because administrative privileges may allow system files to be deleted as well. Before using rm -rf, inspect the target with pwd, ls -lah, du -sh and preferably tree or find. Professional Linux users respect this command because it obeys exactly what was typed.

What does grep do in Linux?

The grep command searches text for lines that match a pattern. For example, grep “error” app.log prints lines from app.log that contain the word error. It is one of the most important Linux commands because Linux stores a great deal of useful information as text, including logs, configuration files, command output and scripts. Common options include grep -i for case-insensitive search, grep -r for recursive search through directories, grep -n for line numbers and grep -v for inverted matches. grep is especially powerful in pipelines because it can filter large command outputs into only the lines that matter.

What does find do in Linux?

The find command searches the filesystem for files and directories based on criteria such as name, type, size, modification time, ownership and location. For example, find /home/pat -name “*.txt” searches for text files under /home/pat. find . -type f lists files below the current directory, while find . -type d lists directories. It can also find large files with -size, recently changed files with -mtime and run commands on results with -exec. find is essential for cleanup, troubleshooting, audits, automation and file discovery because it searches through directory trees with precise conditions.

What is the difference between grep and find?

grep searches inside text, while find searches for filesystem objects such as files and directories. If you need to locate files by name, type, size or modification date, use find. If you need to locate lines of text inside files or command output, use grep. For example, find /var/log -name “*.log” finds log files, while grep “permission denied” /var/log/syslog searches for a phrase inside a log file. The two commands are often used together. A user may first use find to locate a set of files and then use grep to search inside those files.

What are pipes in Linux?

Pipes send the output of one command into another command as input. The pipe character is |. For example, ps aux | grep nginx sends the list of running processes into grep, which filters lines containing nginx. Pipes are one of the most important ideas in Linux because they allow small commands to be combined into custom workflows. One command can list data, another can filter it, another can sort it, another can count it and another can save it. This is why Linux commands are powerful even when individual commands are simple. The real strength often comes from combining tools correctly.

What is output redirection in Linux?

Output redirection sends command output to a file instead of displaying it in the terminal. The > operator writes output to a file and replaces existing content, while >> appends output to the end of a file. For example, ls -lah > listing.txt saves a directory listing into listing.txt, and date >> activity.log appends the current date to activity.log. Redirection is useful for reports, logs, automation and scripts. It must be used carefully because > can overwrite an existing file. If preserving previous content matters, >> is safer, but the user should still confirm which file is being written.

What is standard error in Linux?

Standard error, often called stderr, is a separate output stream used for error messages. Standard output, or stdout, is used for normal command results. This separation allows a command to send useful results to one place and error messages to another. For example, normal output can be saved to a file while errors remain visible in the terminal. In shell syntax, > redirects standard output, while 2> redirects standard error. Understanding standard error is important in scripts and troubleshooting because a command may fail even when its normal output file looks empty. Error streams help explain what went wrong and where.

An exit code is a numeric status returned by a command when it finishes. In general, an exit code of 0 means success, while a non-zero exit code means an error or special condition occurred. The most recent exit code is stored in $?. For example, after running a command, echo $?

shows whether it succeeded. Exit codes are essential in shell scripting because they allow scripts to make decisions. A script can continue only if a command succeeded, stop when a command fails or report failure to another tool. Exit codes are one of the reasons Linux commands work well in automation.

What does awk do in Linux?

awk is a text processing language commonly used to extract, filter and transform structured text. It is especially useful when working with columns, logs, CSV-like files or command output. For example, awk ‘{print $1}’ access.log prints the first whitespace-separated field from each line. awk can also apply conditions, calculate totals, format output and process records line by line. While grep is excellent for finding matching lines, awk is better when the user needs specific fields or more complex logic. It is one of the classic Linux tools for turning raw text into meaningful information.

What does sed do in Linux?

sed is a stream editor used to transform text. It can replace text, delete lines, print selected ranges and perform automated edits. A common use is substitution, such as sed ‘s/old/new/g’ file.txt, which prints the file content with occurrences of old replaced by new. By default, sed usually writes transformed output to the terminal without changing the original file. In-place editing requires an option such as -i, which should be used carefully. sed is powerful in scripts because it can apply repeatable text transformations to logs, configuration files and generated output, but every expression should be tested before modifying important files.

What does cut do in Linux?

The cut command extracts selected parts of each line from text input. It is commonly used to extract fields or character ranges. For example, cut -d: -f1 /etc/passwd uses the colon as a delimiter and prints the first field, which contains usernames. cut is useful when the input has a consistent structure and delimiter. It is simpler than awk, which makes it convenient for quick field extraction. However, cut is less flexible when spacing is inconsistent or when conditional logic is needed. In those cases, awk is usually more appropriate. cut is best for simple, predictable text extraction tasks.

What does wc do in Linux?

The wc command counts lines, words, bytes or characters. For example, wc -l file.txt counts the number of lines in a file. In pipelines, wc -l is often used to count how many results another command produced. For example, find . -type f | wc -l counts files below the current directory. wc is useful in administration, scripting, data validation and log analysis. It can answer practical questions such as how many errors appeared, how many files match a condition or whether an export contains the expected number of lines. It is simple, but it becomes powerful when combined with pipes.

What does sort do in Linux?

The sort command sorts lines of text. It can sort alphabetically, numerically, in reverse order or by specific fields depending on options. For example, sort names.txt sorts names alphabetically, while sort -n numbers.txt sorts numbers numerically. In pipelines, sort is often used before uniq so repeated values appear next to each other and can be counted. This is common in log analysis, where users may extract IP addresses, sort them and count repeated entries. sort does not normally modify the original file unless output is redirected or special options are used. It is primarily an organization and analysis tool.

What does uniq do in Linux?

The uniq command filters adjacent duplicate lines. It is usually used after sort because duplicate lines must be next to each other for uniq to detect them reliably. For example, sort names.txt | uniq prints unique sorted names. With uniq -c, it counts repeated lines, which is useful for frequency analysis. A common log analysis pattern is to extract values, sort them, count them with uniq -c and sort the counts again. This can reveal the most common IP addresses, errors, URLs, usernames or repeated events. uniq is simple, but it is very effective in command pipelines.

What does tar do in Linux?

The tar command creates and extracts archive files. An archive combines many files and directories into one file. With compression, tar archives often use extensions such as .tar.gz or .tgz. For example, tar -czf backup.tar.gz project/ creates a compressed archive of the project directory, while tar -xzf backup.tar.gz extracts it. tar is widely used for backups, software distribution, log packaging and migration. The common options include c for create, x for extract, z for gzip compression and f for filename. Users should inspect paths carefully before extracting archives because files may be placed in unexpected locations.

What is the difference between tar, gzip and zip?

tar creates an archive by combining files and directories into one file, but it does not necessarily compress them by itself. gzip compresses a file or stream. A .tar.gz file is usually a tar archive compressed with gzip. zip combines archiving and compression in a format commonly used across Windows, macOS and Linux. On Linux systems, .tar.gz is common for backups, source code and software packages because it preserves Unix-style structure well. zip is often convenient when sharing files with users on different operating systems. The right choice depends on compatibility, preservation needs and workflow.

What does chmod do in Linux?

The chmod command changes file and directory permissions. Permissions decide who can read, write or execute a file. For example, chmod +x script.sh makes a script executable, while chmod 644 file.txt sets a common permission mode for a regular text file. For directories, execute permission has a special meaning because it allows users to enter or traverse the directory. chmod is essential for scripts, web hosting, shared directories and security. It should be used precisely. Broad commands such as recursive permission changes or chmod 777 can create security problems or break applications if the user does not understand the effect.

What does chown do in Linux?

The chown command changes the owner and optionally the group of a file or directory. For example, sudo chown pat:www-data file.txt changes the owner to pat and the group to www-data. Ownership is central to Linux permissions because access is evaluated differently for the owner, group and others. chown is often used in web hosting, deployment, shared directories and service configuration. It usually requires administrative privileges when changing ownership to another user. Recursive ownership changes with chown -R should be used carefully because they can affect many files at once. Wrong ownership can break services or expose sensitive data.

What is the difference between permissions and ownership in Linux?

Ownership defines who owns a file and which group is associated with it. Permissions define what the owner, group and others can do with that file. For example, a file may be owned by pat, assigned to the group www-data and configured so the owner can write while the group can read. chown changes ownership, while chmod changes permission bits. Both must be understood together. If a web server cannot read a file, the problem may be ownership, permissions or parent directory access. A good troubleshooting workflow checks the user running the process, the file owner, the group and the permission mode.

What does umask do in Linux?

umask controls the default permissions assigned to newly created files and directories. It does not change existing files. Instead, it subtracts permissions from the system’s default creation mode. For example, a common umask of 022 allows the owner to write while preventing group and others from writing by default. This matters for security and collaboration because it affects how open or restrictive new files are. If files are created with permissions that are too broad, sensitive data may be exposed. If they are too restrictive, services or team members may not be able to access them. umask explains many default permission behaviors.

What are users and groups in Linux?

Users represent accounts that can own files and run processes. Groups are collections of users used to manage shared access. Every file has an owner and a group, and permissions are evaluated for the owner, the group and everyone else. Processes also run as users, which affects what files and ports they can access. This is why services such as web servers and databases often run under dedicated service accounts instead of root. Groups make collaboration safer because they allow several users or services to share access without making files open to everyone. Understanding users and groups is essential for Linux permissions, security and administration.

What does apt do in Linux?

The apt command manages software packages on Debian-based Linux distributions such as Debian, Ubuntu and Linux Mint. It can update package information, install software, upgrade installed packages, remove software and search available packages. Common examples include sudo apt update, sudo apt upgrade, sudo apt install package-name and sudo apt remove package-name. apt is important because it does more than download software. It also works with repositories, dependency information, package versions and system integration. A user should understand that installing software through apt is usually safer and more maintainable than downloading random installation files from the internet, because the package manager can track installed files and future updates.

What is the difference between apt update and apt upgrade?

apt update refreshes the local package index from configured software repositories. It does not install new versions by itself. It only tells the system what package versions are currently available. apt upgrade installs available updates for packages that are already installed on the system. This distinction is important because users often think apt update updates the operating system, but it only updates package information. A normal maintenance workflow on Debian-based systems often begins with sudo apt update, then continues with sudo apt upgrade. On production servers, upgrades should be reviewed carefully because package updates may restart services, change dependencies or require configuration decisions.

What does dpkg do in Linux?

dpkg is a lower-level package management tool used on Debian-based Linux systems. While apt works with repositories and resolves dependencies, dpkg directly installs, removes and queries individual .deb package files. For example, sudo dpkg -i package.deb installs a local Debian package file. If dependencies are missing, dpkg may report errors instead of automatically resolving them the way apt usually does. dpkg -l lists installed packages and is often combined with grep to search for a specific package. For everyday package management, apt is usually more convenient, but dpkg remains important for manual installations, package audits and troubleshooting broken package states.

What does systemctl do in Linux?

systemctl controls and inspects services and system units managed by systemd. It can start, stop, restart, reload, enable, disable and check the status of services. For example, systemctl status nginx shows whether the Nginx service is active, failed or inactive, while sudo systemctl restart nginx restarts it. sudo systemctl enable nginx configures the service to start automatically at boot. systemctl is one of the most important commands for modern Linux administration because many background services, including web servers, databases, SSH, scheduled units and system components, are managed by systemd. It should generally be preferred over older service-management commands on systemd-based systems.

What is the difference between restarting and reloading a Linux service?

Restarting a service stops it and starts it again. Reloading a service asks it to re-read configuration without fully stopping, if the service supports that behavior. For example, a web server may support reload so configuration changes can be applied with less disruption than a full restart. However, not every service supports reload, and not every change can be applied safely without restarting. A professional workflow is to test the configuration first when the service provides a test command, then reload if appropriate, then verify status and logs. Restarting is more disruptive but often more complete. Reloading is gentler, but it depends on the service.

What does journalctl do in Linux?

journalctl reads logs collected by the systemd journal. It is essential on modern Linux systems because many service messages, boot logs and system events are stored in the journal. For example, journalctl -u nginx shows logs for the Nginx service, while journalctl -f follows new log entries in real time. journalctl -u service-name -f is especially useful when restarting a service or reproducing an error because it shows new messages as they appear. Compared with reading one static log file, journalctl can filter by service, boot, priority and time range. It is one of the strongest troubleshooting tools in systemd-based Linux administration.

What does ps do in Linux?

The ps command shows running processes. A common form is ps aux, which lists processes from all users with details such as user, process ID, CPU usage, memory usage, start time and command. ps is useful when a user needs to know whether a program is running, which user started it, what command launched it or which process ID should be inspected. Unlike top or htop, ps shows a snapshot at one moment rather than a live updating view. It is often combined with filtering commands such as grep, although commands such as pgrep may be cleaner for finding processes by name.

What does top do in Linux?

The top command displays a live, updating view of system activity. It shows running processes, CPU usage, memory usage, load average, task counts and other system information. top is useful when a system feels slow and the user needs to identify which processes are consuming resources. It can show whether high CPU usage comes from one process, whether memory is under pressure or whether the system is handling an unusual workload. top is available on many Linux systems by default, which makes it reliable during troubleshooting. Although htop is often more comfortable to use, top remains a standard command every administrator should understand.

What does htop do in Linux?

htop is an interactive process viewer similar to top, but usually more readable and easier to control. It shows CPU, memory, swap and process information in a visual terminal interface. Users can sort processes, search, filter and send signals more conveniently than with basic top. htop is especially useful for beginners because it makes system activity easier to understand. However, it may not be installed by default on minimal servers, so it may need to be installed through a package manager. htop does not replace understanding process behavior, but it provides a practical live view of which programs are using system resources.

What does kill do in Linux?

The kill command sends a signal to a process. Despite its name, it does not always immediately destroy a process. By default, it usually sends a termination signal, asking the process to stop gracefully. For example, kill 12345 sends a signal to the process with the process ID 12345. If a process does not respond, kill -9 12345 sends SIGKILL, which forces termination and cannot be handled by the process. This should be a last resort because it does not allow clean shutdown or cleanup. A careful workflow is to identify the process, understand its purpose and attempt graceful termination before forcing it.

What does killall do in Linux?

The killall command sends a signal to processes by name rather than by process ID. For example, killall php sends a signal to all processes named php. This can be convenient, but it can also be risky because it may affect more processes than intended. On a shared server or production machine, several unrelated tasks may use the same command name. Before using killall, it is safer to inspect matching processes with tools such as ps, pgrep or htop. killall is useful when the target is clear, but precise process IDs are safer when only one specific process should be stopped.

What is a process ID in Linux?

A process ID, often shortened to PID, is a unique number assigned to a running process. Commands such as ps, top, htop, pgrep and systemctl status can show process IDs. PIDs matter because many administrative actions target a specific process. For example, kill 12345 sends a signal to the process with PID 12345. A PID exists only while the process is running, and Linux may reuse that number later for a different process. This means users should verify the current process before acting on a PID. Process IDs are central to understanding how Linux tracks and controls running programs.

The df command reports disk space usage at the filesystem level. The common form df -h shows mounted filesystems with human-readable sizes, used space, available space and usage percentage. It helps answer the question: which filesystem is full or nearly full?

This is important because a full filesystem can cause package updates, logs, databases, uploads and services to fail. df does not tell which directory is responsible for the usage. It shows the filesystem overview. After identifying a full filesystem with df -h, administrators usually use du to investigate which directories or files are consuming space.

What does du do in Linux?

The du command estimates disk usage for files and directories. For example, du -sh /var/log shows the total size of the /var/log directory in a human-readable summary. It is commonly used after df -h shows that a filesystem is full. While df identifies the full filesystem, du helps locate the directories responsible for the usage. A practical troubleshooting pattern is to check major directories one level at a time, then drill down into the largest one. du is a read-only inspection command, but it may require administrative privileges to inspect directories that the current user cannot access.

What is the difference between df and du?

df reports used and available space at the filesystem level, while du reports estimated usage by files and directories. If a server has a full disk, df -h tells which filesystem has no space left. Then du helps identify what directory or file tree is using the space. The two commands can sometimes appear to disagree. One common reason is that a large file has been deleted but is still held open by a running process. In that case, du may not show the file because it no longer has a visible name, while df still shows the space as used. Commands such as lsof can help diagnose that situation.

What does mount do in Linux?

The mount command attaches a filesystem to a directory in the Linux filesystem tree. A disk partition, USB drive, network share or image file can be mounted so its contents appear under a mount point such as /mnt/usb or /mnt/backup. This reflects the Linux design where storage devices are integrated into one directory hierarchy instead of being represented primarily as drive letters. Mounting usually requires administrative privileges. It should be done carefully because mounting a filesystem over an existing directory can temporarily hide the original contents of that directory. mount is a core command for storage administration, recovery work and removable media handling.

What does umount do in Linux?

The umount command detaches a mounted filesystem from the Linux directory tree. For example, sudo umount /mnt/usb unmounts the filesystem mounted at /mnt/usb. This is important before removing external drives because Linux may cache writes for performance. A proper unmount helps ensure that pending data is written and the filesystem is cleanly detached. If umount reports that the target is busy, some process may still be using files inside the mounted filesystem. In that case, tools such as lsof or fuser can help identify the process. Forced unmounts should be avoided unless truly necessary because they can risk data integrity.

What does ip do in Linux?

The ip command displays and manages network configuration. It is the modern replacement for many older tools such as ifconfig and route. Common uses include ip addr to show network interfaces and IP addresses, ip link to show interface state and ip route to show routing information. The ip command is essential for diagnosing network problems because it shows whether an interface has an address, whether it is up and which gateway is being used. New Linux users may still find older tutorials using ifconfig, but learning ip is more accurate for current Linux administration.

What does ping do in Linux?

The ping command tests basic network reachability by sending ICMP echo requests to a host and waiting for replies. For example, ping 8.8.8.8 tests whether the system can reach that IP address, while ping example.com also involves DNS resolution because the hostname must be translated to an IP address. Ping results can show latency and packet loss. However, ping is not a complete test of network health. Some systems block ICMP, and a successful ping does not prove that a specific service such as HTTP, SSH or a database is reachable. It is best used as one step in a layered network diagnosis.

What does ss do in Linux?

The ss command displays socket and network connection information. It is the modern replacement for many uses of netstat. A common administrative command is ss -tulpn, which shows listening TCP and UDP sockets and the associated processes when permissions allow. This helps answer whether a service is listening on the expected port and address. For example, if a web server is running but unreachable, ss can show whether it is actually listening on port 80 or 443. ss is especially useful for troubleshooting web servers, databases, SSH, reverse proxies and application services that depend on network ports.

What does netstat do in Linux?

netstat displays network connections, routing tables, interface statistics and listening ports, but it is considered a legacy tool on many modern Linux systems. It may not be installed by default because newer tools such as ss and ip have replaced much of its functionality. Older tutorials often use commands like netstat -tulpn to show listening services. On current systems, ss -tulpn is usually the preferred equivalent. netstat remains useful when maintaining older systems or reading older documentation, but new Linux learners should understand that it belongs to an older generation of networking tools.

What does ssh do in Linux?

ssh provides secure remote access to another system over the network. For example, ssh pat@192.168.1.10 connects to the host at that IP address as the user pat, if authentication succeeds. SSH encrypts the session, which makes it the standard way to administer Linux servers remotely. It can use password authentication, but key-based authentication is usually more secure and convenient for professional use. SSH can also run remote commands, forward ports and support secure file transfer through tools such as scp and rsync. Because SSH often protects administrative access, it should be configured carefully and secured with strong authentication.

What does scp do in Linux?

scp copies files securely between systems using SSH. For example, scp file.txt pat@server:/home/pat/ copies file.txt to the remote server. It is simple and useful for one-time transfers when SSH access is already available. However, for large transfers, repeated synchronization, deployments or backups, rsync is often more efficient and flexible. scp is still valuable because its syntax is straightforward and it works well for basic file copying. Users should pay close attention to local and remote paths. A missing colon, wrong username or incorrect destination can change the meaning of the command and place files somewhere unexpected.

What does rsync do in Linux?

rsync synchronizes files and directories locally or over SSH. It is more efficient than simple copying because it can transfer only changed files or changed parts of files. A common form is rsync -av source/ destination/, where -a preserves attributes and -v shows verbose output. Over SSH, it can synchronize with a remote server, such as rsync -av site/ user@server:/var/www/site/. rsync is widely used for backups, deployments, migrations and large directory transfers. The trailing slash in the source path is very important because it changes whether the directory itself or only its contents are copied.

Why does the trailing slash matter in rsync?

The trailing slash in an rsync source path changes what is copied. When the source ends with a slash, such as project/, rsync copies the contents of the directory. Without the trailing slash, such as project, it may copy the directory itself into the destination. This difference can create unexpected nested directories or deploy files to the wrong level. For example, a website deployment may accidentally produce /var/www/html/project instead of placing files directly into /var/www/html. Because rsync is powerful and often works with important data, using –dry-run before a real synchronization is a professional safety practice.

What does wget do in Linux?

The wget command downloads files from the web or another network location directly from the terminal. It is useful on servers, minimal systems and SSH sessions where no graphical browser is available. For example, a user can download an archive, installation file, text resource or backup file by giving wget a URL. wget can also save files under a different name, resume interrupted downloads in some cases and work in scripts. It should be used carefully because downloading a file is not the same as trusting it. Before running anything downloaded with wget, users should verify the source, prefer HTTPS, check official documentation and use checksums or signatures when available.

What does curl do in Linux?

The curl command transfers data to or from servers using protocols such as HTTP, HTTPS, FTP and others. It is widely used for testing websites, inspecting HTTP headers, calling APIs, downloading files and debugging network services. For example, curl -I https://example.com retrieves HTTP response headers, while curl https://example.com prints the response body. Compared with wget, curl is often better for APIs and diagnostics because it gives fine control over headers, methods, authentication and request data. Developers, system administrators and DevOps engineers use curl constantly because modern infrastructure often communicates through web services, REST APIs and HTTP-based endpoints.

What does hostname do in Linux?

The hostname command displays the current system hostname and, depending on usage and permissions, may temporarily set it. A hostname identifies a machine in prompts, logs, monitoring tools and network contexts. On modern Linux systems, persistent hostname changes are often managed with hostnamectl, for example with a command that sets a new static hostname. A clear hostname is important in server administration because it helps distinguish production servers, staging machines, development systems and containers. Hostname changes should be planned because they may affect scripts, certificates, service discovery, monitoring, configuration management and documentation. A hostname is not just a label; it is part of operational clarity.

What does date do in Linux?

The date command displays the current system date and time. It can also format date output in specific ways, which makes it useful in scripts, backup filenames, logs and reports. For example, a script may use a formatted date to create a filename for a daily archive. Accurate time is important on Linux because logs, scheduled jobs, certificates, authentication, databases and distributed systems depend on correct timestamps. If the time is wrong, troubleshooting becomes harder because events appear out of order or certificates may fail validation. Changing system time usually requires administrative privileges and is often handled through time synchronization services rather than manual commands.

What does uptime do in Linux?

The uptime command shows how long the system has been running, how many users are logged in and the system load averages. It is a quick health check during troubleshooting. A very short uptime may indicate a recent reboot, crash or maintenance event. A very long uptime may look impressive, but it can also mean kernel updates have not been applied. Load averages help show how much work the system has been handling over the last one, five and fifteen minutes. However, load must be interpreted in context. A load average that is high for a single-core machine may be normal for a server with many CPU cores.

What does history do in Linux?

The history command shows previously executed shell commands. It is useful for repeating commands, reviewing recent work, documenting troubleshooting steps and learning from real command usage. Many shells also support reverse search through history, often with Ctrl+R, which helps find a command typed earlier. Shell history is helpful, but it should not be treated as a secure audit log. It may be incomplete, edited, disabled or cleared. Users should also avoid typing passwords, tokens or secrets directly into commands because they may be stored in history or visible to other tools. History is a productivity feature, not a safe place for sensitive information.

What does crontab do in Linux?

The crontab command manages scheduled tasks for cron. Cron allows commands or scripts to run automatically at specific times, such as every hour, every night or every week. It is commonly used for backups, cleanup tasks, reports, monitoring scripts and maintenance jobs. A cron entry contains time fields followed by the command to run. Cron is powerful, but it can surprise beginners because scheduled jobs often run with a limited environment. They may not have the same PATH, working directory or environment variables as an interactive terminal. Good cron jobs use absolute paths, log their output, handle errors and are tested manually before being scheduled.

What does screen do in Linux?

The screen command starts a persistent terminal session that can continue running even if the user disconnects. This is useful over SSH when running long tasks such as backups, migrations, package builds, large file transfers or maintenance scripts. A user can start a screen session, run a command, detach from the session and later reattach to continue monitoring it. This protects work from network interruptions or accidental terminal closure. Many administrators now also use tmux, which provides similar functionality with modern features. The important concept is persistent terminal work: long-running tasks should not depend entirely on one fragile SSH connection.

What does alias do in Linux?

An alias creates a shortcut or replacement for a command in the shell. For example, an alias can make a short command such as ll run a longer command such as ls -lah. Aliases can improve productivity, standardize frequently used options and reduce typing. They can also create safer defaults, although users should be careful not to hide important behavior behind unexpected shortcuts. If a command behaves differently than documentation suggests, type command-name can reveal whether an alias is involved. Aliases are often stored in shell configuration files such as .bashrc or .zshrc. They are useful, but they should remain clear and predictable.

What is the PATH variable in Linux?

PATH is an environment variable that tells the shell where to look for executable commands. It contains a list of directories separated by colons. When a user types a command such as grep, the shell searches the directories in PATH until it finds a matching executable. If a program is installed but its directory is not in PATH, the shell may return “command not found” even though the file exists. Understanding PATH helps diagnose command resolution problems, conflicting software versions and script behavior. It is especially important for root, cron jobs, deployment scripts and development environments where different command versions may exist.

What are environment variables in Linux?

Environment variables are named values available to processes and shells. They store information such as the current user’s home directory, preferred editor, language settings, command search path and application-specific configuration. Common examples include HOME, USER, SHELL, PATH and LANG. Programs and scripts often read environment variables to decide how they should behave. This is why a command may work in an interactive terminal but fail in cron, systemd or a deployment job where the environment is different. Understanding environment variables helps users troubleshoot inconsistent behavior, configure applications and write scripts that are predictable across different execution contexts.

What is a shell script?

A shell script is a text file containing commands that are executed by a shell. Shell scripts automate repeated tasks such as backups, deployments, log cleanup, system checks, file processing and maintenance workflows. A script can turn a manual sequence of commands into a reusable tool. Good shell scripts are careful with paths, quote variables, check errors and avoid destructive actions without validation. They should be tested on safe data before being used in production. Shell scripting is one of the most practical extensions of Linux command knowledge because it moves a user from typing individual commands to building repeatable administrative workflows.

What is a shebang in a Linux script?

A shebang is the first line of a script that tells Linux which interpreter should run the file. It begins with #!. For example, #!/bin/bash tells the system to run the script with Bash when the file is executed directly. Another common form is #!/usr/bin/env bash, which finds Bash through the environment. The shebang matters because different shells support different syntax. A script written for Bash may fail if it is run by a more minimal shell. A correct shebang makes script behavior more predictable and easier to understand. It is a small line with a major effect on script execution.

Why should variables be quoted in shell scripts?

Variables should usually be quoted in shell scripts to prevent word splitting and unexpected wildcard expansion. If a variable contains a filename with spaces and the script uses it without quotes, the shell may treat it as multiple arguments. Quoting the variable keeps the value together as one argument. This is one of the most important safety habits in shell scripting. It protects scripts from filenames with spaces, empty values, special characters and unexpected input. Many script bugs and data-loss incidents come from unquoted variables in commands such as rm, cp, mv, rsync or loops. A good default is to quote variables unless there is a deliberate reason not to.

What does source do in Linux?

The source command runs a script or configuration file in the current shell instead of launching a separate shell process. This matters because a normal script usually cannot permanently change the parent shell’s environment. When a file is sourced, variable assignments, functions, aliases and directory changes can remain active in the current session. For example, users often source shell configuration files after editing them so the changes apply immediately. source is useful for environment setup, development workflows and shell customization. It should be used only with trusted files because sourced code runs directly in the current shell context with the user’s privileges.

What does ln do in Linux?

The ln command creates links between files. It can create hard links or symbolic links. Symbolic links, created with ln -s, are more common in everyday administration because they act like path-based shortcuts to another file or directory. For example, a symlink may point from an enabled configuration location to an available configuration file. Links are useful for version switching, shared resources, configuration management and directory organization. However, symbolic links can break if the target is moved or deleted. Understanding links helps users understand many Linux systems, because symlinks are widely used in configuration directories, software paths and service setups.

What is a symbolic link in Linux?

A symbolic link, often called a symlink, is a special file that points to another path. It behaves like a shortcut. If the target exists, accessing the symlink usually accesses the target. If the target is removed or moved, the symlink becomes broken. Symlinks are created with ln -s target link-name. They are different from copies because they do not duplicate the target content. They are also different from hard links because they store a path reference rather than another direct name for the same file data. Symlinks are common in Linux because they provide flexible ways to connect files, directories, versions and configurations.

What does file do in Linux?

The file command identifies the type of a file by inspecting its contents and metadata rather than relying only on the filename extension. This is useful because Linux does not depend on extensions in the same way many users expect. A file named .txt may not contain plain text, and an executable file may have no extension at all. For example, file script.sh may identify a shell script, while file image.png may identify image data. The command is helpful before opening unknown files, troubleshooting downloads or checking whether a file is text, binary, compressed, executable or something else.

What does stat do in Linux?

The stat command displays detailed metadata about a file or directory. It can show size, ownership, permissions, inode number and timestamps such as access time, modification time and status change time. It provides more precise information than a basic ls -l listing. stat is useful when troubleshooting permissions, synchronization, backups, deployment issues or unexpected file changes. For example, it can help determine whether a file was modified recently or whether permissions differ from what an application expects. stat does not change the file. It is an inspection command, which makes it safe and useful when gathering evidence before making changes.

What does lsof do in Linux?

The lsof command lists open files. In Linux, many resources are represented as files, including regular files, directories, devices and network sockets. This makes lsof extremely useful for troubleshooting. It can show which process is using a file, which process is keeping a mount point busy or which process still holds a deleted file open. This last case is important when disk space appears full even after a large file was deleted. The file may be gone from the directory listing, but the space may not be released until the process closes it. lsof helps reveal these hidden relationships between processes and files.

What does dmesg do in Linux?

The dmesg command displays messages from the kernel ring buffer. These messages often relate to hardware, drivers, boot events, disk detection, USB devices, network interfaces and kernel-level errors. For example, after connecting a USB drive, dmesg may show how the kernel detected it and which device name was assigned. It is useful when troubleshooting hardware recognition, boot problems, disk errors, driver issues and low-level system events. On some systems, access to dmesg may be restricted for security reasons. It should be understood as a kernel diagnostic tool, not as a replacement for application logs or service-specific logs.

What does watch do in Linux?

The watch command repeatedly runs another command and displays updated output. For example, watch df -h refreshes disk usage every few seconds. This is useful when observing a changing condition, such as disk space during cleanup, process counts during a test, network sockets during service startup or file growth during a backup. watch helps users move from single snapshots to live observation. It is practical during troubleshooting because some problems appear only over time. However, users should avoid running expensive commands too frequently with watch, especially on production systems. Monitoring should provide insight without creating unnecessary load.

How do you troubleshoot “permission denied” in Linux?

To troubleshoot “permission denied,” first identify the exact file, directory or operation that failed. Then check the current user with whoami or id, inspect the file or directory with ls -l or stat, and verify the permissions of parent directories. If a service is involved, identify the user that the service runs as, because the interactive user may not be the relevant one. Avoid immediately using sudo or setting broad permissions such as chmod 777. The correct fix is usually a precise adjustment to ownership, group membership or permission bits. Good permission troubleshooting finds the smallest safe change that allows the required action.

How do you troubleshoot a full disk in Linux?

Start with df -h to identify which filesystem is full. Then use du to find which directories are consuming the most space. A typical investigation checks large top-level directories and drills down step by step. Common causes include logs, backups, caches, database files, container images, temporary files and deleted files still held open by running processes. If df shows high usage but du does not explain it, lsof may reveal deleted open files. Do not delete files randomly just because they are large. First understand what they belong to, whether a service is using them and whether there is a safe cleanup method.

How do you troubleshoot a failed Linux service?

Begin with systemctl status service-name to check whether the service is active, inactive, failed or repeatedly restarting. Then inspect detailed logs with journalctl -u service-name. Look for clear causes such as permission errors, invalid configuration, missing files, port conflicts, dependency failures or resource limits. If the service provides a configuration test command, run it before restarting. After making a change, restart or reload the service and verify status again. A strong troubleshooting workflow follows evidence: check status, read logs, test configuration, make one controlled change and verify the result. Restarting blindly may temporarily hide the real cause.

How do you troubleshoot network connectivity in Linux?

Use a layered approach. First check whether the network interface exists and has an IP address with ip addr. Then check routing with ip route. Test basic reachability with ping to an IP address. Then test name resolution with a hostname. If the issue is with a specific service, check whether it is listening with ss -tulpn. Use curl for HTTP services and verbose SSH output for SSH problems. Also consider firewall rules, DNS configuration, gateway availability and service binding addresses. Network troubleshooting is easier when each layer is tested separately instead of treating every failure as a general internet problem.

How do you know whether a Linux command is safe to run?

A Linux command is safer to run when the user understands what it will affect, whether it reads or modifies data, what privileges it needs and what the possible failure modes are. Inspection commands such as pwd, ls, cat, less, df, du, ps and systemctl status are generally safer because they mainly read information. Destructive or system-changing commands such as rm, mkfs, dd, recursive chmod, recursive chown, package removal and forced service operations require much more caution. Before running an unfamiliar command, read it from left to right, identify options and arguments, check the target path and consult trusted documentation.

Author:
Jan Bielik
CEO & Founder of Webiano Digital & Marketing Agency

Linux commands explained from the ground up
Linux commands explained from the ground up