<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Linux Tips, Tricks and Tutorials on Linuxize</title><link>https://linuxize.com/</link><description>Recent content in Linux Tips, Tricks and Tutorials on Linuxize</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><managingEditor>hello@linuxize.com (Linuxize)</managingEditor><webMaster>hello@linuxize.com (Linuxize)</webMaster><lastBuildDate>Sun, 20 Sep 2026 09:25:00 +0200</lastBuildDate><atom:link href="https://linuxize.com/index.xml" rel="self" type="application/rss+xml"/><image><url>https://linuxize.com/icons/icon-512x512.png</url><title>Linuxize</title><link>https://linuxize.com/</link></image><item><title>sudo Cheatsheet</title><link>https://linuxize.com/cheatsheet/sudo/</link><pubDate>Sun, 20 Sep 2026 09:25:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/sudo/</guid><description>sudo at a glance: running commands as root, credential caching, environment handling, sudoers rule syntax, aliases, Defaults, and logging.</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="basic-usage"&gt;Basic Usage &lt;a class="headline-link" href="#basic-usage" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run commands with elevated privileges.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/sudo-command-in-linux/"&gt;&lt;code&gt;sudo command&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Run a command as root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -u username command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run a command as another user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -g groupname command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run a command with another primary group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -u#1000 command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run as a user ID instead of a name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open a root login shell that reads root&amp;rsquo;s profile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open a root shell that keeps the current directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -e /etc/hosts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Edit a root-owned file with an editor running as your user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -b command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the command in the background&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -- command -l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop option parsing so the flags reach the command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo !!&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Re-run the previous command with &lt;code&gt;sudo&lt;/code&gt; in Bash or Zsh&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="password-caching"&gt;Password Caching &lt;a class="headline-link" href="#password-caching" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Control how often &lt;code&gt;sudo&lt;/code&gt; asks for a password.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -v&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Refresh the cached credentials without running a command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -k&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Invalidate the cache for the current terminal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -K&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove the cached credentials for every terminal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -n command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fail with an error instead of prompting, for cron and scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -A command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read the password from the program named in &lt;code&gt;SUDO_ASKPASS&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -p &amp;quot;Password for %u: &amp;quot; command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set a custom prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults timestamp_timeout=10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cache the password for 10 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults timestamp_timeout=0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prompt for every command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults timestamp_type=global&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Share one timestamp across all terminals&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Debian and Ubuntu packages ship a 15 minute timeout, while Fedora and RHEL keep the upstream five minute default.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="listing-privileges"&gt;Listing Privileges &lt;a class="headline-link" href="#listing-privileges" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Check what a rule actually grants before you rely on it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List the commands the current user may run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -ll&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List the same rules in long form&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -l -U username&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List another user&amp;rsquo;s privileges as root or an authorized user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -l /usr/bin/systemctl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check whether one command is permitted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -V&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the version, and as root the full &lt;code&gt;Defaults&lt;/code&gt; list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;id -nG&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List group membership, which &lt;code&gt;%group&lt;/code&gt; rules match on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;getent group sudo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the members of the &lt;code&gt;sudo&lt;/code&gt; group&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="environment-handling"&gt;Environment Handling &lt;a class="headline-link" href="#environment-handling" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sudo&lt;/code&gt; builds a new environment rather than passing yours through.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -E command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Request preservation of the current environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo --preserve-env=http_proxy command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Request preservation of only the named variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo -H command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;HOME&lt;/code&gt; to the target user&amp;rsquo;s home directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo env&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the environment &lt;code&gt;sudo&lt;/code&gt; actually builds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo env PATH=&amp;quot;/opt/tool/bin:/usr/bin&amp;quot; command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run with an explicit trusted &lt;code&gt;PATH&lt;/code&gt; instead of &lt;code&gt;secure_path&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults env_reset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strip the caller&amp;rsquo;s environment, the default on most distros&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults env_keep += &amp;quot;http_proxy https_proxy&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Let named variables through &lt;code&gt;env_reset&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults secure_path=&amp;quot;/usr/sbin:/usr/bin:/sbin:/bin&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace &lt;code&gt;PATH&lt;/code&gt; for every &lt;code&gt;sudo&lt;/code&gt; command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults always_set_home&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set target &lt;code&gt;HOME&lt;/code&gt; when &lt;code&gt;env_reset&lt;/code&gt; does not already do so&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;sudo&lt;/code&gt; exports &lt;code&gt;SUDO_USER&lt;/code&gt;, &lt;code&gt;SUDO_UID&lt;/code&gt;, &lt;code&gt;SUDO_GID&lt;/code&gt;, and &lt;code&gt;SUDO_COMMAND&lt;/code&gt; into the command environment, so a privileged script can recover who called it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="redirects-and-pipes"&gt;Redirects and Pipes &lt;a class="headline-link" href="#redirects-and-pipes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The shell expands &lt;code&gt;&amp;gt;&lt;/code&gt; and &lt;code&gt;|&lt;/code&gt; before &lt;code&gt;sudo&lt;/code&gt; runs, so redirects need their own root process.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo echo text &amp;gt; /root/file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Usually fails: the shell opens the file as your user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo sh -c 'echo text &amp;gt; /root/file'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the whole line, redirect included, as root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;echo text | sudo tee /root/file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write the file as root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;echo text | sudo tee -a /root/file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Append to the file as root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;echo text | sudo tee /root/file &amp;gt; /dev/null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write without echoing the content back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo sh -c 'cmd1 &amp;amp;&amp;amp; cmd2'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Chain several commands under one &lt;code&gt;sudo&lt;/code&gt; call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo cat /root/file | grep pattern&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read as root, filter as your user&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="editing-the-sudoers-file"&gt;Editing the sudoers File &lt;a class="headline-link" href="#editing-the-sudoers-file" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Never open &lt;code&gt;/etc/sudoers&lt;/code&gt; in a plain editor. A syntax error there can disable &lt;code&gt;sudo&lt;/code&gt; access.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo visudo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Edit &lt;code&gt;/etc/sudoers&lt;/code&gt; with a syntax check on save&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo visudo -c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check every sudoers file without editing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo visudo -f /etc/sudoers.d/webops&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Edit a drop-in file with the same check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo visudo -s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Treat undefined aliases and alias cycles as errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@includedir /etc/sudoers.d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Parse eligible files in the drop-in directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo chown root:root /etc/sudoers.d/webops&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the required owner and group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo chmod 0440 /etc/sudoers.d/webops&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the permissions a drop-in file requires&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo ls /etc/sudoers.d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List the files in the drop-in directory&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;On &lt;code&gt;sudo&lt;/code&gt; older than 1.9.1 the directive is written &lt;code&gt;#includedir /etc/sudoers.d&lt;/code&gt;. Despite the leading &lt;code&gt;#&lt;/code&gt;, that line is not a comment. Drop-in files whose names contain a dot or end in &lt;code&gt;~&lt;/code&gt; are skipped.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;visudo&lt;/code&gt; reads &lt;code&gt;SUDO_EDITOR&lt;/code&gt;, &lt;code&gt;VISUAL&lt;/code&gt;, and &lt;code&gt;EDITOR&lt;/code&gt; when the policy lets those variables through. A command rule that matches &lt;code&gt;ALL&lt;/code&gt; implies &lt;code&gt;SETENV&lt;/code&gt;, while a rule granting only &lt;code&gt;/usr/sbin/visudo&lt;/code&gt; must add &lt;code&gt;SETENV&lt;/code&gt; or preserve the editor variables. To avoid depending on that policy, open a root shell with &lt;code&gt;sudo -i&lt;/code&gt;, then run &lt;code&gt;EDITOR=/usr/bin/vim visudo&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="sudoers-rule-syntax"&gt;sudoers Rule Syntax &lt;a class="headline-link" href="#sudoers-rule-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each rule reads &lt;code&gt;user host=(runas:rungroup) tagged commands&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;username ALL=(ALL:ALL) ALL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full access for one user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-add-user-to-sudoers-in-ubuntu/"&gt;&lt;code&gt;%sudo ALL=(ALL:ALL) ALL&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Full access for a group, Debian and Ubuntu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-add-user-to-sudoers-in-centos/"&gt;&lt;code&gt;%wheel ALL=(ALL) ALL&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Full access for a group, Fedora and RHEL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-run-sudo-command-without-password/"&gt;&lt;code&gt;username ALL=(ALL) NOPASSWD: ALL&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Skip the password prompt for every command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;username ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip the prompt for one exact command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;username ALL=(www-data) /usr/bin/php&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run one command as a service account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;username ALL=(ALL) NOEXEC: /usr/bin/less&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Block child commands where &lt;code&gt;NOEXEC&lt;/code&gt; is supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;username ALL=(ALL) PASSWD: /usr/bin/su&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Force a prompt for one command inside a &lt;code&gt;NOPASSWD&lt;/code&gt; rule&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Command paths generally must be absolute. A rule listing &lt;code&gt;apt&lt;/code&gt; never matches; write &lt;code&gt;/usr/bin/apt&lt;/code&gt;. Wildcards in command arguments can match whitespace, so exact arguments or anchored regular expressions are safer. Do not use an editor as a security boundary: &lt;code&gt;/usr/bin/vim&lt;/code&gt; can start a shell even without a wildcard.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="aliases"&gt;Aliases &lt;a class="headline-link" href="#aliases" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Aliases keep long rule sets readable and reduce repetition.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Declaration&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;User_Alias ADMINS = alice, bob, %ops&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Name a set of users or groups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Runas_Alias SUPERUSER = root&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Name a set of target users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Host_Alias WEB = web01, web02, 10.0.5.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Name a set of hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Cmnd_Alias NGINX = /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Name a set of exact commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ADMINS WEB=(SUPERUSER) NGINX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Combine aliases in a rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ADMINS ALL=(root) NOPASSWD: NGINX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply a tag to a command alias&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Alias names start with an uppercase letter and contain uppercase letters, digits, or underscores. The parser resolves aliases across the complete policy, so a definition may appear before or after a rule that uses it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="defaults-directives"&gt;Defaults Directives &lt;a class="headline-link" href="#defaults-directives" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Policy settings that apply to every matching &lt;code&gt;sudo&lt;/code&gt; call.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults env_reset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run commands with a clean environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults secure_path=&amp;quot;/usr/sbin:/usr/bin:/sbin:/bin&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed &lt;code&gt;PATH&lt;/code&gt; for &lt;code&gt;sudo&lt;/code&gt; commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults timestamp_timeout=15&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Minutes before the password is asked for again&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults passwd_tries=3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Password attempts before &lt;code&gt;sudo&lt;/code&gt; gives up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults targetpw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ask for the target user&amp;rsquo;s password, not the caller&amp;rsquo;s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults lecture=never&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip the warning shown on first use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults mail_badpass&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mail the administrator after a failed password&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults:username timestamp_timeout=30&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply a setting to one user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults@web01 log_output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply a setting on one host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults!/usr/sbin/visudo env_keep += &amp;quot;SUDO_EDITOR VISUAL EDITOR&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preserve editor variables for &lt;code&gt;visudo&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="logging-and-auditing"&gt;Logging and Auditing &lt;a class="headline-link" href="#logging-and-auditing" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By default, &lt;code&gt;sudoers&lt;/code&gt; logs allowed and denied commands as well as errors.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo journalctl _COMM=sudo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show &lt;code&gt;sudo&lt;/code&gt; events from the systemd journal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo journalctl -t sudo -S today&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show today&amp;rsquo;s events by syslog tag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo grep sudo /var/log/auth.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read the log on Debian and Ubuntu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo grep sudo /var/log/secure&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read the log on Fedora, RHEL, and derivatives&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults logfile=&amp;quot;/var/log/sudo.log&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write a dedicated &lt;code&gt;sudo&lt;/code&gt; log file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Defaults log_input, log_output&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Record full sessions for replay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo sudoreplay -l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List the recorded sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo sudoreplay ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replay one recorded session&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What the common failures mean and where to look.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Message&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;username is not in the sudoers file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add the user to &lt;code&gt;sudo&lt;/code&gt; on Debian and Ubuntu or &lt;code&gt;wheel&lt;/code&gt; on Fedora and RHEL, then log in again&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo: unable to resolve host name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Map the current hostname in &lt;code&gt;/etc/hosts&lt;/code&gt;, such as &lt;code&gt;127.0.1.1 name&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/fix-sudo-command-not-found/"&gt;&lt;code&gt;sudo: command not found&lt;/code&gt;&lt;/a&gt;
or &lt;code&gt;sudo: name: command not found&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The shell cannot find &lt;code&gt;sudo&lt;/code&gt;, or the target command is missing or outside &lt;code&gt;secure_path&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sorry, you are not allowed to set the following environment variables&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preserve the variable or grant &lt;code&gt;SETENV&lt;/code&gt; narrowly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sorry, you are not allowed to preserve the environment&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Grant &lt;code&gt;SETENV&lt;/code&gt;; matching &lt;code&gt;ALL&lt;/code&gt; implies it unless &lt;code&gt;NOSETENV&lt;/code&gt; overrides it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; /etc/sudoers: syntax error near line N &amp;lt;&amp;lt;&amp;lt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Press &lt;code&gt;e&lt;/code&gt; to re-edit; &lt;code&gt;Q&lt;/code&gt; force-saves the broken file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo: no tty present and no askpass program specified&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;-n&lt;/code&gt; to fail fast, configure &lt;code&gt;-A&lt;/code&gt;, or grant &lt;code&gt;NOPASSWD&lt;/code&gt; narrowly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo: effective uid is not 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check root ownership, setuid, &lt;code&gt;nosuid&lt;/code&gt;, and NFS mounts; repair from root or recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Deeper reading on privilege escalation and user administration.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/sudo-command-in-linux/"&gt;sudo Command in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Full &lt;code&gt;sudo&lt;/code&gt; guide with examples, sudoedit, and credential caching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-add-user-to-sudoers-in-ubuntu/"&gt;How to Add User to Sudoers in Ubuntu&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Grant sudo access on Debian and Ubuntu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-add-user-to-sudoers-in-centos/"&gt;How to Add User to Sudoers in CentOS&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Grant sudo access on RHEL and derivatives&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-run-sudo-command-without-password/"&gt;How to Run sudo Command Without Password&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Set up a &lt;code&gt;NOPASSWD&lt;/code&gt; rule safely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/su-command-in-linux/"&gt;su Command in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Switch user accounts instead of running one command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/su/"&gt;su cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Quick reference for &lt;code&gt;su&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>nice and renice Commands in Linux: Set Process Priority</title><link>https://linuxize.com/post/nice-and-renice-command-in-linux/</link><pubDate>Fri, 18 Sep 2026 18:00:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/nice-and-renice-command-in-linux/</guid><category>linux commands</category><description>Control Linux process priority with nice and renice. See how nice values work, start lower-priority jobs, and change the priority of running processes.</description><content:encoded>&lt;p&gt;When you run a CPU-heavy task on a shared server, a long compile job or a background backup can slow down everything else. Linux lets you give that process a lower priority, so it receives a smaller share of CPU time when it competes with other work. Use &lt;code&gt;nice&lt;/code&gt; to adjust the priority when you start a command and &lt;code&gt;renice&lt;/code&gt; to change the priority of a process that is already running.&lt;/p&gt;
&lt;p&gt;This guide explains how nice values work in Linux and how to use &lt;code&gt;nice&lt;/code&gt; and &lt;code&gt;renice&lt;/code&gt; to start and adjust processes at different priority levels.&lt;/p&gt;
&lt;h2 id="how-nice-values-work"&gt;How Nice Values Work &lt;a class="headline-link" href="#how-nice-values-work" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For processes using normal time-sharing or batch scheduling, the kernel uses a nice value to decide how much CPU time they should receive relative to competing processes. The range goes from &lt;code&gt;-20&lt;/code&gt; (highest priority) to &lt;code&gt;19&lt;/code&gt; (lowest priority). New processes inherit their parent&amp;rsquo;s nice value, which is usually &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A higher nice value means the process is &amp;ldquo;nicer&amp;rdquo; to other work and receives a smaller CPU share under contention. A lower nice value gives it a larger share. Without contention, even a process at nice &lt;code&gt;19&lt;/code&gt; can use a full CPU core. Niceness does not set a CPU usage limit.&lt;/p&gt;
&lt;p&gt;On most systems, regular users can only increase the nice value of their own processes (lower their priority). Decreasing the value normally requires root privileges, even when changing it from &lt;code&gt;10&lt;/code&gt; back to &lt;code&gt;0&lt;/code&gt;. An administrator can allow exceptions through the &lt;code&gt;RLIMIT_NICE&lt;/code&gt; resource limit.&lt;/p&gt;
&lt;p&gt;You can check the current nice value of a process in the &lt;code&gt;NI&lt;/code&gt; column of &lt;a href="https://linuxize.com/post/ps-command-in-linux/"&gt;&lt;code&gt;ps&lt;/code&gt;&lt;/a&gt;
or &lt;a href="https://linuxize.com/post/top-command-in-linux/"&gt;&lt;code&gt;top&lt;/code&gt;&lt;/a&gt;
:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps -eo pid,ni,comm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For example, the output may look like this:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt; PID NI COMMAND
1 0 systemd
842 0 sshd
1024 10 rsync&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;rsync&lt;/code&gt; process in the example above is running with a nice value of &lt;code&gt;10&lt;/code&gt;, which is lower priority than the default.&lt;/p&gt;
&lt;h2 id="nice-command-syntax"&gt;nice Command Syntax &lt;a class="headline-link" href="#nice-command-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;nice&lt;/code&gt; command runs a command with an adjustment to the inherited nice value:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nice [OPTION] [COMMAND [ARGS]...]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With no command, &lt;code&gt;nice&lt;/code&gt; prints its current nice value, inherited from your shell:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nice&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In a shell with the usual nice value of &lt;code&gt;0&lt;/code&gt;, the output is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This does not change the shell&amp;rsquo;s priority. When you pass a command, &lt;code&gt;nice&lt;/code&gt; adds &lt;code&gt;10&lt;/code&gt; to the inherited nice value unless you choose a different adjustment with &lt;code&gt;-n&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The examples below assume a starting nice value of &lt;code&gt;0&lt;/code&gt; and use GNU &lt;code&gt;nice&lt;/code&gt; from coreutils and &lt;code&gt;renice&lt;/code&gt; from util-linux, the implementations commonly found on Linux.&lt;/p&gt;
&lt;h2 id="running-a-command-with-lower-priority"&gt;Running a Command With Lower Priority &lt;a class="headline-link" href="#running-a-command-with-lower-priority" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To try the default adjustment without creating files or running a heavy workload, use &lt;code&gt;nice&lt;/code&gt; to run another copy of itself:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nice nice&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The second &lt;code&gt;nice&lt;/code&gt; prints the adjusted value:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;10&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The outer command adds &lt;code&gt;10&lt;/code&gt; to the inherited value of &lt;code&gt;0&lt;/code&gt;. The inner command only prints that value and exits.&lt;/p&gt;
&lt;p&gt;For a practical example, you can run an archive job at a lower CPU priority. Choose an unused archive filename and replace &lt;code&gt;/var/www&lt;/code&gt; with a directory you can read:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nice tar -czf backup.tar.gz /var/www&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;tar&lt;/code&gt; process runs with a nice value of &lt;code&gt;10&lt;/code&gt; instead of &lt;code&gt;0&lt;/code&gt;. This can help interactive programs stay responsive when they compete with the archive job for CPU time.&lt;/p&gt;
&lt;p&gt;You can choose a different adjustment with the &lt;code&gt;-n&lt;/code&gt; option. For example, to add &lt;code&gt;15&lt;/code&gt; when running an existing build script:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nice -n &lt;span class="m"&gt;15&lt;/span&gt; ./build.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;From a starting value of &lt;code&gt;0&lt;/code&gt;, the build script runs at nice &lt;code&gt;15&lt;/code&gt;. If your shell already has a nice value of &lt;code&gt;10&lt;/code&gt;, the result is &lt;code&gt;19&lt;/code&gt;, the maximum allowed value, rather than &lt;code&gt;15&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="running-a-command-with-higher-priority"&gt;Running a Command With Higher Priority &lt;a class="headline-link" href="#running-a-command-with-higher-priority" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To raise a command&amp;rsquo;s priority, use a negative adjustment. This normally requires root privileges. For example, a regular user without a suitable nice resource limit can try:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nice -n -5 nice&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;From a starting value of &lt;code&gt;0&lt;/code&gt;, GNU &lt;code&gt;nice&lt;/code&gt; reports the failed adjustment and the inner command prints the unchanged value:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;nice: cannot set niceness: Permission denied
0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;GNU &lt;code&gt;nice&lt;/code&gt; still runs the command after this permission error, so the warning does not mean the workload was stopped.&lt;/p&gt;
&lt;p&gt;With &lt;a href="https://linuxize.com/post/sudo-command-in-linux/"&gt;&lt;code&gt;sudo&lt;/code&gt;&lt;/a&gt;
, you can normally apply the adjustment:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nice -n -5 nice&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When the starting value is &lt;code&gt;0&lt;/code&gt;, the inner command prints:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;-5&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This command runs as root. To raise the priority of a job you already started as your own user, use &lt;code&gt;sudo renice&lt;/code&gt; as shown below. Changing its nice value does not change its owner.&lt;/p&gt;
&lt;p&gt;Use negative values carefully. A CPU-heavy process at nice &lt;code&gt;-20&lt;/code&gt; can leave competing work with little CPU time.&lt;/p&gt;
&lt;h2 id="renice-command-syntax"&gt;renice Command Syntax &lt;a class="headline-link" href="#renice-command-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;renice&lt;/code&gt; command changes the nice value of a process that is already running:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;renice PRIORITY [-p|-g|-u] IDENTIFIER...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;By default, &lt;code&gt;renice&lt;/code&gt; interprets the identifier as a process ID. The &lt;code&gt;-p&lt;/code&gt; option makes that explicit, &lt;code&gt;-g&lt;/code&gt; targets a process group, and &lt;code&gt;-u&lt;/code&gt; targets processes owned by a given user.&lt;/p&gt;
&lt;p&gt;Unlike &lt;code&gt;nice -n&lt;/code&gt;, the priority in this form is an absolute nice value. For example, &lt;code&gt;renice 10 -p PID&lt;/code&gt; sets the value to &lt;code&gt;10&lt;/code&gt;; it does not add &lt;code&gt;10&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In util-linux, &lt;code&gt;renice -n 10&lt;/code&gt; also sets an absolute value by default, but it becomes a relative adjustment when the &lt;code&gt;POSIXLY_CORRECT&lt;/code&gt; environment variable is set. We use the form without &lt;code&gt;-n&lt;/code&gt; to keep the examples unambiguous. See the &lt;a href="https://man7.org/linux/man-pages/man1/renice.1.html" target="_blank" rel="noopener noreferrer"&gt;renice manual&lt;/a&gt;
for details.&lt;/p&gt;
&lt;h2 id="changing-the-priority-of-a-running-process"&gt;Changing the Priority of a Running Process &lt;a class="headline-link" href="#changing-the-priority-of-a-running-process" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To lower the priority of a running process, find its PID with &lt;code&gt;ps&lt;/code&gt; or &lt;a href="https://linuxize.com/post/pgrep-command-in-linux/"&gt;&lt;code&gt;pgrep&lt;/code&gt;&lt;/a&gt;
, then pass it to &lt;code&gt;renice&lt;/code&gt;. Replace &lt;code&gt;4821&lt;/code&gt; with the PID of your process:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;renice &lt;span class="m"&gt;10&lt;/span&gt; -p &lt;span class="m"&gt;4821&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the process starts at nice &lt;code&gt;0&lt;/code&gt;, the output is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;4821 (process ID) old priority 0, new priority 10&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The output confirms the change from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;10&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To try this on a harmless process, start &lt;a href="https://linuxize.com/post/how-to-use-linux-sleep-command-to-pause-a-bash-script/"&gt;&lt;code&gt;sleep&lt;/code&gt;&lt;/a&gt;
in the background, capture its PID, and change its nice value:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sleep &lt;span class="m"&gt;60&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;job_pid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;renice &lt;span class="m"&gt;10&lt;/span&gt; -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$job_pid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$job_pid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -o pid,ni,comm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;$!&lt;/code&gt; holds the PID of the last background job. The &lt;code&gt;NI&lt;/code&gt; column from &lt;code&gt;ps&lt;/code&gt; should show &lt;code&gt;10&lt;/code&gt;. The process exits on its own after 60 seconds, so run the following examples before it finishes.&lt;/p&gt;
&lt;p&gt;To change the value again, pass the new absolute value:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;renice &lt;span class="m"&gt;15&lt;/span&gt; -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$job_pid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This changes the nice value from &lt;code&gt;10&lt;/code&gt; to &lt;code&gt;15&lt;/code&gt;, rather than adding &lt;code&gt;15&lt;/code&gt; to it.&lt;/p&gt;
&lt;p&gt;Restoring the value to &lt;code&gt;0&lt;/code&gt; raises the process&amp;rsquo;s priority and normally requires &lt;code&gt;sudo&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo renice &lt;span class="m"&gt;0&lt;/span&gt; -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$job_pid&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On Linux, nice values are per thread. Renicing a PID does not automatically update every worker thread or an existing child process. Newly created children inherit the calling thread&amp;rsquo;s nice value.&lt;/p&gt;
&lt;h2 id="renicing-all-processes-for-a-user"&gt;Renicing All Processes for a User &lt;a class="headline-link" href="#renicing-all-processes-for-a-user" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To adjust the current processes owned by a user, pass the username with &lt;code&gt;-u&lt;/code&gt;. For example, if your backup jobs run under an account named &lt;code&gt;backup&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo renice &lt;span class="m"&gt;15&lt;/span&gt; -u backup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This sets the account&amp;rsquo;s current processes to nice &lt;code&gt;15&lt;/code&gt;. It does not configure a permanent default for the account or change jobs that will start independently later.&lt;/p&gt;
&lt;h2 id="renicing-a-process-group"&gt;Renicing a Process Group &lt;a class="headline-link" href="#renicing-a-process-group" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To target a process group, use &lt;code&gt;-g&lt;/code&gt; with the process group ID (PGID). First, list process IDs and their groups:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps -eo pid,pgid,ni,comm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the jobs you want to adjust belong to group &lt;code&gt;1820&lt;/code&gt;, set their nice value to &lt;code&gt;5&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo renice &lt;span class="m"&gt;5&lt;/span&gt; -g &lt;span class="m"&gt;1820&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Replace &lt;code&gt;1820&lt;/code&gt; with the PGID you found. A process group can contain several commands from the same job, such as the stages of a shell pipeline.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Show the nice value inherited from your shell&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nice&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add &lt;code&gt;10&lt;/code&gt; when starting a command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nice command&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add &lt;code&gt;15&lt;/code&gt; when starting a command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nice -n 15 command&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subtract &lt;code&gt;5&lt;/code&gt; when starting a command as root&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo nice -n -5 command&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set a running process to nice &lt;code&gt;10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;renice 10 -p PID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restore a running process to nice &lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo renice 0 -p PID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set a user&amp;rsquo;s current processes to nice &lt;code&gt;15&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo renice 15 -u USER&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set processes in a group to nice &lt;code&gt;5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo renice 5 -g PGID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;nice: cannot set niceness: Permission denied&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
You tried to apply a negative adjustment without permission to raise priority. Use &lt;code&gt;sudo&lt;/code&gt; when appropriate, or choose a nonnegative adjustment. GNU &lt;code&gt;nice&lt;/code&gt; still runs the command at its inherited nice value after this warning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;renice reports permission denied or operation not permitted&lt;/strong&gt;&lt;br&gt;
You tried to change a process you do not own, or to decrease a nice value without the required privileges. On most systems, even restoring your own process from nice &lt;code&gt;10&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt; requires &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;renice reports no such process&lt;/strong&gt;&lt;br&gt;
The process has exited or the PID is wrong. Find the current PID with &lt;code&gt;ps&lt;/code&gt; or &lt;code&gt;pgrep&lt;/code&gt; and try again. In the &lt;code&gt;sleep&lt;/code&gt; example above, the process disappears after 60 seconds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nice value does not seem to affect performance&lt;/strong&gt;&lt;br&gt;
Nice values matter when processes compete for CPU time. On an idle system, a niced process can still use a full CPU core. Use &lt;a href="https://linuxize.com/post/htop-command-in-linux/"&gt;&lt;code&gt;htop&lt;/code&gt;&lt;/a&gt;
to check whether the workload is CPU-bound.&lt;/p&gt;
&lt;p&gt;Autogrouping and cgroup CPU scheduling also affect how CPU time is shared. With autogrouping enabled, changing niceness in one terminal session may have little effect on a job in another session. Process nice values apply within the same scheduling group; see the &lt;a href="https://man7.org/linux/man-pages/man7/sched.7.html" target="_blank" rel="noopener noreferrer"&gt;Linux scheduling documentation&lt;/a&gt;
for the details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A backup still slows down disk access&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;nice&lt;/code&gt; and &lt;code&gt;renice&lt;/code&gt; adjust CPU scheduling, so they do not directly set disk I/O priority. Some I/O schedulers derive a default I/O priority from CPU niceness, but the behavior depends on the scheduler. Use &lt;a href="https://man7.org/linux/man-pages/man1/ionice.1.html" target="_blank" rel="noopener noreferrer"&gt;ionice&lt;/a&gt;
when you need to set I/O priority explicitly, and check whether your active I/O scheduler supports it.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a long job that can wait, start with the default &lt;code&gt;nice&lt;/code&gt; adjustment and check its &lt;code&gt;NI&lt;/code&gt; value with &lt;code&gt;ps&lt;/code&gt;. If you prefer to adjust priorities interactively, see how to change nice values in &lt;a href="https://linuxize.com/post/htop-command-in-linux/"&gt;htop&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/nice-and-renice-command-in-linux/featured_hu_a9d7c9374bf33d76.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>Nginx Cheatsheet</title><link>https://linuxize.com/cheatsheet/nginx/</link><pubDate>Wed, 16 Sep 2026 17:45:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/nginx/</guid><description>Nginx directives at a glance: server blocks, location matching, reverse proxy headers, TLS, redirects, rate limits, caching, and log formats.</description><content:encoded>&lt;div class="card wrap-commands"&gt;
&lt;h3 id="service-and-cli-commands"&gt;Service and CLI Commands &lt;a class="headline-link" href="#service-and-cli-commands" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Control the service and check the configuration before it goes live.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/start-stop-restart-nginx/"&gt;&lt;code&gt;sudo systemctl reload nginx&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Apply a new configuration without dropping connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl start nginx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start the service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl stop nginx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop the service immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl restart nginx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop and start the service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl status nginx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the service state and recent log lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl enable --now nginx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start now and at every boot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nginx -t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Test the configuration for syntax errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nginx -T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Test and print the full merged configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nginx -s reload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reload through the master process signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nginx -s quit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shut down gracefully after current requests finish&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nginx -s reopen&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reopen the log files after rotation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nginx -V&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the version and the configure arguments&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Always run &lt;code&gt;nginx -t&lt;/code&gt; before a reload. A failed reload leaves the old configuration running, but a restart with a broken file leaves the service down.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="configuration-layout"&gt;Configuration Layout &lt;a class="headline-link" href="#configuration-layout" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Where the files live and how a site is switched on.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-install-nginx-on-ubuntu-26-04/"&gt;&lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Main configuration file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/nginx/conf.d/*.conf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Common include pattern; verify it in &lt;code&gt;nginx.conf&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/nginx/sites-available/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Site definitions on Ubuntu and Debian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/nginx/sites-enabled/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Symlinks to the active sites&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/nginx/snippets/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reusable fragments on Ubuntu and Debian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/var/www/html&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Default document root on Ubuntu and Debian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/usr/share/nginx/html&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Default document root on Fedora and RHEL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/var/log/nginx/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Access and error logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable a site on Ubuntu and Debian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo unlink /etc/nginx/sites-enabled/default&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Disable the default site&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Fedora and RHEL have no &lt;code&gt;sites-available&lt;/code&gt; directory. Put each site in its own file under &lt;code&gt;/etc/nginx/conf.d/&lt;/code&gt; instead.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="server-blocks"&gt;Server Blocks &lt;a class="headline-link" href="#server-blocks" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Directives that decide which server block answers a request.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-set-up-nginx-server-blocks-on-ubuntu-22-04/"&gt;&lt;code&gt;listen 80;&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Listen on IPv4 port 80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;listen [::]:80;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Listen on IPv6 port 80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;listen 80 default_server;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Serve requests matching no other server name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;server_name example.com www.example.com;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Match these host names&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;server_name *.example.com;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Match any subdomain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;server_name _;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Invalid name used as a catch-all placeholder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;root /var/www/example.com;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the document root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;index index.html index.htm;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;File served when a directory is requested&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;include /etc/nginx/snippets/ssl.conf;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pull in a shared fragment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Nginx matches the exact name first, then the longest wildcard starting with an asterisk, then the longest wildcard ending with one, and finally the first matching regular expression.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="location-matching"&gt;Location Matching &lt;a class="headline-link" href="#location-matching" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Modifiers that set both the match rule and its priority.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/nginx-location-block/"&gt;&lt;code&gt;location = /health { ... }&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Exact match, checked first and wins immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location ^~ /static/ { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prefix match that suppresses the regex pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location ~ \.php$ { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Case-sensitive regular expression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location ~* \.css$ { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Case-insensitive regular expression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location /images/ { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Plain prefix match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location / { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fallback for every request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;location @fallback { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Named location, reachable only from &lt;code&gt;error_page&lt;/code&gt; or &lt;code&gt;try_files&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Nginx checks the exact match first, then stores the longest matching prefix. If that prefix uses &lt;code&gt;^~&lt;/code&gt;, it is used right away. Otherwise the regular expressions are tried in file order and the first match wins. The stored prefix is used only when no regular expression matches.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="serving-files"&gt;Serving Files &lt;a class="headline-link" href="#serving-files" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Map a request to a file on disk and decide what happens when it is missing.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;root /var/www/example.com;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Append the current normalized URI path, without the query string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;alias /srv/media/;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace the matched location prefix with this path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;try_files $uri $uri/ =404;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Try the file, then the directory, then return 404&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;try_files $uri $uri/ /index.html;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single-page application fallback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;try_files $uri $uri/ /index.php?$query_string;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WordPress and PHP framework fallback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;autoindex on;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate a directory listing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;error_page 404 /404.html;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Serve a custom error page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;error_page 502 503 504 /5xx.html;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One page for several statuses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sendfile on;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Copy files to the socket in the kernel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;With &lt;code&gt;root&lt;/code&gt;, nginx appends the current normalized URI path without the query string, so &lt;code&gt;location /images/&lt;/code&gt; with &lt;code&gt;root /data&lt;/code&gt; serves &lt;code&gt;/data/images/cat.png&lt;/code&gt;. With &lt;code&gt;alias&lt;/code&gt;, the matched prefix is replaced instead, so the same location with &lt;code&gt;alias /data/pictures/&lt;/code&gt; serves &lt;code&gt;/data/pictures/cat.png&lt;/code&gt;. Keep the trailing slash on both the location and the alias.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="reverse-proxy"&gt;Reverse Proxy &lt;a class="headline-link" href="#reverse-proxy" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Forward requests to an application and pass on the client details.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/nginx-reverse-proxy/"&gt;&lt;code&gt;proxy_pass http://127.0.0.1:3000;&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Forward to a local application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_pass http://backend;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Forward to a named upstream group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_set_header Host $host;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pass the original host name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_set_header X-Real-IP $remote_addr;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pass the client address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Append the client to the forwarding chain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_set_header X-Forwarded-Proto $scheme;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tell the application whether TLS was used&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_http_version 1.1;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use HTTP/1.1 for upstream keepalive and WebSocket upgrades&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_set_header Upgrade $http_upgrade;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pass the WebSocket upgrade request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_set_header Connection &amp;quot;upgrade&amp;quot;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Complete the WebSocket handshake&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_read_timeout 300s;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wait longer for a slow response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_buffering off;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stream the response as it arrives&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The trailing slash changes the result. &lt;code&gt;proxy_pass http://127.0.0.1:3000;&lt;/code&gt; forwards the full request URI, while &lt;code&gt;proxy_pass http://127.0.0.1:3000/;&lt;/code&gt; replaces the matched location prefix with &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="load-balancing"&gt;Load Balancing &lt;a class="headline-link" href="#load-balancing" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Spread traffic across a pool of backends. Define the pool in &lt;code&gt;http&lt;/code&gt; and put the other directives inside &lt;code&gt;upstream&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upstream backend { server 10.0.0.1:8080; server 10.0.0.2:8080; }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Define a pool, round-robin by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;least_conn;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Send each request to the least busy server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ip_hash;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pin a client address to one server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hash $request_uri consistent;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Distribute by key with minimal reshuffling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;server 10.0.0.1:8080 weight=3;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Take three times the usual share&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;After three qualifying failures within 30 seconds, mark unavailable for 30 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;server 10.0.0.3:8080 backup;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use only when the others are down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;server 10.0.0.4:8080 down;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Take a server out of rotation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;server unix:/run/app.sock;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Proxy to a Unix socket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;keepalive 32;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cache up to 32 idle upstream connections per worker&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Choose only one of &lt;code&gt;least_conn&lt;/code&gt;, &lt;code&gt;ip_hash&lt;/code&gt;, or &lt;code&gt;hash&lt;/code&gt;; round-robin is the default. The &lt;code&gt;backup&lt;/code&gt; parameter cannot be combined with &lt;code&gt;hash&lt;/code&gt; or &lt;code&gt;ip_hash&lt;/code&gt;. On nginx versions older than 1.29.7, set &lt;code&gt;proxy_http_version 1.1;&lt;/code&gt; and &lt;code&gt;proxy_set_header Connection &amp;quot;&amp;quot;;&lt;/code&gt; in the proxy location to use HTTP/1.1 upstream keepalive. Since 1.29.7, HTTP/1.1 and upstream keepalive are enabled by default, and the default proxy configuration no longer sends &lt;code&gt;Connection: close&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="https-and-tls"&gt;HTTPS and TLS &lt;a class="headline-link" href="#https-and-tls" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Terminate TLS and keep the protocol settings current.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/secure-nginx-with-let-s-encrypt-on-ubuntu-20-04/"&gt;&lt;code&gt;listen 443 ssl;&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Accept TLS connections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;http2 on;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable HTTP/2 on nginx 1.25.1 and later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;listen 443 ssl http2;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable HTTP/2 on older releases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Certificate and intermediate chain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Private key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ssl_protocols TLSv1.2 TLSv1.3;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Allow only modern protocol versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ssl_prefer_server_ciphers off;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Let the client pick from the allowed ciphers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ssl_session_cache shared:SSL:10m;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Share the session cache between workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ssl_session_timeout 1d;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep sessions resumable for a day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;add_header Strict-Transport-Security &amp;quot;max-age=63072000&amp;quot; always;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Send HSTS on every response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo certbot --nginx -d example.com -d www.example.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Issue and install a certificate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Keep the private key readable by root only. Never copy a key into a repository or a document root, and add &lt;code&gt;*.pem&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt; when the configuration lives in version control.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="redirects-and-rewrites"&gt;Redirects and Rewrites &lt;a class="headline-link" href="#redirects-and-rewrites" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Move URLs without losing the original path.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/redirect-http-to-https-in-nginx/"&gt;&lt;code&gt;return 301 https://$host$request_uri;&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Redirect every request to HTTPS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;return 301 https://www.example.com$request_uri;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Redirect to the www host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;return 302 /maintenance.html;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Temporary redirect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;return 444;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Close the connection without a response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rewrite ^/old/(.*)$ /new/$1 permanent;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;301 rewrite that keeps the path tail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rewrite ^/old/(.*)$ /new/$1 redirect;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The same rewrite as a 302&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rewrite ^/blog/(.*)$ /$1 last;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rewrite internally and restart location matching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rewrite ^/api/(.*)$ /$1 break;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rewrite internally and stop processing rewrites&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Prefer &lt;code&gt;return&lt;/code&gt; over &lt;code&gt;rewrite&lt;/code&gt; for plain redirects. It is faster, easier to read, and it skips the regular expression evaluation that &lt;code&gt;rewrite&lt;/code&gt; performs on every request.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="access-control-and-limits"&gt;Access Control and Limits &lt;a class="headline-link" href="#access-control-and-limits" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Guard the upstream against oversized uploads and traffic spikes. Use &lt;code&gt;htpasswd -c&lt;/code&gt; only for a new password file, because it overwrites an existing one.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;client_max_body_size 64m;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Raise the upload size limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;allow 10.0.0.0/8;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permit a network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deny all;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Block everything else&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;auth_basic &amp;quot;Restricted&amp;quot;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Turn on HTTP basic authentication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;auth_basic_user_file /etc/nginx/.htpasswd;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Point to the password file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo htpasswd -c /etc/nginx/.htpasswd admin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new password file, first creation only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo htpasswd /etc/nginx/.htpasswd editor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add or update a user in the existing file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;limit_req_zone $binary_remote_addr zone=req:10m rate=10r/s;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Define a rate limit zone in &lt;code&gt;http&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;limit_req zone=req burst=20 nodelay;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply the zone with a burst allowance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;limit_conn_zone $binary_remote_addr zone=conn:10m;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Define a connection limit zone in &lt;code&gt;http&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;limit_conn conn 10;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limit active connections to ten per address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;server_tokens off;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hide the version number in responses and error pages&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;.htpasswd&lt;/code&gt; file holds hashed credentials. Keep it outside the document root and out of version control. In HTTP/2 and HTTP/3, &lt;code&gt;limit_conn&lt;/code&gt; counts each concurrent request as a separate connection.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="compression-and-caching"&gt;Compression and Caching &lt;a class="headline-link" href="#compression-and-caching" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Cut response size and avoid repeat trips to the backend.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gzip on;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compress responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gzip_types text/css application/javascript application/json;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compress these types beyond &lt;code&gt;text/html&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gzip_min_length 256;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip responses too small to benefit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gzip_comp_level 5;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Balance CPU time against size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gzip_vary on;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;Vary: Accept-Encoding&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;expires 30d;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set a far-future expiry inside a static location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;add_header Cache-Control &amp;quot;public, immutable&amp;quot;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mark fingerprinted assets as cacheable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_cache_path /var/cache/nginx keys_zone=cache:10m max_size=1g;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Define a proxy cache in &lt;code&gt;http&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_cache cache;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Turn the cache on for a location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy_cache_valid 200 10m;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cache successful responses for ten minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;add_header X-Cache-Status $upstream_cache_status;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expose cache hits and misses while debugging&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;By default, a block with its own &lt;code&gt;add_header&lt;/code&gt; directives does not inherit its parent&amp;rsquo;s &lt;code&gt;add_header&lt;/code&gt; directives. Repeat the ones you still need, or use &lt;code&gt;add_header_inherit merge;&lt;/code&gt; on nginx 1.29.3 and later.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="logging"&gt;Logging &lt;a class="headline-link" href="#logging" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Choose what gets recorded and where to watch it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/nginx-log-files/"&gt;&lt;code&gt;access_log /var/log/nginx/access.log combined;&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Write access logs in the default format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;access_log off;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Disable access logging for a location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;error_log /var/log/nginx/error.log warn;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the error log file and level&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;log_format main '$remote_addr $status &amp;quot;$request&amp;quot; $request_time';&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Define a custom format in &lt;code&gt;http&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;access_log /var/log/nginx/api.log main;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use that custom format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo tail -f /var/log/nginx/error.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Follow errors live&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo journalctl -u nginx -f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Follow service-level messages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nginx -s reopen&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reopen log files after rotation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Error log levels run &lt;code&gt;debug&lt;/code&gt;, &lt;code&gt;info&lt;/code&gt;, &lt;code&gt;notice&lt;/code&gt;, &lt;code&gt;warn&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;, &lt;code&gt;crit&lt;/code&gt;, &lt;code&gt;alert&lt;/code&gt;, and &lt;code&gt;emerg&lt;/code&gt;, from most to least verbose, and each level includes everything more severe. The &lt;code&gt;debug&lt;/code&gt; level needs a build configured with &lt;code&gt;--with-debug&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="common-variables"&gt;Common Variables &lt;a class="headline-link" href="#common-variables" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Values available in log formats, proxy headers, redirects, and conditions.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$host&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Host from the request line, then the Host header, then the matching server name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$remote_addr&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Client IP address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$request_uri&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full original URI including the query string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$uri&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Current URI after rewrites, without the query string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$args&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Query string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$scheme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;http&lt;/code&gt; or &lt;code&gt;https&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$request_method&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;GET, POST, and so on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Response status code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$body_bytes_sent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Size of the response body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$request_time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Request duration in seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$http_user_agent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;User-Agent header&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$proxy_add_x_forwarded_for&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Existing X-Forwarded-For plus the client address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$upstream_addr&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Backend that served the request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$upstream_response_time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Backend response time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$document_root&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Document root for the current request&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card wrap-commands"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use these guides for the longer explanations behind these directives.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/nginx-commands-you-should-know/"&gt;&lt;code&gt;Nginx Commands You Should Know&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Service, testing, and reload commands in detail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/nginx-location-block/"&gt;&lt;code&gt;Nginx Location Blocks&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Match rules and the full priority order&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/nginx-reverse-proxy/"&gt;&lt;code&gt;Nginx Reverse Proxy&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;proxy_pass, headers, and WebSocket support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/nginx-log-files/"&gt;&lt;code&gt;Configuring the Nginx Error and Access Logs&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Log formats, levels, and rotation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/redirect-http-to-https-in-nginx/"&gt;&lt;code&gt;Redirect HTTP to HTTPS in Nginx&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Redirect patterns and the pitfalls to avoid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/start-stop-restart-nginx/"&gt;&lt;code&gt;How to Start, Stop, or Restart Nginx&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Reload versus restart and what each one does&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-set-up-nginx-server-blocks-on-ubuntu-22-04/"&gt;&lt;code&gt;Nginx Server Blocks on Ubuntu&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Hosting several sites on one server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-install-nginx-on-ubuntu-26-04/"&gt;&lt;code&gt;How to Install Nginx on Ubuntu 26.04&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Installation, firewall rules, and first steps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>Fix "No Space Left on Device" When df Shows Free Space</title><link>https://linuxize.com/post/fix-no-space-left-on-device/</link><pubDate>Mon, 14 Sep 2026 18:10:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/fix-no-space-left-on-device/</guid><category>disk</category><category>linux commands</category><description>Fix Linux no-space errors when df shows free space by checking the target mount, inode usage, tmpfs limits, container storage, Btrfs, and inotify watches.</description><content:encoded>&lt;p&gt;A command can fail with &lt;code&gt;No space left on device&lt;/code&gt; even when &lt;code&gt;df -h&lt;/code&gt; reports gigabytes of free space:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;touch: cannot touch &amp;#39;/var/lib/app/cache/item&amp;#39;: No space left on device&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The message does not always mean that the filesystem has run out of data blocks. Linux also needs a free inode for every new file, and the affected path may be on a different mount or a size-limited memory filesystem. Btrfs can run out of usable data or metadata space while &lt;code&gt;df&lt;/code&gt; still reports free capacity, and the kernel returns the same error when a program exhausts its inotify watch limit.&lt;/p&gt;
&lt;p&gt;This guide shows how to check each cause in a practical order, identify the exhausted resource, and free space safely.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Space on the affected path&lt;/td&gt;
&lt;td&gt;&lt;code&gt;df -h /affected/path&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inodes on the affected path&lt;/td&gt;
&lt;td&gt;&lt;code&gt;df -ih /affected/path&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filesystem and source device&lt;/td&gt;
&lt;td&gt;&lt;code&gt;findmnt -T /affected/path&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inode-heavy directories&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo du --inodes -x -d 2 /path | sort -n | tail -20&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deleted files still open&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo lsof +L1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Btrfs allocation details&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo btrfs filesystem usage /affected/path&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;inotify watch limit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sysctl fs.inotify.max_user_watches&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker storage usage&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker system df&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Journal size&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo journalctl --disk-usage&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APT cache size&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo du -sh /var/cache/apt/archives&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="check-the-exact-path-that-failed"&gt;Check the Exact Path That Failed &lt;a class="headline-link" href="#check-the-exact-path-that-failed" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start by passing the affected path to &lt;a href="https://linuxize.com/post/how-to-check-disk-space-in-linux-using-the-df-command/"&gt;&lt;code&gt;df&lt;/code&gt;&lt;/a&gt;
, not only the root directory:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;df -h /var/lib/app/cache&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p5 40G 17G 22G 44% /var&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Mounted on&lt;/code&gt; column shows which filesystem actually holds the path. Here the failing directory lives on a separate &lt;code&gt;/var&lt;/code&gt; filesystem, not on the root filesystem that &lt;code&gt;df -h /&lt;/code&gt; would have reported. A server may have separate filesystems for &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/var&lt;/code&gt;, &lt;code&gt;/home&lt;/code&gt;, &lt;code&gt;/tmp&lt;/code&gt;, container storage, or application data, and each one fills up independently.&lt;/p&gt;
&lt;p&gt;Display the source device, filesystem type, and mount point with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;findmnt -T /var/lib/app/cache&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;TARGET SOURCE FSTYPE OPTIONS
/var /dev/nvme0n1p5 ext4 rw,relatime&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If &lt;code&gt;Use%&lt;/code&gt; is 100%, the filesystem is genuinely out of data blocks. Use &lt;a href="https://linuxize.com/post/du-command-in-linux/"&gt;&lt;code&gt;du&lt;/code&gt;&lt;/a&gt;
or the guide on &lt;a href="https://linuxize.com/post/find-large-files-in-linux/"&gt;finding large files in Linux&lt;/a&gt;
to locate the largest directories and files.&lt;/p&gt;
&lt;h2 id="check-inode-usage"&gt;Check Inode Usage &lt;a class="headline-link" href="#check-inode-usage" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When block usage looks normal, check inodes on the same path:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;df -ih /var/lib/app/cache&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/nvme0n1p5 2.6M 2.6M 0 100% /var&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each file and directory consumes &lt;a href="https://linuxize.com/post/what-is-an-inode-in-linux/"&gt;an inode&lt;/a&gt;
. A filesystem containing millions of tiny cache, session, queue, or temporary files can run out of inodes while still having substantial free capacity in bytes.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;IFree&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;IUse%&lt;/code&gt; is &lt;code&gt;100%&lt;/code&gt;, inode exhaustion is the cause.&lt;/p&gt;
&lt;h3 id="find-directories-using-the-most-inodes"&gt;Find Directories Using the Most Inodes &lt;a class="headline-link" href="#find-directories-using-the-most-inodes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The GNU &lt;code&gt;du&lt;/code&gt; command can count inodes instead of bytes. To inspect &lt;code&gt;/var&lt;/code&gt; without crossing into other mounted filesystems:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo du --inodes -x -d &lt;span class="m"&gt;2&lt;/span&gt; /var 2&amp;gt;/dev/null &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sort -n &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tail -20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;12540 /var/lib/systemd
48201 /var/lib/docker
73122 /var/cache
2310884 /var/lib/app/cache
2485119 /var/lib
2621402 /var&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The largest counts appear at the bottom. In this example, &lt;code&gt;/var/lib/app/cache&lt;/code&gt; alone accounts for almost every inode on the filesystem. Repeat the command on the highest directory with a greater depth:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo du --inodes -x -d &lt;span class="m"&gt;3&lt;/span&gt; /var/lib/app/cache 2&amp;gt;/dev/null &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sort -n &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tail -20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This narrows the search before you remove anything.&lt;/p&gt;
&lt;p&gt;For a file-count view grouped by parent directory, use:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo find /var -xdev -type f -printf &lt;span class="s1"&gt;&amp;#39;%h\n&amp;#39;&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sort &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; uniq -c &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sort -n &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tail -20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This command may take time on a filesystem containing millions of files. It does not delete anything.&lt;/p&gt;
&lt;h3 id="remove-excess-small-files-safely"&gt;Remove Excess Small Files Safely &lt;a class="headline-link" href="#remove-excess-small-files-safely" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once you identify the directory, determine which application owns it and whether the files are disposable. Common sources include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Application caches that do not expire old entries.&lt;/li&gt;
&lt;li&gt;PHP session directories.&lt;/li&gt;
&lt;li&gt;Mail queues.&lt;/li&gt;
&lt;li&gt;Container image layers and build caches.&lt;/li&gt;
&lt;li&gt;Monitoring data and rotated logs.&lt;/li&gt;
&lt;li&gt;Temporary files created by failed jobs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Preview old temporary files before deleting them:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo find /tmp -xdev -type f -mtime +7 -print&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the list contains only files that are safe to remove, rerun it with &lt;code&gt;-delete&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo find /tmp -xdev -type f -mtime +7 -delete&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Do not run broad &lt;code&gt;find ... -delete&lt;/code&gt; commands against application directories until you know their retention rules. Prefer the application&amp;rsquo;s own cleanup command when one exists.&lt;/p&gt;
&lt;p&gt;On Ubuntu and Debian, clear downloaded package archives with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt clean&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Check the system journal&amp;rsquo;s current size:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo journalctl --disk-usage&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To remove archived journal data older than seven days:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo journalctl --vacuum-time&lt;span class="o"&gt;=&lt;/span&gt;7d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After cleanup, confirm that inodes are available again:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;df -ih /var/lib/app/cache&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="check-for-deleted-files-still-held-open"&gt;Check for Deleted Files Still Held Open &lt;a class="headline-link" href="#check-for-deleted-files-still-held-open" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This check covers a different version of the problem: &lt;code&gt;df&lt;/code&gt; reports a full filesystem, but &lt;code&gt;du&lt;/code&gt; cannot account for the usage. A process may still have a deleted file open. The directory entry is gone, but the kernel does not release its blocks until the process closes the file descriptor.&lt;/p&gt;
&lt;p&gt;List deleted files that remain open:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lsof +L1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
java 4217 app 7w REG 259,3 8589934592 0 8123 /var/log/app.log (deleted)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The example shows an 8 GB deleted log still held by a Java process. Restart the owning service during an appropriate maintenance window:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart app.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Use the actual service name for your process. Confirm the file is gone from the &lt;code&gt;lsof +L1&lt;/code&gt; output and check space again with &lt;code&gt;df -h&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For a detailed explanation of deleted open files, see the &lt;a href="https://linuxize.com/post/lsof-command-in-linux/"&gt;&lt;code&gt;lsof&lt;/code&gt; command guide&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="check-tmpfs-and-container-filesystems"&gt;Check tmpfs and Container Filesystems &lt;a class="headline-link" href="#check-tmpfs-and-container-filesystems" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Paths such as &lt;code&gt;/run&lt;/code&gt;, &lt;code&gt;/dev/shm&lt;/code&gt;, and sometimes &lt;code&gt;/tmp&lt;/code&gt; may use &lt;code&gt;tmpfs&lt;/code&gt;, which is backed by memory and has its own size limit. Check the affected path directly:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;df -h /run /dev/shm /tmp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If a tmpfs mount is full, remove stale files owned by the relevant application or increase the mount limit after checking available memory.&lt;/p&gt;
&lt;p&gt;Containers also write through overlay filesystems and mounted volumes. A host filesystem may have free space while a container-specific mount or storage pool is full. From the host, identify the path and mount with &lt;code&gt;findmnt -T&lt;/code&gt;. Inside the container, run &lt;code&gt;df -h&lt;/code&gt; and &lt;code&gt;df -i&lt;/code&gt; to inspect its view.&lt;/p&gt;
&lt;p&gt;For Docker, display the space used by images, containers, local volumes, and the build cache with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker system df&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This command reports Docker&amp;rsquo;s storage usage without removing anything. Review the detailed output before deciding which objects are safe to clean up.&lt;/p&gt;
&lt;h2 id="check-btrfs-data-and-metadata-allocation"&gt;Check Btrfs Data and Metadata Allocation &lt;a class="headline-link" href="#check-btrfs-data-and-metadata-allocation" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Btrfs manages data and metadata in separate block groups. Its copy-on-write allocation can return &lt;code&gt;No space left on device&lt;/code&gt; even when the free-space total from &lt;code&gt;df&lt;/code&gt; looks sufficient.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;findmnt&lt;/code&gt; reports &lt;code&gt;btrfs&lt;/code&gt; for the affected path, inspect its allocation details with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo btrfs filesystem usage /affected/path&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Review the &lt;code&gt;Device unallocated&lt;/code&gt;, &lt;code&gt;Free (estimated)&lt;/code&gt;, &lt;code&gt;Data&lt;/code&gt;, and &lt;code&gt;Metadata&lt;/code&gt; values together. A filesystem may have free data space but too little unallocated capacity to create another metadata block group.&lt;/p&gt;
&lt;p&gt;First, remove unneeded files or snapshots according to your retention policy. You can then reclaim completely unused data and metadata block groups with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo btrfs balance start -dusage&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; -musage&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; /mountpoint&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Replace &lt;code&gt;/mountpoint&lt;/code&gt; with the Btrfs mount point shown by &lt;code&gt;findmnt&lt;/code&gt;. The &lt;code&gt;usage=0&lt;/code&gt; filters select only empty block groups and do not need extra workspace. Do not run an unfiltered balance as a general disk-full fix because it rewrites all selected block groups, can take a long time, and needs temporary free space.&lt;/p&gt;
&lt;h2 id="check-the-inotify-watch-limit"&gt;Check the inotify Watch Limit &lt;a class="headline-link" href="#check-the-inotify-watch-limit" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Editors, build tools, log shippers, and file sync daemons watch files through inotify. Every watched file or directory consumes one watch, and the kernel enforces a per-user limit. When a program exceeds that limit, &lt;code&gt;inotify_add_watch()&lt;/code&gt; fails with the same &lt;code&gt;No space left on device&lt;/code&gt; error even though the filesystem has free blocks and free inodes. Applications often report it in their own wording:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Error: ENOSPC: System limit for number of file watchers reached, watch &amp;#39;/srv/app/src&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Display the current limit:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl fs.inotify.max_user_watches&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;fs.inotify.max_user_watches = 65536&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The value varies by distribution and kernel version. To find which process is consuming the watches, count them per file descriptor:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sh -c &lt;span class="s2"&gt;&amp;#34;grep -c &amp;#39;^inotify&amp;#39; /proc/*/fdinfo/* 2&amp;gt;/dev/null&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; awk -F: &lt;span class="s1"&gt;&amp;#39;$2 &amp;gt; 0 {print $2, $1}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sort -rn &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; head&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;62184 /proc/2811/fdinfo/23
1204 /proc/1533/fdinfo/9
118 /proc/994/fdinfo/12&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The PID appears in the path, so &lt;code&gt;ps -p 2811 -o comm=&lt;/code&gt; names the program holding the watches. If that program is watching a directory it does not need, such as a dependency or build output directory, exclude the directory in the program&amp;rsquo;s own configuration instead of raising the limit.&lt;/p&gt;
&lt;p&gt;When the workload genuinely needs more watches, raise the limit for the running system:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sysctl fs.inotify.max_user_watches&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;524288&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Make the change persistent across reboots:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;fs.inotify.max_user_watches=524288&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sudo tee /etc/sysctl.d/90-inotify.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Each watch consumes a small amount of kernel memory that cannot be swapped out, so set the limit to match the workload rather than to the largest value the system accepts.&lt;/p&gt;
&lt;h2 id="check-filesystem-and-kernel-errors"&gt;Check Filesystem and Kernel Errors &lt;a class="headline-link" href="#check-filesystem-and-kernel-errors" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If space and inodes are available but writes still fail, inspect recent kernel messages:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dmesg --level&lt;span class="o"&gt;=&lt;/span&gt;err,warn &lt;span class="p"&gt;|&lt;/span&gt; tail -50&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Also check the system journal:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo journalctl -k -p warning --since &lt;span class="s2"&gt;&amp;#34;1 hour ago&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Look for Btrfs allocation warnings, I/O errors, filesystem corruption, a read-only remount, or storage device failures. Errors such as &lt;code&gt;Input/output error&lt;/code&gt; and &lt;code&gt;Read-only file system&lt;/code&gt; need a different fix than &lt;code&gt;No space left on device&lt;/code&gt;. A filesystem check may be required, but do not run &lt;code&gt;fsck&lt;/code&gt; against a mounted filesystem. Schedule downtime, unmount the filesystem, and follow the appropriate recovery procedure.&lt;/p&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;df -h shows space but df -i shows 100 percent&lt;/strong&gt;&lt;br&gt;
The filesystem has exhausted its inode table. Find directories containing very large numbers of files, then remove or archive files according to the owning application&amp;rsquo;s retention policy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;df shows more usage than du&lt;/strong&gt;&lt;br&gt;
A process probably holds a deleted file open. Run &lt;code&gt;sudo lsof +L1&lt;/code&gt;, identify the process, and restart the owning service to release the blocks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The error occurs only in /tmp, /run, or /dev/shm&lt;/strong&gt;&lt;br&gt;
The path may be a size-limited tmpfs mount. Run &lt;code&gt;df -h&lt;/code&gt; and &lt;code&gt;df -i&lt;/code&gt; against that exact path rather than checking &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Docker reports no space while the host has free capacity&lt;/strong&gt;&lt;br&gt;
Check Docker&amp;rsquo;s storage path and filesystem with &lt;code&gt;docker info&lt;/code&gt;, &lt;code&gt;docker system df&lt;/code&gt;, and &lt;code&gt;findmnt -T /var/lib/docker&lt;/code&gt;. Review unused images, containers, build cache, and volumes before removing them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Btrfs reports no space while df shows free capacity&lt;/strong&gt;&lt;br&gt;
Run &lt;code&gt;sudo btrfs filesystem usage /affected/path&lt;/code&gt; and compare data, metadata, and unallocated space. After removing unneeded files or snapshots, a balance limited to &lt;code&gt;-dusage=0 -musage=0&lt;/code&gt; can reclaim empty block groups without starting a full balance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An editor, build tool, or sync daemon reports no space while df and df -i look fine&lt;/strong&gt;&lt;br&gt;
The process reached the inotify watch limit. Check &lt;code&gt;fs.inotify.max_user_watches&lt;/code&gt;, exclude directories the program does not need to watch, and raise the limit in &lt;code&gt;/etc/sysctl.d/&lt;/code&gt; when the workload requires it.&lt;/p&gt;
&lt;h2 id="faq"&gt;FAQ &lt;a class="headline-link" href="#faq" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What is an inode?&lt;/strong&gt;&lt;br&gt;
An inode stores filesystem metadata for a file or directory, such as its size, ownership, permissions, timestamps, and the location of its data blocks. Each filesystem has a finite inode supply, and each file normally consumes one inode regardless of its size.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can I add more inodes to an existing ext4 filesystem?&lt;/strong&gt;&lt;br&gt;
The inode count is chosen when the filesystem is created and cannot be increased with an online setting change. The practical fixes are to remove excess files, move the workload to another filesystem, or recreate the filesystem with a smaller bytes-per-inode ratio suited to many small files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why does deleting a large file not free space immediately?&lt;/strong&gt;&lt;br&gt;
A running process may still have the deleted file open. Linux releases the blocks only when the last file descriptor closes, so &lt;code&gt;df&lt;/code&gt; keeps reporting the space as used. Run &lt;code&gt;sudo lsof +L1&lt;/code&gt; to find the process and restart the owning service.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why does the error appear on a system with terabytes of free space?&lt;/strong&gt;&lt;br&gt;
The failing write is limited by something other than total capacity, most often the inode count of the specific mount, a size-limited tmpfs, container storage, Btrfs allocation, or the inotify watch limit. Always check the exact path that failed rather than the root filesystem.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When &lt;code&gt;df -h&lt;/code&gt; shows free space, check the affected path with &lt;code&gt;df -ih&lt;/code&gt; and use &lt;code&gt;findmnt&lt;/code&gt; to confirm its mount and filesystem type. Inode exhaustion, a full nested mount or tmpfs, container storage, Btrfs allocation, and the inotify watch limit each need a different fix, while &lt;code&gt;lsof +L1&lt;/code&gt; solves the separate case where &lt;code&gt;df&lt;/code&gt; is full but &lt;code&gt;du&lt;/code&gt; cannot explain the usage.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/fix-no-space-left-on-device/featured_hu_b710fcb3d23cc03a.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>ffmpeg Cheatsheet</title><link>https://linuxize.com/cheatsheet/ffmpeg/</link><pubDate>Sun, 13 Sep 2026 10:30:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/ffmpeg/</guid><description>Keep essential ffmpeg commands close at hand, from stream inspection and lossless remuxing to CRF encoding, filters, subtitles, and GPU acceleration.</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="install-ffmpeg"&gt;Install ffmpeg &lt;a class="headline-link" href="#install-ffmpeg" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Get the ffmpeg binaries and confirm the build.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/ffmpeg-command-in-linux/"&gt;&lt;code&gt;sudo apt install ffmpeg&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Install on Ubuntu, Debian, and derivatives&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo dnf install ffmpeg&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install the full build from RPM Fusion on Fedora or RHEL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo dnf install ffmpeg-free&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install the codec-limited build from Fedora or EPEL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the version and build configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -encoders&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List every available encoder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -decoders&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List every available decoder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -formats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List supported container formats&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="inspect-media-files"&gt;Inspect Media Files &lt;a class="headline-link" href="#inspect-media-files" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Read stream details before deciding how to re-encode.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/ffmpeg-command-in-linux/"&gt;&lt;code&gt;ffprobe -hide_banner in.mp4&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Show streams, codecs, and duration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffprobe -v error -show_format in.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print container metadata only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffprobe -v error -show_streams in.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print every stream property&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffprobe -v error -print_format json -show_format -show_streams in.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Machine-readable output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 in.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the video resolution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffprobe -v error -show_entries format=duration -of csv=p=0 in.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the duration in seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="common-options"&gt;Common Options &lt;a class="headline-link" href="#common-options" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Options that control inputs, outputs, and command behavior.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-i input&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set an input file (repeat for multiple inputs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Overwrite the output file without asking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Never overwrite an existing output file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-hide_banner&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Suppress the build and library banner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-loglevel error&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print errors only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-stats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep the progress line while quiet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-threads:v 4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Request four threads for the video encoder when supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-f format&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Force an input or output format&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="convert-between-formats"&gt;Convert Between Formats &lt;a class="headline-link" href="#convert-between-formats" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Change the container, with or without re-encoding.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/ffmpeg-command-in-linux/"&gt;&lt;code&gt;ffmpeg -i in.mkv -c copy out.mp4&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Repackage compatible streams without re-encoding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.avi out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Convert using the default encoders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mov -c:v libx264 -c:a aac out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Convert to H.264 and AAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -c:v libvpx-vp9 -c:a libopus out.webm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Convert to WebM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -c:v copy -c:a aac out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Re-encode the audio, keep the video&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.wav out.flac&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Convert between audio formats&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="compress-video"&gt;Compress Video &lt;a class="headline-link" href="#compress-video" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Lower the bitrate with constant quality or a controlled bitrate.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/ffmpeg-command-in-linux/"&gt;&lt;code&gt;ffmpeg -i in.mp4 -c:v libx264 -crf 23 -preset slow -c:a aac -b:a 128k out.mp4&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Compress with H.264&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -c:v libx265 -crf 28 -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compress with H.265 at a similar quality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -c:v libx264 -crf 18 out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep near-source quality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -c:v libx264 -b:v 2M -maxrate 2M -bufsize 4M -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Target 2 Mb/s with a 2 Mb/s VBV ceiling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -c:v h264_nvenc -cq 23 -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Encode on an NVIDIA GPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -vaapi_device /dev/dri/renderD128 -i in.mp4 -vf 'format=nv12,hwupload' -c:v h264_vaapi -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Encode with VA-API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;CRF runs from 0 (lossless) to 51 (worst). Lower values mean larger files, and 18 to 28 covers most work. Slower presets such as &lt;code&gt;slow&lt;/code&gt; or &lt;code&gt;veryslow&lt;/code&gt; shrink the file further at the same CRF.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="audio"&gt;Audio &lt;a class="headline-link" href="#audio" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Extract, convert, and adjust audio tracks.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/convert-mp4-to-mp3-with-ffmpeg/"&gt;&lt;code&gt;ffmpeg -i in.mp4 -vn -c:a libmp3lame -q:a 2 out.mp3&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Extract audio as MP3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vn -c:a copy out.m4a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Copy compatible audio without re-encoding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vn -c:a aac -b:a 192k out.aac&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extract audio as AAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp3 -ac 1 -ar 16000 out.wav&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Downmix to mono at 16 kHz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -c:v copy -af 'volume=1.5' out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Raise the volume by 50 percent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -c:v copy -af 'loudnorm=I=-23' -ar 48000 out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply one-pass EBU R128 normalization at -23 LUFS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -an -c:v copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strip the audio track&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;-q:a&lt;/code&gt; scale for libmp3lame runs from 0 (best) to 9 (worst), and 2 is a good default for speech and music alike.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="resize-crop-and-rotate"&gt;Resize, Crop, and Rotate &lt;a class="headline-link" href="#resize-crop-and-rotate" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Reshape the picture with video filters.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/ffmpeg-command-in-linux/"&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf scale=1280:-2 -c:a copy out.mp4&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Scale to 1280 wide, keep the aspect ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf scale=-2:720 -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scale to 720 high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf scale=1920:1080 -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Force an exact resolution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf 'crop=640:480:100:50' -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Crop 640x480 starting at x=100, y=50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf 'transpose=1' -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rotate 90 degrees clockwise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf 'hflip' -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mirror horizontally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf 'pad=1920:1080:(ow-iw)/2:(oh-ih)/2' -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pad to 1080p with centered bars&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use &lt;code&gt;-2&lt;/code&gt; rather than &lt;code&gt;-1&lt;/code&gt; for the free dimension so the calculated size stays even, as required by common 4:2:0 output formats.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="trim-and-concatenate"&gt;Trim and Concatenate &lt;a class="headline-link" href="#trim-and-concatenate" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Cut clips and join files back together.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/ffmpeg-command-in-linux/"&gt;&lt;code&gt;ffmpeg -ss 00:01:00 -to 00:02:30 -i in.mp4 -c copy clip.mp4&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Fast cut at the nearest keyframe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -ss 00:01:00 -to 00:02:30 -i in.mp4 -c:v libx264 -c:a aac clip.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Frame-accurate cut by re-encoding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -ss 00:00:30 -t 15 -i in.mp4 -c copy clip.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cut 15 seconds starting at 30 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -t 60 -c copy first-minute.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep the first minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -f concat -safe 0 -i list.txt -c copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Join files listed in list.txt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -c copy -f segment -segment_time 600 part%03d.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Split near ten-minute boundaries at keyframes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each line of &lt;code&gt;list.txt&lt;/code&gt; takes the form &lt;code&gt;file '/path/to/clip.mp4'&lt;/code&gt;. The concat demuxer requires matching stream layouts and parameters, including codecs and time bases.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="images-thumbnails-and-gifs"&gt;Images, Thumbnails, and GIFs &lt;a class="headline-link" href="#images-thumbnails-and-gifs" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Move between video and still images.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/ffmpeg-command-in-linux/"&gt;&lt;code&gt;ffmpeg -ss 00:00:10 -i in.mp4 -frames:v 1 thumb.jpg&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Grab a single frame at ten seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf fps=1 frame%04d.png&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Export one frame per second&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf 'fps=1/10' frame%04d.jpg&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Export one frame every ten seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -framerate 30 -i frame%04d.png -c:v libx264 -pix_fmt yuv420p out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build a video from an image sequence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf 'fps=10,scale=480:-1:flags=lanczos' out.gif&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a GIF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf 'fps=10,scale=480:-1:flags=lanczos,palettegen' palette.png&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build a GIF color palette&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -i palette.png -lavfi 'fps=10,scale=480:-1:flags=lanczos [x]; [x][1:v] paletteuse' out.gif&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a GIF with that palette&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="subtitles"&gt;Subtitles &lt;a class="headline-link" href="#subtitles" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Attach, burn in, or pull out subtitle tracks.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -i subs.srt -map 0 -map 1:0 -c copy -c:s mov_text out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add soft subtitles to MP4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mkv -i subs.srt -map 0 -map 1:0 -c copy out.mkv&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add soft subtitles to MKV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -vf subtitles=subs.srt -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Burn subtitles into the picture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mkv -vf 'subtitles=in.mkv:si=0' -c:a copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Burn in an embedded subtitle stream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mkv -map 0:s:0 subs.srt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Convert the first subtitle track to SRT when it is text based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mkv -map 0 -sn -c copy out.mkv&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove every subtitle track and keep other streams&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="stream-mapping-and-metadata"&gt;Stream Mapping and Metadata &lt;a class="headline-link" href="#stream-mapping-and-metadata" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Choose which streams reach the output.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mkv -map 0:v:0 -map 0:a:1 -c copy out.mkv&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep the first video and second audio stream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mkv -map 0 -c copy out.mkv&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep every stream from the input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i video.mp4 -i audio.mp3 -map 0:v -map 1:a -c:v copy -shortest out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Combine separate video and audio files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -map_metadata -1 -c copy out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strip global metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp3 -metadata title='Track name' -c copy out.mp3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set a metadata tag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Move the MP4 index to the front for streaming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;for f in *.mkv; do ffmpeg -i &amp;quot;$f&amp;quot; -c:v libx264 -crf 23 -c:a aac &amp;quot;${f%.mkv}.mp4&amp;quot;; done&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Batch convert a directory&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use these guides for the longer explanations behind these commands.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/ffmpeg-command-in-linux/"&gt;&lt;code&gt;ffmpeg Command in Linux&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Full ffmpeg tutorial with worked examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/convert-mp4-to-mp3-with-ffmpeg/"&gt;&lt;code&gt;Convert MP4 to MP3 with ffmpeg&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Audio extraction and quality settings in detail&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>pnpm Cheatsheet</title><link>https://linuxize.com/cheatsheet/pnpm/</link><pubDate>Fri, 11 Sep 2026 08:45:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/pnpm/</guid><description>Quick reference for pnpm commands covering installation, dependencies, lockfiles, scripts, workspace filtering, the package store, and Node.js runtimes</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="install-and-update-pnpm"&gt;Install and Update pnpm &lt;a class="headline-link" href="#install-and-update-pnpm" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Set up the pnpm executable and keep it current.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/pnpm-command/"&gt;&lt;code&gt;curl -fsSL https://get.pnpm.io/install.sh | sh -&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Install with the standalone script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wget -qO- https://get.pnpm.io/install.sh | sh -&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install without curl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npx get-pnpm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install through npm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm self-update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update pnpm to the current release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm self-update 12.3.4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Move to a specific pnpm version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm setup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create PNPM_HOME and update the shell profile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the installed pnpm version&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="nodejs-runtimes"&gt;Node.js Runtimes &lt;a class="headline-link" href="#nodejs-runtimes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install language runtimes with pnpm itself.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/pnpm-command/"&gt;&lt;code&gt;pnpm runtime set node lts -g&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Install the Node.js LTS release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm runtime set node 22 -g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install a Node.js major version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm runtime set node latest -g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install the newest Node.js release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm runtime set node 22.23.2 -g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install an exact Node.js version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm runtime set deno 2 -g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install Deno&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm runtime set bun latest -g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install Bun&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="project-setup"&gt;Project Setup &lt;a class="headline-link" href="#project-setup" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create and edit project metadata.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/pnpm-command/"&gt;&lt;code&gt;pnpm init&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Create package.json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm init --init-package-manager&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create package.json and pin pnpm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm init --bare&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create package.json with required fields only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm import&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build pnpm-lock.yaml from another lockfile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm pkg get name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print a package.json field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm pkg set scripts.start=&amp;quot;node index.js&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add or update a field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm pkg delete scripts.old&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove a package.json field&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="add-dependencies"&gt;Add Dependencies &lt;a class="headline-link" href="#add-dependencies" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Record packages in package.json and the lockfile.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/pnpm-command/"&gt;&lt;code&gt;pnpm add express&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Add a runtime dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm add -D eslint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a development dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm add -O sharp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add an optional dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm add -E express&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add without a version range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm add express@5.1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a specific version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm add -g http-server&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a global package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm add -w typescript&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add to the workspace root&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="install-dependencies"&gt;Install Dependencies &lt;a class="headline-link" href="#install-dependencies" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Reproduce a dependency tree from the lockfile.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install everything package.json declares&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/pnpm-command/"&gt;&lt;code&gt;pnpm install --frozen-lockfile&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Install without changing the lockfile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm ci&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clean install for CI pipelines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm install --prod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip development dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm install --offline&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install from the store only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm install --ignore-scripts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install without lifecycle scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm fetch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetch the lockfile contents into the store&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="update-and-inspect"&gt;Update and Inspect &lt;a class="headline-link" href="#update-and-inspect" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Check versions and trace where packages come from.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/pnpm-command/"&gt;&lt;code&gt;pnpm outdated&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Show packages with newer versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update within package.json ranges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm update express --latest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update one package and its range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm update -i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Choose updates interactively&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm list --depth 0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List direct dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm why express&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Explain why a package is installed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm licenses list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List dependency licenses&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="remove-and-clean"&gt;Remove and Clean &lt;a class="headline-link" href="#remove-and-clean" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Drop packages and reclaim project space.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/pnpm-command/"&gt;&lt;code&gt;pnpm remove express&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Remove a dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm remove -g http-server&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove a global package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm prune&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove extraneous packages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm prune --prod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove development dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm dedupe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Collapse duplicate versions in the lockfile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm dedupe --check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Report duplicates without writing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm pm clean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove node_modules from every workspace project&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="scripts-and-execution"&gt;Scripts and Execution &lt;a class="headline-link" href="#scripts-and-execution" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run package scripts and one-off tools.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/pnpm-command/"&gt;&lt;code&gt;pnpm run build&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Run a named script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the start script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the test script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm run build -- --watch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pass arguments to a script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm exec eslint .&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run a local package binary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm dlx create-vite@latest app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run a package without installing it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm pm &amp;lt;command&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Force a built-in command over a same-named script&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="workspaces-and-filtering"&gt;Workspaces and Filtering &lt;a class="headline-link" href="#workspaces-and-filtering" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Target one package or a slice of a monorepo.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/pnpm-command/"&gt;&lt;code&gt;pnpm -r run build&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Run a script in every workspace package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm --filter web-app add zod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a dependency to one package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm --filter web-app run test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run a script in one package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm --filter &amp;quot;@scope/*&amp;quot; test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select packages by pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm --filter web-app... build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select a package and its dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm --filter ...web-app build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select a package and its dependents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm --filter &amp;quot;...[origin/main]&amp;quot; build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select packages changed since a branch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="store-and-cache"&gt;Store and Cache &lt;a class="headline-link" href="#store-and-cache" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Maintain the shared content-addressable store.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm store path&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the store location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm store status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check the store for modified packages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm store prune&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove orphaned packages from the store&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm store add express@5.1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a package to the store&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm cache path&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the metadata cache directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm root -g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the global node_modules path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm bin -g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the global binary directory&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="security-and-diagnostics"&gt;Security and Diagnostics &lt;a class="headline-link" href="#security-and-diagnostics" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Audit dependencies and check the installation.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm audit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan dependencies for advisories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm audit --prod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Audit production dependencies only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm audit --fix&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add overrides for non-vulnerable versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm doctor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run diagnostics on the pnpm environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm sbom --sbom-format spdx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate a software bill of materials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm approve-builds&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Approve dependency build scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pnpm ignored-builds&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List packages with blocked build scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use these references for Node.js package workflows.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/pnpm-command/"&gt;&lt;code&gt;pnpm Command&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Full pnpm tutorial with examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/npm-command/"&gt;&lt;code&gt;npm Command&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;The npm equivalents of these commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-install-node-js-on-ubuntu-26-04/"&gt;&lt;code&gt;Install Node.js on Ubuntu 26.04&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Install Node.js and npm&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>How to Fix APT and dpkg Lock Errors on Ubuntu and Debian</title><link>https://linuxize.com/post/fix-dpkg-lock-error/</link><pubDate>Wed, 09 Sep 2026 10:20:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/fix-dpkg-lock-error/</guid><category>apt</category><category>ubuntu</category><category>debian</category><description>Resolve APT and dpkg lock errors safely on Ubuntu and Debian by finding the process holding the lock and repairing interrupted package operations.</description><content:encoded>&lt;p&gt;When you install or update packages on Ubuntu or Debian, you may see an error saying that APT or dpkg could not obtain a lock:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 2481 (apt)
N: Be aware that removing the lock file is not a solution and may break your system.
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The lock prevents two package managers from changing the package database at the same time. In most cases, another update is still running and the correct fix is to let it finish. If the process is stuck, you need to identify and stop it before repairing the package state.&lt;/p&gt;
&lt;p&gt;This guide explains how to resolve APT and dpkg lock errors without deleting lock files or damaging the package database.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/apt/"&gt;apt cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Show the process from the error&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ps -p PID -o pid,etime,cmd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check APT lock holders&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo lsof /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/cache/apt/archives/lock /var/lib/apt/lists/lock&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check with fuser&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo fuser -v /var/lib/dpkg/lock-frontend&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check automatic update services&lt;/td&gt;
&lt;td&gt;&lt;code&gt;systemctl status apt-daily.service apt-daily-upgrade.service unattended-upgrades.service&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ask a stuck process to stop&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo kill PID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finish pending package configuration&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo dpkg --configure -a&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repair broken dependencies&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt --fix-broken install&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refresh the package index&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt update&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="why-the-lock-error-occurs"&gt;Why the Lock Error Occurs &lt;a class="headline-link" href="#why-the-lock-error-occurs" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;APT and dpkg use lock files to coordinate access to package data. A lock error commonly appears when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Another terminal is running &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;apt-get&lt;/code&gt;, &lt;code&gt;dpkg&lt;/code&gt;, or a graphical software manager.&lt;/li&gt;
&lt;li&gt;Ubuntu&amp;rsquo;s automatic update services are checking for or installing updates.&lt;/li&gt;
&lt;li&gt;A package operation was interrupted and left a process running.&lt;/li&gt;
&lt;li&gt;A package manager process stopped responding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The error often includes the process ID that holds the lock. That PID is the safest place to start because it tells you which process currently owns package management.&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;Do not delete &lt;code&gt;/var/lib/dpkg/lock&lt;/code&gt;, &lt;code&gt;/var/lib/dpkg/lock-frontend&lt;/code&gt;, &lt;code&gt;/var/cache/apt/archives/lock&lt;/code&gt;, or &lt;code&gt;/var/lib/apt/lists/lock&lt;/code&gt; as a first response. Removing a lock file does not stop the process using the package database, and two concurrent writers can leave packages in an inconsistent state.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="step-1-check-the-process-holding-the-lock"&gt;Step 1: Check the Process Holding the Lock &lt;a class="headline-link" href="#step-1-check-the-process-holding-the-lock" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Replace &lt;code&gt;2481&lt;/code&gt; with the PID shown in your error:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps -p &lt;span class="m"&gt;2481&lt;/span&gt; -o pid,etime,cmd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt; PID ELAPSED CMD
2481 01:42 apt upgrade&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;ELAPSED&lt;/code&gt; column shows how long the process has been running. If it is an expected &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;dpkg&lt;/code&gt;, or update process and its runtime is reasonable, wait for it to finish.&lt;/p&gt;
&lt;p&gt;When the error does not show a PID, check the common lock files with &lt;code&gt;lsof&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lsof &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /var/lib/dpkg/lock-frontend &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /var/lib/dpkg/lock &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /var/cache/apt/archives/lock &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /var/lib/apt/lists/lock&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
apt 2481 root 4uW REG 8,2 0 812 /var/lib/dpkg/lock-frontend&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;COMMAND&lt;/code&gt; and &lt;code&gt;PID&lt;/code&gt; columns identify the process. If &lt;code&gt;lsof&lt;/code&gt; is unavailable, use &lt;code&gt;fuser&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo fuser -v /var/lib/dpkg/lock-frontend&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt; USER PID ACCESS COMMAND
/var/lib/dpkg/lock-frontend:
root 2481 F.... apt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Do not start another package command until the listed process has finished or been stopped safely.&lt;/p&gt;
&lt;h2 id="step-2-check-automatic-updates"&gt;Step 2: Check Automatic Updates &lt;a class="headline-link" href="#step-2-check-automatic-updates" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ubuntu and Debian systems may run background package operations through systemd. Check the APT update services with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl status apt-daily.service apt-daily-upgrade.service unattended-upgrades.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If any of these services is active, wait several minutes and check again:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl is-active apt-daily.service apt-daily-upgrade.service unattended-upgrades.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;inactive
inactive
inactive&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once all three services are inactive, retry your original package command.&lt;/p&gt;
&lt;p&gt;You can also inspect recent service messages:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo journalctl -u apt-daily.service -u apt-daily-upgrade.service -u unattended-upgrades.service --since &lt;span class="s2"&gt;&amp;#34;30 minutes ago&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The journal shows whether the updater is downloading packages, installing them, or failing repeatedly.&lt;/p&gt;
&lt;h2 id="step-3-stop-a-stuck-package-process"&gt;Step 3: Stop a Stuck Package Process &lt;a class="headline-link" href="#step-3-stop-a-stuck-package-process" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Only stop the process when it has clearly stopped making progress. Check the terminal output or service journal first, then confirm its command, state, and elapsed time:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps -p &lt;span class="m"&gt;2481&lt;/span&gt; -o pid,stat,etime,cmd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;STAT&lt;/code&gt; column shows the current process state, but it does not prove that a process is stuck. A sleeping package process may still be waiting for network or disk activity, so use the command output and logs as your main evidence.&lt;/p&gt;
&lt;p&gt;First, ask the process to terminate normally:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo &lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="m"&gt;2481&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Wait a few seconds, then check whether it still exists:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps -p &lt;span class="m"&gt;2481&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the command prints no process row, it has exited. Avoid sending &lt;code&gt;SIGKILL&lt;/code&gt; unless a normal termination fails, because an immediate kill gives the package manager no opportunity to clean up.&lt;/p&gt;
&lt;p&gt;If an automatic update service owns the process, stop the service instead of killing a child process:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl stop apt-daily.service apt-daily-upgrade.service unattended-upgrades.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Check the lock again before continuing:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo fuser -v /var/lib/dpkg/lock-frontend&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;No output means no visible process is accessing that lock file.&lt;/p&gt;
&lt;h2 id="step-4-repair-interrupted-package-configuration"&gt;Step 4: Repair Interrupted Package Configuration &lt;a class="headline-link" href="#step-4-repair-interrupted-package-configuration" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Stopping a package process may leave unpacked packages waiting to be configured. Complete those pending operations with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dpkg --configure -a&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This command configures packages that were unpacked but not fully configured. Our &lt;a href="https://linuxize.com/post/dpkg-command-in-linux/"&gt;dpkg command guide&lt;/a&gt;
explains package states and other useful recovery options.&lt;/p&gt;
&lt;p&gt;Next, repair missing or broken dependencies:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt --fix-broken install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Review the proposed package changes before confirming. After the repair completes, refresh the package index:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can then retry the original install or upgrade command.&lt;/p&gt;
&lt;h2 id="lock-file-locations"&gt;Lock File Locations &lt;a class="headline-link" href="#lock-file-locations" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The path in the error depends on which package-management layer is busy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/var/lib/dpkg/lock-frontend&lt;/code&gt; - Frontend lock used by APT before it calls dpkg.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/var/lib/dpkg/lock&lt;/code&gt; - Lock for the dpkg package database.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/var/cache/apt/archives/lock&lt;/code&gt; - Lock for downloaded package archives.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/var/lib/apt/lists/lock&lt;/code&gt; - Lock for repository index files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The diagnostic process is the same for each path: identify the process using the file, let it finish or stop it safely, and repair interrupted package configuration when necessary.&lt;/p&gt;
&lt;h2 id="if-no-process-holds-the-lock"&gt;If No Process Holds the Lock &lt;a class="headline-link" href="#if-no-process-holds-the-lock" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If &lt;code&gt;lsof&lt;/code&gt; and &lt;code&gt;fuser&lt;/code&gt; show no holder, do not remove the lock file. The dpkg tools keep these files in place, and the presence of a file does not mean that its lock is active.&lt;/p&gt;
&lt;p&gt;First, confirm that no package manager is running:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps aux &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;[a]pt|[d]pkg|unattended-upgrade&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Retry the original package command. If the lock error returns with a PID, another process acquired the lock between your checks. Inspect that new process before taking any other action.&lt;/p&gt;
&lt;p&gt;Run the recovery commands only if an earlier package operation was interrupted:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dpkg --configure -a
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt --fix-broken install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The lock is held by unattended-upgrade&lt;/strong&gt;&lt;br&gt;
Wait for the automatic update to finish and monitor it with &lt;code&gt;systemctl status apt-daily-upgrade.service unattended-upgrades.service&lt;/code&gt; or &lt;code&gt;sudo journalctl -u apt-daily-upgrade.service -u unattended-upgrades.service&lt;/code&gt;. Stop it only when it has clearly failed or remained stuck for an unreasonable time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;dpkg &amp;ndash;configure -a reports dependency problems&lt;/strong&gt;&lt;br&gt;
Run &lt;code&gt;sudo apt --fix-broken install&lt;/code&gt; to install missing dependencies and finish incomplete package operations. Then run &lt;code&gt;sudo dpkg --configure -a&lt;/code&gt; again if the error requests it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The lock returns immediately&lt;/strong&gt;&lt;br&gt;
Check the PID in the new error instead of assuming that the previous process restarted. An APT timer may have launched a new one-shot package operation between your checks. Inspect the services and their next scheduled runs with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl status apt-daily.service apt-daily-upgrade.service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl list-timers apt-daily.timer apt-daily-upgrade.timer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Do not repeatedly kill package processes. Wait for the active service to finish or stop that service only after confirming that it is stuck.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The lock error appears inside a script&lt;/strong&gt;&lt;br&gt;
Another package process may overlap with the script. For an &lt;code&gt;apt-get install&lt;/code&gt; command, set a bounded dpkg lock timeout so the script waits instead of failing immediately:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get -o DPkg::Lock::Timeout&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt; install -y curl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This example waits up to 60 seconds for the dpkg lock. If the timeout expires, log the failure and stop the script. Do not add &lt;code&gt;rm&lt;/code&gt; commands for APT or dpkg lock files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A graphical software manager is open&lt;/strong&gt;&lt;br&gt;
Close applications such as App Center, Software Updater, Synaptic, or other package frontends. Wait for their background process to exit, then retry the terminal command.&lt;/p&gt;
&lt;h2 id="faq"&gt;FAQ &lt;a class="headline-link" href="#faq" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Is it safe to delete /var/lib/dpkg/lock?&lt;/strong&gt;&lt;br&gt;
Deleting the file is not the correct first fix. The lock is associated with a running process, so removing the path does not stop that process. Identify the holder with &lt;code&gt;lsof&lt;/code&gt;, &lt;code&gt;fuser&lt;/code&gt;, or the PID in the error and deal with the process instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How long should I wait for apt-daily?&lt;/strong&gt;&lt;br&gt;
Most background checks finish within a few minutes, but upgrades can take longer depending on package downloads and installation work. Check its status and journal rather than relying on a fixed timeout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What does dpkg &amp;ndash;configure -a do?&lt;/strong&gt;&lt;br&gt;
It configures all packages that were unpacked but not fully configured. This is the standard recovery step after a package operation is interrupted.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why does the error mention lock-frontend instead of lock?&lt;/strong&gt;&lt;br&gt;
APT uses a frontend lock to ensure that only one high-level package manager controls dpkg at a time. The lower-level dpkg database has its own lock as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can I prevent automatic updates from taking the lock?&lt;/strong&gt;&lt;br&gt;
You can change the system&amp;rsquo;s automatic update schedule or policy, but disabling security updates only to avoid occasional lock contention is usually a poor tradeoff. It is safer to schedule maintenance commands outside the automatic update window.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An APT or dpkg lock error usually means package management is already active, not that the lock file is broken. Identify the holder, wait or stop it safely, then use &lt;code&gt;dpkg --configure -a&lt;/code&gt; and &lt;code&gt;apt --fix-broken install&lt;/code&gt; to repair any interrupted work. For more package maintenance examples, see our &lt;a href="https://linuxize.com/post/how-to-use-apt-command/"&gt;APT command guide&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/fix-dpkg-lock-error/featured_hu_142dac0e3ad9fbd3.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>vmstat Command in Linux: Memory, CPU, and I/O Statistics</title><link>https://linuxize.com/post/vmstat-command-in-linux/</link><pubDate>Mon, 07 Sep 2026 17:10:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/vmstat-command-in-linux/</guid><category>linux commands</category><description>Use vmstat to monitor Linux CPU, memory, swap, processes, and disk I/O. This guide explains each column, live sampling, timestamps, and disk statistics.</description><content:encoded>&lt;p&gt;When a server slows down, the first question is what it is waiting on. Is the CPU saturated? Is memory exhausted and the system is swapping? Is disk I/O holding up processes? The &lt;code&gt;vmstat&lt;/code&gt; command puts clues about each resource in one compact table, making it a useful first check before you move to a more specialized monitoring tool.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vmstat&lt;/code&gt; stands for virtual memory statistics and is provided by procps-ng. Most full Linux installations include it through a package named &lt;code&gt;procps&lt;/code&gt; or &lt;code&gt;procps-ng&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This guide explains how to read &lt;code&gt;vmstat&lt;/code&gt; output and use its most useful options.&lt;/p&gt;
&lt;h2 id="syntax"&gt;Syntax &lt;a class="headline-link" href="#syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat [OPTIONS] [delay [count]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;delay&lt;/code&gt; - Seconds between reports. Without it, &lt;code&gt;vmstat&lt;/code&gt; prints a single report and exits.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count&lt;/code&gt; - Number of reports to print. When you set a delay without a count, &lt;code&gt;vmstat&lt;/code&gt; runs until you press &lt;code&gt;Ctrl+C&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="reading-the-default-output"&gt;Reading the Default Output &lt;a class="headline-link" href="#reading-the-default-output" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Running &lt;code&gt;vmstat&lt;/code&gt; without arguments prints one report:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
1 0 0 362824 94368 1207160 0 0 12 5 48 112 1 0 99 0 0 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The process and memory columns show values from the moment the command runs. In the first report, swap, I/O, system, and CPU activity is averaged since the last boot. The output has six sections.&lt;/p&gt;
&lt;h3 id="procs"&gt;procs &lt;a class="headline-link" href="#procs" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt; - Runnable processes, including processes running or waiting for CPU time. Compare a sustained value with the logical CPU count from &lt;code&gt;nproc&lt;/code&gt;; a busy run queue together with little idle CPU suggests CPU contention.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;b&lt;/code&gt; - Processes blocked while waiting for I/O to complete.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="memory-default-kib"&gt;memory (default KiB) &lt;a class="headline-link" href="#memory-default-kib" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;swpd&lt;/code&gt; - Swap space currently in use.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;free&lt;/code&gt; - Idle memory that is not currently in use.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;buff&lt;/code&gt; - Memory used as buffers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cache&lt;/code&gt; - Memory used as cache. Linux uses otherwise idle RAM to cache data, so a large value is normal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;free&lt;/code&gt; column alone does not show how much memory applications can readily use. Check the &lt;code&gt;available&lt;/code&gt; value from the &lt;a href="https://linuxize.com/post/free-command-in-linux/"&gt;&lt;code&gt;free&lt;/code&gt; command&lt;/a&gt;
when you need that figure.&lt;/p&gt;
&lt;h3 id="swap-kibs"&gt;swap (KiB/s) &lt;a class="headline-link" href="#swap-kibs" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;si&lt;/code&gt; - Memory swapped in from disk per second.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;so&lt;/code&gt; - Memory swapped out to disk per second.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Occasional swap activity is not enough to diagnose a problem. Sustained &lt;code&gt;si&lt;/code&gt; or &lt;code&gt;so&lt;/code&gt; activity together with falling free and cache memory is a stronger sign of memory pressure.&lt;/p&gt;
&lt;h3 id="io-kibs"&gt;io (KiB/s) &lt;a class="headline-link" href="#io-kibs" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bi&lt;/code&gt; - Kibibytes received from block devices per second.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bo&lt;/code&gt; - Kibibytes sent to block devices per second.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="system"&gt;system &lt;a class="headline-link" href="#system" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;in&lt;/code&gt; - Interrupts per second, including the clock interrupt.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cs&lt;/code&gt; - Context switches per second. Compare this value with the system&amp;rsquo;s normal workload rather than using a fixed threshold.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cpu-percentage-of-total-cpu-time"&gt;cpu (percentage of total CPU time) &lt;a class="headline-link" href="#cpu-percentage-of-total-cpu-time" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;us&lt;/code&gt; - Time spent running user-space code, including nice time.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sy&lt;/code&gt; - Time spent running kernel code.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id&lt;/code&gt; - Idle time.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wa&lt;/code&gt; - Time the CPU was idle while waiting for I/O. A sustained increase is a clue to investigate I/O, but it does not identify the device or prove that storage is the bottleneck.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;st&lt;/code&gt; - Time taken from a virtual machine by the hypervisor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gu&lt;/code&gt; - Time spent running KVM guest code, including guest nice time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Older procps-ng versions may end the CPU columns at &lt;code&gt;st&lt;/code&gt;. The meaning of the preceding columns is unchanged.&lt;/p&gt;
&lt;h2 id="continuous-monitoring"&gt;Continuous Monitoring &lt;a class="headline-link" href="#continuous-monitoring" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A single report gives limited information about a live problem. Pass a delay to watch activity over consecutive intervals:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat &lt;span class="m"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This prints a new line every two seconds until you press &lt;code&gt;Ctrl+C&lt;/code&gt;. The first line still contains activity averages since boot, while later lines cover each two-second interval. Add &lt;code&gt;-y&lt;/code&gt; when you want to omit that first report:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat -y &lt;span class="m"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To collect ten interval reports and then stop, add a count:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat -y &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
0 0 0 360988 94504 1208068 0 0 0 0 92 198 0 0 100 0 0 0
1 0 0 360744 94504 1208068 0 0 0 16 104 231 1 0 99 0 0 0
0 0 0 360720 94504 1208080 0 0 0 0 89 190 0 0 100 0 0 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Only the first three rows are shown here. Because &lt;code&gt;-y&lt;/code&gt; skips the immediate boot-average report, the command waits for and records ten two-second intervals, taking about 20 seconds.&lt;/p&gt;
&lt;p&gt;Add timestamps and redirect the reports to a file when you want to review them later:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat -y -t &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &amp;gt; vmstat.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="active-and-inactive-memory"&gt;Active and Inactive Memory &lt;a class="headline-link" href="#active-and-inactive-memory" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-a&lt;/code&gt; flag replaces the &lt;code&gt;buff&lt;/code&gt; and &lt;code&gt;cache&lt;/code&gt; columns with &lt;code&gt;inact&lt;/code&gt; (inactive memory) and &lt;code&gt;active&lt;/code&gt; (active memory):&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat -a&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free inact active si so bi bo in cs us sy id wa st gu
0 0 0 358900 921048 490836 0 0 12 5 48 112 1 0 99 0 0 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Active memory contains pages used recently and likely to be referenced again. Inactive memory has not been accessed recently and contains candidates for reclaim when the system needs space. This view is useful when several workloads compete for memory.&lt;/p&gt;
&lt;h2 id="adding-timestamps"&gt;Adding Timestamps &lt;a class="headline-link" href="#adding-timestamps" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-t&lt;/code&gt; flag appends a timestamp column to each line, which is useful when capturing output to a log file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat -y -t &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu------- -----timestamp-----
r b swpd free buff cache si so bi bo in cs us sy id wa st gu EEST
0 0 0 362824 94368 1207160 0 0 0 0 88 195 0 0 100 0 0 0 2026-09-07 10:30:02
0 0 0 362700 94368 1207160 0 0 0 12 94 207 1 0 99 0 0 0 2026-09-07 10:30:04&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The timestamp uses the system&amp;rsquo;s local time zone. The example shows only the first two of the five requested reports.&lt;/p&gt;
&lt;h2 id="wide-output-mode"&gt;Wide Output Mode &lt;a class="headline-link" href="#wide-output-mode" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On systems with many CPU cores or high counter values, the default column widths can cause numbers to truncate or columns to overlap. The &lt;code&gt;-w&lt;/code&gt; flag switches to a wider format that avoids truncation:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat -w &lt;span class="m"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="memory-event-counters"&gt;Memory Event Counters &lt;a class="headline-link" href="#memory-event-counters" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-s&lt;/code&gt; flag prints current memory totals followed by CPU and event counters accumulated since boot:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat -s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt; 2023560 K total memory
417148 K used memory
493280 K active memory
921048 K inactive memory
362824 K free memory
94368 K buffer memory
1207160 K swap cache
2097148 K total swap
0 K used swap
2097148 K free swap
48712 non-nice user cpu ticks
952 nice user cpu ticks
12836 system cpu ticks
5181148 idle cpu ticks
5984 IO-wait cpu ticks
0 IRQ cpu ticks
3268 softirq cpu ticks
0 stolen cpu ticks
0 non-nice guest cpu ticks
0 nice guest cpu ticks
621264 K paged in
247908 K paged out
0 pages swapped in
0 pages swapped out
2518704 interrupts
5884112 CPU context switches
1788713671 boot time
52364 forks&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The exact list varies with the kernel and procps-ng version. This view is useful for checking current swap totals and cumulative paging activity. The event counters and CPU ticks start again after a reboot.&lt;/p&gt;
&lt;h2 id="disk-statistics"&gt;Disk Statistics &lt;a class="headline-link" href="#disk-statistics" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-d&lt;/code&gt; flag shows cumulative read and write statistics broken down by disk device:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;disk- ------------reads------------ ------------writes----------- -----IO------
total merged sectors ms total merged sectors ms cur sec
sda 12486 983 956342 34208 18402 4682 920612 142104 0 42
sdb 142 0 9168 252 0 0 0 0 0 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;total&lt;/code&gt; - Total number of completed read or write operations.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;merged&lt;/code&gt; - Adjacent requests grouped into a single I/O operation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sectors&lt;/code&gt; - Total sectors read or written.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ms&lt;/code&gt; - Total milliseconds spent reading or writing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cur&lt;/code&gt; - I/O operations currently in progress.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sec&lt;/code&gt; - Total seconds spent doing I/O.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To see statistics for a specific partition rather than the whole disk:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat -p /dev/sda1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;sda1 reads read sectors writes requested writes
12384 948812 18320 910484&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="changing-output-units"&gt;Changing Output Units &lt;a class="headline-link" href="#changing-output-units" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, memory and swap values use 1024-byte kibibytes. The &lt;code&gt;-S&lt;/code&gt; flag changes their display unit:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmstat -S M &lt;span class="m"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Accepted values are &lt;code&gt;k&lt;/code&gt; (1000 bytes), &lt;code&gt;K&lt;/code&gt; (1024 bytes), &lt;code&gt;m&lt;/code&gt; (1,000,000 bytes), and &lt;code&gt;M&lt;/code&gt; (1,048,576 bytes). This option does not change the swap (&lt;code&gt;si&lt;/code&gt;, &lt;code&gt;so&lt;/code&gt;) or I/O (&lt;code&gt;bi&lt;/code&gt;, &lt;code&gt;bo&lt;/code&gt;) fields, which stay in KiB/s.&lt;/p&gt;
&lt;h2 id="options-reference"&gt;Options Reference &lt;a class="headline-link" href="#options-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Show active and inactive memory instead of buffer and cache values.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Display disk statistics per device.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-D&lt;/code&gt; - Display summary disk statistics.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Show the number of forks since boot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; - Display slab memory information.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Print the header only once.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p device&lt;/code&gt; - Display partition-level disk statistics.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; - Display memory statistics and event counters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-S unit&lt;/code&gt; - Set the memory and swap output unit to &lt;code&gt;k&lt;/code&gt;, &lt;code&gt;K&lt;/code&gt;, &lt;code&gt;m&lt;/code&gt;, or &lt;code&gt;M&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Append a timestamp to each line.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-w&lt;/code&gt; - Use wider columns to prevent unwanted column breaks.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-y&lt;/code&gt; - Omit the first report containing activity averages since boot.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Single snapshot&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update every 2 seconds&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skip the boot-average report&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat -y 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10 interval reports, 2 seconds apart&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat -y 2 10&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active/inactive memory view&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat -a 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timestamped output&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat -t 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wide output&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat -w 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory event counters&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat -s&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk statistics&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat -d&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partition statistics&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat -p /dev/sda1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output in megabytes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmstat -S M 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;All values look like averages, not live activity&lt;/strong&gt;&lt;br&gt;
The first line contains activity averages since boot, although its process and memory fields are current values. Run &lt;code&gt;vmstat -y 2&lt;/code&gt; to skip that line and show only two-second interval reports.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The shell reports vmstat: command not found&lt;/strong&gt;&lt;br&gt;
Install the &lt;code&gt;procps&lt;/code&gt; package on Ubuntu and Debian with &lt;code&gt;sudo apt install procps&lt;/code&gt;. Fedora and RHEL use &lt;code&gt;sudo dnf install procps-ng&lt;/code&gt;, while Arch Linux uses &lt;code&gt;sudo pacman -S procps-ng&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;vmstat cannot read data under /proc&lt;/strong&gt;&lt;br&gt;
The command needs access to files under &lt;code&gt;/proc&lt;/code&gt;. Containers and systems mounted with restrictive &lt;code&gt;/proc&lt;/code&gt; options may hide some statistics. The &lt;code&gt;vmstat -m&lt;/code&gt; view also requires access to &lt;code&gt;/proc/slabinfo&lt;/code&gt;, which may be unavailable to a standard user.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;vmstat -y 2&lt;/code&gt; as a first check when a system slows down, then follow the signal: use &lt;a href="https://linuxize.com/post/top-command-in-linux/"&gt;&lt;code&gt;top&lt;/code&gt;&lt;/a&gt;
or &lt;a href="https://linuxize.com/post/htop-command-in-linux/"&gt;&lt;code&gt;htop&lt;/code&gt;&lt;/a&gt;
for per-process CPU and memory usage, or &lt;code&gt;iostat -xz 2&lt;/code&gt; for device latency and queues.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/vmstat-command-in-linux/featured_hu_b116ea65517c393a.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>btop Command in Linux: Monitor System Resources</title><link>https://linuxize.com/post/btop-command-in-linux/</link><pubDate>Sat, 05 Sep 2026 14:35:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/btop-command-in-linux/</guid><category>linux commands</category><description>Monitor CPU, memory, disks, network traffic, and processes with btop. This guide covers installation, keyboard shortcuts, process actions, and configuration.</description><content:encoded>&lt;p&gt;When a server feels slow, the first minutes are often spent juggling tools: &lt;code&gt;top&lt;/code&gt; for processes, &lt;code&gt;free&lt;/code&gt; for memory, and separate commands for network and disk activity. &lt;code&gt;btop&lt;/code&gt; puts these metrics on one screen, with live graphs for CPU, memory, disks, and network traffic alongside a filterable process list. It is the C++ continuation of the bashtop and bpytop resource monitors.&lt;/p&gt;
&lt;p&gt;This guide explains how to install &lt;code&gt;btop&lt;/code&gt;, read its dashboard, manage processes from it, and adjust its configuration.&lt;/p&gt;
&lt;h2 id="installing-btop"&gt;Installing btop &lt;a class="headline-link" href="#installing-btop" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;btop&lt;/code&gt; is available from the package repositories of current Ubuntu, Debian, Fedora, RHEL-based, and Arch Linux releases.&lt;/p&gt;
&lt;p&gt;On Ubuntu, Debian, and Derivatives, install it with &lt;code&gt;apt&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install btop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On Fedora, RHEL, and Derivatives, use &lt;code&gt;dnf&lt;/code&gt;. Fedora provides the package directly:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install btop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On RHEL, Rocky Linux, and AlmaLinux, enable the EPEL repository before installing &lt;code&gt;btop&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install epel-release
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install btop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On Arch Linux, install the package with &lt;code&gt;pacman&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo pacman -S btop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Verify the installation with the version option:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;btop --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="btop-syntax"&gt;btop Syntax &lt;a class="headline-link" href="#btop-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;btop&lt;/code&gt; command accepts the following general syntax:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;btop [OPTIONS]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Run it without options to open the interactive dashboard:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;btop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Use the built-in help to see the options supported by your installed version:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;btop --help&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The options you will use most often are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--low-color&lt;/code&gt; - Disable truecolor and convert to 256 colors.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Force TTY mode with 16 colors and tty-friendly graph symbols.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p &amp;lt;id&amp;gt;&lt;/code&gt; - Start with one of the saved presets, 0 through 9.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--version&lt;/code&gt; - Print the installed version.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Short option names changed in btop 1.4.2, so prefer the long forms above when you write scripts or aliases that must work across distributions.&lt;/p&gt;
&lt;h2 id="reading-the-dashboard"&gt;Reading the Dashboard &lt;a class="headline-link" href="#reading-the-dashboard" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The screen is divided into four boxes. The top box graphs per-core CPU usage along with frequency, temperature (when sensors are available), load average, and uptime. The left box covers memory and disks: used, available, and cached memory, plus usage and I/O activity for each mounted filesystem. The right box graphs network download and upload per interface. The bottom box is the process list.&lt;/p&gt;
&lt;p&gt;Everything is live and mouse-aware: you can click a process to select it, click column headers to change sorting, and scroll the list with the wheel. The same navigation works from the keyboard. Press &lt;code&gt;1&lt;/code&gt; to toggle the CPU box, &lt;code&gt;2&lt;/code&gt; for memory and disks, &lt;code&gt;3&lt;/code&gt; for network, and &lt;code&gt;4&lt;/code&gt; for processes.&lt;/p&gt;
&lt;p&gt;In the process list, memory usage is based on resident memory. By default, CPU usage is shown as a share of the machine&amp;rsquo;s total CPU capacity. Press &lt;code&gt;c&lt;/code&gt; to switch to per-core scaling, where 100% represents one fully used core and a multithreaded process can exceed 100%. For more detail on the underlying numbers, see the &lt;a href="https://linuxize.com/post/free-command-in-linux/"&gt;&lt;code&gt;free&lt;/code&gt;&lt;/a&gt;
command for memory and the load discussion in our &lt;a href="https://linuxize.com/post/top-command-in-linux/"&gt;top command guide&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="working-with-the-process-list"&gt;Working with the Process List &lt;a class="headline-link" href="#working-with-the-process-list" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The process list supports keyboard and mouse navigation. These keys cover the most common tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Up and Down arrows select a process; Enter opens a detail view with its own CPU and memory graphs for the selected process.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f&lt;/code&gt; or &lt;code&gt;/&lt;/code&gt; starts a filter. Type part of a process name and press Enter to keep only matching rows. Press Delete after leaving the filter editor to clear the active filter; Esc cancels an edit and restores the previous filter.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;e&lt;/code&gt; toggles tree view, showing parent-child relationships so you can see what started a process.&lt;/li&gt;
&lt;li&gt;Left and Right arrows change the sort column (CPU, memory, PID, and so on), and &lt;code&gt;r&lt;/code&gt; reverses the order.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Filtering plus the detail view covers the &amp;ldquo;what is eating this machine&amp;rdquo; workflow: filter to the suspect, Enter to watch its graphs, and you have a per-process monitor without leaving the dashboard.&lt;/p&gt;
&lt;h2 id="managing-processes"&gt;Managing Processes &lt;a class="headline-link" href="#managing-processes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With a process selected, three keys open signal actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;t&lt;/code&gt; opens a confirmation prompt for &lt;code&gt;SIGTERM&lt;/code&gt;, the normal termination request.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;k&lt;/code&gt; opens a confirmation prompt for &lt;code&gt;SIGKILL&lt;/code&gt;, which stops the process immediately.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt; opens a menu of all signals, for cases like &lt;code&gt;SIGHUP&lt;/code&gt; or &lt;code&gt;SIGSTOP&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;Try &lt;code&gt;SIGTERM&lt;/code&gt; first and wait for the process to exit. &lt;code&gt;SIGKILL&lt;/code&gt; does not let the process save data or run cleanup handlers, so use it only when the process ignores &lt;code&gt;SIGTERM&lt;/code&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can signal processes owned by your user. Run &lt;code&gt;sudo btop&lt;/code&gt; only when you need to manage a process owned by another account, and confirm the selected PID before sending a signal.&lt;/p&gt;
&lt;h2 id="options-and-themes"&gt;Options and Themes &lt;a class="headline-link" href="#options-and-themes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Press &lt;code&gt;F2&lt;/code&gt; or &lt;code&gt;o&lt;/code&gt; to open the options screen directly. You can change the update interval, visible boxes, temperature units, network interface, and color theme from this menu. Press Esc for the main menu or &lt;code&gt;q&lt;/code&gt; to quit.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;$XDG_CONFIG_HOME&lt;/code&gt; is set, &lt;code&gt;btop&lt;/code&gt; stores its settings in &lt;code&gt;$XDG_CONFIG_HOME/btop/btop.conf&lt;/code&gt;. Otherwise, it uses &lt;code&gt;~/.config/btop/btop.conf&lt;/code&gt;. The file is plain text and can also be edited directly:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.config/btop/btop.conf&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;color_theme = &amp;#34;tokyo-night&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;theme_background = False
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;update_ms = 2000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;shown_boxes = &amp;#34;cpu mem net proc&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Setting &lt;code&gt;theme_background = False&lt;/code&gt; makes &lt;code&gt;btop&lt;/code&gt; use your terminal&amp;rsquo;s background. The 2000 ms update interval is the upstream default and provides steadier graph samples than a very short interval.&lt;/p&gt;
&lt;p&gt;Distribution packages usually place system themes in &lt;code&gt;/usr/share/btop/themes&lt;/code&gt;, while source installations may use &lt;code&gt;/usr/local/share/btop/themes&lt;/code&gt;. Put additional themes in &lt;code&gt;$XDG_CONFIG_HOME/btop/themes&lt;/code&gt; or &lt;code&gt;~/.config/btop/themes&lt;/code&gt; to make them available in the picker.&lt;/p&gt;
&lt;p&gt;GPU panels appear only when the &lt;code&gt;btop&lt;/code&gt; binary was built with GPU support and the required driver libraries are available. On Linux x86_64, upstream supports NVIDIA and AMD GPUs and Intel integrated GPUs, but the exact support depends on how your distribution packaged &lt;code&gt;btop&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key or Command&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;btop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open the resource dashboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;btop --help&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show options supported by the installed version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;btop --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the installed version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;btop -p 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start with preset 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;btop -t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start in 16-color TTY mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;btop --low-color&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start in 256-color mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt; / &lt;code&gt;2&lt;/code&gt; / &lt;code&gt;3&lt;/code&gt; / &lt;code&gt;4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle the CPU, memory, network, or process box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Up / Down&lt;/td&gt;
&lt;td&gt;Select a process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enter&lt;/td&gt;
&lt;td&gt;Open or close details for the selected process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Space&lt;/td&gt;
&lt;td&gt;Expand or collapse the selected process in tree view&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;f&lt;/code&gt; or &lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Edit the process filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete&lt;/td&gt;
&lt;td&gt;Clear the active process filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Left / Right&lt;/td&gt;
&lt;td&gt;Change the process sort column&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reverse the process sort order&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;e&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle process tree view&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle per-core process CPU percentages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;t&lt;/code&gt; / &lt;code&gt;k&lt;/code&gt; / &lt;code&gt;s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open SIGTERM, SIGKILL, or signal selection actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt; / &lt;code&gt;-&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add or subtract 100 ms from the update timer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;F2&lt;/code&gt; or &lt;code&gt;o&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;h&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the help window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Esc&lt;/td&gt;
&lt;td&gt;Toggle the main menu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Quit &lt;code&gt;btop&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The interface renders as broken boxes or stray characters&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;btop&lt;/code&gt; needs a UTF-8 locale and a font with Braille, geometric shape, and box-drawing characters. Fix the locale or font first. The flag that bypasses locale detection was renamed in btop 1.4.2. Version 1.4.2 and newer accept &lt;code&gt;btop --force-utf&lt;/code&gt;, while 1.4.1 and earlier, including the packages in Ubuntu 24.04 and Debian 13, accept &lt;code&gt;btop --utf-force&lt;/code&gt;. Run &lt;code&gt;btop --help&lt;/code&gt; to confirm which form your version accepts. TTY mode is another fallback for limited terminals:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;btop -t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;No temperatures are shown&lt;/strong&gt;&lt;br&gt;
On Linux, &lt;code&gt;btop&lt;/code&gt; reads sensor data through the kernel&amp;rsquo;s hwmon interface. Check whether the &lt;code&gt;sensors&lt;/code&gt; command reports a CPU temperature, then select the correct sensor under Options &amp;gt; CPU if automatic detection chose the wrong one. If the kernel module for your hardware is missing, install &lt;code&gt;lm-sensors&lt;/code&gt; and run &lt;code&gt;sudo sensors-detect&lt;/code&gt;. Virtual machines usually do not expose hardware temperature sensors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Colors look wrong or washed out&lt;/strong&gt;&lt;br&gt;
Try 256-color mode when the terminal does not render truecolor correctly:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;btop --low-color&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For a basic console or a terminal with limited character support, use &lt;code&gt;btop -t&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sending a signal returns an insufficient permissions error&lt;/strong&gt;&lt;br&gt;
Your user can normally signal only its own processes. Exit and restart with &lt;code&gt;sudo btop&lt;/code&gt; if you must manage a system process, then verify the process name and PID before confirming the signal.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;btop&lt;/code&gt; combines CPU, memory, disk, network, and process monitoring in one interactive terminal view. Keep &lt;a href="https://linuxize.com/post/top-command-in-linux/"&gt;&lt;code&gt;top&lt;/code&gt;&lt;/a&gt;
as the widely available fallback, or use &lt;a href="https://linuxize.com/post/htop-command-in-linux/"&gt;&lt;code&gt;htop&lt;/code&gt;&lt;/a&gt;
when you want a process-focused interface with fewer system-wide graphs.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/btop-command-in-linux/featured_hu_cbe34142fa413278.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>How to Open a Port in the Firewall on Linux</title><link>https://linuxize.com/post/how-to-open-a-port-in-the-firewall-on-linux/</link><pubDate>Wed, 02 Sep 2026 09:35:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/how-to-open-a-port-in-the-firewall-on-linux/</guid><category>firewall</category><category>security</category><description>Open a port in a Linux firewall with ufw, firewalld, nftables, or iptables, then make the rule persistent and test remote access.</description><content:encoded>&lt;p&gt;When a service works locally but cannot be reached from another machine, the host firewall is one of the first places to check. Opening the port tells the firewall to accept matching traffic, but it does not start the service or change the address on which it listens.&lt;/p&gt;
&lt;p&gt;This guide shows how to open a port with &lt;code&gt;ufw&lt;/code&gt;, &lt;code&gt;firewalld&lt;/code&gt;, &lt;code&gt;nftables&lt;/code&gt;, and legacy &lt;code&gt;iptables&lt;/code&gt; rules, make the change persistent, and test the connection from another host.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/ufw/"&gt;ufw cheatsheet&lt;/a&gt;
, &lt;a href="https://linuxize.com/cheatsheet/firewalld/"&gt;firewalld cheatsheet&lt;/a&gt;
, and &lt;a href="https://linuxize.com/cheatsheet/iptables/"&gt;iptables cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Check ufw&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo ufw status&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check firewalld&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo firewall-cmd --state&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find the active firewalld zone&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo firewall-cmd --get-active-zones&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open TCP port 80 with ufw&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo ufw allow 80/tcp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open TCP port 80 with firewalld&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo firewall-cmd --zone=public --add-port=80/tcp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add a permanent firewalld rule&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo firewall-cmd --permanent --zone=public --add-port=80/tcp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inspect nftables rules&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo nft -a list ruleset&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open TCP port 80 with iptables&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check the local listener&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo ss -ltnp 'sport = :80'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test from another host&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nc -zv server.example.com 80&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The firewalld example uses the &lt;code&gt;public&lt;/code&gt; zone. Replace it with the zone attached to your incoming network interface. Raw nftables rules use administrator-defined table and chain names, so inspect the ruleset before changing it.&lt;/p&gt;
&lt;h2 id="check-whether-the-service-is-listening"&gt;Check Whether the Service Is Listening &lt;a class="headline-link" href="#check-whether-the-service-is-listening" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before changing the firewall, confirm that the service is listening on the expected TCP port. This example checks port 80:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ss -ltnp &lt;span class="s1"&gt;&amp;#39;sport = :80&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the command returns no output, nothing is listening on that port. Start or reconfigure the service before changing the firewall. If the local address is &lt;code&gt;127.0.0.1:80&lt;/code&gt; or &lt;code&gt;[::1]:80&lt;/code&gt;, the service accepts only local connections. Configure it to listen on the server&amp;rsquo;s network address, such as &lt;code&gt;0.0.0.0:80&lt;/code&gt; or &lt;code&gt;[::]:80&lt;/code&gt;, when remote access is required.&lt;/p&gt;
&lt;p&gt;For a UDP service, replace &lt;code&gt;-ltnp&lt;/code&gt; with &lt;code&gt;-lunp&lt;/code&gt;. The &lt;a href="https://linuxize.com/post/ss-command-in-linux/"&gt;&lt;code&gt;ss&lt;/code&gt; command guide&lt;/a&gt;
covers socket filters and listener output in more detail.&lt;/p&gt;
&lt;h2 id="identify-the-active-firewall"&gt;Identify the Active Firewall &lt;a class="headline-link" href="#identify-the-active-firewall" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use the firewall manager that is already active on the system. Do not add raw nftables or iptables rules alongside &lt;code&gt;ufw&lt;/code&gt; or &lt;code&gt;firewalld&lt;/code&gt;, because the manager may replace or reorder them during a reload.&lt;/p&gt;
&lt;p&gt;On Ubuntu and systems configured with &lt;code&gt;ufw&lt;/code&gt;, check its status:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ufw status&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Use the &lt;code&gt;ufw&lt;/code&gt; section when the output begins with &lt;code&gt;Status: active&lt;/code&gt;. An inactive &lt;code&gt;ufw&lt;/code&gt; configuration is not enforcing its saved rules.&lt;/p&gt;
&lt;p&gt;On Fedora, RHEL, and derivatives, check &lt;code&gt;firewalld&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --state&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the command prints &lt;code&gt;running&lt;/code&gt;, use the firewalld section. When neither manager is active, check whether the system loads a raw nftables configuration:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl is-active nftables&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;An &lt;code&gt;active&lt;/code&gt; result means the nftables service is running. If all three checks are inactive or unavailable, the machine may not have an active host firewall. A cloud firewall, security group, or router can still block incoming traffic before it reaches the server.&lt;/p&gt;
&lt;h2 id="opening-a-port-with-ufw"&gt;Opening a Port with ufw &lt;a class="headline-link" href="#opening-a-port-with-ufw" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ubuntu uses &lt;code&gt;ufw&lt;/code&gt; as its default firewall configuration tool, and it is also available on Debian. To allow TCP traffic on port 80, run:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ufw allow 80/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The rule takes effect immediately when &lt;code&gt;ufw&lt;/code&gt; is active and remains in place after a reboot. Replace &lt;code&gt;tcp&lt;/code&gt; with &lt;code&gt;udp&lt;/code&gt; when the application uses UDP.&lt;/p&gt;
&lt;p&gt;You can also use a service name from &lt;code&gt;/etc/services&lt;/code&gt;. The following rule opens the standard HTTP port:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ufw allow http&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Do not expose a database or an administration port to every source unless the service is meant to be public. To allow one address to reach PostgreSQL on port 5432, use:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ufw allow proto tcp from 203.0.113.10 to any port &lt;span class="m"&gt;5432&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Replace &lt;code&gt;203.0.113.10&lt;/code&gt; with the client address. You can also provide a CIDR range, such as &lt;code&gt;192.168.1.0/24&lt;/code&gt;, when a trusted network needs access.&lt;/p&gt;
&lt;p&gt;For a TCP port range, separate the first and last ports with a colon:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ufw allow 6000:6007/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;List the rules with their numbers to confirm the change:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ufw status numbered&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Status: active
To Action From
-- ------ ----
[ 1] 80/tcp ALLOW IN Anywhere
[ 2] 80/tcp (v6) ALLOW IN Anywhere (v6)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The two entries allow port 80 over IPv4 and IPv6. For more examples, including deleting a rule, see the &lt;a href="https://linuxize.com/post/ufw-command-in-linux/"&gt;ufw command guide&lt;/a&gt;
.&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;If you are enabling &lt;code&gt;ufw&lt;/code&gt; over SSH, allow the SSH service or its custom port first. Otherwise, &lt;code&gt;sudo ufw enable&lt;/code&gt; can block the connection and leave you dependent on console access.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="opening-a-port-with-firewalld"&gt;Opening a Port with firewalld &lt;a class="headline-link" href="#opening-a-port-with-firewalld" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;firewalld&lt;/code&gt; organizes rules into zones, and each network interface or source is assigned to a zone. Find the zone that receives the incoming connection before adding the rule:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --get-active-zones&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;public
interfaces: enp1s0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This server uses the &lt;code&gt;public&lt;/code&gt; zone for traffic arriving on &lt;code&gt;enp1s0&lt;/code&gt;. Open TCP port 80 in the runtime configuration so the change takes effect immediately:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --zone&lt;span class="o"&gt;=&lt;/span&gt;public --add-port&lt;span class="o"&gt;=&lt;/span&gt;80/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Add the same rule to the permanent configuration so it survives a reload or reboot:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --permanent --zone&lt;span class="o"&gt;=&lt;/span&gt;public --add-port&lt;span class="o"&gt;=&lt;/span&gt;80/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Running both commands avoids reloading the entire firewall and does not disturb unrelated runtime-only rules. If your interface belongs to another zone, replace &lt;code&gt;public&lt;/code&gt; in both commands.&lt;/p&gt;
&lt;p&gt;For standard services, a named service is easier to read than a port number. These commands allow HTTP immediately and permanently:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --zone&lt;span class="o"&gt;=&lt;/span&gt;public --add-service&lt;span class="o"&gt;=&lt;/span&gt;http
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --permanent --zone&lt;span class="o"&gt;=&lt;/span&gt;public --add-service&lt;span class="o"&gt;=&lt;/span&gt;http&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A port range works the same way, except that &lt;code&gt;firewalld&lt;/code&gt; separates the two ports with a hyphen rather than the colon &lt;code&gt;ufw&lt;/code&gt; expects. These commands open TCP ports 6000 through 6007:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --zone&lt;span class="o"&gt;=&lt;/span&gt;public --add-port&lt;span class="o"&gt;=&lt;/span&gt;6000-6007/tcp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --permanent --zone&lt;span class="o"&gt;=&lt;/span&gt;public --add-port&lt;span class="o"&gt;=&lt;/span&gt;6000-6007/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Query the active zone to confirm that the port rule is present:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --zone&lt;span class="o"&gt;=&lt;/span&gt;public --query-port&lt;span class="o"&gt;=&lt;/span&gt;80/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;yes&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you add &lt;code&gt;http&lt;/code&gt; as a named service, verify it with &lt;code&gt;sudo firewall-cmd --zone=public --query-service=http&lt;/code&gt; instead.&lt;/p&gt;
&lt;h2 id="opening-a-port-with-nftables"&gt;Opening a Port with nftables &lt;a class="headline-link" href="#opening-a-port-with-nftables" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use raw &lt;code&gt;nft&lt;/code&gt; commands only when nftables itself manages the firewall. &lt;code&gt;ufw&lt;/code&gt; and &lt;code&gt;firewalld&lt;/code&gt; can also use nftables as a backend, but their rules should still be changed through &lt;code&gt;ufw&lt;/code&gt; or &lt;code&gt;firewall-cmd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Unlike iptables, nftables does not create standard table and chain names. Display the current ruleset, including rule handles, before adding anything:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nft -a list ruleset&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The following example assumes the ruleset contains an &lt;code&gt;inet&lt;/code&gt; table named &lt;code&gt;filter&lt;/code&gt; and an input chain named &lt;code&gt;input&lt;/code&gt;. It inserts an allow rule at the beginning of that chain so an existing catch-all drop rule cannot match first:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nft insert rule inet filter input tcp dport &lt;span class="m"&gt;80&lt;/span&gt; accept&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Substitute the family, table, and chain names shown on your system. The command changes the running ruleset immediately, but it does not update the configuration loaded during boot.&lt;/p&gt;
&lt;p&gt;On Debian, persistent nftables rules are normally stored in &lt;code&gt;/etc/nftables.conf&lt;/code&gt;. Add the equivalent rule inside the existing input chain, before its final &lt;code&gt;drop&lt;/code&gt; or &lt;code&gt;reject&lt;/code&gt; rule:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;/etc/nftables.conf&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tcp dport 80 accept&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Validate the complete file before loading it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nft --check --file /etc/nftables.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the check produces no error, apply the file and enable the service at boot:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nft --file /etc/nftables.conf
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; nftables&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Some systems split the rules across files included from &lt;code&gt;/etc/nftables.conf&lt;/code&gt;. In that case, edit the file that defines the input chain rather than adding a second copy of the chain.&lt;/p&gt;
&lt;h2 id="opening-a-port-with-iptables"&gt;Opening a Port with iptables &lt;a class="headline-link" href="#opening-a-port-with-iptables" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;iptables&lt;/code&gt; is the legacy interface and is often a compatibility front end for nftables on current distributions. Prefer &lt;code&gt;ufw&lt;/code&gt;, &lt;code&gt;firewalld&lt;/code&gt;, or native nftables for a new firewall, but use iptables syntax when maintaining an existing iptables ruleset.&lt;/p&gt;
&lt;p&gt;Insert an IPv4 rule at the top of the &lt;code&gt;INPUT&lt;/code&gt; chain to allow TCP port 80:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo iptables -I INPUT &lt;span class="m"&gt;1&lt;/span&gt; -p tcp --dport &lt;span class="m"&gt;80&lt;/span&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Using &lt;code&gt;-I INPUT 1&lt;/code&gt; places the rule before a later rule that drops unmatched traffic. List the chain with rule numbers to verify its position:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo iptables -L INPUT -n --line-numbers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The running rule disappears after a reboot unless the system restores it. On Ubuntu and Debian, install the persistence package and save the current ruleset:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install iptables-persistent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo netfilter-persistent save&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;iptables&lt;/code&gt; command affects IPv4 only. If the service also accepts IPv6 connections, add the equivalent rule with &lt;code&gt;ip6tables&lt;/code&gt; and save again:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ip6tables -I INPUT &lt;span class="m"&gt;1&lt;/span&gt; -p tcp --dport &lt;span class="m"&gt;80&lt;/span&gt; -j ACCEPT
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo netfilter-persistent save&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;See the &lt;a href="https://linuxize.com/post/iptables-command-in-linux/"&gt;iptables command guide&lt;/a&gt;
when you need to inspect, remove, or reorder existing rules.&lt;/p&gt;
&lt;h2 id="verifying-the-port-is-reachable"&gt;Verifying the Port Is Reachable &lt;a class="headline-link" href="#verifying-the-port-is-reachable" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After applying the firewall rule, check the local listener again:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ss -ltnp &lt;span class="s1"&gt;&amp;#39;sport = :80&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then test from another machine that should be allowed through the firewall. Replace the hostname and port with your server details:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nc -zv server.example.com &lt;span class="m"&gt;80&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A successful connection confirms that the service is listening and the network path permits the traffic. A timeout usually points to a firewall, routing, or upstream network filter. &lt;code&gt;Connection refused&lt;/code&gt; usually means the host is reachable but nothing accepts the connection on that address and port.&lt;/p&gt;
&lt;p&gt;For additional remote tests with &lt;code&gt;nmap&lt;/code&gt;, netcat, and Bash, see &lt;a href="https://linuxize.com/post/check-open-ports-linux/"&gt;how to check open ports in Linux&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The firewall rule exists, but the port is still unreachable&lt;/strong&gt;&lt;br&gt;
Run &lt;code&gt;sudo ss -ltnp 'sport = :80'&lt;/code&gt; and inspect the local address. A service bound only to &lt;code&gt;127.0.0.1&lt;/code&gt; or &lt;code&gt;::1&lt;/code&gt; cannot accept remote connections.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The ufw rule does not filter any traffic&lt;/strong&gt;&lt;br&gt;
Check &lt;code&gt;sudo ufw status&lt;/code&gt;. Rules are saved while &lt;code&gt;ufw&lt;/code&gt; is inactive, but they are not enforced until you enable the firewall.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The firewalld rule is in the wrong zone&lt;/strong&gt;&lt;br&gt;
Compare &lt;code&gt;sudo firewall-cmd --get-active-zones&lt;/code&gt; with the zone used in the command. Add the rule to the zone attached to the incoming interface or source.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The rule uses the wrong protocol&lt;/strong&gt;&lt;br&gt;
TCP and UDP rules are separate. Check the application&amp;rsquo;s documentation or use &lt;code&gt;ss -ltnp&lt;/code&gt; for TCP and &lt;code&gt;ss -lunp&lt;/code&gt; for UDP before adding the rule.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A cloud server still blocks the port&lt;/strong&gt;&lt;br&gt;
Cloud security groups and provider firewalls operate outside the Linux host. Allow the same port and source in the provider control panel. A server behind a router may also need a port-forwarding rule before internet clients can reach it.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open only the port, protocol, and source range the service needs. Check both the local listener and a remote connection after every change, and remove temporary rules when the service no longer requires them.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/how-to-open-a-port-in-the-firewall-on-linux/featured_hu_c0bffd4c1adacec1.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>PHP Cheatsheet</title><link>https://linuxize.com/cheatsheet/php/</link><pubDate>Tue, 01 Sep 2026 10:55:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/php/</guid><description>PHP 8 quick reference for syntax, arrays, functions, classes, request data, files, JSON, exceptions, CLI commands, Composer, configuration, and PHP-FPM.</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="basic-syntax"&gt;Basic Syntax &lt;a class="headline-link" href="#basic-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every PHP file starts with an opening tag. Closing tags are omitted in pure PHP files to avoid stray output.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;?php ... ?&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Standard PHP tags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;?= $name ?&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Short echo tag (always available)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;declare(strict_types=1);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use strict scalar checks for calls and returns in this file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;// comment&lt;/code&gt;, &lt;code&gt;# comment&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Single-line comment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/* comment */&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Multi-line comment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;echo &amp;quot;text&amp;quot;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Output one or more strings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;print_r($var)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Human-readable dump of an array or object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;var_dump($var)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dump value with type and length&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;require 'file.php'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Include file, fatal error if missing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;include 'file.php'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Include file, warning if missing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;require_once 'file.php'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Include only once&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="variables-and-types"&gt;Variables and Types &lt;a class="headline-link" href="#variables-and-types" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PHP variables start with &lt;code&gt;$&lt;/code&gt; and are dynamically typed. Type declarations are optional but recommended.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$name = &amp;quot;Alice&amp;quot;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Assign a value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;, &lt;code&gt;float&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scalar types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array&lt;/code&gt;, &lt;code&gt;object&lt;/code&gt;, &lt;code&gt;callable&lt;/code&gt;, &lt;code&gt;iterable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compound types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Absence of a value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;const MAX = 10;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compile-time constant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;define('MAX', 10);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runtime constant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gettype($x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Return the type name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;is_int($x)&lt;/code&gt;, &lt;code&gt;is_string($x)&lt;/code&gt;, &lt;code&gt;is_array($x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Type checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(int) $x&lt;/code&gt;, &lt;code&gt;(string) $x&lt;/code&gt;, &lt;code&gt;(bool) $x&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Explicit casts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;intval($x)&lt;/code&gt;, &lt;code&gt;floatval($x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Convert to int or float&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isset($x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt; if set and not &lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;empty($x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt; when unset or equal to &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;0&amp;quot;&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;0.0&lt;/code&gt;, &lt;code&gt;[]&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;, or &lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unset($x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Destroy a variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;?int $x&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nullable type (int or null)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int|string $x&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Union type&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="operators"&gt;Operators &lt;a class="headline-link" href="#operators" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Arithmetic, comparison, logical, and null-handling operators.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operator&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Arithmetic and modulo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;**&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exponentiation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String concatenation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.=&lt;/code&gt;, &lt;code&gt;+=&lt;/code&gt;, &lt;code&gt;-=&lt;/code&gt;, &lt;code&gt;*=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compound assignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;==&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Loose comparison (type juggling)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;===&lt;/code&gt;, &lt;code&gt;!==&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strict comparison (value and type)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Relational comparison&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Spaceship, returns -1, 0, or 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;, &lt;code&gt;!&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Logical AND, OR, NOT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, &lt;code&gt;xor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Low-precedence logical operators&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;? :&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ternary conditional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;?:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Elvis, returns left side if truthy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;??&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Null coalescing, returns right side if left is null&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;??=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Null coalescing assignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;?-&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nullsafe method or property access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;|&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pipe operator, PHP 8.5 and later&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="strings"&gt;Strings &lt;a class="headline-link" href="#strings" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Double-quoted strings interpolate variables; single-quoted strings do not.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;strlen($s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String length in bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mb_strlen($s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Character length (requires the mbstring extension)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;strtolower($s)&lt;/code&gt; / &lt;code&gt;strtoupper($s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Change case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ucfirst($s)&lt;/code&gt; / &lt;code&gt;ucwords($s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Capitalize first letter / each word&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trim($s)&lt;/code&gt;, &lt;code&gt;ltrim($s)&lt;/code&gt;, &lt;code&gt;rtrim($s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strip whitespace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;str_contains($s, &amp;quot;x&amp;quot;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt; if substring is present&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;str_starts_with($s, &amp;quot;x&amp;quot;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt; if string starts with prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;str_ends_with($s, &amp;quot;x&amp;quot;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt; if string ends with suffix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;strpos($s, &amp;quot;x&amp;quot;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;First index of substring, &lt;code&gt;false&lt;/code&gt; if absent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;substr($s, 0, 5)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extract part of a string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;str_replace(&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, $s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace all occurrences&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;explode(&amp;quot;,&amp;quot;, $s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Split into an array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;implode(&amp;quot;, &amp;quot;, $arr)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Join array elements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sprintf(&amp;quot;%s has %d&amp;quot;, $a, $b)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Format into a string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;number_format(1234.5, 2)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Format a number with separators&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;str_pad($s, 10, &amp;quot;0&amp;quot;, STR_PAD_LEFT)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pad to a fixed width&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;str_repeat($s, 3)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Repeat a string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;htmlspecialchars($s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Escape HTML before output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nl2br($s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Convert newlines to &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;quot;Hello $name&amp;quot;&lt;/code&gt; / &lt;code&gt;&amp;quot;Sum: {$a['b']}&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Interpolation, braces for complex expressions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;&amp;lt;&amp;lt;EOT ... EOT;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Heredoc (interpolates) and nowdoc &lt;code&gt;&amp;lt;&amp;lt;&amp;lt;'EOT'&lt;/code&gt; (does not)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="arrays"&gt;Arrays &lt;a class="headline-link" href="#arrays" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PHP arrays are ordered maps and cover both lists and dictionaries.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$a = [1, 2, 3];&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Indexed array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$a = [&amp;quot;k&amp;quot; =&amp;gt; &amp;quot;v&amp;quot;];&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Associative array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$a[] = 4;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Append an element&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$a[&amp;quot;k&amp;quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Access by key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$a[0][1]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nested access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;count($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number of elements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_key_exists(&amp;quot;k&amp;quot;, $a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt; if the key exists, even when null&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;in_array(4, $a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt; if the value exists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_search(4, $a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Return the key of a value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[$x, $y] = $a;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Destructuring assignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[&amp;quot;k&amp;quot; =&amp;gt; $v] = $a;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Destructure by key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[...$a, ...$b]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Spread into a new array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;foreach ($a as $k =&amp;gt; $v)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Iterate keys and values&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="array-functions"&gt;Array Functions &lt;a class="headline-link" href="#array-functions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Transform, filter, and sort arrays without writing loops.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_push($a, $v)&lt;/code&gt; / &lt;code&gt;array_pop($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add or remove at the end&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_unshift($a, $v)&lt;/code&gt; / &lt;code&gt;array_shift($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add or remove at the start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_merge($a, $b)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Merge arrays, reindex numeric keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_keys($a)&lt;/code&gt; / &lt;code&gt;array_values($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extract keys or values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_slice($a, 1, 3)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extract a portion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_splice($a, 1, 2)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove or replace a portion in place&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_map(fn($x) =&amp;gt; $x * 2, $a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply a callback to each element&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_filter($a, fn($x) =&amp;gt; $x &amp;gt; 2)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep elements passing a test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_reduce($a, fn($c, $x) =&amp;gt; $c + $x, 0)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reduce to a single value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_column($rows, &amp;quot;name&amp;quot;, &amp;quot;id&amp;quot;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pull one column, optionally keyed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_unique($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove duplicate values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_combine($keys, $vals)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build an array from two arrays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_flip($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Swap keys and values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_sum($a)&lt;/code&gt; / &lt;code&gt;array_product($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sum or product of values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;min($a)&lt;/code&gt; / &lt;code&gt;max($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Smallest or largest value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;range(1, 10)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build a sequence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sort($a)&lt;/code&gt; / &lt;code&gt;rsort($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sort values ascending / descending&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;asort($a)&lt;/code&gt; / &lt;code&gt;ksort($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sort by value / key, keep keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;usort($a, fn($x, $y) =&amp;gt; $x &amp;lt;=&amp;gt; $y)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sort with a custom comparator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_find($a, $fn)&lt;/code&gt;, &lt;code&gt;array_any($a, $fn)&lt;/code&gt;, &lt;code&gt;array_all($a, $fn)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Search and test, PHP 8.4 and later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array_first($a)&lt;/code&gt; / &lt;code&gt;array_last($a)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;First or last value, PHP 8.5 and later&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="control-flow"&gt;Control Flow &lt;a class="headline-link" href="#control-flow" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Conditionals and loops. The alternative syntax with &lt;code&gt;endif&lt;/code&gt; and &lt;code&gt;endforeach&lt;/code&gt; reads better inside HTML templates.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;if (...) { } elseif (...) { } else { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Standard branching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;if (...): ... endif;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Alternative syntax for templates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;switch ($x) { case 1: ...; break; default: ...; }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Multi-branch on loose comparison&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;match($x) { 1 =&amp;gt; &amp;quot;a&amp;quot;, default =&amp;gt; &amp;quot;b&amp;quot; }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strict comparison, returns a value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;for ($i = 0; $i &amp;lt; 10; $i++)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Counter loop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;foreach ($arr as $value)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Iterate values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;foreach ($arr as $key =&amp;gt; $value)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Iterate keys and values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;foreach ($arr as &amp;amp;$value)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Iterate by reference (unset after)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;while (cond)&lt;/code&gt; / &lt;code&gt;do { } while (cond);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Conditional loops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;break;&lt;/code&gt; / &lt;code&gt;break 2;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exit the loop, or two levels of loops&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;continue;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip to the next iteration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;return $x;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Return from a function&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="functions"&gt;Functions &lt;a class="headline-link" href="#functions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Functions support default values, type declarations, named arguments, and variadics.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;function name($a, $b) { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Function declaration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;function name(int $a): string { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Typed parameters and return type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;function name($a = 10) { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Default parameter value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;function name(...$args) { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Variadic parameters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name(b: 2, a: 1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Named arguments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;function name(&amp;amp;$a) { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pass by reference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;function (): void { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No return value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fn($x) =&amp;gt; $x * 2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Arrow function, captures scope automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;function ($x) use ($y) { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Closure with an explicit captured variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$fn = strlen(...);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;First-class callable syntax&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;call_user_func($fn, $arg)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Call a callable dynamically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;function gen() { yield $x; }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generator function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;static function () { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Closure without &lt;code&gt;$this&lt;/code&gt; binding&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="classes-and-objects"&gt;Classes and Objects &lt;a class="headline-link" href="#classes-and-objects" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PHP 8 adds constructor promotion, enums, readonly properties, and property hooks.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;class User { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Class declaration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;new User()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Instantiate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;public&lt;/code&gt;, &lt;code&gt;protected&lt;/code&gt;, &lt;code&gt;private&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Visibility modifiers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;public function __construct(private string $name) { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Constructor property promotion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;public readonly int $id;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write once, then immutable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;private(set) string $name;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Asymmetric visibility, PHP 8.4 and later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;public string $full { get =&amp;gt; &amp;quot;$this-&amp;gt;a $this-&amp;gt;b&amp;quot;; }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Property hook, PHP 8.4 and later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$this-&amp;gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Access a property on the instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;self::CONST&lt;/code&gt;, &lt;code&gt;static::method()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Class and late static binding access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;parent::__construct()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Call the parent constructor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;class Admin extends User { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inheritance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;interface Jsonable { }&lt;/code&gt; / &lt;code&gt;implements Jsonable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Interfaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;abstract class Base { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Abstract class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trait Loggable { }&lt;/code&gt; / &lt;code&gt;use Loggable;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Trait reuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enum Status: string { case Active = 'active'; }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Backed enum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Status::from('active')&lt;/code&gt;, &lt;code&gt;Status::tryFrom($x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enum lookup, &lt;code&gt;tryFrom&lt;/code&gt; returns null&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$obj instanceof User&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Type check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;User::class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fully qualified class name as a string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;__get&lt;/code&gt;, &lt;code&gt;__set&lt;/code&gt;, &lt;code&gt;__call&lt;/code&gt;, &lt;code&gt;__toString&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Magic methods&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;namespace App\Models;&lt;/code&gt; / &lt;code&gt;use App\Models\User;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Namespaces and imports&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="superglobals-and-request-data"&gt;Superglobals and Request Data &lt;a class="headline-link" href="#superglobals-and-request-data" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Superglobals are available in every scope. Treat all of them as untrusted input.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$_GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Query string parameters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$_POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Form body parameters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$_REQUEST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Merge of GET, POST, and cookies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$_SERVER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Request and server metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$_SERVER['REQUEST_METHOD']&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP method&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$_SERVER['REMOTE_ADDR']&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Client IP address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$_FILES&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Uploaded file metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$_COOKIE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cookies sent by the client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$_SESSION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Session data, after &lt;code&gt;session_start()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$_ENV&lt;/code&gt;, &lt;code&gt;getenv('NAME')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Environment variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read and validate in one call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;filter_var($email, FILTER_VALIDATE_EMAIL)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Validate a value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;htmlspecialchars($v, ENT_QUOTES)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Escape before printing to HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;header('Location: /home'); exit;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Redirect and stop further execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;http_response_code(404)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the response status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;password_hash($p, PASSWORD_DEFAULT)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hash a password&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;password_verify($p, $hash)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verify a password against a hash&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="files-and-json"&gt;Files and JSON &lt;a class="headline-link" href="#files-and-json" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;File helpers for small payloads, plus JSON encoding and decoding.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;file_get_contents($path)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read a whole file into a string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;file_put_contents($path, $data)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write a string to a file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;file($path, FILE_IGNORE_NEW_LINES)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read a file into an array of lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fopen($path, 'r')&lt;/code&gt;, &lt;code&gt;fgets($fh)&lt;/code&gt;, &lt;code&gt;fclose($fh)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Streamed reads for large files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fwrite($fh, $data)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write to an open handle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;file_exists($p)&lt;/code&gt;, &lt;code&gt;is_file($p)&lt;/code&gt;, &lt;code&gt;is_dir($p)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Existence and type checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;is_readable($p)&lt;/code&gt;, &lt;code&gt;is_writable($p)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permission checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unlink($p)&lt;/code&gt;, &lt;code&gt;rename($a, $b)&lt;/code&gt;, &lt;code&gt;copy($a, $b)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete, move, copy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mkdir($p, 0755, true)&lt;/code&gt; / &lt;code&gt;rmdir($p)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create or remove directories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scandir($p)&lt;/code&gt; / &lt;code&gt;glob(&amp;quot;*.log&amp;quot;)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List directory entries or match a pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dirname($p)&lt;/code&gt;, &lt;code&gt;basename($p)&lt;/code&gt;, &lt;code&gt;pathinfo($p)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Split a path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;__DIR__&lt;/code&gt;, &lt;code&gt;__FILE__&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Directory and path of the current file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;realpath($p)&lt;/code&gt;, &lt;code&gt;filesize($p)&lt;/code&gt;, &lt;code&gt;filemtime($p)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resolve path, size, modification time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;json_encode($data, JSON_PRETTY_PRINT)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Encode to JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;json_decode($s, true)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Decode to an associative array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;json_encode($d, JSON_THROW_ON_ERROR)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Throw &lt;code&gt;JsonException&lt;/code&gt; on failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;json_validate($s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check validity without decoding, PHP 8.3 and later&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="dates-and-times"&gt;Dates and Times &lt;a class="headline-link" href="#dates-and-times" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;DateTimeImmutable&lt;/code&gt; is the safer default because arithmetic returns a new object instead of mutating the original.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;time()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Current Unix timestamp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;date('Y-m-d H:i:s')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Format the current time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;date('Y-m-d', $ts)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Format a given timestamp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;strtotime('+1 day')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Parse a relative or absolute string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mktime($h, $m, $s, $mo, $d, $y)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build a timestamp from parts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;new DateTimeImmutable('2026-09-01')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create an immutable date object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$d-&amp;gt;format('D, d M Y')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Format a date object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$d-&amp;gt;modify('+2 weeks')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Return a shifted copy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$d-&amp;gt;add(new DateInterval('P1M'))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add an interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$a-&amp;gt;diff($b)-&amp;gt;days&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Difference in days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;new DateTimeZone('Europe/Berlin')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Time zone object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;date_default_timezone_set('UTC')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the script time zone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;checkdate($m, $d, $y)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Validate a calendar date&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Y m d H i s&lt;/code&gt;, &lt;code&gt;D M&lt;/code&gt;, &lt;code&gt;N&lt;/code&gt;, &lt;code&gt;U&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Common format characters&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="errors-and-exceptions"&gt;Errors and Exceptions &lt;a class="headline-link" href="#errors-and-exceptions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Error&lt;/code&gt; covers engine failures and &lt;code&gt;Exception&lt;/code&gt; covers application failures; both implement &lt;code&gt;Throwable&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;try { } catch (Exception $e) { } finally { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Handle and clean up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;catch (TypeError | ValueError $e)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Catch multiple types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;catch (Exception)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Catch without capturing the object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;throw new RuntimeException(&amp;quot;msg&amp;quot;, 500);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Throw an exception&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$e-&amp;gt;getMessage()&lt;/code&gt;, &lt;code&gt;$e-&amp;gt;getCode()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read the message and code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$e-&amp;gt;getFile()&lt;/code&gt;, &lt;code&gt;$e-&amp;gt;getLine()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Where the exception was thrown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$e-&amp;gt;getTraceAsString()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stack trace as text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$e-&amp;gt;getPrevious()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Chained exception&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;class MyException extends Exception { }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Custom exception&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;error_reporting(E_ALL)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Report every error level&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ini_set('display_errors', '1')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show errors, development only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ini_set('log_errors', '1')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write errors to the log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;set_error_handler($fn)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Register a user-defined error handler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;set_exception_handler($fn)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Catch uncaught exceptions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;trigger_error(&amp;quot;msg&amp;quot;, E_USER_WARNING)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Raise a user-level error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@$value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Error suppression operator, avoid it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="regular-expressions"&gt;Regular Expressions &lt;a class="headline-link" href="#regular-expressions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PHP uses PCRE. Patterns need delimiters, usually &lt;code&gt;/&lt;/code&gt; or &lt;code&gt;#&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preg_match('/^a/', $s, $m)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Match once, fill &lt;code&gt;$m&lt;/code&gt; with captures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preg_match_all('/\d+/', $s, $m)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Match every occurrence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preg_replace('/\s+/', ' ', $s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace matches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preg_replace_callback('/\d/', $fn, $s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace using a callback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preg_split('/[\s,]+/', $s)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Split on a pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preg_quote($s, '/')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Escape user input used in a pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;preg_grep('/^a/', $arr)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter array entries by pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/pattern/i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Case-insensitive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/pattern/m&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Multiline, &lt;code&gt;^&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; match each line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/pattern/s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dot matches newlines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/pattern/u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Treat pattern and subject as UTF-8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(?&amp;lt;name&amp;gt;...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Named capture group, read as &lt;code&gt;$m['name']&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="php-cli"&gt;PHP CLI &lt;a class="headline-link" href="#php-cli" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;php&lt;/code&gt; binary runs scripts, checks syntax, and starts a development server without a web server in front of it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php script.php&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run a script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -v&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the PHP version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -m&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List compiled and loaded modules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the full &lt;code&gt;phpinfo()&lt;/code&gt; output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php --ini&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show which &lt;code&gt;php.ini&lt;/code&gt; files are loaded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -l script.php&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Syntax check without executing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -r 'echo PHP_VERSION;'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run inline code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Interactive shell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -S localhost:8000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Built-in development server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -S localhost:8000 -t public&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Serve a specific document root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -d memory_limit=512M script.php&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Override an &lt;code&gt;ini&lt;/code&gt; setting for one run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -c /path/to/php.ini script.php&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use a specific config file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php --rf str_replace&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reflect on a function signature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php --rc DateTimeImmutable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reflect on a class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php --re json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reflect on an extension&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -n script.php&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run without loading any &lt;code&gt;php.ini&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="configuration-and-extensions"&gt;Configuration and Extensions &lt;a class="headline-link" href="#configuration-and-extensions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Configuration paths depend on the SAPI and distribution. Use &lt;code&gt;php --ini&lt;/code&gt; for the CLI or &lt;code&gt;phpinfo()&lt;/code&gt; through the web server to confirm which files are active.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path or command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php --ini&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Locate the CLI configuration files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/php/&amp;lt;version&amp;gt;/cli/php.ini&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CLI config on Debian and Ubuntu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/php/&amp;lt;version&amp;gt;/fpm/php.ini&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PHP-FPM config on Debian and Ubuntu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/php/&amp;lt;version&amp;gt;/apache2/php.ini&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apache module config on Debian and Ubuntu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/php.ini&lt;/code&gt;, &lt;code&gt;/etc/php.d/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Main config and snippets on Fedora and RHEL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/php/&amp;lt;version&amp;gt;/mods-available/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extension snippets on Debian and Ubuntu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;memory_limit&lt;/code&gt;, &lt;code&gt;max_execution_time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Per-script resource limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upload_max_filesize&lt;/code&gt;, &lt;code&gt;post_max_size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Upload limits, raise both together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;display_errors&lt;/code&gt;, &lt;code&gt;error_log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Error output and log destination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;date.timezone&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Default time zone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;opcache.enable&lt;/code&gt;, &lt;code&gt;opcache.memory_consumption&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bytecode cache settings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt install php-gd php-curl php-mbstring&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install default-version extensions on Ubuntu or Debian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo dnf install php-gd php-curl php-mbstring&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install extensions on Fedora or RHEL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php -m | grep -E 'curl|gd|mbstring'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Confirm extensions are loaded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo phpenmod curl&lt;/code&gt; / &lt;code&gt;sudo phpdismod curl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable or disable an extension on Debian or Ubuntu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo update-alternatives --config php&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select an installed CLI version on Debian or Ubuntu&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="php-fpm"&gt;PHP-FPM &lt;a class="headline-link" href="#php-fpm" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PHP-FPM is the process manager that Nginx and Apache hand PHP requests to. The versioned examples below use PHP 8.5 on Ubuntu 26.04; Debian 13 uses 8.4, while Fedora and RHEL use unversioned &lt;code&gt;php-fpm&lt;/code&gt; names. Reload or restart FPM after config or extension changes.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command or directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl status php8.5-fpm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check the Ubuntu 26.04 service state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl status php-fpm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check the Fedora or RHEL service state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl restart php8.5-fpm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Restart the versioned service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl reload php8.5-fpm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gracefully reload FPM workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo php-fpm8.5 -t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Test Ubuntu 26.04 configuration before reloading&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/php/8.5/fpm/pool.d/www.conf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ubuntu 26.04 default pool configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;listen = /run/php/php8.5-fpm.sock&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unix socket the web server connects to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;user&lt;/code&gt; / &lt;code&gt;group&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;System account the workers run as&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pm = dynamic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Process manager mode: &lt;code&gt;static&lt;/code&gt;, &lt;code&gt;dynamic&lt;/code&gt;, or &lt;code&gt;ondemand&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pm.max_children&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hard cap on worker processes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pm.start_servers&lt;/code&gt;, &lt;code&gt;pm.min_spare_servers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Warm pool sizing for &lt;code&gt;dynamic&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pm.max_requests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recycle a worker after N requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;php_admin_value[memory_limit] = 256M&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Override an &lt;code&gt;ini&lt;/code&gt; value per pool&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;slowlog&lt;/code&gt;, &lt;code&gt;request_slowlog_timeout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Log requests that run too long&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo journalctl -u php8.5-fpm -f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Follow the versioned service log&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="composer"&gt;Composer &lt;a class="headline-link" href="#composer" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Composer manages dependencies and the autoloader for almost every modern PHP project.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer init&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a &lt;code&gt;composer.json&lt;/code&gt; interactively&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer require vendor/package&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer require --dev phpunit/phpunit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a development dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install from &lt;code&gt;composer.lock&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update dependencies and the lock file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer update vendor/package&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update a single package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer remove vendor/package&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove a dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer install --no-dev --optimize-autoloader&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Production install&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer dump-autoload -o&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Regenerate an optimized autoloader&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer show&lt;/code&gt; / &lt;code&gt;composer show -t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List packages, or show the dependency tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer outdated&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List packages with newer versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer why vendor/package&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Explain why a package is installed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer audit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check dependencies for known vulnerabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;composer create-project vendor/skeleton app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start a project from a skeleton&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;require 'vendor/autoload.php';&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Load the autoloader in your entry script&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use these guides to install PHP, check the running version, and debug errors on a server.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-install-php-on-ubuntu-26-04/"&gt;How to Install PHP on Ubuntu 26.04&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Install PHP 8.5 with Apache or Nginx and PHP-FPM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-check-php-version/"&gt;How to Check the PHP Version&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Find the CLI and web server PHP versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/php-error-reporting/"&gt;PHP Error Reporting&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Show, log, and control PHP errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-install-lamp-stack-on-ubuntu-26-04/"&gt;How to Install a LAMP Stack on Ubuntu 26.04&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Apache, MySQL, and PHP on one server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/mysql-mariadb/"&gt;MySQL and MariaDB Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Database commands for the data layer behind PHP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>What Is .bashrc? When It Runs and What to Put in It</title><link>https://linuxize.com/post/what-is-bashrc/</link><pubDate>Mon, 31 Aug 2026 14:35:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/what-is-bashrc/</guid><category>bash</category><description>~/.bashrc controls aliases, functions, prompts, and other interactive Bash settings. See when it runs, what belongs inside it, and how to reload changes.</description><content:encoded>&lt;p&gt;You define an alias in your terminal, use it happily for an hour, then open a new tab and it is gone. Shell settings typed at the prompt live only as long as that shell does. To make them permanent, they have to go in a file that Bash reads every time it starts a new session. On most Linux systems that file is &lt;code&gt;~/.bashrc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This guide covers where &lt;code&gt;.bashrc&lt;/code&gt; lives, when Bash reads it, what belongs inside it, and how to apply your changes without opening a new terminal.&lt;/p&gt;
&lt;h2 id="what-bashrc-does"&gt;What .bashrc Does &lt;a class="headline-link" href="#what-bashrc-does" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;.bashrc&lt;/code&gt; is a per-user Bash startup script, not a generic Linux configuration file. When Bash loads it, each command runs in the current shell. That is why aliases, functions, prompt settings, and shell options become part of the session without a separate import step. Other shells use their own files, such as &lt;code&gt;~/.zshrc&lt;/code&gt; for zsh.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;rc&lt;/code&gt; suffix comes from RUNCOM, an early CTSS program that executed commands stored in a file. The name survives in Unix configuration files such as &lt;code&gt;.vimrc&lt;/code&gt;, &lt;code&gt;.screenrc&lt;/code&gt;, and &lt;code&gt;.inputrc&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="where-the-bashrc-file-is-located"&gt;Where the .bashrc File Is Located &lt;a class="headline-link" href="#where-the-bashrc-file-is-located" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;.bashrc&lt;/code&gt; sits in your home directory. The leading dot makes it a hidden file, so a plain &lt;code&gt;ls&lt;/code&gt; will not show it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -la ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;-rw-r--r-- 1 dejan dejan 3771 Aug 14 09:12 /home/dejan/.bashrc&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Every user account has its own copy, and editing yours has no effect on anyone else on the system. The file is plain text, so any editor works:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nano ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the file does not exist, nothing is broken. Bash simply skips it. Most distributions ship a template in &lt;code&gt;/etc/skel/&lt;/code&gt; that is copied into each new home directory, so you can restore the default version with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp /etc/skel/.bashrc ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can also &lt;a href="https://linuxize.com/post/create-a-file-in-linux/"&gt;create the file&lt;/a&gt;
from scratch and start with an empty one.&lt;/p&gt;
&lt;h2 id="when-bash-reads-bashrc"&gt;When Bash Reads .bashrc &lt;a class="headline-link" href="#when-bash-reads-bashrc" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Bash reads &lt;code&gt;~/.bashrc&lt;/code&gt; when it starts an interactive shell that is not a login shell. In everyday terms, that means opening a new terminal window or tab in your desktop environment, or typing &lt;code&gt;bash&lt;/code&gt; inside a shell you already have open.&lt;/p&gt;
&lt;p&gt;Two common cases do not fit that description. Logging in over &lt;a href="https://linuxize.com/post/ssh-command-in-linux/"&gt;SSH&lt;/a&gt;
or at a console starts a login shell. Bash reads &lt;code&gt;/etc/profile&lt;/code&gt;, then the first readable file it finds from &lt;code&gt;~/.bash_profile&lt;/code&gt;, &lt;code&gt;~/.bash_login&lt;/code&gt;, and &lt;code&gt;~/.profile&lt;/code&gt;. Running a local script starts a non-interactive shell, which normally reads none of those files. If &lt;code&gt;BASH_ENV&lt;/code&gt; is set, Bash reads the file named by that variable before running the script.&lt;/p&gt;
&lt;p&gt;Because most people want the same interactive settings in both login and non-login shells, the usual arrangement is to keep those settings in &lt;code&gt;~/.bashrc&lt;/code&gt; and have the login file source it. For the full startup order and the reasoning behind that setup, see &lt;a href="https://linuxize.com/post/bashrc-vs-bash-profile/"&gt;.bashrc vs .bash_profile&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="the-guard-at-the-top-of-the-file"&gt;The Guard at the Top of the File &lt;a class="headline-link" href="#the-guard-at-the-top-of-the-file" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open the default &lt;code&gt;~/.bashrc&lt;/code&gt; on Debian or Ubuntu and the first real line is this:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.bashrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# If not running interactively, don&amp;#39;t do anything&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;$-&lt;/span&gt; in
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; *i*&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; *&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;esac&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;$-&lt;/code&gt; variable holds the current shell option flags, and it contains &lt;code&gt;i&lt;/code&gt; only in an interactive shell. If the &lt;code&gt;i&lt;/code&gt; flag is missing, &lt;code&gt;return&lt;/code&gt; stops reading the file right there.&lt;/p&gt;
&lt;p&gt;That guard exists because of one specific Bash behavior: when Bash detects that its standard input is connected to a network connection, as happens with &lt;code&gt;ssh user@host 'command'&lt;/code&gt;, it reads &lt;code&gt;~/.bashrc&lt;/code&gt; even though the shell is not interactive. Without the guard, everything below it could run during remote commands and file transfers that start Bash on the server.&lt;/p&gt;
&lt;p&gt;Keep the guard where it is, and add interactive settings below it. A setting required by a non-interactive remote command is an exception, but anything placed above the guard must stay silent.&lt;/p&gt;
&lt;h2 id="what-to-put-in-bashrc"&gt;What to Put in .bashrc &lt;a class="headline-link" href="#what-to-put-in-bashrc" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Anything that shapes how an interactive shell behaves belongs here. The most common additions follow.&lt;/p&gt;
&lt;h3 id="aliases"&gt;Aliases &lt;a class="headline-link" href="#aliases" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://linuxize.com/post/how-to-create-bash-aliases/"&gt;Aliases&lt;/a&gt;
are short names for longer commands:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.bashrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;ll&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ls -alF&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;gs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;git status&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; ..&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cd ..&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="functions"&gt;Functions &lt;a class="headline-link" href="#functions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When a shortcut needs arguments or more than one command, use a &lt;a href="https://linuxize.com/post/bash-functions/"&gt;function&lt;/a&gt;
instead of an alias:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.bashrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkcd &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mkdir -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Running &lt;code&gt;mkcd projects/api&lt;/code&gt; now creates the directory and moves into it.&lt;/p&gt;
&lt;h3 id="interactive-path-additions"&gt;Interactive PATH Additions &lt;a class="headline-link" href="#interactive-path-additions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To make Bash find executables in a directory of your own at the interactive prompt, &lt;a href="https://linuxize.com/post/how-to-add-directory-to-path-in-linux/"&gt;add it to &lt;code&gt;$PATH&lt;/code&gt;&lt;/a&gt;
:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.bashrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.local/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Putting &lt;code&gt;$PATH&lt;/code&gt; at the end preserves the existing directories. Placing your directory first means your version of a command wins over a system one with the same name.&lt;/p&gt;
&lt;p&gt;This change applies to shells that read &lt;code&gt;.bashrc&lt;/code&gt;. If the path must also reach GUI programs or other shells, set it in &lt;code&gt;~/.profile&lt;/code&gt; or &lt;code&gt;~/.bash_profile&lt;/code&gt; instead.&lt;/p&gt;
&lt;h3 id="environment-variables"&gt;Environment Variables &lt;a class="headline-link" href="#environment-variables" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://linuxize.com/post/how-to-set-and-list-environment-variables-in-linux/"&gt;Environment variables&lt;/a&gt;
needed by programs you start from interactive Bash can go here. Export them so child processes inherit their values:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.bashrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nano
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;LESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-R&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For variables that must exist across the entire login session, including applications not launched from a terminal, use a login or desktop environment file instead.&lt;/p&gt;
&lt;p&gt;Do not put API keys, tokens, or passwords in &lt;code&gt;.bashrc&lt;/code&gt;. The file often ends up in a dotfiles repository. Keep secrets in a separate file that is excluded from version control and protected with &lt;code&gt;chmod 600&lt;/code&gt;, or use a dedicated secret manager.&lt;/p&gt;
&lt;h3 id="the-shell-prompt"&gt;The Shell Prompt &lt;a class="headline-link" href="#the-shell-prompt" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;PS1&lt;/code&gt; defines the prompt string. The following example shows the username, host, and current directory in color:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.bashrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;\[\e[32m\]\u@\h\[\e[0m\]:\[\e[34m\]\w\[\e[0m\]\$ &amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;\[&lt;/code&gt; and &lt;code&gt;\]&lt;/code&gt; markers tell Bash that the enclosed escape sequences take up no screen width. Leaving them out makes long command lines wrap incorrectly.&lt;/p&gt;
&lt;h3 id="shell-options"&gt;Shell Options &lt;a class="headline-link" href="#shell-options" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;shopt&lt;/code&gt; toggles Bash behaviors that are off by default:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.bashrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;shopt&lt;/span&gt; -s autocd &lt;span class="c1"&gt;# type a directory name to cd into it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;shopt&lt;/span&gt; -s cdspell &lt;span class="c1"&gt;# fix minor typos in cd arguments&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;shopt&lt;/span&gt; -s globstar &lt;span class="c1"&gt;# ** matches files across subdirectories&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;shopt&lt;/span&gt; -s histappend &lt;span class="c1"&gt;# append to the history file instead of overwriting&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;History settings such as &lt;code&gt;HISTSIZE&lt;/code&gt; and &lt;code&gt;HISTCONTROL&lt;/code&gt; also live in this file. See the &lt;a href="https://linuxize.com/post/history-command-in-linux/"&gt;history command guide&lt;/a&gt;
for working with the entries themselves.&lt;/p&gt;
&lt;h2 id="apply-changes-without-restarting-the-terminal"&gt;Apply Changes Without Restarting the Terminal &lt;a class="headline-link" href="#apply-changes-without-restarting-the-terminal" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Bash reads &lt;code&gt;~/.bashrc&lt;/code&gt; at startup, so an edit has no effect on shells that are already running. Before loading an edited file, check its syntax:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash -n ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;No output means Bash found no syntax errors. You can then &lt;a href="https://linuxize.com/post/bash-source-command/"&gt;source&lt;/a&gt;
the file instead of closing the terminal:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The dot command is the POSIX spelling of &lt;code&gt;source&lt;/code&gt; and does the same thing in Bash:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;. ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Either command runs the file in your current shell, so aliases, functions, and variables become available immediately. Sourcing does not undo anything: if you deleted an alias from the file, it stays defined in the current session until you run &lt;code&gt;unalias&lt;/code&gt; or open a new terminal.&lt;/p&gt;
&lt;h2 id="split-bashrc-into-separate-files"&gt;Split .bashrc Into Separate Files &lt;a class="headline-link" href="#split-bashrc-into-separate-files" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;.bashrc&lt;/code&gt; that has grown past a couple of hundred lines is easier to manage in pieces. Debian and Ubuntu already use this pattern for aliases, and their default file includes:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.bashrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f ~/.bash_aliases &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; . ~/.bash_aliases
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For a more general split, create a directory for the extra files:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p ~/.bashrc.d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then add a loop to &lt;code&gt;~/.bashrc&lt;/code&gt; that sources every readable shell file in the directory:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.bashrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -d ~/.bashrc.d &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; rc in ~/.bashrc.d/*.sh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt; -r &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$rc&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; . &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$rc&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;unset&lt;/span&gt; rc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Files are sourced in alphabetical order, so a &lt;code&gt;10-path.sh&lt;/code&gt; runs before a &lt;code&gt;20-aliases.sh&lt;/code&gt;. This keeps work-specific settings in one file that you can drop in or remove without editing &lt;code&gt;.bashrc&lt;/code&gt; itself. A &lt;code&gt;bash -n ~/.bashrc&lt;/code&gt; check does not read the sourced files, so check each of them separately after an edit.&lt;/p&gt;
&lt;p&gt;Fedora and RHEL already source files from &lt;code&gt;~/.bashrc.d/&lt;/code&gt; in their default configuration, so check your existing file before adding another loop.&lt;/p&gt;
&lt;h2 id="what-not-to-put-in-bashrc"&gt;What Not to Put in .bashrc &lt;a class="headline-link" href="#what-not-to-put-in-bashrc" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Commands that print output are the main thing to avoid. A &lt;code&gt;neofetch&lt;/code&gt; call or an &lt;code&gt;echo &amp;quot;Welcome back&amp;quot;&lt;/code&gt; line placed above the interactivity guard looks harmless in a terminal, but it also runs during &lt;code&gt;scp&lt;/code&gt;, &lt;code&gt;rsync&lt;/code&gt;, and &lt;code&gt;ssh host 'command'&lt;/code&gt; sessions. The extra text can corrupt the protocol stream and make those tools fail. Keep printed output below the guard, or move a login banner to the login profile.&lt;/p&gt;
&lt;p&gt;Long-running commands are worth avoiding too. Everything in &lt;code&gt;.bashrc&lt;/code&gt; runs before you get a prompt, so a network call or a version-manager initialization that takes half a second adds that delay to every terminal you open.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/bash/"&gt;Bash cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alias&lt;/td&gt;
&lt;td&gt;&lt;code&gt;alias ll='ls -alF'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Short name for a longer command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mkcd () { mkdir -p &amp;quot;$1&amp;quot; &amp;amp;&amp;amp; cd &amp;quot;$1&amp;quot;; }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shortcut that takes arguments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interactive PATH&lt;/td&gt;
&lt;td&gt;&lt;code&gt;export PATH=&amp;quot;$HOME/.local/bin:$PATH&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add an executable directory to interactive Bash&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Environment variable&lt;/td&gt;
&lt;td&gt;&lt;code&gt;export EDITOR=nano&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Setting inherited by programs launched from Bash&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PS1='\u@\h:\w\$ '&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Format of the shell prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shell option&lt;/td&gt;
&lt;td&gt;&lt;code&gt;shopt -s autocd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle a Bash behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source a file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;. ~/.bash_aliases&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Load settings from another file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Syntax check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bash -n ~/.bashrc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check the file without running it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reload&lt;/td&gt;
&lt;td&gt;&lt;code&gt;source ~/.bashrc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply edits to the current shell&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Changes do not take effect&lt;/strong&gt;&lt;br&gt;
Bash reads &lt;code&gt;~/.bashrc&lt;/code&gt; only when a shell starts. Run &lt;code&gt;bash -n ~/.bashrc&lt;/code&gt;, then &lt;code&gt;source ~/.bashrc&lt;/code&gt; in the current terminal, or open a new one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Settings work in a new terminal but not over SSH&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;ssh user@host&lt;/code&gt; opens a login shell, which reads the first available file from &lt;code&gt;~/.bash_profile&lt;/code&gt;, &lt;code&gt;~/.bash_login&lt;/code&gt;, and &lt;code&gt;~/.profile&lt;/code&gt; rather than &lt;code&gt;~/.bashrc&lt;/code&gt;. Debian and Ubuntu ship a &lt;code&gt;~/.profile&lt;/code&gt; that sources &lt;code&gt;~/.bashrc&lt;/code&gt; already, so the default setup works. On other systems, or after replacing the login file, add &lt;code&gt;. ~/.bashrc&lt;/code&gt; to it so both shell types load the same interactive configuration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;scp or rsync fails after editing .bashrc&lt;/strong&gt;&lt;br&gt;
Something in the file may be printing output during the remote session. Move any &lt;code&gt;echo&lt;/code&gt;, &lt;code&gt;neofetch&lt;/code&gt;, or banner command below the interactivity guard, then test with &lt;code&gt;ssh user@host 'true'&lt;/code&gt;, which should print nothing at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A syntax error appears in every new terminal&lt;/strong&gt;&lt;br&gt;
Bash reports the offending line number. Open a shell that skips the file with &lt;code&gt;bash --norc&lt;/code&gt;, fix the line, then run &lt;code&gt;bash -n ~/.bashrc&lt;/code&gt; before reloading. A missing &lt;code&gt;fi&lt;/code&gt; or an unclosed quote is the usual cause.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The file was deleted or emptied&lt;/strong&gt;&lt;br&gt;
Copy the distribution default back with &lt;code&gt;cp /etc/skel/.bashrc ~/.bashrc&lt;/code&gt; and reload it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A command is found in one terminal but not another&lt;/strong&gt;&lt;br&gt;
The two shells may read different startup files, or the &lt;code&gt;$PATH&lt;/code&gt; addition may be below an early &lt;code&gt;return&lt;/code&gt; or inside a conditional that does not match. Run &lt;code&gt;echo &amp;quot;$PATH&amp;quot;&lt;/code&gt; in both shells to compare.&lt;/p&gt;
&lt;h2 id="faq"&gt;FAQ &lt;a class="headline-link" href="#faq" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Does .bashrc run when I execute a script?&lt;/strong&gt;&lt;br&gt;
Normally, no. A local script runs in a non-interactive shell, which does not read &lt;code&gt;~/.bashrc&lt;/code&gt; unless the script sources it or &lt;code&gt;BASH_ENV&lt;/code&gt; points to it. Bash may also read &lt;code&gt;.bashrc&lt;/code&gt; when a remote shell daemon starts a non-interactive command, but the interactivity guard usually stops the file immediately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I use zsh. Where do these settings go?&lt;/strong&gt;&lt;br&gt;
Use &lt;code&gt;~/.zshrc&lt;/code&gt;, which serves the same role for zsh. Aliases, functions, and &lt;code&gt;PATH&lt;/code&gt; changes carry over unchanged, but prompt escapes and some &lt;code&gt;shopt&lt;/code&gt; options do not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Should I put .bashrc in version control?&lt;/strong&gt;&lt;br&gt;
Yes, as long as it holds no secrets. A dotfiles repository makes it easy to set up a new machine. Keep tokens and passwords in a separate file that is listed in &lt;code&gt;.gitignore&lt;/code&gt; and sourced from &lt;code&gt;.bashrc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why is my .bashrc not read on macOS?&lt;/strong&gt;&lt;br&gt;
Terminal and iTerm2 normally open a login shell. If you configured them to use Bash, Bash reads the first available login file instead of &lt;code&gt;~/.bashrc&lt;/code&gt;. Current macOS releases use zsh by default, and its interactive configuration belongs in &lt;code&gt;~/.zshrc&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Treat &lt;code&gt;~/.bashrc&lt;/code&gt; as code that runs every time you open an interactive Bash shell. Keep it fast, keep secrets out of it, and check each edit with &lt;code&gt;bash -n ~/.bashrc&lt;/code&gt; before loading the change.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/what-is-bashrc/featured_hu_dc8aabe3f4f9449f.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>Regex Cheatsheet</title><link>https://linuxize.com/cheatsheet/regex/</link><pubDate>Fri, 28 Aug 2026 17:40:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/regex/</guid><description>Regex syntax and examples for Linux tools, including metacharacters, quantifiers, character classes, anchors, groups, BRE, ERE, and PCRE</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="metacharacters"&gt;Metacharacters &lt;a class="headline-link" href="#metacharacters" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Characters that mean something other than themselves.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any single character except a newline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Zero or more of the item before it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[...]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any one character from the set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[^...]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any one character not in the set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;^&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start of the line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;End of the line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Escape a character or begin a special sequence, depending on the regex flavor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Most other characters match themselves. Line-based tools such as grep, sed, and awk read one line at a time, so &lt;code&gt;.&lt;/code&gt; never matches the line ending.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="anchors-and-word-boundaries"&gt;Anchors and Word Boundaries &lt;a class="headline-link" href="#anchors-and-word-boundaries" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Tie a pattern to a position instead of a character.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;^error&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Line starts with &lt;code&gt;error&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;done$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Line ends with &lt;code&gt;done&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;^exact$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Match the whole line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;^$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Match an empty line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\&amp;lt;word&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start of a word (GNU tools and Vim)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;word\&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;End of a word&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\bword\b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Word boundary on both sides (GNU and PCRE)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any position that is not a word boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Anchors match a position of zero width, so they never consume a character. In awk, &lt;code&gt;\b&lt;/code&gt; means a backspace rather than a word boundary; gawk provides &lt;code&gt;\y&lt;/code&gt; instead.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="bracket-expressions"&gt;Bracket Expressions &lt;a class="headline-link" href="#bracket-expressions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Match one character out of a set you define.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[abc]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, or &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[^abc]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any character except &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, or &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[a-z]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One lowercase letter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[0-9a-fA-F]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One hexadecimal digit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[]abc]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Include a literal &lt;code&gt;]&lt;/code&gt; by putting it first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[abc-]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Include a literal &lt;code&gt;-&lt;/code&gt; by putting it last&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[a^]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;^&lt;/code&gt; is literal when it is not first&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Most metacharacters lose their meaning inside brackets, so &lt;code&gt;[.*]&lt;/code&gt; matches a dot or an asterisk. Ranges follow the current locale, so use &lt;code&gt;LC_ALL=C&lt;/code&gt; or a POSIX class when you need predictable results.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="posix-character-classes"&gt;POSIX Character Classes &lt;a class="headline-link" href="#posix-character-classes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Portable, locale-aware sets that go inside a bracket expression.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Matches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[:digit:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Digits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[:alpha:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Letters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[:alnum:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Letters and digits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[:lower:]]&lt;/code&gt; &lt;code&gt;[[:upper:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lowercase and uppercase letters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[:space:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whitespace, including tabs and newlines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[:blank:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Spaces and tabs only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[:punct:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Punctuation characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[:xdigit:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hexadecimal digits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[:print:]]&lt;/code&gt; &lt;code&gt;[[:graph:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Printable, and printable except space&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[:cntrl:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Control characters&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The double brackets are not a typo. The class itself is &lt;code&gt;[:digit:]&lt;/code&gt;, and the outer brackets are the bracket expression that holds it, so &lt;code&gt;[[:digit:]_]&lt;/code&gt; matches a digit or an underscore.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="quantifiers"&gt;Quantifiers &lt;a class="headline-link" href="#quantifiers" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Say how many times the preceding item repeats.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Zero or more &lt;code&gt;a&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a\+&lt;/code&gt; / &lt;code&gt;a+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One or more, BRE and ERE forms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a\?&lt;/code&gt; / &lt;code&gt;a?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Zero or one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a\{3\}&lt;/code&gt; / &lt;code&gt;a{3}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exactly three&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a{3,}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Three or more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a{,3}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Up to three (GNU extension for &lt;code&gt;{0,3}&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a{2,4}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Between two and four&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any run of characters, including none&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Quantifiers are greedy and take the longest match available. In a basic regular expression, a &lt;code&gt;*&lt;/code&gt; at the very start of the pattern is a literal asterisk because there is nothing for it to repeat.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="groups-alternation-and-backreferences"&gt;Groups, Alternation, and Backreferences &lt;a class="headline-link" href="#groups-alternation-and-backreferences" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Treat several characters as one unit and reuse what they matched.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(ab)+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ERE group repeated one or more times&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\(ab\)\+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The same group in BRE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cat|dog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ERE alternation, either side matches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cat\|dog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The same alternation in GNU BRE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;^(a|b)c$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Alternation limited to the group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whatever group 1 matched&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\(.\)\1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any character repeated twice&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Groups are numbered from left to right by their opening parenthesis. Backreferences are part of POSIX BRE, and GNU grep and GNU sed also accept them in extended patterns. POSIX ERE and awk do not support backreferences. In a &lt;code&gt;sed&lt;/code&gt; replacement, &lt;code&gt;\1&lt;/code&gt; inserts group 1 and &lt;code&gt;&amp;amp;&lt;/code&gt; inserts the whole match.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="escaping-special-characters"&gt;Escaping Special Characters &lt;a class="headline-link" href="#escaping-special-characters" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Match a metacharacter as an ordinary character.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A literal dot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A literal backslash&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\*&lt;/code&gt; &lt;code&gt;\[&lt;/code&gt; &lt;code&gt;\^&lt;/code&gt; &lt;code&gt;\$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The literal symbol&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[.]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A dot, escaped by a bracket expression instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -F 'a.b'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Treat the whole pattern as a fixed string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\Q...\E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Quote a run of characters in PCRE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Quote patterns with single quotes so the shell passes the backslashes through untouched. Inside double quotes, the shell expands &lt;code&gt;$&lt;/code&gt; and consumes some backslashes before the tool ever sees the pattern.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="shorthand-classes"&gt;Shorthand Classes &lt;a class="headline-link" href="#shorthand-classes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Short names for common sets, provided as extensions rather than by POSIX.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Matches and Availability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\w&lt;/code&gt; &lt;code&gt;\W&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Word and non-word characters in GNU grep, GNU sed, gawk, PCRE, and Vim; the exact character set varies by engine and locale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\s&lt;/code&gt; &lt;code&gt;\S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whitespace and non-whitespace in GNU grep, GNU sed, gawk, PCRE, and Vim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\d&lt;/code&gt; &lt;code&gt;\D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Digits and non-digits in PCRE and Vim; not defined by POSIX BRE or ERE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\h&lt;/code&gt; &lt;code&gt;\v&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Horizontal and vertical whitespace in PCRE; Vim assigns different meanings to both sequences&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Do not use &lt;code&gt;\d&lt;/code&gt; with grep&amp;rsquo;s basic or extended syntax. GNU grep documents an escaped ordinary character such as &lt;code&gt;\d&lt;/code&gt; as unspecified, and other grep implementations may interpret it differently. Use &lt;code&gt;[[:digit:]]&lt;/code&gt;, &lt;code&gt;[0-9]&lt;/code&gt;, or &lt;code&gt;grep -P&lt;/code&gt; instead.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="pcre-extras"&gt;PCRE Extras &lt;a class="headline-link" href="#pcre-extras" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Available with &lt;code&gt;grep -P&lt;/code&gt; and other Perl-compatible engines.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.*?&lt;/code&gt; &lt;code&gt;+?&lt;/code&gt; &lt;code&gt;??&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lazy quantifiers that take the shortest match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(?:...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Group without capturing it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(?&amp;lt;name&amp;gt;...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Named capture group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(?=...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lookahead, text must follow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(?!...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Negative lookahead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(?&amp;lt;=...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lookbehind, text must precede&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(?&amp;lt;!...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Negative lookbehind&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(?i)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Case-insensitive from this point on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\K&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Drop everything matched so far from the result&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Lookarounds check their surroundings without adding them to the match, which pairs well with &lt;code&gt;grep -oP&lt;/code&gt;. None of this works in sed or awk, and &lt;code&gt;grep -P&lt;/code&gt; needs a build with PCRE support.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="bre-ere-and-pcre"&gt;BRE, ERE, and PCRE &lt;a class="headline-link" href="#bre-ere-and-pcre" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The same idea written three ways.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Syntax by Flavor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Grouping&lt;/td&gt;
&lt;td&gt;BRE &lt;code&gt;\(ab\)&lt;/code&gt;; ERE and PCRE &lt;code&gt;(ab)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alternation&lt;/td&gt;
&lt;td&gt;GNU BRE &lt;code&gt;a\|b&lt;/code&gt;; ERE and PCRE &lt;code&gt;a|b&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One or more&lt;/td&gt;
&lt;td&gt;GNU BRE &lt;code&gt;a\+&lt;/code&gt;; ERE and PCRE &lt;code&gt;a+&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;GNU BRE &lt;code&gt;a\?&lt;/code&gt;; ERE and PCRE &lt;code&gt;a?&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interval&lt;/td&gt;
&lt;td&gt;BRE &lt;code&gt;a\{2,4\}&lt;/code&gt;; ERE and PCRE &lt;code&gt;a{2,4}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backreference&lt;/td&gt;
&lt;td&gt;BRE and PCRE &lt;code&gt;\1&lt;/code&gt;; GNU grep and GNU sed also accept &lt;code&gt;\1&lt;/code&gt; in ERE, but POSIX ERE and awk do not&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\d&lt;/code&gt; and lookaround&lt;/td&gt;
&lt;td&gt;PCRE supports both; BRE and ERE do not&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default in&lt;/td&gt;
&lt;td&gt;BRE: &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;; ERE: &lt;code&gt;grep -E&lt;/code&gt;, &lt;code&gt;sed -E&lt;/code&gt;, awk; PCRE: &lt;code&gt;grep -P&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In GNU grep, BRE and ERE provide the same pattern-matching functionality with different notation. The characters &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;()&lt;/code&gt;, &lt;code&gt;{}&lt;/code&gt;, and &lt;code&gt;|&lt;/code&gt; are special without backslashes in ERE and with backslashes in GNU BRE. This equivalence does not extend to POSIX ERE backreferences or PCRE-only features.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="regex-in-grep"&gt;Regex in grep &lt;a class="headline-link" href="#regex-in-grep" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Pick the flavor with a flag.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-use-grep-command-to-search-files-in-linux/"&gt;&lt;code&gt;grep 'pattern' file&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Basic regular expression, the default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/regular-expressions-in-grep/"&gt;&lt;code&gt;grep -E 'pattern' file&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Extended regular expression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -P 'pattern' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Perl-compatible regular expression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -F 'pattern' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No regex at all, fixed string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -o 'pattern' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print only the matched text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -w 'pattern' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Require word boundaries around the match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -i 'pattern' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ignore case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -v 'pattern' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the lines that do not match&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use &lt;code&gt;-o&lt;/code&gt; while building a pattern to see exactly what it captures. GNU grep 3.8 and later print a warning for &lt;code&gt;egrep&lt;/code&gt; and &lt;code&gt;fgrep&lt;/code&gt;, so write &lt;code&gt;grep -E&lt;/code&gt; and &lt;code&gt;grep -F&lt;/code&gt; instead.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="regex-in-sed"&gt;Regex in sed &lt;a class="headline-link" href="#regex-in-sed" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Patterns select lines, and the same syntax drives substitutions.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-use-sed-to-find-and-replace-string-in-files/"&gt;&lt;code&gt;sed 's/old/new/' file&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Substitute using a basic regular expression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sed -E 's/[0-9]+/N/g' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extended syntax, with &lt;code&gt;-r&lt;/code&gt; as a synonym&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sed -n '/error/p' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print only matching lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/sed-delete-lines/"&gt;&lt;code&gt;sed '/^$/d' file&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Delete every empty line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sed 's/\(a\)\(b\)/\2\1/' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Swap two captured groups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sed 's/word/[&amp;amp;]/' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wrap the whole match in brackets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sed 's/error/ERROR/gI' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace every match, ignoring case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sed -E 's/(\w+)/\U\1/' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Uppercase group 1 with a GNU escape&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The delimiter does not have to be a slash. Writing &lt;code&gt;sed 's|/usr/bin|/usr/local/bin|'&lt;/code&gt; avoids escaping every slash in a path.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="regex-in-awk"&gt;Regex in awk &lt;a class="headline-link" href="#regex-in-awk" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Patterns are extended regular expressions and sit between slashes.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/awk-command/"&gt;&lt;code&gt;awk '/error/' file&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Print lines matching the pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;awk '$1 ~ /^web/' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Match a single field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;awk '$3 !~ /ok/' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Match fields that fail the pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;awk '/start/,/stop/' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print an inclusive range of lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;awk '{ gsub(/[0-9]+/, &amp;quot;N&amp;quot;); print }' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace every match on the line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;awk '{ sub(/^ +/, &amp;quot;&amp;quot;); print }' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace the first match only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;awk 'match($0, /[0-9]+/) { print substr($0, RSTART, RLENGTH) }' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Locate a match and extract it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gawk '{ gsub(/\yroot\y/, &amp;quot;USER&amp;quot;); print }' file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Word boundaries in gawk&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Awk always uses extended syntax, so &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, and &lt;code&gt;{n,m}&lt;/code&gt; work without a backslash. When the pattern is a string rather than a &lt;code&gt;/.../&lt;/code&gt; literal, every backslash needs doubling, so &lt;code&gt;gsub(/\./, &amp;quot;-&amp;quot;)&lt;/code&gt; becomes &lt;code&gt;gsub(&amp;quot;\\.&amp;quot;, &amp;quot;-&amp;quot;)&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="regex-in-vim"&gt;Regex in Vim &lt;a class="headline-link" href="#regex-in-vim" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Vim uses its own flavor, close to ERE once you turn on very magic mode.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/vim-search/"&gt;&lt;code&gt;/pattern&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Search forward in the file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/vim-find-replace/"&gt;&lt;code&gt;:%s/old/new/g&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Replace every match in the file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a\+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One or more, since &lt;code&gt;+&lt;/code&gt; needs a backslash by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\v&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Very magic mode, so &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;(&lt;/code&gt;, and &lt;code&gt;|&lt;/code&gt; work unescaped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\v\d+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Digits in very magic mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\&amp;lt;word\&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whole word match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;price: \zs\d\+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start the match after &lt;code&gt;\zs&lt;/code&gt;, end it at &lt;code&gt;\ze&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\cerror&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ignore case for this pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Very magic mode is the shortcut worth remembering. Writing &lt;code&gt;:%s/\v(\w+), (\w+)/\2 \1/g&lt;/code&gt; to swap two fields keeps a pattern readable instead of filling it with backslashes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="regex-in-bash"&gt;Regex in Bash &lt;a class="headline-link" href="#regex-in-bash" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;=~&lt;/code&gt; operator inside &lt;code&gt;[[ ]]&lt;/code&gt; takes an extended regular expression.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Snippet&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[ $ip =~ ^[0-9.]+$ ]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Test a string against a pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[ ! $name =~ ^[a-z] ]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Negate the test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;re='^v([0-9]+)\.([0-9]+)$'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep the pattern in a variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[[ $tag =~ $re ]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use the variable unquoted so it stays a regex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${BASH_REMATCH[0]}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The whole match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${BASH_REMATCH[1]}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The first capture group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/bash-case-statement/"&gt;&lt;code&gt;case $file in *.txt) ;; esac&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;A reminder that &lt;code&gt;case&lt;/code&gt; uses globs, not regex&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Quoting the right-hand side turns the pattern into a literal string, so &lt;code&gt;[[ abc =~ &amp;quot;a.c&amp;quot; ]]&lt;/code&gt; fails while &lt;code&gt;[[ abc =~ a.c ]]&lt;/code&gt; succeeds. Store the pattern in a variable when it contains spaces or quotes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="common-patterns"&gt;Common Patterns &lt;a class="headline-link" href="#common-patterns" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Working starting points to copy and adjust.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Matches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -E '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Anything shaped like an IPv4 address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -P '\b((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\b'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An IPv4 candidate with each octet under 256&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -E '[[:alnum:]._%+-]+@[[:alnum:].-]+\.[[:alpha:]]{2,}'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An email-shaped address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -E '[0-9]{4}-[0-9]{2}-[0-9]{2}'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An ISO date such as &lt;code&gt;2026-08-28&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -E '#[0-9a-fA-F]{6}\b'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A six-digit hex color&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -nE '[[:space:]]+$'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Trailing whitespace, with line numbers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -cE '^[[:space:]]*$'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Count blank lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -E '^[[:space:]]*#'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Commented-out configuration lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -vE '^[[:space:]]*(#|$)'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Everything except comments and blank lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -E '\b([[:alpha:]]+) \1\b'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A word accidentally repeated twice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -oE '&amp;quot;[^&amp;quot;]*&amp;quot;'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A double-quoted string, quotes included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -oP 'user=\K\S+'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The value after a &lt;code&gt;user=&lt;/code&gt; key, key excluded&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The address patterns describe a shape rather than validate it. Use them to pull candidates out of logs, and check the results with a real parser when correctness matters.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Common regex problems and what to check first.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\d&lt;/code&gt; fails or behaves unexpectedly&lt;/td&gt;
&lt;td&gt;BRE and ERE do not define &lt;code&gt;\d&lt;/code&gt;; use &lt;code&gt;[[:digit:]]&lt;/code&gt;, &lt;code&gt;[0-9]&lt;/code&gt;, or &lt;code&gt;grep -P&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt; or &lt;code&gt;?&lt;/code&gt; matched literally&lt;/td&gt;
&lt;td&gt;The pattern is basic syntax; escape them as &lt;code&gt;\+&lt;/code&gt; and &lt;code&gt;\?&lt;/code&gt;, or switch to &lt;code&gt;grep -E&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alternation found nothing&lt;/td&gt;
&lt;td&gt;ERE takes a bare pipe, BRE takes an escaped one; &lt;code&gt;grep -E&lt;/code&gt; is the simpler fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The shell changed the pattern&lt;/td&gt;
&lt;td&gt;Wrap the pattern in single quotes so backslashes and &lt;code&gt;$&lt;/code&gt; survive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[a-z]&lt;/code&gt; also matched uppercase&lt;/td&gt;
&lt;td&gt;Range order follows the locale; use &lt;code&gt;LC_ALL=C&lt;/code&gt; or &lt;code&gt;[[:lower:]]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lookahead or lookbehind rejected&lt;/td&gt;
&lt;td&gt;BRE and ERE do not support them; use &lt;code&gt;grep -P&lt;/code&gt;, or the engine&amp;rsquo;s own syntax such as Vim&amp;rsquo;s &lt;code&gt;\@=&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -P&lt;/code&gt; is not supported&lt;/td&gt;
&lt;td&gt;The build lacks PCRE; use &lt;code&gt;pcre2grep&lt;/code&gt;, &lt;code&gt;perl -ne&lt;/code&gt;, or rewrite the pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\b&lt;/code&gt; did nothing in awk&lt;/td&gt;
&lt;td&gt;Awk reads &lt;code&gt;\b&lt;/code&gt; as a backspace; use &lt;code&gt;\y&lt;/code&gt; in gawk or &lt;code&gt;\&amp;lt;&lt;/code&gt; and &lt;code&gt;\&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The match ran too far&lt;/td&gt;
&lt;td&gt;Quantifiers are greedy; use a negated class such as &lt;code&gt;[^&amp;quot;]*&lt;/code&gt;, or a lazy &lt;code&gt;.*?&lt;/code&gt; with &lt;code&gt;-P&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intervals matched literally in Vim&lt;/td&gt;
&lt;td&gt;Vim needs &lt;code&gt;\{2,4}&lt;/code&gt; in magic mode, or &lt;code&gt;\v&lt;/code&gt; first&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Longer walkthroughs and per-tool references.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/regular-expressions-basics/"&gt;Regular Expressions Basics&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Learn the building blocks from the ground up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/regular-expressions-in-grep/"&gt;Regular Expressions in Grep&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Every grep flavor with worked examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/grep/"&gt;grep Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Search options, recursion, and context output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/sed/"&gt;sed Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Substitution, addresses, and in-place editing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/awk/"&gt;awk Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Fields, patterns, actions, and built-in variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/vim/"&gt;Vim Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Motions, editing, search, and replace&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>parted Cheatsheet</title><link>https://linuxize.com/cheatsheet/parted/</link><pubDate>Tue, 25 Aug 2026 18:50:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/parted/</guid><description>Quick reference for parted commands: inspect disks, create GPT and MBR tables, add aligned partitions, manage flags, resize boundaries, and remove partitions safely</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="basic-usage"&gt;Basic Usage &lt;a class="headline-link" href="#basic-usage" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Core command forms and help options.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;parted [OPTIONS] DEVICE [COMMAND [ARGUMENTS]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;General syntax&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/parted-command-in-linux/"&gt;&lt;code&gt;sudo parted /dev/sdX&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Open a disk in interactive mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX -- print&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print one disk&amp;rsquo;s partition table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List partition tables on all detected disks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;parted --help&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show command-line options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;parted --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the installed version&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Always pass the whole-disk path explicitly. Most &lt;code&gt;parted&lt;/code&gt; changes take effect immediately, even in interactive mode.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="identify-the-target-disk"&gt;Identify the Target Disk &lt;a class="headline-link" href="#identify-the-target-disk" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Confirm the device name, size, model, and current use before changing it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lsblk -d -o NAME,SIZE,MODEL,TRAN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List whole disks with identifying details&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show disks, partitions, filesystems, and mounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lsblk -f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show filesystem labels and UUIDs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;findmnt -S /dev/sdX1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check whether a partition is mounted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX -- print&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Review the current partition table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX -- unit MiB print free&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show partitions and unallocated space&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use &lt;code&gt;/dev/sdX&lt;/code&gt; for the whole disk and &lt;code&gt;/dev/sdX1&lt;/code&gt; for its first partition. NVMe and eMMC disks insert &lt;code&gt;p&lt;/code&gt; before the number, so partition 1 of &lt;code&gt;/dev/nvme0n1&lt;/code&gt; is &lt;code&gt;/dev/nvme0n1p1&lt;/code&gt;. The &lt;code&gt;MOUNTPOINTS&lt;/code&gt; column needs util-linux 2.37 or later; use &lt;code&gt;MOUNTPOINT&lt;/code&gt; on older releases. Replace every placeholder with a verified device path.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="command-line-options"&gt;Command-Line Options &lt;a class="headline-link" href="#command-line-options" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Options must appear before the device and session command.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-l&lt;/code&gt;, &lt;code&gt;--list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List partition layouts on all block devices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-s&lt;/code&gt;, &lt;code&gt;--script&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Never prompt for input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-m&lt;/code&gt;, &lt;code&gt;--machine&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print colon-separated, machine-readable output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-j&lt;/code&gt;, &lt;code&gt;--json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print JSON output on supported versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-f&lt;/code&gt;, &lt;code&gt;--fix&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatically choose &lt;code&gt;fix&lt;/code&gt; for repairable exceptions in script mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-a optimal&lt;/code&gt;, &lt;code&gt;--align optimal&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use optimal alignment for new partitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;End option parsing before session commands and negative positions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Script mode is not a dry run. Inspect the disk separately before using &lt;code&gt;--script&lt;/code&gt; or &lt;code&gt;--fix&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="interactive-commands"&gt;Interactive Commands &lt;a class="headline-link" href="#interactive-commands" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Enter these commands at the &lt;code&gt;(parted)&lt;/code&gt; prompt.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;help&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List available session commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;help mkpart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show help for one command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;print&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the current partition table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;print free&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Include unallocated space&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unit MiB&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the default display and input unit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;select /dev/sdY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Switch to another disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exit Parted&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;quit&lt;/code&gt; command does not undo earlier changes because Parted writes most changes as each command runs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="create-a-partition-table"&gt;Create a Partition Table &lt;a class="headline-link" href="#create-a-partition-table" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a disk label on a new or intentionally cleared disk.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- mklabel gpt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a GPT partition table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- mklabel msdos&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create an MBR partition table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX -- print&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Confirm the new table type&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;mklabel&lt;/code&gt; replaces the existing partition table and makes its partitions inaccessible. Use GPT for current systems; use MBR only when legacy compatibility requires it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="create-gpt-partitions"&gt;Create GPT Partitions &lt;a class="headline-link" href="#create-gpt-partitions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Give each GPT partition a name, filesystem type hint, start, and end.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- mkpart data ext4 1MiB 100%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create one partition using the available disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- mkpart data ext4 1MiB 50GiB&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a partition ending at 50 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- mkpart backup ext4 50GiB 100%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use the remaining space for a second partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX -- print&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Review the finished layout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX -- align-check optimal 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check partition 1 alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The filesystem type is a partition-table hint. &lt;code&gt;mkpart&lt;/code&gt; does not create a filesystem.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="create-mbr-partitions"&gt;Create MBR Partitions &lt;a class="headline-link" href="#create-mbr-partitions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An MBR table takes a partition type where GPT takes a name.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- mkpart primary ext4 1MiB 100%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create one primary partition using the available disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- mkpart primary ext4 1MiB 50GiB&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a primary partition ending at 50 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- mkpart primary ext4 50GiB 100%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a second primary partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- mkpart extended 50GiB 100%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create an extended partition to hold logical partitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- mkpart logical ext4 51GiB 100%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a logical partition inside the extended partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX -- print&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Review the finished layout&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;An MBR table holds four primary partitions, or three primary partitions plus one extended partition that contains the logical ones. Start the first logical partition after the extended partition&amp;rsquo;s start so Parted can write the extended boot record. The &lt;code&gt;name&lt;/code&gt; command does not work on MBR partitions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="units-and-positions"&gt;Units and Positions &lt;a class="headline-link" href="#units-and-positions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Suffix boundary values so Parted does not have to infer the unit.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sectors, used for exact sector positions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MiB&lt;/code&gt;, &lt;code&gt;GiB&lt;/code&gt;, &lt;code&gt;TiB&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exact IEC binary positions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MB&lt;/code&gt;, &lt;code&gt;GB&lt;/code&gt;, &lt;code&gt;TB&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Decimal positions that may allow a nearby boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1MiB&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Common aligned start for a new partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;100%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;End at the last usable part of the disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-1s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Last sector of the disk; put &lt;code&gt;--&lt;/code&gt; before the command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX -- unit s print&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Display all boundaries in sectors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use &lt;code&gt;MiB&lt;/code&gt; or &lt;code&gt;GiB&lt;/code&gt; for repeatable commands and &lt;code&gt;unit MiB print free&lt;/code&gt; when comparing boundaries.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="partition-names-and-flags"&gt;Partition Names and Flags &lt;a class="headline-link" href="#partition-names-and-flags" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Names and available flags depend on the partition table type.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- name 1 data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rename GPT partition 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- set 1 esp on&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mark an EFI System Partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- set 1 bios_grub on&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mark a BIOS GRUB partition on GPT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- set 1 swap on&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mark a swap partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- set 1 lvm on&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mark an LVM physical volume where supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- set 1 raid on&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mark a software RAID member where supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- set 1 FLAG off&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Disable a flag&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Run &lt;code&gt;help set&lt;/code&gt; interactively to see the flags supported by the current table. Flags record a partition&amp;rsquo;s purpose but do not create an EFI filesystem, swap area, LVM volume, or RAID array.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="resize-a-partition-boundary"&gt;Resize a Partition Boundary &lt;a class="headline-link" href="#resize-a-partition-boundary" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Confirm that free space is adjacent to the partition before extending it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX -- unit MiB print free&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check the partition and adjacent free space&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- resizepart 1 100%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Move partition 1&amp;rsquo;s end to the end of the disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo partprobe /dev/sdX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ask the kernel to reread the partition table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo resize2fs /dev/sdX1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Grow an ext2, ext3, or ext4 filesystem afterward&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo xfs_growfs /mount/point&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Grow a mounted XFS filesystem afterward&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lsblk -f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check the resulting partition and filesystem size&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;resizepart&lt;/code&gt; changes only the partition boundary. When shrinking, shrink the filesystem first and use a filesystem-specific procedure.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="remove-or-rescue-a-partition"&gt;Remove or Rescue a Partition &lt;a class="headline-link" href="#remove-or-rescue-a-partition" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Keep inspection and removal as separate commands.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX -- print&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Note the target partition number and boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdX -- rm 2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove partition 2 immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open interactive mode for recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rescue START END&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Search near the old boundaries for a lost partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo partprobe /dev/sdX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ask the kernel to reread the changed table&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;After an accidental removal, stop writing to the disk and try &lt;code&gt;rescue&lt;/code&gt; before creating another partition. Recovery is not guaranteed.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="format-and-mount"&gt;Format and Mount &lt;a class="headline-link" href="#format-and-mount" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a filesystem only after checking the new partition path.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lsblk -f /dev/sdX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Confirm the new partition and existing filesystems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mkfs.ext4 -L data /dev/sdX1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create an ext4 filesystem with label &lt;code&gt;data&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mkfs.xfs -L data /dev/sdX1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create an XFS filesystem with label &lt;code&gt;data&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mkswap -L swap /dev/sdX2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create swap space on partition 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mkdir -p /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a mount point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount /dev/sdX1 /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount the new filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lsblk -f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Confirm filesystem and mount details&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Formatting destroys data on the selected partition. A partition name and a filesystem label are separate values.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Common Parted problems and the next check to run.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Partition is not aligned&lt;/td&gt;
&lt;td&gt;Run &lt;code&gt;align-check optimal NUMBER&lt;/code&gt;; recreate an empty partition with a suitable start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kernel still shows the old table&lt;/td&gt;
&lt;td&gt;Unmount filesystems, disable swap, then run &lt;code&gt;sudo partprobe /dev/sdX&lt;/code&gt; or reboot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Device or resource is busy&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;lsblk&lt;/code&gt;, &lt;code&gt;findmnt&lt;/code&gt;, swap, LVM, RAID, and encrypted mappings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New partition does not appear&lt;/td&gt;
&lt;td&gt;Run &lt;code&gt;sudo partprobe /dev/sdX&lt;/code&gt;, then check &lt;code&gt;lsblk&lt;/code&gt;; reboot if the disk remains busy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unrecognised disk label&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The disk has no supported table; verify it is the correct empty disk before using &lt;code&gt;mklabel&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mkpart&lt;/code&gt; rejects the partition name&lt;/td&gt;
&lt;td&gt;The disk uses an MBR table; pass &lt;code&gt;primary&lt;/code&gt;, &lt;code&gt;extended&lt;/code&gt;, or &lt;code&gt;logical&lt;/code&gt; instead of a name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filesystem size did not change&lt;/td&gt;
&lt;td&gt;Run the correct filesystem grow command after &lt;code&gt;resizepart&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use these guides and cheatsheets for the complete storage workflow.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/parted-command-in-linux/"&gt;parted Command in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Full walkthrough for inspecting and changing partitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/linux-block-devices-partitions-filesystems/"&gt;Linux Block Devices, Partitions, Filesystems, and Mount Points&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Understand where partitioning fits in the storage stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/fdisk/"&gt;fdisk Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Menu-driven partitioning command reference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/mount/"&gt;mount Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Mount options, UUIDs, labels, and &lt;code&gt;/etc/fstab&lt;/code&gt; entries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>parted Command in Linux: Manage Disk Partitions</title><link>https://linuxize.com/post/parted-command-in-linux/</link><pubDate>Mon, 24 Aug 2026 20:40:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/parted-command-in-linux/</guid><category>disk</category><category>linux commands</category><description>Use the parted command to inspect disks, create GPT partition tables, add aligned partitions, resize boundaries, and remove partitions safely on Linux.</description><content:encoded>&lt;p&gt;When a new disk appears in &lt;code&gt;lsblk&lt;/code&gt;, it is visible to Linux but still has nowhere to store files. The disk needs a partition table and at least one partition before you create a filesystem and mount it. The &lt;code&gt;parted&lt;/code&gt; command manages those boundaries from the terminal, works with both GPT and MBR tables, and can run interactively or from a script.&lt;/p&gt;
&lt;p&gt;Unlike &lt;code&gt;fdisk&lt;/code&gt;, which stages changes until you write the table, &lt;code&gt;parted&lt;/code&gt; applies most commands immediately. This guide explains how to inspect a disk, create a GPT partition table, add aligned partitions, resize a partition boundary, and remove a partition without losing track of which storage layer you are changing.&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;Partitioning the wrong disk can make its data inaccessible. Before every write operation, confirm the device with &lt;a href="https://linuxize.com/post/lsblk-command-in-linux/" target="_blank" rel="noopener noreferrer"&gt;&lt;code&gt;lsblk&lt;/code&gt;&lt;/a&gt;
, use the whole-disk name such as &lt;code&gt;/dev/sdb&lt;/code&gt; rather than a partition such as &lt;code&gt;/dev/sdb1&lt;/code&gt;, and keep a current backup of any disk that holds data.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="parted-command-syntax"&gt;parted Command Syntax &lt;a class="headline-link" href="#parted-command-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The general form of the command is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;parted [OPTIONS] [DEVICE [COMMAND [ARGUMENTS]]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Always pass the device explicitly. If you omit it, &lt;code&gt;parted&lt;/code&gt; tries to choose a device, which is not a risk worth taking on a machine with several disks.&lt;/p&gt;
&lt;p&gt;The options you will use most often are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt;, &lt;code&gt;--list&lt;/code&gt; - List partition layouts on all detected block devices.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt;, &lt;code&gt;--script&lt;/code&gt; - Never prompt for input. Use this only after validating the device and command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt;, &lt;code&gt;--machine&lt;/code&gt; - Produce colon-separated output for scripts.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-j&lt;/code&gt;, &lt;code&gt;--json&lt;/code&gt; - Produce JSON output on versions that support it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt;, &lt;code&gt;--align&lt;/code&gt; - Choose the alignment type for newly created partitions. The default is &lt;code&gt;optimal&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The examples place options before the device and put &lt;code&gt;--&lt;/code&gt; before the parted command. The separator matters when an argument begins with a dash, such as the &lt;code&gt;-1s&lt;/code&gt; end position that means the last sector of the disk. Without it, &lt;code&gt;parted&lt;/code&gt; reads &lt;code&gt;-1s&lt;/code&gt; as an invalid option instead of a position.&lt;/p&gt;
&lt;h2 id="installing-parted"&gt;Installing parted &lt;a class="headline-link" href="#installing-parted" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most distributions include &lt;code&gt;parted&lt;/code&gt;. If the command is missing, install it with your distribution package manager.&lt;/p&gt;
&lt;p&gt;On Ubuntu, Debian, and Derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install parted&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On Fedora, RHEL, and Derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install parted&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Confirm the installed version before continuing:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;parted --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="listing-disks-and-free-space"&gt;Listing Disks and Free Space &lt;a class="headline-link" href="#listing-disks-and-free-space" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start with &lt;code&gt;lsblk&lt;/code&gt; so you can match each device name to its size, model, filesystem, and mount points:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A row with &lt;code&gt;TYPE&lt;/code&gt; set to &lt;code&gt;disk&lt;/code&gt; is a whole device, while rows marked &lt;code&gt;part&lt;/code&gt; are partitions. Confirm the size and model instead of relying on a name such as &lt;code&gt;/dev/sdb&lt;/code&gt;, since device names can change between boots.&lt;/p&gt;
&lt;p&gt;Next, list the partition table on every detected disk:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Model: ATA Samsung SSD 870 (scsi)
Disk /dev/sda: 500GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 538MB 537MB fat32 EFI System Partition boot, esp
2 538MB 500GB 500GB ext4&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Partition Table&lt;/code&gt; line identifies the layout as &lt;code&gt;gpt&lt;/code&gt; or &lt;code&gt;msdos&lt;/code&gt; (MBR). The partition rows show the boundaries, detected filesystem, GPT name, and any flags.&lt;/p&gt;
&lt;p&gt;To inspect one disk in MiB and include its unallocated regions, use &lt;code&gt;unit MiB&lt;/code&gt; followed by &lt;code&gt;print free&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted /dev/sdb -- unit MiB print free&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Model: QEMU QEMU HARDDISK (scsi)
Disk /dev/sdb: 102400MiB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
0.02MiB 1.00MiB 0.98MiB Free Space
1 1.00MiB 51200MiB 51199MiB ext4 data
51200MiB 102400MiB 51200MiB Free Space&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Rows without a number are unallocated regions. The small gap at the start of the disk holds the GPT header, while the 51200MiB region after partition 1 is space available for a new partition. This read-only command is the one to run before creating or extending a partition, since it shows whether free space exists and on which side of the existing partitions it sits.&lt;/p&gt;
&lt;p&gt;On parted 3.4 and later, &lt;code&gt;--json&lt;/code&gt; returns the same layout as structured data for scripts:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --json /dev/sdb -- unit MiB print&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;{
&amp;#34;disk&amp;#34;: {
&amp;#34;path&amp;#34;: &amp;#34;/dev/sdb&amp;#34;,
&amp;#34;size&amp;#34;: &amp;#34;102400MiB&amp;#34;,
&amp;#34;model&amp;#34;: &amp;#34;QEMU QEMU HARDDISK (scsi)&amp;#34;,
&amp;#34;transport&amp;#34;: &amp;#34;scsi&amp;#34;,
&amp;#34;logical-sector-size&amp;#34;: 512,
&amp;#34;physical-sector-size&amp;#34;: 512,
&amp;#34;label&amp;#34;: &amp;#34;gpt&amp;#34;,
&amp;#34;max-partitions&amp;#34;: 128,
&amp;#34;partitions&amp;#34;: [
{
&amp;#34;number&amp;#34;: 1,
&amp;#34;start&amp;#34;: &amp;#34;1.00MiB&amp;#34;,
&amp;#34;end&amp;#34;: &amp;#34;51200MiB&amp;#34;,
&amp;#34;size&amp;#34;: &amp;#34;51199MiB&amp;#34;,
&amp;#34;name&amp;#34;: &amp;#34;data&amp;#34;,
&amp;#34;filesystem&amp;#34;: &amp;#34;ext4&amp;#34;
}
]
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pipe that into &lt;code&gt;jq&lt;/code&gt; when a script needs a single value, such as &lt;code&gt;jq -r '.disk.partitions[].size'&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can also open an interactive session by passing only the device:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted /dev/sdb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;GNU Parted 3.7
Using /dev/sdb
Welcome to GNU Parted! Type &amp;#39;help&amp;#39; to view a list of commands.
(parted)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At the &lt;code&gt;(parted)&lt;/code&gt; prompt, enter commands such as &lt;code&gt;print&lt;/code&gt;, &lt;code&gt;mkpart&lt;/code&gt;, and &lt;code&gt;quit&lt;/code&gt;. The remaining examples use command-line mode so each operation and its target are visible in one copy-pasteable command.&lt;/p&gt;
&lt;h2 id="creating-a-gpt-partition-table"&gt;Creating a GPT Partition Table &lt;a class="headline-link" href="#creating-a-gpt-partition-table" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A new disk needs a partition table before it can hold partitions. GPT is the standard choice for current systems and is required when an MBR table with 512-byte sectors would exceed its 2 TiB addressing limit.&lt;/p&gt;
&lt;p&gt;Run the inspection command again immediately before creating the table:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL /dev/sdb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Once &lt;code&gt;/dev/sdb&lt;/code&gt; is confirmed as the intended disk, create the GPT label:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --script /dev/sdb -- mklabel gpt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This replaces the existing partition table and makes its old partitions inaccessible. The &lt;code&gt;--script&lt;/code&gt; option suppresses prompts; it is not a dry run and does not make the operation safer. Use &lt;code&gt;mklabel msdos&lt;/code&gt; only when you specifically need an MBR table for legacy compatibility.&lt;/p&gt;
&lt;h2 id="creating-an-aligned-partition"&gt;Creating an Aligned Partition &lt;a class="headline-link" href="#creating-an-aligned-partition" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;mkpart&lt;/code&gt; command takes a GPT partition name, a filesystem type hint, and the start and end positions. To create one data partition that fills the usable disk space, run:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --script /dev/sdb -- mkpart data ext4 1MiB 100%&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The name is &lt;code&gt;data&lt;/code&gt;, and &lt;code&gt;ext4&lt;/code&gt; sets the intended partition type. It does not create an ext4 filesystem. Starting at &lt;code&gt;1MiB&lt;/code&gt; leaves room for the GPT metadata and gives the partition a common aligned starting point; &lt;code&gt;100%&lt;/code&gt; extends it to the last usable part of the disk.&lt;/p&gt;
&lt;p&gt;For two partitions, give each one its own range. This example creates a 50 GiB data partition and uses the remaining space for backups:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --script /dev/sdb -- mkpart data ext4 1MiB 50GiB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --script /dev/sdb -- mkpart backup ext4 50GiB 100%&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;IEC units such as &lt;code&gt;MiB&lt;/code&gt; and &lt;code&gt;GiB&lt;/code&gt; identify exact positions. Decimal units such as &lt;code&gt;MB&lt;/code&gt; and &lt;code&gt;GB&lt;/code&gt; allow &lt;code&gt;parted&lt;/code&gt; to choose a nearby position, so explicit IEC units are easier to reason about in repeatable commands.&lt;/p&gt;
&lt;p&gt;Print the finished layout:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted /dev/sdb -- unit MiB print free&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then check the alignment of partition 1:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted /dev/sdb -- align-check optimal &lt;span class="m"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;1 aligned&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The alignment check confirms that the partition starts on a boundary suited to the device. If it reports &lt;code&gt;not aligned&lt;/code&gt;, recreate an empty partition with a suitable start position before writing data to it.&lt;/p&gt;
&lt;p&gt;The new partition still has no filesystem. After verifying that &lt;code&gt;/dev/sdb1&lt;/code&gt; is the new empty partition, format it separately:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkfs.ext4 -L data /dev/sdb1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-L data&lt;/code&gt; option assigns a filesystem label, which is separate from the GPT partition name. Follow the &lt;a href="https://linuxize.com/post/how-to-mount-and-unmount-file-systems-in-linux/"&gt;mount and unmount guide&lt;/a&gt;
when you are ready to attach the filesystem to the directory tree.&lt;/p&gt;
&lt;h2 id="renaming-a-gpt-partition"&gt;Renaming a GPT Partition &lt;a class="headline-link" href="#renaming-a-gpt-partition" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;GPT stores a human-readable name for each partition. To rename partition 1 without changing its filesystem label, use the &lt;code&gt;name&lt;/code&gt; command:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --script /dev/sdb -- name &lt;span class="m"&gt;1&lt;/span&gt; archive&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Run &lt;code&gt;print&lt;/code&gt; afterward to confirm the new value in the &lt;code&gt;Name&lt;/code&gt; column. Partition names are available with GPT and several other table formats, but not with an MBR table.&lt;/p&gt;
&lt;h2 id="setting-partition-flags"&gt;Setting Partition Flags &lt;a class="headline-link" href="#setting-partition-flags" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Flags mark what a partition is for so that firmware and other tools treat it correctly. The &lt;code&gt;set&lt;/code&gt; command takes the partition number, the flag name, and &lt;code&gt;on&lt;/code&gt; or &lt;code&gt;off&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --script /dev/sdb -- &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; esp on&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The flags you will use most often on a GPT disk are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;esp&lt;/code&gt; - Mark the partition as an EFI System Partition. On GPT, &lt;code&gt;boot&lt;/code&gt; and &lt;code&gt;esp&lt;/code&gt; are the same flag.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bios_grub&lt;/code&gt; - Mark the small unformatted partition that GRUB needs to boot a GPT disk on BIOS firmware.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lvm&lt;/code&gt; - Mark the partition as an LVM physical volume.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;raid&lt;/code&gt; - Mark the partition as a software RAID member.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msftdata&lt;/code&gt; - Mark the partition as Microsoft basic data, which is the type Windows expects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Turn a flag off by passing &lt;code&gt;off&lt;/code&gt; instead:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --script /dev/sdb -- &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; lvm off&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Flags record intent and set the GPT partition type, but they create nothing. Setting &lt;code&gt;lvm&lt;/code&gt; does not run &lt;code&gt;pvcreate&lt;/code&gt;, and setting &lt;code&gt;esp&lt;/code&gt; does not put a FAT32 filesystem on the partition. To see which flags the current table supports, open an interactive session and run &lt;code&gt;help set&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="resizing-a-partition"&gt;Resizing a Partition &lt;a class="headline-link" href="#resizing-a-partition" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before extending a partition, use &lt;code&gt;print free&lt;/code&gt; to confirm that unallocated space begins directly after it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted /dev/sdb -- unit MiB print free&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If partition 1 is followed by free space, move its end boundary to the end of the disk:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --script /dev/sdb -- resizepart &lt;span class="m"&gt;1&lt;/span&gt; 100%&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;resizepart&lt;/code&gt; command changes only the partition boundary. It does not resize the filesystem inside. For an ext4 filesystem, grow the filesystem afterward:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo resize2fs /dev/sdb1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;a href="https://linuxize.com/post/how-to-check-disk-space-in-linux-using-the-df-command/"&gt;&lt;code&gt;df&lt;/code&gt;&lt;/a&gt;
to confirm the filesystem now sees the extra capacity. Other filesystems need their own resizing tools; XFS, for example, grows with &lt;code&gt;xfs_growfs&lt;/code&gt; and cannot be shrunk.&lt;/p&gt;
&lt;p&gt;Shrinking is a different workflow. You must unmount and shrink a shrinkable filesystem first, check it for errors, and only then move the partition boundary. Do not use &lt;code&gt;resizepart&lt;/code&gt; alone to shrink a partition, since it can cut off live filesystem data.&lt;/p&gt;
&lt;h2 id="removing-a-partition"&gt;Removing a Partition &lt;a class="headline-link" href="#removing-a-partition" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;List the table one final time and note the number of the partition you intend to remove:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted /dev/sdb -- print&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When the number is confirmed, remove partition 2:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo parted --script /dev/sdb -- rm &lt;span class="m"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The partition disappears from the table immediately, and its former space becomes unallocated. Script mode provides no confirmation, so keep the inspection and removal as separate commands rather than chaining them.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/parted/"&gt;parted cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List all partition tables&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted --list&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show one disk and its free space&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdb -- unit MiB print free&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Print the layout as JSON&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted --json /dev/sdb -- unit MiB print&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open interactive mode&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdb&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Create a GPT table&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdb -- mklabel gpt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Create an ext4 data partition&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdb -- mkpart data ext4 1MiB 100%&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check optimal alignment&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted /dev/sdb -- align-check optimal 1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rename GPT partition 1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdb -- name 1 archive&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set the EFI system partition flag&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdb -- set 1 esp on&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extend partition 1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdb -- resizepart 1 100%&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove partition 2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo parted --script /dev/sdb -- rm 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The kernel still uses the old partition table&lt;/strong&gt;&lt;br&gt;
Unmount filesystems on the disk, disable any swap partition it contains, and run &lt;code&gt;sudo partprobe /dev/sdb&lt;/code&gt; to ask the kernel to reread the table. If the device is still busy, schedule a reboot instead of forcing another partition change.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;parted reports that a partition is not properly aligned&lt;/strong&gt;&lt;br&gt;
Use &lt;code&gt;sudo parted /dev/sdb -- align-check optimal NUMBER&lt;/code&gt; to verify the start boundary. If the partition is empty, recreate it with a &lt;code&gt;1MiB&lt;/code&gt; start or another boundary that satisfies the device&amp;rsquo;s reported alignment requirements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A partition was removed by mistake&lt;/strong&gt;&lt;br&gt;
Stop writing to the disk. Open &lt;code&gt;sudo parted /dev/sdb&lt;/code&gt;, run &lt;code&gt;rescue START END&lt;/code&gt; with the approximate old boundaries, and confirm the discovered partition only when its location and filesystem match. Recovery is not guaranteed, especially after new data has been written.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;parted says a partition is in use&lt;/strong&gt;&lt;br&gt;
Check &lt;code&gt;lsblk&lt;/code&gt; and &lt;code&gt;findmnt&lt;/code&gt;, then unmount the filesystem before changing its boundaries. A disk can also remain busy because it contains active swap, an LVM physical volume, software RAID, or an encrypted mapping.&lt;/p&gt;
&lt;h2 id="faq"&gt;FAQ &lt;a class="headline-link" href="#faq" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Should I use parted or fdisk?&lt;/strong&gt;&lt;br&gt;
Both tools support GPT and MBR tables. &lt;a href="https://linuxize.com/post/fdisk-command-in-linux/"&gt;&lt;code&gt;fdisk&lt;/code&gt;&lt;/a&gt;
provides an interactive workflow that stages changes until you write them, while &lt;code&gt;parted&lt;/code&gt; is convenient for one-line commands, scripts, alignment checks, and changing a partition&amp;rsquo;s end boundary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Does parted format partitions?&lt;/strong&gt;&lt;br&gt;
No. &lt;code&gt;parted&lt;/code&gt; creates the partition entry and can record an intended filesystem type, but it does not create the filesystem. Run the appropriate &lt;code&gt;mkfs&lt;/code&gt; command on the new partition after checking the device name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Does resizepart resize the filesystem too?&lt;/strong&gt;&lt;br&gt;
No. &lt;code&gt;resizepart&lt;/code&gt; only moves the partition&amp;rsquo;s end boundary. Grow or shrink the filesystem separately with the tool designed for that filesystem, and always shrink the filesystem before shrinking its partition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Should I use GPT or MBR?&lt;/strong&gt;&lt;br&gt;
Use GPT for current Linux systems, UEFI boot disks, and disks larger than 2 TiB. Use MBR only when an older operating system or firmware requires it.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;parted&lt;/code&gt; is most useful when you need precise, repeatable control over partition boundaries, especially on GPT disks. Keep inspection and write commands separate, use explicit units, and stop after unexpected output instead of pushing through with &lt;code&gt;--script&lt;/code&gt;.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/parted-command-in-linux/featured_hu_c93b99cd1ae66e4c.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>DNS Record Types Explained: A, AAAA, CNAME, MX, TXT, and More</title><link>https://linuxize.com/post/dns-record-types-explained/</link><pubDate>Fri, 21 Aug 2026 16:00:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/dns-record-types-explained/</guid><category>dns</category><category>networking</category><description>DNS record types map domains to servers, route email, publish verification data, and control certificate issuance. See zone-file examples and dig queries.</description><content:encoded>&lt;p&gt;A website can load normally while mail delivery, domain verification, or certificate issuance fails. Each service asks DNS a different question, and the answer comes from a specific record type.&lt;/p&gt;
&lt;p&gt;A and AAAA records provide server addresses, MX records route email, TXT records publish verification and policy data, and several other types handle aliases, delegation, service discovery, and security. This guide explains the DNS record types you will encounter most often, shows their zone-file syntax, and demonstrates how to inspect them with &lt;code&gt;dig&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="what-a-dns-record-contains"&gt;What a DNS Record Contains &lt;a class="headline-link" href="#what-a-dns-record-contains" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DNS is a distributed database that associates names with typed data. A resource record contains a name, time to live (TTL), class, type, and value. The class is almost always &lt;code&gt;IN&lt;/code&gt;, which means Internet.&lt;/p&gt;
&lt;p&gt;Here are three records in zone-file notation:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 3600 IN A 203.0.113.10
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;www.example.com. 3600 IN CNAME example.com.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 3600 IN MX 10 mail.example.com.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The final dot marks each name as fully qualified. DNS control panels often hide this detail and let you enter &lt;code&gt;@&lt;/code&gt; for the zone apex or only the subdomain label, such as &lt;code&gt;www&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The TTL in this example is 3600 seconds, so a resolver may reuse a cached answer for up to one hour. A shorter TTL lets resolvers fetch a changed record sooner, but it does not shorten the lifetime of copies already cached with the old value. Before a planned migration, lower the TTL at least one old-TTL interval in advance, wait for existing caches to expire, and then make the change.&lt;/p&gt;
&lt;h2 id="a-records-ipv4-addresses"&gt;A Records: IPv4 Addresses &lt;a class="headline-link" href="#a-records-ipv4-addresses" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An A record maps a hostname to an IPv4 address:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 3600 IN A 203.0.113.10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is the usual record for pointing a website or another network service at an IPv4 server. The value must be an IPv4 address, not a URL, port number, or hostname.&lt;/p&gt;
&lt;p&gt;A name can have several A records. Resolvers usually return the complete set, and clients may try the addresses in different orders. This provides basic round-robin traffic distribution, but DNS does not check whether each server is healthy. An unavailable address can remain in the answer until you remove it and its cached TTL expires.&lt;/p&gt;
&lt;h2 id="aaaa-records-ipv6-addresses"&gt;AAAA Records: IPv6 Addresses &lt;a class="headline-link" href="#aaaa-records-ipv6-addresses" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An AAAA record maps a hostname to an IPv6 address:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 3600 IN AAAA 2001:db8::10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A dual-stack service commonly publishes both A and AAAA records. Current clients usually request both types and use a connection strategy such as Happy Eyeballs to try IPv6 and IPv4 without waiting through a long failure.&lt;/p&gt;
&lt;p&gt;Publish an AAAA record only when the service is reachable at that IPv6 address. IPv4-only clients will continue using the A record, but an incorrect AAAA record can delay or break connections for visitors whose systems prefer IPv6.&lt;/p&gt;
&lt;h2 id="cname-records-aliases"&gt;CNAME Records: Aliases &lt;a class="headline-link" href="#cname-records-aliases" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A CNAME record makes one name an alias of another name:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;www.example.com. 3600 IN CNAME example.com.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When a resolver receives this answer, it continues the lookup at &lt;code&gt;example.com&lt;/code&gt;. CNAME records are useful when a subdomain must follow a hostname managed by a CDN, application host, or other provider whose IP addresses may change.&lt;/p&gt;
&lt;p&gt;The owner of a CNAME cannot also hold ordinary A, AAAA, MX, or TXT data. The zone apex (&lt;code&gt;example.com&lt;/code&gt;) must hold SOA and NS records, so it cannot be a CNAME. Providers implement apex aliasing through non-standard features named ALIAS, ANAME, or CNAME flattening, which resolve the target and publish A or AAAA answers on your behalf.&lt;/p&gt;
&lt;h2 id="mx-records-mail-routing"&gt;MX Records: Mail Routing &lt;a class="headline-link" href="#mx-records-mail-routing" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;MX records identify the servers that accept email for a domain. Each value starts with a preference number, and lower numbers are preferred:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 3600 IN MX 10 mail1.example.com.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 3600 IN MX 20 mail2.example.com.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A sending server tries &lt;code&gt;mail1.example.com&lt;/code&gt; first and falls back to &lt;code&gt;mail2.example.com&lt;/code&gt; if the preferred server is unavailable. Records with equal preference can share delivery attempts.&lt;/p&gt;
&lt;p&gt;An MX target must be a hostname that resolves directly through A or AAAA records. It cannot be an IP address or a CNAME alias. The trailing dot is also important in a zone file because omitting it may cause the DNS server to append the zone name.&lt;/p&gt;
&lt;h2 id="txt-records-verification-and-policy-data"&gt;TXT Records: Verification and Policy Data &lt;a class="headline-link" href="#txt-records-verification-and-policy-data" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TXT records store text associated with a name. Providers use them for domain-ownership challenges, while email systems use them for SPF, DKIM, and DMARC:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 3600 IN TXT &amp;#34;v=spf1 mx -all&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;_dmarc.example.com. 3600 IN TXT &amp;#34;v=DMARC1; p=quarantine&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The SPF value lists which systems may send mail for the domain. A domain must not publish multiple TXT records beginning with &lt;code&gt;v=spf1&lt;/code&gt; at the same name. DMARC lives at &lt;code&gt;_dmarc&lt;/code&gt;, while DKIM keys use a selector name such as &lt;code&gt;default._domainkey.example.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Long TXT data can appear as several quoted strings because each individual character-string has a size limit. DNS clients concatenate those strings into one record value. Our guide to &lt;a href="https://linuxize.com/post/email-authentication-spf-dkim-dmarc/"&gt;SPF, DKIM, and DMARC&lt;/a&gt;
explains how the three email checks work together.&lt;/p&gt;
&lt;h2 id="ns-records-zone-delegation"&gt;NS Records: Zone Delegation &lt;a class="headline-link" href="#ns-records-zone-delegation" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;NS records name the authoritative servers for a DNS zone:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 86400 IN NS ns1.dns-provider.net.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 86400 IN NS ns2.dns-provider.net.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The parent zone publishes a delegation that directs resolvers to these servers, and the delegated zone publishes its own NS set at the apex. Changing name servers at a registrar updates the parent delegation. The parent and authoritative-zone sets should agree, or different resolution paths may produce inconsistent results.&lt;/p&gt;
&lt;p&gt;DNS zones should have at least two authoritative servers for availability, and most registries require it. Managed providers normally create the apex NS records automatically, although you still select or confirm the delegation through the registrar.&lt;/p&gt;
&lt;h2 id="soa-records-zone-metadata"&gt;SOA Records: Zone Metadata &lt;a class="headline-link" href="#soa-records-zone-metadata" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every zone contains one SOA (start of authority) record. It identifies the primary server, encodes the administrator contact, and stores a serial number and timers used by secondary servers:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 86400 IN SOA ns1.dns-provider.net. admin.example.com. (
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2026082101 ; serial
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 7200 ; refresh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 3600 ; retry
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1209600 ; expire
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 3600 ) ; minimum&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this example, &lt;code&gt;admin.example.com.&lt;/code&gt; represents the email address &lt;code&gt;admin@example.com&lt;/code&gt;. Secondary servers compare the serial number with their copy and transfer the zone when the serial increases.&lt;/p&gt;
&lt;p&gt;The final MINIMUM field participates in negative caching. A resolver may cache a response stating that a name or record does not exist for the lower of this value and the SOA record&amp;rsquo;s own TTL. Managed DNS services maintain the SOA fields for you, but the serial and timers remain useful when diagnosing stale or inconsistent authoritative servers.&lt;/p&gt;
&lt;h2 id="ptr-records-reverse-dns"&gt;PTR Records: Reverse DNS &lt;a class="headline-link" href="#ptr-records-reverse-dns" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A PTR record maps an IP address to a hostname. IPv4 records live below &lt;code&gt;in-addr.arpa&lt;/code&gt;, with the address octets reversed, while IPv6 uses &lt;code&gt;ip6.arpa&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;10.113.0.203.in-addr.arpa. 3600 IN PTR mail.example.com.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The organization that controls the IP block also controls its reverse zone. For a server address, this is usually your hosting provider or ISP, so you configure PTR data through its control panel rather than your domain&amp;rsquo;s normal DNS zone.&lt;/p&gt;
&lt;p&gt;Forward and reverse records are independent. Mail systems often check that the PTR hostname resolves forward to the sending address, so a mail server should have matching PTR and A or AAAA data.&lt;/p&gt;
&lt;h2 id="srv-records-service-discovery"&gt;SRV Records: Service Discovery &lt;a class="headline-link" href="#srv-records-service-discovery" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An SRV record advertises the hostname and port for a service. Its owner name begins with underscore-prefixed service and protocol labels:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;_sip._tcp.example.com. 3600 IN SRV 10 60 5060 sipserver.example.com.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The four values are priority, weight, port, and target. Clients prefer lower priorities. When several records share a priority, weight helps distribute requests among their targets.&lt;/p&gt;
&lt;p&gt;SRV records are common with SIP, XMPP, LDAP, Active Directory, and some game servers. Web browsers did not adopt SRV for ordinary HTTP and HTTPS navigation, so websites still depend on address, alias, and newer HTTPS records.&lt;/p&gt;
&lt;h2 id="caa-records-certificate-issuance"&gt;CAA Records: Certificate Issuance &lt;a class="headline-link" href="#caa-records-certificate-issuance" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A CAA record authorizes a certificate authority to issue TLS certificates for a domain:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 3600 IN CAA 0 issue &amp;#34;letsencrypt.org&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A public certificate authority checks the relevant CAA set before issuance. If a name has no CAA record, the search continues up its DNS name hierarchy, so a policy at &lt;code&gt;example.com&lt;/code&gt; also applies to subdomains that do not publish their own CAA set.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;issue&lt;/code&gt; property covers standard certificates, &lt;code&gt;issuewild&lt;/code&gt; can set a separate wildcard policy, and &lt;code&gt;iodef&lt;/code&gt; supplies a contact for policy reports. Check the issuer identifier required by your certificate authority before adding CAA records. An incorrect policy can block both initial issuance and automated renewal.&lt;/p&gt;
&lt;h2 id="other-dns-record-types"&gt;Other DNS Record Types &lt;a class="headline-link" href="#other-dns-record-types" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DNSSEC uses DNSKEY, DS, RRSIG, NSEC, and NSEC3 records so validating resolvers can authenticate DNS answers. The DNS provider creates signatures and DNSKEY records in the zone, while a DS record in the parent zone completes the chain of trust. Enabling DNSSEC only at the provider without publishing the required DS record does not establish that chain.&lt;/p&gt;
&lt;p&gt;SVCB and HTTPS records publish connection parameters and alternative service endpoints. HTTPS records can advertise supported application protocols, including HTTP/3, and provide address hints before a client opens its connection. DNS providers and content delivery networks may create these records automatically.&lt;/p&gt;
&lt;p&gt;You may also encounter TLSA for DANE certificate association, SSHFP for SSH host-key fingerprints, and NAPTR for rule-based service discovery. These specialized types are not needed for most domain setups.&lt;/p&gt;
&lt;h2 id="querying-dns-records-with-dig"&gt;Querying DNS Records with dig &lt;a class="headline-link" href="#querying-dns-records-with-dig" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The general short-answer form of a &lt;code&gt;dig&lt;/code&gt; query is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig +short NAME TYPE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For a stable public example, query the A records for Cloudflare&amp;rsquo;s resolver hostname:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig +short one.one.one.one A&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;1.0.0.1
1.1.1.1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The order may vary because both addresses belong to the same A record set. Remove &lt;code&gt;+short&lt;/code&gt; when you need the response status, authoritative flag, TTL, and server details.&lt;/p&gt;
&lt;p&gt;To inspect a domain&amp;rsquo;s mail routing, request its MX records:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig +short gmail.com MX&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;5 gmail-smtp-in.l.google.com.
10 alt1.gmail-smtp-in.l.google.com.
20 alt2.gmail-smtp-in.l.google.com.
30 alt3.gmail-smtp-in.l.google.com.
40 alt4.gmail-smtp-in.l.google.com.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each answer starts with its preference number, followed by the mail-server hostname. A sending server tries &lt;code&gt;gmail-smtp-in.l.google.com&lt;/code&gt; first because its preference of 5 is the lowest. The returned servers and their order can change as the domain operator updates its mail infrastructure.&lt;/p&gt;
&lt;p&gt;TXT, CAA, NS, and other records use the same pattern:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig +short example.com TXT
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig +short example.com CAA
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig +short example.com NS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For reverse DNS, pass an address to &lt;code&gt;-x&lt;/code&gt; instead of building the reverse-zone name manually:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig +short -x 1.1.1.1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;one.one.one.one.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href="https://linuxize.com/post/how-to-use-dig-command-to-query-dns-in-linux/"&gt;dig command guide&lt;/a&gt;
covers server selection, trace queries, and DNSSEC checks. The &lt;a href="https://linuxize.com/post/host-command-in-linux/"&gt;host&lt;/a&gt;
and &lt;a href="https://linuxize.com/post/nslookup-command-in-linux/"&gt;nslookup&lt;/a&gt;
commands provide simpler alternatives. After changing a record, remember that your resolver or operating system may keep the previous answer until its TTL expires, although you can &lt;a href="https://linuxize.com/post/how-to-clear-the-dns-cache/"&gt;clear the local DNS cache&lt;/a&gt;
during testing.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Record type&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Point a name to an IPv4 address&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;&lt;code&gt;203.0.113.10&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Point a name to an IPv6 address&lt;/td&gt;
&lt;td&gt;AAAA&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2001:db8::10&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Make a name follow another hostname&lt;/td&gt;
&lt;td&gt;CNAME&lt;/td&gt;
&lt;td&gt;&lt;code&gt;example.com.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Route incoming email&lt;/td&gt;
&lt;td&gt;MX&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10 mail.example.com.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Publish verification or policy text&lt;/td&gt;
&lt;td&gt;TXT&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;quot;v=spf1 mx -all&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delegate a zone to authoritative servers&lt;/td&gt;
&lt;td&gt;NS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ns1.dns-provider.net.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Store zone authority and transfer data&lt;/td&gt;
&lt;td&gt;SOA&lt;/td&gt;
&lt;td&gt;Primary server, serial, and timers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Map an IP address back to a hostname&lt;/td&gt;
&lt;td&gt;PTR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mail.example.com.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advertise a service hostname and port&lt;/td&gt;
&lt;td&gt;SRV&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10 60 5060 sip.example.com.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restrict certificate authorities&lt;/td&gt;
&lt;td&gt;CAA&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 issue &amp;quot;letsencrypt.org&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before saving a DNS change, confirm the record owner, value format, and whether the target must be an address or a hostname. Lower the TTL ahead of planned migrations, keep the old service available while caches expire, and use &lt;code&gt;dig&lt;/code&gt; to verify the answers that resolvers actually receive.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/dns-record-types-explained/featured_hu_bcf152475aceaab9.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>Block Devices, Partitions, and Filesystems in Linux Explained</title><link>https://linuxize.com/post/linux-block-devices-partitions-filesystems/</link><pubDate>Sat, 15 Aug 2026 10:35:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/linux-block-devices-partitions-filesystems/</guid><category>disk</category><description>Linux storage works in layers: block device, partition, filesystem, mount point. This guide explains what each layer does and which command inspects it.</description><content:encoded>&lt;p&gt;You attach a new disk to a server, run &lt;a href="https://linuxize.com/post/lsblk-command-in-linux/"&gt;&lt;code&gt;lsblk&lt;/code&gt;&lt;/a&gt;
, and the drive is there. Then you try to copy a file onto it and nothing works, because there is no path to copy to. The disk is visible to the kernel, but it has no partition, no filesystem, and no place in the directory tree.&lt;/p&gt;
&lt;p&gt;Linux storage is built from four layers stacked on top of each other, and most confusion comes from treating them as one thing. This guide explains what a block device, a partition, a filesystem, and a mount point each are, how they connect, and which command shows you the state of each layer.&lt;/p&gt;
&lt;h2 id="what-a-block-device-is"&gt;What a Block Device Is &lt;a class="headline-link" href="#what-a-block-device-is" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A block device is how the kernel represents a piece of storage that can be read and written in fixed-size chunks called blocks, rather than one byte at a time. Hard drives, SSDs, USB sticks, SD cards, and the virtual disks of a cloud instance are all block devices.&lt;/p&gt;
&lt;p&gt;Every block device gets a file under &lt;code&gt;/dev&lt;/code&gt;. The name depends on the driver that claims the hardware:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/dev/sda&lt;/code&gt;, &lt;code&gt;/dev/sdb&lt;/code&gt; - SATA, SAS, and USB storage&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/dev/nvme0n1&lt;/code&gt; - the first namespace of the first NVMe drive&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/dev/vda&lt;/code&gt; - a virtual disk on a KVM or cloud guest&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/dev/mmcblk0&lt;/code&gt; - an SD card or eMMC device&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These files are not ordinary files. Running &lt;code&gt;ls -l&lt;/code&gt; on one shows what they really are:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -l /dev/sda /dev/null&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;brw-rw---- 1 root disk 8, 0 Aug 14 09:12 /dev/sda
crw-rw-rw- 1 root root 1, 3 Aug 14 09:12 /dev/null&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first character of the permission string is the giveaway. &lt;code&gt;b&lt;/code&gt; marks a block device and &lt;code&gt;c&lt;/code&gt; marks a character device such as &lt;code&gt;/dev/null&lt;/code&gt;. The pair of numbers where a file size would normally appear, &lt;code&gt;8, 0&lt;/code&gt;, is the major and minor number that identifies the driver and the specific device it handles.&lt;/p&gt;
&lt;p&gt;The kernel also publishes every block device under &lt;code&gt;/sys/block&lt;/code&gt;, which is where tools such as &lt;code&gt;lsblk&lt;/code&gt; read their information from. A block device at this stage is just an addressable range of storage. Nothing on it means anything yet.&lt;/p&gt;
&lt;h2 id="partitions-divide-a-disk"&gt;Partitions Divide a Disk &lt;a class="headline-link" href="#partitions-divide-a-disk" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A partition is a labeled region of a block device. The disk keeps a small table near its start that records where each region begins and ends, and the kernel exposes each region as its own block device: &lt;code&gt;/dev/sda1&lt;/code&gt;, &lt;code&gt;/dev/sda2&lt;/code&gt;, and so on. NVMe and SD devices insert a &lt;code&gt;p&lt;/code&gt; before the number, so the first partition of &lt;code&gt;/dev/nvme0n1&lt;/code&gt; is &lt;code&gt;/dev/nvme0n1p1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Two partition table formats are in common use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MBR&lt;/strong&gt; (also called msdos) is the older format. It supports four primary partitions, works around that limit with extended partitions, and cannot address a disk larger than 2 TiB with standard 512-byte sectors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT&lt;/strong&gt; is the modern format. It commonly provides 128 partition entries, supports disks far larger than MBR, and stores a backup copy of the table at the end of the disk. UEFI firmware supports both GPT and legacy MBR, though GPT is the standard choice for current UEFI installations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To see which format a disk uses, run &lt;a href="https://linuxize.com/post/fdisk-command-in-linux/"&gt;&lt;code&gt;fdisk&lt;/code&gt;&lt;/a&gt;
with the &lt;code&gt;-l&lt;/code&gt; flag:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo fdisk -l /dev/sda&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The output starts with the disk size and model, then prints a &lt;code&gt;Disklabel type&lt;/code&gt; line that reads either &lt;code&gt;gpt&lt;/code&gt; or &lt;code&gt;dos&lt;/code&gt;, followed by the partition list.&lt;/p&gt;
&lt;p&gt;Partitioning is a convention rather than a hard requirement. You can create a filesystem directly on a whole disk, and some storage appliances do exactly that. On a system that boots from the disk, though, partitions are what separate the EFI system partition, the boot files, and the root filesystem from each other.&lt;/p&gt;
&lt;p&gt;A partition still holds no structure. It marks out space and stops there.&lt;/p&gt;
&lt;h2 id="filesystems-give-a-partition-structure"&gt;Filesystems Give a Partition Structure &lt;a class="headline-link" href="#filesystems-give-a-partition-structure" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A filesystem is the format written inside a partition that turns raw space into directories, filenames, permissions, and timestamps. Creating one is called formatting, and the &lt;code&gt;mkfs&lt;/code&gt; family of commands does it:&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;Creating a filesystem destroys any existing filesystem and data on the target. Before running &lt;code&gt;mkfs&lt;/code&gt;, confirm the device name with &lt;code&gt;lsblk -f&lt;/code&gt;, verify that it is the intended empty partition, and make sure it is not mounted.&lt;/div&gt;
&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkfs.ext4 /dev/sdb1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This writes ext4 metadata across &lt;code&gt;/dev/sdb1&lt;/code&gt;, including the superblock, the inode tables, and the free-space maps. From that moment the partition can hold files, and each file gets an &lt;a href="https://linuxize.com/post/what-is-an-inode-in-linux/"&gt;inode&lt;/a&gt;
that stores its metadata.&lt;/p&gt;
&lt;p&gt;Linux supports many filesystem types, and the choice matters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ext4&lt;/code&gt; - the default on most Debian and Ubuntu installations, stable and well understood&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xfs&lt;/code&gt; - the default on RHEL and derivatives, strong with large files and parallel writes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;btrfs&lt;/code&gt; - supports snapshots, checksums, and built-in volume management&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vfat&lt;/code&gt; - used for EFI System Partitions and broadly compatible removable drives&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exfat&lt;/code&gt; - suited to large removable drives shared with Windows and macOS&lt;/li&gt;
&lt;li&gt;&lt;code&gt;swap&lt;/code&gt; - not a filesystem for files at all, but a formatted area the kernel uses as &lt;a href="https://linuxize.com/post/create-a-linux-swap-file/"&gt;swap space&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Formatting also assigns the filesystem a UUID, and optionally a label. Both identify the filesystem itself rather than the device it happens to sit on. This distinction matters more than it first appears: device names are assigned in detection order, so a disk that is &lt;code&gt;/dev/sdb&lt;/code&gt; today can come up as &lt;code&gt;/dev/sdc&lt;/code&gt; after you add another drive or reboot a cloud instance. The UUID does not move. That is why configuration files should reference &lt;code&gt;UUID=&lt;/code&gt; instead of &lt;code&gt;/dev/sdb1&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="mount-points-attach-a-filesystem-to-the-tree"&gt;Mount Points Attach a Filesystem to the Tree &lt;a class="headline-link" href="#mount-points-attach-a-filesystem-to-the-tree" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Linux has no drive letters. Every filesystem on the machine appears somewhere inside a single tree that starts at &lt;code&gt;/&lt;/code&gt;. A mount point is the directory where a filesystem is attached, and &lt;a href="https://linuxize.com/post/how-to-mount-and-unmount-file-systems-in-linux/"&gt;mounting&lt;/a&gt;
is the act of attaching it. Create the mount point, then attach the filesystem:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir -p /srv/data
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mount /dev/sdb1 /srv/data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first command creates the directory if it does not already exist. After the second command, everything written under &lt;code&gt;/srv/data&lt;/code&gt; lands on &lt;code&gt;/dev/sdb1&lt;/code&gt;, while the rest of the tree stays on whatever filesystem holds &lt;code&gt;/&lt;/code&gt;. The reader cannot tell from the path alone which disk a file lives on, which is the point of the design.&lt;/p&gt;
&lt;p&gt;A mount point is an ordinary directory. There is no special flag that makes &lt;code&gt;/srv/data&lt;/code&gt; mountable, and any empty directory works.&lt;/p&gt;
&lt;div class="note callout callout-info"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" &gt;
&lt;path d="M 16 3 C 8.832031 3 3 8.832031 3 16 C 3 23.167969 8.832031 29 16 29 C 23.167969 29 29 23.167969 29 16 C 29 8.832031 23.167969 3 16 3 Z M 16 5 C 22.085938 5 27 9.914063 27 16 C 27 22.085938 22.085938 27 16 27 C 9.914063 27 5 22.085938 5 16 C 5 9.914063 9.914063 5 16 5 Z M 15 10 L 15 12 L 17 12 L 17 10 Z M 15 14 L 15 22 L 17 22 L 17 14 Z "&gt;&lt;/path&gt;
&lt;/svg&gt;&lt;span class="callout-title"&gt;Info&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;If the directory already contains files when you mount over it, those files are hidden rather than deleted. They are still on the underlying filesystem and reappear once you unmount.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A manual &lt;code&gt;mount&lt;/code&gt; command lasts until reboot. To make it persistent, the filesystem needs an entry in &lt;a href="https://linuxize.com/post/etc-fstab-file/"&gt;&lt;code&gt;/etc/fstab&lt;/code&gt;&lt;/a&gt;
, which the system reads at boot and mounts automatically.&lt;/p&gt;
&lt;h2 id="walking-through-one-real-layout"&gt;Walking Through One Real Layout &lt;a class="headline-link" href="#walking-through-one-real-layout" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Putting the four layers side by side makes the stack easier to read. The &lt;code&gt;-o&lt;/code&gt; flag selects the columns, and adding &lt;code&gt;TYPE&lt;/code&gt; shows what each row actually is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -o NAME,TYPE,FSTYPE,LABEL,MOUNTPOINTS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;NAME TYPE FSTYPE LABEL MOUNTPOINTS
nvme0n1 disk
├─nvme0n1p1 part vfat /boot/efi
├─nvme0n1p2 part ext4 boot /boot
└─nvme0n1p3 part LVM2_member
├─vg0-root lvm ext4 root /
└─vg0-swap lvm swap [SWAP]
sdb disk
└─sdb1 part xfs data /srv/data&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Read it from the outside in. &lt;code&gt;nvme0n1&lt;/code&gt; and &lt;code&gt;sdb&lt;/code&gt; have &lt;code&gt;TYPE&lt;/code&gt; of &lt;code&gt;disk&lt;/code&gt; and no filesystem of their own, because they are the block devices. The indented rows marked &lt;code&gt;part&lt;/code&gt; are partitions. The &lt;code&gt;FSTYPE&lt;/code&gt; column tells you which of those partitions were formatted, and with what. The &lt;code&gt;MOUNTPOINTS&lt;/code&gt; column tells you where each formatted filesystem was attached.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;nvme0n1p3&lt;/code&gt; shows all four layers coming apart cleanly. It is a partition, it has a format, but that format is &lt;code&gt;LVM2_member&lt;/code&gt; rather than a filesystem you can browse, and it has no mount point. Its two children are the layer that carries the actual filesystems.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;sdb&lt;/code&gt; disk is the simple case: one disk, one partition, one XFS filesystem labeled &lt;code&gt;data&lt;/code&gt;, mounted at &lt;code&gt;/srv/data&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="where-lvm-raid-and-encryption-fit"&gt;Where LVM, RAID, and Encryption Fit &lt;a class="headline-link" href="#where-lvm-raid-and-encryption-fit" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The four layers describe the common path, but Linux lets you insert extra layers between the partition and the filesystem. Each one consumes a block device and produces a new one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LVM&lt;/strong&gt; groups one or more physical volumes into a volume group, then carves logical volumes out of it. The logical volume is a block device at &lt;code&gt;/dev/mapper/vg0-root&lt;/code&gt;, and you format that instead of the partition. Logical volumes can be resized and moved between disks without repartitioning, which is why servers so often use them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Software RAID&lt;/strong&gt; combines several devices into one &lt;code&gt;/dev/md0&lt;/code&gt; device with mirroring or striping across the members. The filesystem sits on &lt;code&gt;/dev/md0&lt;/code&gt; and never sees the individual disks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LUKS encryption&lt;/strong&gt; wraps a device in an encrypted container. Unlocking it produces a decrypted block device under &lt;code&gt;/dev/mapper&lt;/code&gt;, and the filesystem goes there. &lt;code&gt;lsblk&lt;/code&gt; shows the container with &lt;code&gt;TYPE&lt;/code&gt; of &lt;code&gt;crypt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These stack in any sensible order, and a common server layout runs all of them at once: partition, then LUKS, then LVM, then ext4. Each layer only needs to know about the block device directly beneath it.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;Typical name&lt;/th&gt;
&lt;th&gt;Inspect with&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Block device&lt;/td&gt;
&lt;td&gt;Raw addressable storage exposed by the kernel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/dev/sda&lt;/code&gt;, &lt;code&gt;/dev/nvme0n1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lsblk -d&lt;/code&gt;, &lt;code&gt;ls -l /dev/sd*&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partition&lt;/td&gt;
&lt;td&gt;A labeled region of a block device&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/dev/sda1&lt;/code&gt;, &lt;code&gt;/dev/nvme0n1p1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo fdisk -l&lt;/code&gt;, &lt;code&gt;lsblk&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filesystem&lt;/td&gt;
&lt;td&gt;The format written inside a partition&lt;/td&gt;
&lt;td&gt;ext4, xfs, btrfs, vfat&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lsblk -f&lt;/code&gt;, &lt;code&gt;blkid&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mount point&lt;/td&gt;
&lt;td&gt;The directory where a filesystem is attached&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/boot&lt;/code&gt;, &lt;code&gt;/srv/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;findmnt&lt;/code&gt;, &lt;code&gt;df -h&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="faq"&gt;FAQ &lt;a class="headline-link" href="#faq" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What is the difference between a partition and a filesystem?&lt;/strong&gt;&lt;br&gt;
A partition reserves a region of a disk and records its boundaries in the partition table. A filesystem is the structure written inside that region so it can store files. A freshly created partition has no filesystem, which is why &lt;code&gt;mkfs&lt;/code&gt; is a separate step after &lt;code&gt;fdisk&lt;/code&gt; or &lt;code&gt;parted&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is /dev/sda a file or a device?&lt;/strong&gt;&lt;br&gt;
Both, in a sense. &lt;code&gt;/dev/sda&lt;/code&gt; is a special file that acts as the interface to the device, so tools can open, read, and write it with ordinary file operations. The leading &lt;code&gt;b&lt;/code&gt; in &lt;code&gt;ls -l&lt;/code&gt; output marks it as a block device rather than a regular file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why does my disk name change between reboots?&lt;/strong&gt;&lt;br&gt;
Kernel device names are assigned in detection order, not fixed to the hardware. Adding a drive or rebooting a virtual machine can shift &lt;code&gt;/dev/sdb&lt;/code&gt; to &lt;code&gt;/dev/sdc&lt;/code&gt;. Refer to filesystems by &lt;code&gt;UUID=&lt;/code&gt; or &lt;code&gt;LABEL=&lt;/code&gt; in &lt;code&gt;/etc/fstab&lt;/code&gt; and scripts so the reference survives reordering.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do I tell which disk a directory lives on?&lt;/strong&gt;&lt;br&gt;
Pass the path to &lt;code&gt;findmnt --target&lt;/code&gt;, for example &lt;code&gt;findmnt --target /srv/data&lt;/code&gt;, and it prints the source device, filesystem type, and mount options for the filesystem containing that path. Running &lt;a href="https://linuxize.com/post/how-to-check-disk-space-in-linux-using-the-df-command/"&gt;&lt;code&gt;df -h /srv/data&lt;/code&gt;&lt;/a&gt;
shows the source device, capacity, usage, and mount point instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can I create a filesystem without partitioning first?&lt;/strong&gt;&lt;br&gt;
Yes. Running &lt;code&gt;mkfs.ext4 /dev/sdb&lt;/code&gt; creates an ext4 filesystem directly on the whole disk with no partition table. Filesystem-aware tools such as &lt;code&gt;lsblk -f&lt;/code&gt; and &lt;code&gt;blkid&lt;/code&gt; still detect it, while partitioning tools report that no partition table is present. This is destructive and should only be done intentionally on a verified empty data disk. Use partitions for boot disks and workflows that expect a partition table.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once you can name which layer a problem sits on, the next check becomes clearer: a missing device is a kernel or cabling question, an unknown partition or filesystem needs inspection before you change it, and a known unmounted filesystem calls for &lt;code&gt;mount&lt;/code&gt;. Start with &lt;code&gt;lsblk -f&lt;/code&gt; on any unfamiliar machine, since it shows three of the four layers in a single screen.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/linux-block-devices-partitions-filesystems/featured_hu_3bf81da214777401.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>nmap Cheatsheet</title><link>https://linuxize.com/cheatsheet/nmap/</link><pubDate>Fri, 14 Aug 2026 15:15:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/nmap/</guid><description>Quick reference for host discovery, port scanning, and service detection with nmap in Linux</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="basic-syntax"&gt;Basic Syntax &lt;a class="headline-link" href="#basic-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Core &lt;code&gt;nmap&lt;/code&gt; command forms.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan the 1000 most common TCP ports on one host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same scan as root, which enables the faster SYN scan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -v 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Increase verbosity, repeat as &lt;code&gt;-vv&lt;/code&gt; for more detail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --reason 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show why each port is in its reported state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --open 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Report only ports that are open&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="target-specification"&gt;Target Specification &lt;a class="headline-link" href="#target-specification" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Point a scan at one host, a range, a subnet, or a list.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap 192.168.1.10 10.0.0.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan several hosts in one run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan a whole subnet in CIDR notation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap 192.168.1.1-50&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan an address range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -iL targets.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read targets from a file, one per line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --exclude 192.168.1.1 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip specific hosts in a larger scan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -6 2001:db8::1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan an IPv6 target&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="host-discovery"&gt;Host Discovery &lt;a class="headline-link" href="#host-discovery" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Find which hosts are up before spending time on port scans.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -sn 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ping scan: list live hosts without scanning ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -Pn 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip discovery and treat the host as online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -PS22,80,443 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Discover hosts with TCP SYN probes to those ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -PA80 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Discover hosts with TCP ACK probes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -PE 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Discover hosts with ICMP echo requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -n 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip reverse DNS lookups to speed up the scan&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="port-selection"&gt;Port Selection &lt;a class="headline-link" href="#port-selection" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Control which ports the scan covers.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -p 22 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan a single port&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -p 22,80,443 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan a list of ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -p 1-1024 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan a port range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -p- 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan all 65535 TCP ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -F 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fast scan of the top 100 ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --top-ports 20 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan the 20 most common ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -sU -sS -p U:53,T:80,443 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mix UDP and TCP ports, which needs both scan types&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="scan-types"&gt;Scan Types &lt;a class="headline-link" href="#scan-types" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Pick how nmap probes each port. The raw-packet scans need root.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -sS 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TCP SYN scan: fast, the default when running as root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -sT 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TCP connect scan: the fallback for an unprivileged user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -sU 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;UDP scan: slow, so pair it with &lt;code&gt;--top-ports&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -sA 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ACK scan: map which ports a firewall filters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -sn 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No port scan at all, discovery only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -sL 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List scan: show the targets without sending probes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="service-and-os-detection"&gt;Service and OS Detection &lt;a class="headline-link" href="#service-and-os-detection" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Identify what is listening and what the host is running.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -sV 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Detect service names and version numbers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -sV --version-intensity 9 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Probe harder for versions, from 0 (light) to 9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -O 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Guess the operating system from TCP/IP fingerprints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -A 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Aggressive scan: &lt;code&gt;-sV&lt;/code&gt;, &lt;code&gt;-O&lt;/code&gt;, default scripts, and traceroute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap --traceroute 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Trace the route to each target&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="timing-and-performance"&gt;Timing and Performance &lt;a class="headline-link" href="#timing-and-performance" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Trade speed against accuracy and network load.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -T4 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Faster timing, a good default on a local network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -T2 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Slower and gentler on fragile or busy networks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --min-rate 1000 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Send at least 1000 packets per second&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --max-retries 1 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Give up sooner on unanswered probes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --host-timeout 5m 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Abandon any host still scanning after 5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="output-formats"&gt;Output Formats &lt;a class="headline-link" href="#output-formats" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Save results for review, diffing, or scripting.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -oN scan.txt 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write human readable output to a file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -oX scan.xml 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write XML for other tools to parse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -oG scan.gnmap 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write grepable output for &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -oA scan 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write all three formats using one base name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --append-output -oN scan.txt 192.168.1.11&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Append to an existing output file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="nse-scripts"&gt;NSE Scripts &lt;a class="headline-link" href="#nse-scripts" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run the Nmap Scripting Engine for deeper checks.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -sC 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the default script set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --script http-title 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run one named script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --script &amp;quot;http-*&amp;quot; 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run every script matching a pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --script vuln 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the vulnerability script category&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --script ssl-enum-ciphers -p 443 example.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List the TLS ciphers a server accepts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap --script-help ssh-auth-methods&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read what a script does before running it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="common-use-cases"&gt;Common Use Cases &lt;a class="headline-link" href="#common-use-cases" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Practical scans for day-to-day network work.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -sn 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inventory the hosts on a local network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -p- -T4 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find every open TCP port on one server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -sV --open 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List running services and their versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nmap -p 80,443 --open 192.168.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Locate the web servers on a subnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -sU --top-ports 20 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check the most common UDP services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo nmap -A -oA audit 192.168.1.10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full audit of one host, saved in every format&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Quick checks for common &lt;code&gt;nmap&lt;/code&gt; problems.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;You requested a scan type which requires root privileges&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the command with &lt;code&gt;sudo&lt;/code&gt;, or use &lt;code&gt;-sT&lt;/code&gt; instead of &lt;code&gt;-sS&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Note: Host seems down&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;-Pn&lt;/code&gt; when ICMP is blocked but the host is reachable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scan takes far too long&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;-T4&lt;/code&gt;, narrow the ports with &lt;code&gt;-F&lt;/code&gt; or &lt;code&gt;--top-ports&lt;/code&gt;, and add &lt;code&gt;-n&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Every UDP port shows &lt;code&gt;open|filtered&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;UDP has no handshake, so add &lt;code&gt;-sV&lt;/code&gt; or scan fewer ports for a clearer answer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Results differ from a local port check&lt;/td&gt;
&lt;td&gt;The firewall may filter the port; compare with &lt;code&gt;ss -tulpn&lt;/code&gt; on the host itself&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use these guides for broader port and network troubleshooting.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/nmap-command/"&gt;nmap Command in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Full &lt;code&gt;nmap&lt;/code&gt; guide with detailed examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/check-open-ports-linux/"&gt;How to Check Open Ports in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Scan a host for open ports with nmap, netcat, or telnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/ss-command-in-linux/"&gt;ss Command in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Inspect sockets and listening services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/netcat/"&gt;netcat cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Test single ports and move data between hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/tcpdump/"&gt;tcpdump cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Capture the packets behind a scan result&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>lsblk Command in Linux: List Block Devices</title><link>https://linuxize.com/post/lsblk-command-in-linux/</link><pubDate>Thu, 13 Aug 2026 11:20:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/lsblk-command-in-linux/</guid><category>disk</category><category>linux commands</category><description>Use lsblk to list disks, partitions, filesystems, UUIDs, and mount points in Linux, then customize columns and produce JSON output for scripts.</description><content:encoded>&lt;p&gt;When you plug in a new drive, set up a fresh partition, or try to remember which disk is mounted where, you need a quick way to see every block device attached to the system. The &lt;code&gt;lsblk&lt;/code&gt; command reads information from &lt;code&gt;sysfs&lt;/code&gt; and the &lt;code&gt;udev&lt;/code&gt; database and prints a tidy tree of disks, partitions, loop devices, and LVM volumes, together with their sizes and mount points.&lt;/p&gt;
&lt;p&gt;This guide explains how to use &lt;code&gt;lsblk&lt;/code&gt; to inspect block devices, pick the columns you need, and format the output for scripts.&lt;/p&gt;
&lt;h2 id="lsblk-syntax"&gt;lsblk Syntax &lt;a class="headline-link" href="#lsblk-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The general form of the command is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk [OPTIONS] [DEVICE...]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With no arguments, &lt;code&gt;lsblk&lt;/code&gt; lists every block device except RAM disks and empty devices. You can pass one or more device paths to limit the output, for example &lt;code&gt;lsblk /dev/sda&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Unlike &lt;a href="https://linuxize.com/post/fdisk-command-in-linux/"&gt;&lt;code&gt;fdisk&lt;/code&gt;&lt;/a&gt;
, &lt;code&gt;lsblk&lt;/code&gt; does not need root privileges for most queries, which makes it safer for quick checks.&lt;/p&gt;
&lt;h2 id="basic-usage"&gt;Basic Usage &lt;a class="headline-link" href="#basic-usage" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;lsblk&lt;/code&gt; with no options to see a tree of all devices on the system:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 465.8G 0 disk
├─sda1 8:1 0 512M 0 part /boot/efi
├─sda2 8:2 0 16G 0 part [SWAP]
└─sda3 8:3 0 449.3G 0 part /
sdb 8:16 1 14.3G 0 disk
└─sdb1 8:17 1 14.3G 0 part /media/john/usb
sr0 11:0 1 1024M 0 rom&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each row describes one device. The tree characters on the left show which partitions belong to which disk. The &lt;code&gt;TYPE&lt;/code&gt; column tells you whether the entry is a whole &lt;code&gt;disk&lt;/code&gt;, a &lt;code&gt;part&lt;/code&gt;ition, an optical &lt;code&gt;rom&lt;/code&gt;, an LVM &lt;code&gt;lvm&lt;/code&gt; volume, a &lt;code&gt;crypt&lt;/code&gt; container, and so on. The &lt;code&gt;MOUNTPOINTS&lt;/code&gt; column is empty when the partition is not mounted.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;RM&lt;/code&gt; column is &lt;code&gt;1&lt;/code&gt; when the kernel marks a device as removable, and &lt;code&gt;RO&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt; for read-only devices. Some USB drives report &lt;code&gt;RM&lt;/code&gt; as &lt;code&gt;0&lt;/code&gt;, so use the &lt;code&gt;TRAN&lt;/code&gt; column when you specifically need to identify USB storage.&lt;/p&gt;
&lt;h2 id="hide-partitions-and-child-devices"&gt;Hide Partitions and Child Devices &lt;a class="headline-link" href="#hide-partitions-and-child-devices" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you only care about top-level devices, pass the &lt;code&gt;-d&lt;/code&gt; (or &lt;code&gt;--nodeps&lt;/code&gt;) flag to hide their partitions, holders, and slaves:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 465.8G 0 disk
sdb 8:16 1 14.3G 0 disk
sr0 11:0 1 1024M 0 rom&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is handy when you do not want partition noise. It does not filter by device type, so entries such as the &lt;code&gt;sr0&lt;/code&gt; optical drive can still appear.&lt;/p&gt;
&lt;p&gt;Snap packages mount as loop devices, so on an Ubuntu desktop the list can fill with &lt;code&gt;loop0&lt;/code&gt; through &lt;code&gt;loop20&lt;/code&gt; before you reach the real disks. Exclude them by major number with &lt;code&gt;-e&lt;/code&gt; (or &lt;code&gt;--exclude&lt;/code&gt;):&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -e &lt;span class="m"&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Major number 7 is the loop driver. You can pass several numbers as a comma-separated list, for example &lt;code&gt;lsblk -e 7,11&lt;/code&gt; to drop optical drives as well.&lt;/p&gt;
&lt;h2 id="show-filesystem-information"&gt;Show Filesystem Information &lt;a class="headline-link" href="#show-filesystem-information" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Passing &lt;code&gt;-f&lt;/code&gt; (or &lt;code&gt;--fs&lt;/code&gt;) replaces the default columns with filesystem details such as the type, label, UUID, and how full each mounted filesystem is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -f&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1 vfat FAT32 4F3A-91BC 470.1M 8% /boot/efi
├─sda2 swap 1 9f4b5a44-6d1e-44a8-a0ae-2c3d3e4f1234 [SWAP]
└─sda3 ext4 1.0 root be2e1f8e-7a0b-4ab1-9f1d-5c6d7e8f9012 312.5G 25% /
sdb
└─sdb1 vfat FAT32 USB 1A2B-3C4D 12.8G 10% /media/john/usb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is usually the fastest way to find a UUID for &lt;code&gt;/etc/fstab&lt;/code&gt; or to confirm which filesystem type sits on a given partition.&lt;/p&gt;
&lt;h2 id="pick-specific-columns"&gt;Pick Specific Columns &lt;a class="headline-link" href="#pick-specific-columns" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The default columns cover the common cases, but you can choose exactly what to show with the &lt;code&gt;-o&lt;/code&gt; (or &lt;code&gt;--output&lt;/code&gt;) option. Pass a comma-separated list of column names:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -o NAME,SIZE,TYPE,MOUNTPOINTS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;NAME SIZE TYPE MOUNTPOINTS
sda 465.8G disk
├─sda1 512M part /boot/efi
├─sda2 16G part [SWAP]
└─sda3 449.3G part /
sdb 14.3G disk
└─sdb1 14.3G part /media/john/usb
sr0 1024M rom&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To see the full list of columns &lt;code&gt;lsblk&lt;/code&gt; understands, run:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk --list-columns&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On util-linux versions older than 2.41, that option does not exist yet, and &lt;code&gt;lsblk --help&lt;/code&gt; prints the column list instead.&lt;/p&gt;
&lt;p&gt;Useful columns include &lt;code&gt;UUID&lt;/code&gt;, &lt;code&gt;LABEL&lt;/code&gt;, &lt;code&gt;MODEL&lt;/code&gt;, &lt;code&gt;SERIAL&lt;/code&gt;, &lt;code&gt;VENDOR&lt;/code&gt;, &lt;code&gt;FSTYPE&lt;/code&gt;, &lt;code&gt;PARTTYPE&lt;/code&gt;, &lt;code&gt;HOTPLUG&lt;/code&gt;, and &lt;code&gt;TRAN&lt;/code&gt; (transport, for example &lt;code&gt;sata&lt;/code&gt;, &lt;code&gt;nvme&lt;/code&gt;, or &lt;code&gt;usb&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;To add columns to the default set rather than replace it, prefix the list with &lt;code&gt;+&lt;/code&gt;. For example, this command adds the model and serial number:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -o +MODEL,SERIAL&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-O&lt;/code&gt; (or &lt;code&gt;--output-all&lt;/code&gt;) flag has a different purpose: it displays every available column.&lt;/p&gt;
&lt;h2 id="show-device-paths"&gt;Show Device Paths &lt;a class="headline-link" href="#show-device-paths" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, &lt;code&gt;lsblk&lt;/code&gt; prints short names such as &lt;code&gt;sda1&lt;/code&gt;. If you want the full &lt;code&gt;/dev&lt;/code&gt; path in the &lt;code&gt;NAME&lt;/code&gt; column, add &lt;code&gt;-p&lt;/code&gt; (or &lt;code&gt;--paths&lt;/code&gt;):&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
/dev/sda 8:0 0 465.8G 0 disk
├─/dev/sda1 8:1 0 512M 0 part /boot/efi
├─/dev/sda2 8:2 0 16G 0 part [SWAP]
└─/dev/sda3 8:3 0 449.3G 0 part /&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Full paths are easier to copy into a script or a mount command.&lt;/p&gt;
&lt;h2 id="list-a-single-device"&gt;List a Single Device &lt;a class="headline-link" href="#list-a-single-device" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can pass a device path to inspect only that device and its partitions:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk /dev/sda&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This narrows the output to one disk, which is useful on servers with many drives.&lt;/p&gt;
&lt;h2 id="flat-and-ascii-output"&gt;Flat and ASCII Output &lt;a class="headline-link" href="#flat-and-ascii-output" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The tree layout is readable in a terminal but awkward to parse in scripts. Use &lt;code&gt;-l&lt;/code&gt; (or &lt;code&gt;--list&lt;/code&gt;) to print one device per line with no tree characters:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -l&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 465.8G 0 disk
sda1 8:1 0 512M 0 part /boot/efi
sda2 8:2 0 16G 0 part [SWAP]
sda3 8:3 0 449.3G 0 part /&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If your terminal does not render Unicode box-drawing characters correctly, swap them for plain ASCII with &lt;code&gt;-i&lt;/code&gt; (or &lt;code&gt;--ascii&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="machine-readable-output"&gt;Machine-Readable Output &lt;a class="headline-link" href="#machine-readable-output" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For scripts, the &lt;code&gt;-J&lt;/code&gt; (or &lt;code&gt;--json&lt;/code&gt;) flag prints the same information as structured JSON that is easy to parse with tools such as &lt;code&gt;jq&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -J -o NAME,SIZE,FSTYPE /dev/sda&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;{
&amp;#34;blockdevices&amp;#34;: [
{
&amp;#34;name&amp;#34;: &amp;#34;sda&amp;#34;,
&amp;#34;size&amp;#34;: &amp;#34;465.8G&amp;#34;,
&amp;#34;fstype&amp;#34;: null,
&amp;#34;children&amp;#34;: [
{
&amp;#34;name&amp;#34;: &amp;#34;sda1&amp;#34;,
&amp;#34;size&amp;#34;: &amp;#34;512M&amp;#34;,
&amp;#34;fstype&amp;#34;: &amp;#34;vfat&amp;#34;
},
{
&amp;#34;name&amp;#34;: &amp;#34;sda2&amp;#34;,
&amp;#34;size&amp;#34;: &amp;#34;16G&amp;#34;,
&amp;#34;fstype&amp;#34;: &amp;#34;swap&amp;#34;
},
{
&amp;#34;name&amp;#34;: &amp;#34;sda3&amp;#34;,
&amp;#34;size&amp;#34;: &amp;#34;449.3G&amp;#34;,
&amp;#34;fstype&amp;#34;: &amp;#34;ext4&amp;#34;
}
]
}
]
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each disk becomes an object, and its partitions appear in the &lt;code&gt;children&lt;/code&gt; array, so the tree relationship survives the conversion. Fields that do not apply are &lt;code&gt;null&lt;/code&gt; rather than empty strings, which keeps the types stable for &lt;code&gt;jq&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can also use &lt;code&gt;-P&lt;/code&gt; (pairs) for line-oriented &lt;code&gt;KEY=&amp;quot;value&amp;quot;&lt;/code&gt; output, or &lt;code&gt;-r&lt;/code&gt; (raw) for space-separated fields with no padding.&lt;/p&gt;
&lt;p&gt;The default columns can change between util-linux releases. In scripts, always select the columns you expect with &lt;code&gt;-o&lt;/code&gt;, then choose a predictable format such as &lt;code&gt;-J&lt;/code&gt;, &lt;code&gt;-P&lt;/code&gt;, or &lt;code&gt;-l&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, to list only mounted ext4 partitions in a script:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -lnp -o NAME,FSTYPE,MOUNTPOINTS &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;$2 == &amp;#34;ext4&amp;#34; &amp;amp;&amp;amp; $3 != &amp;#34;&amp;#34; {print $1, $3}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-n&lt;/code&gt; (or &lt;code&gt;--noheadings&lt;/code&gt;) flag drops the header row so that the output is pure data.&lt;/p&gt;
&lt;h2 id="show-sizes-in-bytes"&gt;Show Sizes in Bytes &lt;a class="headline-link" href="#show-sizes-in-bytes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sizes are printed in human-readable units by default, for example &lt;code&gt;465.8G&lt;/code&gt;. For exact values, use &lt;code&gt;-b&lt;/code&gt; (or &lt;code&gt;--bytes&lt;/code&gt;):&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsblk -b -o NAME,SIZE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is the form you want when comparing sizes in a script, since &lt;code&gt;465.8G&lt;/code&gt; is not directly comparable with &lt;code&gt;449.3G&lt;/code&gt; as a string.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Common &lt;code&gt;lsblk&lt;/code&gt; flags and what they do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-a&lt;/code&gt; - Include empty devices and RAM disks that are normally hidden.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b&lt;/code&gt; - Print sizes in bytes instead of human-readable units.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;/code&gt; - Hide partitions, holders, and slaves.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e LIST&lt;/code&gt; - Exclude devices by major number (7 is loop).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f&lt;/code&gt; - Show filesystem information (type, label, UUID, usage).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Use plain ASCII characters for the tree instead of Unicode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-J&lt;/code&gt; - Output as JSON.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Use a flat list instead of the tree layout.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Omit the header row.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o LIST&lt;/code&gt; - Choose which columns to display.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o +LIST&lt;/code&gt; - Add columns to the default output.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-O&lt;/code&gt; - Display every available column.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Print full device paths such as &lt;code&gt;/dev/sda1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-P&lt;/code&gt; - Output as &lt;code&gt;KEY=&amp;quot;value&amp;quot;&lt;/code&gt; pairs for shell scripts.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Raw output with no padding.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-S&lt;/code&gt; - Show information about SCSI devices only.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Print topology information (alignment, I/O sizes).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="faq"&gt;FAQ &lt;a class="headline-link" href="#faq" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;How is lsblk different from fdisk -l?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;lsblk&lt;/code&gt; reads from &lt;code&gt;sysfs&lt;/code&gt; and &lt;code&gt;udev&lt;/code&gt; and shows a tree of devices with mount points and filesystem details, all without root privileges for the common cases. &lt;a href="https://linuxize.com/post/fdisk-command-in-linux/"&gt;&lt;code&gt;fdisk -l&lt;/code&gt;&lt;/a&gt;
reads the partition table directly from the device and focuses on partition layout, sector offsets, and disk identifiers. Use &lt;code&gt;lsblk&lt;/code&gt; for a quick overview and &lt;code&gt;fdisk&lt;/code&gt; when you care about the raw partition table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why is a device missing from lsblk output?&lt;/strong&gt;&lt;br&gt;
Run &lt;code&gt;lsblk -a&lt;/code&gt; to include empty devices and RAM disks that are normally hidden. If you just connected or changed a device, run &lt;code&gt;udevadm settle&lt;/code&gt; before trying &lt;code&gt;lsblk&lt;/code&gt; again so udev can finish processing the event. A drive that the kernel never detected cannot appear in the list; check the cable or port and inspect recent messages with &lt;code&gt;sudo dmesg | tail -n 30&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How can I get only the UUID of a partition?&lt;/strong&gt;&lt;br&gt;
Combine &lt;code&gt;-n&lt;/code&gt; to drop the header, &lt;code&gt;-o UUID&lt;/code&gt; to pick the column, and the device path:&lt;br&gt;
&lt;code&gt;lsblk -no UUID /dev/sda3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Does lsblk show LVM and encrypted volumes?&lt;/strong&gt;&lt;br&gt;
Yes. LVM logical volumes appear as children of their physical volume with type &lt;code&gt;lvm&lt;/code&gt;, and LUKS-encrypted containers show as &lt;code&gt;crypt&lt;/code&gt;. The tree layout makes the stacking relationship easy to follow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can lsblk show disk model or serial number?&lt;/strong&gt;&lt;br&gt;
Yes. Add them to the output list: &lt;code&gt;lsblk -o NAME,MODEL,SERIAL,SIZE&lt;/code&gt;. Some virtual devices do not expose these fields, so they may be empty.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;lsblk&lt;/code&gt; is the fastest way to answer the &amp;ldquo;what disks and partitions does this machine have?&amp;rdquo; question, and its JSON and column-selection options make it equally useful inside scripts. Pair it with &lt;a href="https://linuxize.com/post/how-to-check-disk-space-in-linux-using-the-df-command/"&gt;&lt;code&gt;df&lt;/code&gt;&lt;/a&gt;
for usage stats and with &lt;a href="https://linuxize.com/post/how-to-mount-and-unmount-file-systems-in-linux/"&gt;&lt;code&gt;mount&lt;/code&gt;&lt;/a&gt;
when you are ready to attach a new device.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/lsblk-command-in-linux/featured_hu_e9209e660fdd0df0.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>How to Tail and Filter Logs in Real Time on Linux</title><link>https://linuxize.com/post/how-to-tail-and-filter-logs-in-real-time/</link><pubDate>Tue, 11 Aug 2026 09:30:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/how-to-tail-and-filter-logs-in-real-time/</guid><category>linux commands</category><description>Follow Linux logs in real time with tail -F, filter live output with grep, pause with less +F, and stream systemd service logs with journalctl -f.</description><content:encoded>&lt;p&gt;When you reproduce a bug or restart a service, the most useful view is often the log scrolling live as it happens. You want to see each new line when it is written, but you may also need to hide routine entries so the warning or error that matters does not disappear in the noise.&lt;/p&gt;
&lt;p&gt;Linux provides several ways to follow logs. Use &lt;code&gt;tail -F&lt;/code&gt; for a plain log file, &lt;code&gt;less +F&lt;/code&gt; when you need to pause and search, and &lt;code&gt;journalctl -f&lt;/code&gt; for output stored in the systemd journal. This guide shows how to use each tool and filter the live stream.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For printable quick references, see the &lt;a href="https://linuxize.com/cheatsheet/tail/"&gt;tail&lt;/a&gt;
, &lt;a href="https://linuxize.com/cheatsheet/grep/"&gt;grep&lt;/a&gt;
, &lt;a href="https://linuxize.com/cheatsheet/less/"&gt;less&lt;/a&gt;
, and &lt;a href="https://linuxize.com/cheatsheet/journalctl/"&gt;journalctl&lt;/a&gt;
cheatsheets.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Follow a file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tail -f /var/log/app.log&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow and survive rotation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tail -F /var/log/app.log&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow only newly appended lines&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tail -n 0 -F /var/log/app.log&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show last N lines, then follow&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tail -n 100 -f /var/log/app.log&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow several files at once&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tail -F /var/log/a.log /var/log/b.log&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow, scroll, search, and filter&lt;/td&gt;
&lt;td&gt;&lt;code&gt;less +F /var/log/app.log&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow a systemd unit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;journalctl -f -u nginx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow errors and more severe entries&lt;/td&gt;
&lt;td&gt;&lt;code&gt;journalctl -f -p err&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filter file logs by text&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tail -F app.log | grep -i error&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filter journal messages by text&lt;/td&gt;
&lt;td&gt;&lt;code&gt;journalctl -f -u nginx -g 'timeout|failed'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="follow-a-file-with-tail--f"&gt;Follow a File with tail -f &lt;a class="headline-link" href="#follow-a-file-with-tail--f" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;tail&lt;/code&gt; command prints the end of a file, and the &lt;code&gt;-f&lt;/code&gt; (&lt;code&gt;--follow&lt;/code&gt;) option keeps reading as new data is appended. This is the quickest way to watch a plain-text log:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -f /var/log/nginx/access.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The terminal shows the last 10 lines and then waits, adding each new request as it arrives. Press &lt;code&gt;Ctrl+C&lt;/code&gt; to stop. To start with more context, specify the number of existing lines to show:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -n &lt;span class="m"&gt;100&lt;/span&gt; -f /var/log/nginx/access.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you want to ignore existing entries and display only lines appended after the command starts, set the initial line count to zero:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -n &lt;span class="m"&gt;0&lt;/span&gt; -f /var/log/nginx/access.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;One catch is log rotation. Plain &lt;code&gt;-f&lt;/code&gt; follows the open file descriptor, so it can keep watching the old file after that file is renamed. On GNU &lt;code&gt;tail&lt;/code&gt;, &lt;code&gt;-F&lt;/code&gt; is equivalent to &lt;code&gt;--follow=name --retry&lt;/code&gt;: it watches the path and keeps trying to reopen the file when it is replaced or temporarily unavailable.&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -F /var/log/nginx/access.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can also watch more than one file in the same session. Pass several paths, and &lt;code&gt;tail&lt;/code&gt; prints a &lt;code&gt;==&amp;gt; path &amp;lt;==&lt;/code&gt; header each time the output switches to a different file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -F /var/log/nginx/access.log /var/log/nginx/error.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Those headers tell you which file produced the lines that follow, which matters when two logs use a similar format.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;-F&lt;/code&gt; for a long-running session on a rotating log. The &lt;a href="https://linuxize.com/post/linux-tail-command/"&gt;tail command&lt;/a&gt;
guide covers line counts, byte offsets, and other follow options.&lt;/p&gt;
&lt;h2 id="filter-a-live-stream-with-grep"&gt;Filter a Live Stream with grep &lt;a class="headline-link" href="#filter-a-live-stream-with-grep" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pipe the followed output into &lt;code&gt;grep&lt;/code&gt; to keep only matching lines. The following command ignores case, so it matches &lt;code&gt;error&lt;/code&gt;, &lt;code&gt;ERROR&lt;/code&gt;, and other capitalization variants:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -F /var/log/app.log &lt;span class="p"&gt;|&lt;/span&gt; grep -i error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this two-command pipeline, &lt;code&gt;grep&lt;/code&gt; writes directly to the terminal and normally displays each match immediately. If you send its output into another command, GNU &lt;code&gt;grep&lt;/code&gt; switches to full buffering. Add &lt;code&gt;--line-buffered&lt;/code&gt; before the next pipeline stage so matches continue moving one line at a time:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -F /var/log/app.log &lt;span class="p"&gt;|&lt;/span&gt; grep --line-buffered -i error &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;{ print $1, $2, $NF }&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here, &lt;code&gt;grep&lt;/code&gt; flushes each match to &lt;code&gt;awk&lt;/code&gt;, which prints the first two and last whitespace-separated fields. A later command can still have its own buffering rules, so check each stage if output remains delayed.&lt;/p&gt;
&lt;p&gt;Use extended regular expressions to match several severity words in one pass:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -F /var/log/app.log &lt;span class="p"&gt;|&lt;/span&gt; grep -Ei &lt;span class="s1"&gt;&amp;#39;error|warning|critical&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To hide a noisy health-check endpoint while keeping all other requests, invert the match with &lt;code&gt;-v&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -F /var/log/nginx/access.log &lt;span class="p"&gt;|&lt;/span&gt; grep -v &lt;span class="s1"&gt;&amp;#39;/health&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href="https://linuxize.com/post/how-to-use-grep-command-to-search-files-in-linux/"&gt;grep command&lt;/a&gt;
guide covers fixed strings, regular expressions, and inverted matches in more detail.&lt;/p&gt;
&lt;h2 id="scroll-and-search-with-less-f"&gt;Scroll and Search with less +F &lt;a class="headline-link" href="#scroll-and-search-with-less-f" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;tail -f&lt;/code&gt; shows new lines but does not let you inspect earlier entries without stopping the command. The &lt;code&gt;less&lt;/code&gt; pager has its own follow mode and lets you switch between live output and normal navigation:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;less +F /var/log/app.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Press &lt;code&gt;Ctrl+C&lt;/code&gt; to pause following. You can then scroll with the arrow keys or search forward by typing &lt;code&gt;/pattern&lt;/code&gt; and pressing &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To hide nonmatching lines, type &lt;code&gt;&amp;amp;pattern&lt;/code&gt; and press &lt;code&gt;Enter&lt;/code&gt;. Enter &lt;code&gt;&amp;amp;&lt;/code&gt; followed by &lt;code&gt;Enter&lt;/code&gt; to clear the filter. Press uppercase &lt;code&gt;F&lt;/code&gt; to return to follow mode; any active filter remains in effect while new lines arrive. The &lt;a href="https://linuxize.com/post/less-command-in-linux/"&gt;less command&lt;/a&gt;
guide covers navigation, searches, and display options.&lt;/p&gt;
&lt;h2 id="follow-a-service-with-journalctl--f"&gt;Follow a Service with journalctl -f &lt;a class="headline-link" href="#follow-a-service-with-journalctl--f" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On a systemd system, service output captured by &lt;code&gt;systemd-journald&lt;/code&gt; is read with &lt;code&gt;journalctl&lt;/code&gt;. Use &lt;code&gt;-f&lt;/code&gt; to follow new journal entries and &lt;code&gt;-u&lt;/code&gt; to limit them to one unit:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;journalctl -f -u nginx&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This follows entries associated with the &lt;code&gt;nginx&lt;/code&gt; unit, including service lifecycle messages and output sent to the journal. Applications can also write dedicated files. If Nginx access requests are stored in &lt;code&gt;/var/log/nginx/access.log&lt;/code&gt;, follow that file with &lt;code&gt;tail -F&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;Because journal entries contain structured fields, you can filter by priority. A single priority includes that level and all more severe levels, so &lt;code&gt;err&lt;/code&gt; shows &lt;code&gt;err&lt;/code&gt;, &lt;code&gt;crit&lt;/code&gt;, &lt;code&gt;alert&lt;/code&gt;, and &lt;code&gt;emerg&lt;/code&gt; entries:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;journalctl -f -u nginx -p err&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;-g&lt;/code&gt; (&lt;code&gt;--grep&lt;/code&gt;) to match a regular expression against the &lt;code&gt;MESSAGE&lt;/code&gt; field while following:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;journalctl -f -u nginx -g &lt;span class="s1"&gt;&amp;#39;timeout|failed&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To follow warnings and more severe entries from the current boot across all accessible units, combine &lt;code&gt;-f&lt;/code&gt;, &lt;code&gt;-p&lt;/code&gt;, and &lt;code&gt;-b&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;journalctl -f -b -p warning&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href="https://linuxize.com/post/journalctl-command-in-linux/"&gt;journalctl command&lt;/a&gt;
guide covers time ranges, boot selection, unit filters, and journal fields.&lt;/p&gt;
&lt;h2 id="which-tool-to-use"&gt;Which Tool to Use &lt;a class="headline-link" href="#which-tool-to-use" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The log destination determines the first choice. Use &lt;code&gt;tail -F&lt;/code&gt; for a rotating plain-text file, then pipe it through &lt;code&gt;grep&lt;/code&gt; when you need text filtering. Use &lt;code&gt;less +F&lt;/code&gt; when you expect to pause, scroll backward, search, or interactively hide nonmatching lines. Use &lt;code&gt;journalctl -f&lt;/code&gt; when the messages are stored in the systemd journal and you want to filter by unit, priority, boot, or message text.&lt;/p&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Permission denied when opening a log&lt;/strong&gt;&lt;br&gt;
Check the file permissions with &lt;code&gt;ls -l /path/to/log&lt;/code&gt;. Run &lt;code&gt;sudo tail -F /path/to/log&lt;/code&gt; only if your account is authorized to read that log. For the system journal, administrators can use &lt;code&gt;sudo journalctl&lt;/code&gt;, while many distributions also grant journal access through groups such as &lt;code&gt;adm&lt;/code&gt; or &lt;code&gt;systemd-journal&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No new lines appear&lt;/strong&gt;&lt;br&gt;
Confirm that the application is still appending to the path you opened. If the file was rotated or recreated, restart with &lt;code&gt;tail -F&lt;/code&gt;. Also remember that &lt;code&gt;tail&lt;/code&gt; follows appended data; it does not report text rewritten in place earlier in the file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;journalctl -p err misses a message containing ERROR&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;-p&lt;/code&gt; option checks the structured &lt;code&gt;PRIORITY&lt;/code&gt; field, not words inside the message. If an application logs the word &lt;code&gt;ERROR&lt;/code&gt; without assigning an error priority, use a text filter such as &lt;code&gt;journalctl -f -u SERVICE -g 'error'&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start with the unfiltered stream to confirm that you have the correct source, then add one filter at a time so you do not hide the event you are trying to diagnose. When a filter proves useful more than once, save it as a shell alias or a short script so the next incident starts from a view you already trust.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/how-to-tail-and-filter-logs-in-real-time/featured_hu_5b652935d1ba1fa6.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>Regular Expressions Explained: How Regex Patterns Work</title><link>https://linuxize.com/post/regular-expressions-basics/</link><pubDate>Mon, 03 Aug 2026 10:10:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/regular-expressions-basics/</guid><category>linux commands</category><description>Regular expressions explained from the ground up: how anchors, character classes, quantifiers, and groups build patterns that work in grep, sed, and awk.</description><content:encoded>&lt;p&gt;Sooner or later every command line session runs into a matching problem that plain text search cannot solve: find lines that start with a number, pull every email address out of a log, or replace dates in one format with another. Regular expressions (regex) are the pattern language that solves these problems, and the same core syntax works in &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, text editors, and most programming languages.&lt;/p&gt;
&lt;p&gt;This guide explains the building blocks of regular expressions, anchors, character classes, quantifiers, grouping, and alternation, and shows how the same pattern carries from &lt;code&gt;grep&lt;/code&gt; to &lt;code&gt;sed&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="what-a-regular-expression-is"&gt;What a Regular Expression Is &lt;a class="headline-link" href="#what-a-regular-expression-is" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A regular expression is a pattern that describes a set of strings. Instead of matching one literal word, a pattern like &lt;code&gt;^error [0-9]+&lt;/code&gt; matches any line that starts with &amp;ldquo;error&amp;rdquo; followed by a space and one or more digits.&lt;/p&gt;
&lt;p&gt;The examples in this guide use GNU &lt;code&gt;grep -E&lt;/code&gt; (extended regular expressions), so every pattern works as written. You can test any of them by piping text into &lt;a href="https://linuxize.com/post/how-to-use-grep-command-to-search-files-in-linux/"&gt;grep&lt;/a&gt;
:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;error 404&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;^error [0-9]+&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;error 404&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The line prints because it matches the pattern. When there is no match, &lt;code&gt;grep&lt;/code&gt; prints nothing and returns a non-zero exit status. Always single-quote the pattern so the shell does not interpret characters like &lt;code&gt;$&lt;/code&gt; and &lt;code&gt;*&lt;/code&gt; before &lt;code&gt;grep&lt;/code&gt; sees them.&lt;/p&gt;
&lt;h2 id="literal-characters-and-metacharacters"&gt;Literal Characters and Metacharacters &lt;a class="headline-link" href="#literal-characters-and-metacharacters" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most characters in a regex match themselves: the pattern &lt;code&gt;cat&lt;/code&gt; matches the string &amp;ldquo;cat&amp;rdquo; anywhere in a line, including inside &amp;ldquo;concatenate&amp;rdquo;. A handful of characters have special meanings instead of matching literally:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;. ^ $ * + ? ( ) [ ] { } | \&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;These are the metacharacters, and the rest of this guide is about what they do. To match one of them literally, escape it with a backslash: &lt;code&gt;\.&lt;/code&gt; matches a real dot, &lt;code&gt;\$&lt;/code&gt; a real dollar sign.&lt;/p&gt;
&lt;h2 id="anchors-and-word-boundaries"&gt;Anchors and Word Boundaries &lt;a class="headline-link" href="#anchors-and-word-boundaries" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Anchors and word boundaries do not match characters; they match positions in the line.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;^&lt;/code&gt; - Matches the start of the line.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$&lt;/code&gt; - Matches the end of the line.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\b&lt;/code&gt; - Matches a word boundary, the position between a word character and a non-word character.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;\b&lt;/code&gt; boundary is a GNU &lt;code&gt;grep&lt;/code&gt; extension rather than part of POSIX extended regular expression syntax.&lt;/p&gt;
&lt;p&gt;The difference is easiest to see on real input. The following input contains three similar lines, but the pattern prints only the line that consists of exactly the word &amp;ldquo;root&amp;rdquo;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;root\nroot:x:0:0\nchroot\n&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;^root$&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;root&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Without anchors, the pattern &lt;code&gt;root&lt;/code&gt; would also match &amp;ldquo;chroot&amp;rdquo; or a line where &amp;ldquo;root&amp;rdquo; appears in the middle. Word boundaries solve the substring problem without pinning the match to the whole line:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;the cat scattered&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -E -o &lt;span class="s1"&gt;&amp;#39;\bcat\b&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;cat&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-o&lt;/code&gt; flag prints only the matched text. Notice that &amp;ldquo;scattered&amp;rdquo; did not produce a match, because &amp;ldquo;cat&amp;rdquo; inside it is not surrounded by word boundaries.&lt;/p&gt;
&lt;h2 id="character-classes-matching-sets"&gt;Character Classes: Matching Sets &lt;a class="headline-link" href="#character-classes-matching-sets" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Square brackets match one character from a set:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[abc]&lt;/code&gt; - One character: a, b, or c.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[a-z]&lt;/code&gt; - One lowercase letter; ranges also work for &lt;code&gt;[0-9]&lt;/code&gt; and &lt;code&gt;[A-Z]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[^abc]&lt;/code&gt; - Negation: one character that is NOT a, b, or c.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, to match &amp;ldquo;gray&amp;rdquo; and &amp;ldquo;grey&amp;rdquo; with one pattern:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gray\ngrey\ngroy\n&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;gr[ae]y&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;gray
grey&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The third line does not match because &amp;ldquo;o&amp;rdquo; is not in the set. Inside brackets, most metacharacters lose their special meaning; &lt;code&gt;[.]&lt;/code&gt; matches a literal dot.&lt;/p&gt;
&lt;p&gt;POSIX character classes are named shortcuts that work inside brackets: &lt;code&gt;[[:digit:]]&lt;/code&gt; is equivalent to &lt;code&gt;[0-9]&lt;/code&gt;, &lt;code&gt;[[:alpha:]]&lt;/code&gt; matches letters, &lt;code&gt;[[:space:]]&lt;/code&gt; matches whitespace. Many tools also support the Perl-style shorthands &lt;code&gt;\d&lt;/code&gt; wherever PCRE is available (&lt;code&gt;grep -P&lt;/code&gt;), but the bracket forms are the portable choice for shell work.&lt;/p&gt;
&lt;h2 id="the-dot-and-quantifiers-matching-repetition"&gt;The Dot and Quantifiers: Matching Repetition &lt;a class="headline-link" href="#the-dot-and-quantifiers-matching-repetition" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The dot &lt;code&gt;.&lt;/code&gt; matches any single character except a newline. Quantifiers apply to the preceding item and control how many times it may repeat:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt; - Zero or more times.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+&lt;/code&gt; - One or more times.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?&lt;/code&gt; - Zero or one time (optional).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{n}&lt;/code&gt; - Exactly n times.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{n,m}&lt;/code&gt; - Between n and m times.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Combining the dot with a quantifier gives &lt;code&gt;.*&lt;/code&gt;, which matches anything, including nothing. A more precise example matches an IPv4-looking address by requiring one to three digits in each group:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;server at 192.168.1.10 is up&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -E -o &lt;span class="s1"&gt;&amp;#39;[0-9]{1,3}(\.[0-9]{1,3}){3}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;192.168.1.10&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Reading it piece by piece: &lt;code&gt;[0-9]{1,3}&lt;/code&gt; matches the first number group, &lt;code&gt;\.&lt;/code&gt; matches a literal dot, and the parentheses with &lt;code&gt;{3}&lt;/code&gt; repeat the dot-plus-number sequence three times.&lt;/p&gt;
&lt;p&gt;A common beginner mistake is reaching for &lt;code&gt;*&lt;/code&gt; when &lt;code&gt;+&lt;/code&gt; is meant. The pattern &lt;code&gt;[0-9]*&lt;/code&gt; happily matches an empty string, so it succeeds on every line; &lt;code&gt;[0-9]+&lt;/code&gt; actually requires a digit.&lt;/p&gt;
&lt;h2 id="grouping-and-alternation"&gt;Grouping and Alternation &lt;a class="headline-link" href="#grouping-and-alternation" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Parentheses group parts of a pattern, and the pipe &lt;code&gt;|&lt;/code&gt; provides alternation (OR):&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;error: disk full\nwarning: low memory\ninfo: started\n&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;^(error|warning):&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;error: disk full
warning: low memory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The group limits the alternation to the two words before the colon; without parentheses, &lt;code&gt;^error|warning:&lt;/code&gt; would mean &amp;ldquo;starts with error, OR contains warning: anywhere&amp;rdquo;, which is rarely what you want.&lt;/p&gt;
&lt;p&gt;Groups also capture what they match, and the captured text can be reused. In &lt;a href="https://linuxize.com/post/how-to-use-sed-to-find-and-replace-string-in-files/"&gt;sed&lt;/a&gt;
, &lt;code&gt;\1&lt;/code&gt; refers to the first group, which makes reordering text possible:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2026-01-15&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed -E &lt;span class="s1"&gt;&amp;#39;s/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;15.01.2026&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The three groups capture the year, month, and day, and the replacement writes them back in reverse order.&lt;/p&gt;
&lt;h2 id="basic-vs-extended-regular-expressions"&gt;Basic vs Extended Regular Expressions &lt;a class="headline-link" href="#basic-vs-extended-regular-expressions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;POSIX defines two regex dialects, and the difference trips up almost everyone at some point. In basic regular expressions (BRE), which plain &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;sed&lt;/code&gt; use, the characters &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;{}&lt;/code&gt;, and &lt;code&gt;()&lt;/code&gt; match literally, and you must escape them (&lt;code&gt;\+&lt;/code&gt;, &lt;code&gt;\(&lt;/code&gt; &amp;hellip; &lt;code&gt;\)&lt;/code&gt;) to get the special behavior. In extended regular expressions (ERE), they are special by default.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construct&lt;/th&gt;
&lt;th&gt;ERE (&lt;code&gt;grep -E&lt;/code&gt;, &lt;code&gt;sed -E&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;BRE (plain &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One or more&lt;/td&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\+&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;&lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\?&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repetition&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{n,m}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\{n,m\}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grouping&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\(...\)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alternation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a|b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a\|b&lt;/code&gt;, GNU extension only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That last row is the one to watch. Alternation is not part of POSIX BRE at all, so &lt;code&gt;\|&lt;/code&gt; works in GNU &lt;code&gt;grep&lt;/code&gt; and GNU &lt;code&gt;sed&lt;/code&gt; but fails silently on the BSD &lt;code&gt;sed&lt;/code&gt; that ships with macOS.&lt;/p&gt;
&lt;p&gt;In practice, the simplest rule is: pass &lt;code&gt;-E&lt;/code&gt; to &lt;code&gt;grep&lt;/code&gt; and &lt;code&gt;sed&lt;/code&gt; and write in the extended dialect, as every example in this guide does. &lt;code&gt;awk&lt;/code&gt; uses extended syntax natively:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;alice 92\nbob 47\ncarol 78\n&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;/^[ab]/ {print $1}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;alice
bob&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href="https://linuxize.com/post/awk-command/"&gt;awk&lt;/a&gt;
pattern selects lines starting with &amp;ldquo;a&amp;rdquo; or &amp;ldquo;b&amp;rdquo; and prints the first field. &lt;code&gt;grep -P&lt;/code&gt; enables a third dialect, Perl-compatible regular expressions (PCRE), which adds features like &lt;code&gt;\d&lt;/code&gt; and lookarounds; reach for it when the POSIX dialects run out.&lt;/p&gt;
&lt;h2 id="one-pattern-three-tools"&gt;One Pattern, Three Tools &lt;a class="headline-link" href="#one-pattern-three-tools" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The syntax is shared, but each tool wraps it differently, which is the part that usually causes confusion when moving a working pattern from one command to another. Create a small log file to follow along:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;error: disk full\nwarning: low memory\ninfo: started\n&amp;#39;&lt;/span&gt; &amp;gt; app.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Because &lt;code&gt;grep&lt;/code&gt; is a filter, the pattern is the whole job and needs nothing around it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -E &lt;span class="s1"&gt;&amp;#39;^(error|warning):&amp;#39;&lt;/span&gt; app.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;sed&lt;/code&gt; prints every input line unless you suppress that with &lt;code&gt;-n&lt;/code&gt;, so selecting lines takes an address followed by an explicit &lt;code&gt;p&lt;/code&gt; command:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -E -n &lt;span class="s1"&gt;&amp;#39;/^(error|warning):/p&amp;#39;&lt;/span&gt; app.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;awk&lt;/code&gt; reads a bare pattern with no action block as &amp;ldquo;print the matching line&amp;rdquo;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;awk &lt;span class="s1"&gt;&amp;#39;/^(error|warning):/&amp;#39;&lt;/span&gt; app.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;error: disk full
warning: low memory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All three print the same two lines and skip the &amp;ldquo;info&amp;rdquo; line. Where the tools part company is what happens after the match. &lt;code&gt;grep&lt;/code&gt; reports lines and stops there, &lt;code&gt;sed&lt;/code&gt; can rewrite the matched text, and &lt;code&gt;awk&lt;/code&gt; splits each matching line into fields you can work with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;awk -F&lt;span class="s1"&gt;&amp;#39;: &amp;#39;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/^(error|warning):/ {print $2}&amp;#39;&lt;/span&gt; app.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;disk full
low memory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Setting the field separator to &lt;code&gt;': '&lt;/code&gt; makes &lt;code&gt;$2&lt;/code&gt; the message text, so the pattern selects the lines and the action block pulls out the part you actually wanted. This is why it pays to learn regex once as its own subject: the pattern you write today for &lt;code&gt;grep&lt;/code&gt; is the same pattern you will paste into &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, a text editor, or a Python script tomorrow.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/regex/"&gt;Regex cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Matches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any single character&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;^&lt;/code&gt; / &lt;code&gt;$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start / end of line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Word boundary in GNU grep&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[abc]&lt;/code&gt; / &lt;code&gt;[^abc]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One of the set / one not in the set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[0-9]&lt;/code&gt;, &lt;code&gt;[[:digit:]]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One digit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt; / &lt;code&gt;+&lt;/code&gt; / &lt;code&gt;?&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Zero or more / one or more / optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;{n,m}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Between n and m repetitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(foo|bar)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;foo or bar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text captured by the first group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Literal dot (escaped metacharacter)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Anchors, character classes, quantifiers, and groups combine into patterns that handle most day-to-day matching on Linux, and the same vocabulary carries over to editors and programming languages. To put the syntax to work in specific tools, see our guides to &lt;a href="https://linuxize.com/post/regular-expressions-in-grep/"&gt;regular expressions in grep&lt;/a&gt;
and &lt;a href="https://linuxize.com/post/how-to-use-sed-to-find-and-replace-string-in-files/"&gt;find and replace with sed&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/regular-expressions-basics/featured_hu_e5f430d4863b69dd.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>git worktree: Work on Multiple Branches at Once</title><link>https://linuxize.com/post/git-worktree/</link><pubDate>Sun, 02 Aug 2026 09:20:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/git-worktree/</guid><category>git</category><category>linux commands</category><description>Use git worktree to check out multiple branches in separate directories, handle urgent fixes without stashing, and clean up linked worktrees safely.</description><content:encoded>&lt;p&gt;A common frustration when working with Git is needing to switch branches while your current working tree has uncommitted changes. You can &lt;a href="https://linuxize.com/post/git-stash/"&gt;stash the changes&lt;/a&gt;
, switch branches, make the fix, switch back, and restore the stash, but that flow interrupts your work and can create conflicts. &lt;code&gt;git worktree&lt;/code&gt; lets you check out another branch in a separate directory, so both workspaces remain available at the same time.&lt;/p&gt;
&lt;p&gt;This guide explains how to create, list, lock, prune, and remove linked worktrees, with a hotfix workflow you can copy.&lt;/p&gt;
&lt;h2 id="how-git-worktree-works"&gt;How git worktree Works &lt;a class="headline-link" href="#how-git-worktree-works" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A Git repository normally has one working tree: the directory where you edit files. With &lt;code&gt;git worktree&lt;/code&gt;, you can attach additional working trees to the same repository. Each linked worktree has its own working directory, index, and &lt;code&gt;HEAD&lt;/code&gt;, while all worktrees share the same object store and repository history. You do not create another clone; you create another workspace for the same repository.&lt;/p&gt;
&lt;h2 id="git-worktree-syntax"&gt;git worktree Syntax &lt;a class="headline-link" href="#git-worktree-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The most-used forms of the command are:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add [OPTIONS] &amp;lt;path&amp;gt; [&amp;lt;commit-ish&amp;gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree list [OPTIONS]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree remove [--force] &amp;lt;worktree&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree prune [OPTIONS]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree lock [--reason &amp;lt;string&amp;gt;] &amp;lt;worktree&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree unlock &amp;lt;worktree&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="add-a-worktree-for-an-existing-branch"&gt;Add a Worktree for an Existing Branch &lt;a class="headline-link" href="#add-a-worktree-for-an-existing-branch" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Suppose you are working on a feature branch and want a separate checkout of &lt;code&gt;main&lt;/code&gt;. Add it in a sibling directory without leaving your current branch:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add ../project-main main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Preparing worktree (checking out &amp;#39;main&amp;#39;)
HEAD is now at a1b2c3d Fix typo in README&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The new directory &lt;code&gt;../project-main&lt;/code&gt; contains &lt;code&gt;main&lt;/code&gt;, while your original working tree stays on the feature branch. Git refuses this command if &lt;code&gt;main&lt;/code&gt; is already checked out in another worktree.&lt;/p&gt;
&lt;h2 id="add-a-worktree-with-a-new-branch"&gt;Add a Worktree with a New Branch &lt;a class="headline-link" href="#add-a-worktree-with-a-new-branch" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a hotfix, create a new branch from &lt;code&gt;main&lt;/code&gt; and check it out in one step:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add -b hotfix/payment-null ../project-hotfix main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Preparing worktree (new branch &amp;#39;hotfix/payment-null&amp;#39;)
HEAD is now at a1b2c3d Fix typo in README&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-b&lt;/code&gt; flag creates &lt;code&gt;hotfix/payment-null&lt;/code&gt; from &lt;code&gt;main&lt;/code&gt; and checks it out in the new directory. After making the fix and running your tests, commit and push from that worktree:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../project-hotfix
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Edit the files and run your tests&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m &lt;span class="s2"&gt;&amp;#34;Fix payment handler&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push -u origin hotfix/payment-null&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Your original directory remains on the feature branch throughout this workflow.&lt;/p&gt;
&lt;h2 id="list-all-worktrees"&gt;List All Worktrees &lt;a class="headline-link" href="#list-all-worktrees" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To display the main worktree and every linked worktree, run:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;/home/user/project abc1234 [feature/new-dashboard]
/home/user/project-hotfix def5678 [hotfix/payment-null]
/home/user/project-main a1b2c3d [main]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first entry is always the main worktree. Each linked worktree shows its path, current commit, and checked-out branch.&lt;/p&gt;
&lt;h2 id="run-tests-across-branches-in-parallel"&gt;Run Tests Across Branches in Parallel &lt;a class="headline-link" href="#run-tests-across-branches-in-parallel" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Worktrees are useful for running a test suite against two commits at the same time. For a temporary test directory that does not need its own branch, create a detached worktree:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add --detach ../project-test main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../project-test &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm ci &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wait&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first background job installs dependencies and runs the tests against &lt;code&gt;main&lt;/code&gt; in &lt;code&gt;../project-test&lt;/code&gt;, while the second runs in your current worktree. Both worktrees share the Git object store but keep their working files and installed dependencies separate.&lt;/p&gt;
&lt;h2 id="remove-a-worktree"&gt;Remove a Worktree &lt;a class="headline-link" href="#remove-a-worktree" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you are done with a linked worktree, remove it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree remove ../project-hotfix&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This deletes the linked directory and unregisters it from the repository. It does not delete the &lt;code&gt;hotfix/payment-null&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;Git refuses to remove a worktree with modified or untracked files. Check its status before deciding whether to force removal:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git -C ../project-hotfix status&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;The &lt;code&gt;--force&lt;/code&gt; option deletes the linked directory even when it contains modified or untracked files. Commit or copy anything you need before running it.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you are certain that the remaining files are disposable, force the removal with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree remove --force ../project-hotfix&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="prune-stale-worktree-references"&gt;Prune Stale Worktree References &lt;a class="headline-link" href="#prune-stale-worktree-references" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you delete a worktree directory manually, Git retains its administrative entry. Preview the stale entries that qualify for removal with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree prune --dry-run --verbose&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After reviewing the output, remove those entries with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree prune --verbose&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This command removes stale metadata, not active worktree directories. &lt;code&gt;git gc&lt;/code&gt; also prunes missing entries older than the configured &lt;code&gt;gc.worktreePruneExpire&lt;/code&gt; period, which defaults to three months.&lt;/p&gt;
&lt;h2 id="lock-a-worktree"&gt;Lock a Worktree &lt;a class="headline-link" href="#lock-a-worktree" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If a worktree lives on a removable drive or a network path that may be temporarily unavailable, lock it so &lt;code&gt;prune&lt;/code&gt; does not remove it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree lock --reason &lt;span class="s2"&gt;&amp;#34;on external drive&amp;#34;&lt;/span&gt; ../project-hotfix&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Unlock it when the path is available again:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree unlock ../project-hotfix&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A lock also protects the worktree from &lt;code&gt;git worktree remove&lt;/code&gt;, and a single &lt;code&gt;--force&lt;/code&gt; is not enough to override it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;fatal: cannot remove a locked working tree, lock reason: on external drive
use &amp;#39;remove -f -f&amp;#39; to override or unlock first&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unlock the worktree first, or pass the force option twice:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree remove --force --force ../project-hotfix&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/git/"&gt;Git cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git worktree add ../path branch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check out an existing branch in a linked worktree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git worktree add -b new-branch ../path main&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new branch from &lt;code&gt;main&lt;/code&gt; in a linked worktree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git worktree add --detach ../path main&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a detached worktree for testing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git worktree list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List the main and linked worktrees&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git worktree lock --reason &amp;quot;text&amp;quot; ../path&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Protect a temporarily unavailable worktree from pruning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git worktree remove ../path&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete and unregister a clean linked worktree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git worktree prune --dry-run --verbose&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview stale administrative entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;git worktree repair /new/path&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Repair the link to a manually moved worktree&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Git reports that a branch is already checked out&lt;/strong&gt;&lt;br&gt;
A branch can normally be checked out in only one worktree. Create a new branch from it instead:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add -b new-branch ../project-new main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you only need the files for testing and do not plan to commit, use a detached worktree:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add --detach ../project-test main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Git cannot find a manually moved worktree&lt;/strong&gt;&lt;br&gt;
If you moved a linked directory without &lt;code&gt;git worktree move&lt;/code&gt;, repair its administrative link from another worktree:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree repair /new/path&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Use the new location as the argument. Git reconnects the linked directory without checking it out again.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git worktree&lt;/code&gt; keeps parallel tasks isolated without creating another clone or disturbing your current files. Create a dedicated branch for changes, use detached worktrees for temporary tests, and see the &lt;a href="https://linuxize.com/post/git-branch-command/"&gt;git branch guide&lt;/a&gt;
when you need to rename, inspect, or delete the branches afterward.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/git-worktree/featured_hu_8ad545d280dbf955.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>killall Command in Linux: Kill Processes by Name</title><link>https://linuxize.com/post/killall-command-in-linux/</link><pubDate>Sat, 01 Aug 2026 08:40:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/killall-command-in-linux/</guid><category>linux commands</category><description>Use the Linux killall command to stop processes by name, select signals, filter by user or age, confirm matches, and compare killall with kill and pkill.</description><content:encoded>&lt;p&gt;When a program misbehaves, it may leave several processes running. Modern browsers start separate worker processes, and a stuck script may have been launched several times in different terminals. Killing each one with the &lt;a href="https://linuxize.com/post/kill-command-in-linux/"&gt;&lt;code&gt;kill&lt;/code&gt; command&lt;/a&gt;
means looking up every PID first. The &lt;code&gt;killall&lt;/code&gt; command skips that step: you give it a process name, and it signals every process running under that name.&lt;/p&gt;
&lt;p&gt;This guide explains how to use &lt;code&gt;killall&lt;/code&gt; to terminate processes by name, choose the signal to send, and narrow matches by user, age, or pattern.&lt;/p&gt;
&lt;h2 id="installing-killall"&gt;Installing killall &lt;a class="headline-link" href="#installing-killall" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;killall&lt;/code&gt; is part of the &lt;code&gt;psmisc&lt;/code&gt; package, which is preinstalled on most desktop and server distributions. If the command is missing, install it from the standard repositories.&lt;/p&gt;
&lt;p&gt;On Ubuntu, Debian, and Derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install psmisc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On Fedora, RHEL, and Derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install psmisc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;On Linux, the &lt;code&gt;psmisc&lt;/code&gt; version of &lt;code&gt;killall&lt;/code&gt; affects only processes matching the given name. On some other Unix systems, such as Solaris and AIX, &lt;code&gt;killall&lt;/code&gt; signals nearly every process on the machine, which is how those systems tear things down at shutdown. Confirm which implementation is installed before running &lt;code&gt;killall&lt;/code&gt; on a remote system, especially as root.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="killall-syntax"&gt;killall Syntax &lt;a class="headline-link" href="#killall-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The general syntax of the &lt;code&gt;killall&lt;/code&gt; command is as follows:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall [OPTIONS] NAME...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;NAME&lt;/code&gt; is the process name to match. You can pass more than one name, and &lt;code&gt;killall&lt;/code&gt; signals every process that matches any of them. Unlike &lt;code&gt;pkill&lt;/code&gt;, which matches partial names, &lt;code&gt;killall&lt;/code&gt; requires the name to match exactly.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;killall&lt;/code&gt; exits with status zero when it successfully signals at least one process for every name you supplied. If a name does not match, it prints a message and returns a non-zero status:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall firefox&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;firefox: no process found&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="killing-a-process-by-name"&gt;Killing a Process by Name &lt;a class="headline-link" href="#killing-a-process-by-name" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To terminate a process, pass its exact name:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall firefox&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;By default, &lt;code&gt;killall&lt;/code&gt; sends the &lt;code&gt;SIGTERM&lt;/code&gt; signal, which asks each matching process to shut down cleanly. The command produces no output when it succeeds. Add &lt;code&gt;-v&lt;/code&gt; to confirm what was signalled:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -v vlc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Killed vlc(8143) with signal 15&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The output shows the process name, its PID, and the signal number. Signal 15 is &lt;code&gt;SIGTERM&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before sending a signal, use &lt;a href="https://linuxize.com/post/pgrep-command-in-linux/"&gt;&lt;code&gt;pgrep&lt;/code&gt;&lt;/a&gt;
to preview exact matches and their full command lines:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pgrep -a -x firefox&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If this command prints nothing, check &lt;code&gt;ps -e -o pid,comm&lt;/code&gt; to find the process name that Linux reports.&lt;/p&gt;
&lt;h2 id="sending-a-specific-signal"&gt;Sending a Specific Signal &lt;a class="headline-link" href="#sending-a-specific-signal" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a process ignores &lt;code&gt;SIGTERM&lt;/code&gt;, you can send a stronger signal. The &lt;code&gt;-s&lt;/code&gt; option accepts a signal name or number:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -s KILL myscript&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;SIGKILL&lt;/code&gt; cannot be caught or ignored, so the process is terminated immediately without a chance to clean up. The same signal can be written in two shorter forms:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -9 myscript
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -SIGKILL myscript&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;SIGKILL&lt;/code&gt; only after a plain &lt;code&gt;killall&lt;/code&gt; has failed. A process killed this way cannot flush buffers or remove its temporary files, which is why trying &lt;code&gt;SIGTERM&lt;/code&gt; first is the safer habit. For a longer discussion of signals and when to use each, see our guide on &lt;a href="https://linuxize.com/post/how-to-kill-a-process-in-linux/"&gt;how to kill a process in Linux&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Signals are also useful for more than termination. For example, BIND reloads its configuration when the &lt;code&gt;named&lt;/code&gt; process receives &lt;code&gt;SIGHUP&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo killall -s HUP named&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To list all signal names that &lt;code&gt;killall&lt;/code&gt; understands, use &lt;code&gt;-l&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -l&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT
CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="matching-names-case-insensitively"&gt;Matching Names Case-Insensitively &lt;a class="headline-link" href="#matching-names-case-insensitively" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Process name matching is case-sensitive by default. If you are not sure about the capitalization, add &lt;code&gt;-I&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -I &lt;span class="s2"&gt;&amp;#34;teamviewer&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This matches &lt;code&gt;TeamViewer&lt;/code&gt;, &lt;code&gt;teamviewer&lt;/code&gt;, and any other case variant of the name.&lt;/p&gt;
&lt;h2 id="matching-with-regular-expressions"&gt;Matching with Regular Expressions &lt;a class="headline-link" href="#matching-with-regular-expressions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-r&lt;/code&gt; option interprets the name as an extended regular expression, so you can signal several related processes at once:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -r &lt;span class="s1"&gt;&amp;#39;^chrom.*&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;^&lt;/code&gt; anchor limits the match to names that begin with &lt;code&gt;chrom&lt;/code&gt;, such as &lt;code&gt;chrome&lt;/code&gt; and &lt;code&gt;chromium&lt;/code&gt;. Quote the pattern so the shell does not interpret special characters before &lt;code&gt;killall&lt;/code&gt; sees them.&lt;/p&gt;
&lt;h2 id="killing-processes-owned-by-a-user"&gt;Killing Processes Owned by a User &lt;a class="headline-link" href="#killing-processes-owned-by-a-user" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-u&lt;/code&gt; option restricts matches to processes owned by a specific user:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -u sarah node&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This terminates only the &lt;code&gt;node&lt;/code&gt; processes running under the &lt;code&gt;sarah&lt;/code&gt; account, leaving other users&amp;rsquo; &lt;code&gt;node&lt;/code&gt; processes alone.&lt;/p&gt;
&lt;p&gt;If you pass &lt;code&gt;-u&lt;/code&gt; without a process name, &lt;code&gt;killall&lt;/code&gt; signals every process the user owns:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo killall -u sarah&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Be careful with this form. It terminates the user&amp;rsquo;s entire session, including their shell and any editors with unsaved work. Combine it with &lt;code&gt;-i&lt;/code&gt; when you want to review each process first.&lt;/p&gt;
&lt;h2 id="confirming-each-kill-interactively"&gt;Confirming Each Kill Interactively &lt;a class="headline-link" href="#confirming-each-kill-interactively" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-i&lt;/code&gt; option asks for confirmation before signalling each matching process:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -i node&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Kill node(2211) ? (y/N)
Kill node(2384) ? (y/N)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Answer &lt;code&gt;y&lt;/code&gt; to signal a process or press Enter to skip it. Interactive mode is a good safety net when a name is common enough to match processes you did not have in mind.&lt;/p&gt;
&lt;h2 id="filtering-by-process-age"&gt;Filtering by Process Age &lt;a class="headline-link" href="#filtering-by-process-age" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-o&lt;/code&gt; (older) and &lt;code&gt;-y&lt;/code&gt; (younger) options filter matches by how long a process has been running. The time is a whole number followed by a unit: &lt;code&gt;s&lt;/code&gt; for seconds, &lt;code&gt;m&lt;/code&gt; for minutes, &lt;code&gt;h&lt;/code&gt; for hours, &lt;code&gt;d&lt;/code&gt; for days, &lt;code&gt;w&lt;/code&gt; for weeks, &lt;code&gt;M&lt;/code&gt; for months, and &lt;code&gt;y&lt;/code&gt; for years.&lt;/p&gt;
&lt;p&gt;To kill &lt;code&gt;myscript&lt;/code&gt; processes that have been running for more than an hour:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -o 1h myscript&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To kill only instances started within the last ten minutes:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -y 10m myscript&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The age filters are handy for cleaning up stuck workers or runaway cron jobs while leaving fresh, healthy instances running.&lt;/p&gt;
&lt;h2 id="waiting-for-processes-to-die"&gt;Waiting for Processes to Die &lt;a class="headline-link" href="#waiting-for-processes-to-die" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, &lt;code&gt;killall&lt;/code&gt; sends the signal and returns immediately. The &lt;code&gt;-w&lt;/code&gt; option makes it wait until all signalled processes have actually terminated:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;killall -w myscript &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;all stopped&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is useful in scripts that must not continue until a service is fully down. The wait can continue forever if the signal is ignored, has no effect, or leaves the process in a zombie state.&lt;/p&gt;
&lt;p&gt;To put a ten-second limit on the wait, run &lt;code&gt;killall&lt;/code&gt; through the &lt;a href="https://linuxize.com/post/timeout-command-in-linux/"&gt;&lt;code&gt;timeout&lt;/code&gt; command&lt;/a&gt;
:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;timeout 10s killall -w myscript&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the limit expires, &lt;code&gt;timeout&lt;/code&gt; stops the &lt;code&gt;killall&lt;/code&gt; command, but the target process may still be running. Inspect it with &lt;code&gt;pgrep&lt;/code&gt; before deciding whether to send &lt;code&gt;SIGKILL&lt;/code&gt;. A process that remains in a zombie state can also cause &lt;code&gt;killall -w&lt;/code&gt; to keep waiting.&lt;/p&gt;
&lt;h2 id="killall-vs-kill-vs-pkill"&gt;killall vs kill vs pkill &lt;a class="headline-link" href="#killall-vs-kill-vs-pkill" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All three commands send signals; they differ in how you select the target processes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kill&lt;/code&gt; targets a specific PID. It is the most precise option, but you have to look the PID up first.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;killall&lt;/code&gt; targets an exact process name and signals every instance of it.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linuxize.com/post/pkill-command-in-linux/"&gt;&lt;code&gt;pkill&lt;/code&gt;&lt;/a&gt;
targets a name pattern, so &lt;code&gt;pkill fire&lt;/code&gt; matches &lt;code&gt;firefox&lt;/code&gt;. It can also match against the full command line with &lt;code&gt;-f&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The exact-name behavior of &lt;code&gt;killall&lt;/code&gt; makes it more predictable than &lt;code&gt;pkill&lt;/code&gt; for everyday use: &lt;code&gt;killall node&lt;/code&gt; cannot accidentally match &lt;code&gt;node_exporter&lt;/code&gt;. Linux limits the process name stored in &lt;code&gt;/proc/PID/stat&lt;/code&gt; to 15 characters. For longer names, &lt;code&gt;killall&lt;/code&gt; may have to fall back to those first 15 characters when the full name is unavailable. Add &lt;code&gt;-e&lt;/code&gt; to skip a long-name match that cannot be verified exactly.&lt;/p&gt;
&lt;h2 id="common-options"&gt;Common Options &lt;a class="headline-link" href="#common-options" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-s SIGNAL&lt;/code&gt; - Send the given signal instead of &lt;code&gt;SIGTERM&lt;/code&gt;. Also accepts the &lt;code&gt;-SIGNAL&lt;/code&gt; and numeric forms.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - List known signal names.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Report each signal that was successfully sent.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; - Do not complain when no process matched.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-I&lt;/code&gt; - Match process names case-insensitively.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Interpret the name as an extended regular expression.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; - Require an exact match for names longer than 15 characters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-u USER&lt;/code&gt; - Match only processes owned by the given user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt; - Ask for confirmation before signalling each process.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o TIME&lt;/code&gt; - Match only processes older than the given age.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-y TIME&lt;/code&gt; - Match only processes younger than the given age.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-w&lt;/code&gt; - Wait until all signalled processes have died.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/kill/"&gt;kill cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Terminate all processes with a name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;killall firefox&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Force kill after a failed terminate&lt;/td&gt;
&lt;td&gt;&lt;code&gt;killall -9 firefox&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reload BIND&amp;rsquo;s configuration&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo killall -s HUP named&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ignore name capitalization&lt;/td&gt;
&lt;td&gt;&lt;code&gt;killall -I teamviewer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Match names by regex&lt;/td&gt;
&lt;td&gt;&lt;code&gt;killall -r '^chrom.*'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kill a user&amp;rsquo;s instances of a program&lt;/td&gt;
&lt;td&gt;&lt;code&gt;killall -u sarah node&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kill all of a user&amp;rsquo;s processes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo killall -u sarah&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confirm each kill&lt;/td&gt;
&lt;td&gt;&lt;code&gt;killall -i node&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kill instances older than one hour&lt;/td&gt;
&lt;td&gt;&lt;code&gt;killall -o 1h myscript&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wait until processes exit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;killall -w myscript&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List signal names&lt;/td&gt;
&lt;td&gt;&lt;code&gt;killall -l&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;killall: no process found&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;killall&lt;/code&gt; requires the process name to match exactly unless you use &lt;code&gt;-r&lt;/code&gt; or &lt;code&gt;-I&lt;/code&gt;. Run &lt;code&gt;pgrep -a pattern&lt;/code&gt; or &lt;code&gt;ps -e -o pid,comm&lt;/code&gt; to check the reported name, capitalization, and command line before trying again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Operation not permitted&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
You can signal your own processes, but another user&amp;rsquo;s process normally requires root privileges. Verify the exact target first, then rerun the command with &lt;code&gt;sudo&lt;/code&gt; only when needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;killall -w does not return&lt;/strong&gt;&lt;br&gt;
The process may have ignored the signal, stayed in a zombie state, or been replaced by a new process with the same PID while &lt;code&gt;killall&lt;/code&gt; was checking it. Stop waiting with &lt;code&gt;Ctrl+C&lt;/code&gt;, inspect the target with &lt;code&gt;pgrep -a -x NAME&lt;/code&gt;, and use &lt;code&gt;SIGKILL&lt;/code&gt; only if the process is still running and cannot shut down cleanly.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;killall&lt;/code&gt; terminates every instance of a program in one command, with filters for user, age, and case when the name alone is too broad. When you need pattern matching instead of exact names, reach for &lt;a href="https://linuxize.com/post/pkill-command-in-linux/"&gt;&lt;code&gt;pkill&lt;/code&gt;&lt;/a&gt;
, and when you need to inspect processes before killing them, start with &lt;a href="https://linuxize.com/post/pgrep-command-in-linux/"&gt;&lt;code&gt;pgrep&lt;/code&gt;&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/killall-command-in-linux/featured_hu_c482ee53e524f8c8.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>AWS CLI Cheatsheet</title><link>https://linuxize.com/cheatsheet/aws-cli/</link><pubDate>Fri, 31 Jul 2026 13:35:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/aws-cli/</guid><description>Quick reference for AWS CLI commands, profiles, and output filtering</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="installation-and-setup"&gt;Installation and Setup &lt;a class="headline-link" href="#installation-and-setup" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install AWS CLI version 2 and set the basic configuration. Full walkthrough in &lt;a href="https://linuxize.com/post/how-to-install-and-configure-aws-cli-on-linux/"&gt;installing and configuring the AWS CLI on Linux&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;curl https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Download the x86_64 installer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;curl https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip -o awscliv2.zip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Download the ARM64 installer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unzip awscliv2.zip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extract the installer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo ./aws/install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install AWS CLI version 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo ./aws/install --update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update from a freshly extracted installer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the installed version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws configure&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Interactive credential and region setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws configure list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show active settings and where they come from&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws configure get region&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read a single config value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws configure set region eu-central-1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write a single config value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;complete -C aws_completer aws&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable Bash command completion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 help&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open the reference for a service&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="profiles-and-authentication"&gt;Profiles and Authentication &lt;a class="headline-link" href="#profiles-and-authentication" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Static access keys configured with &lt;code&gt;aws configure&lt;/code&gt; live in &lt;code&gt;~/.aws/credentials&lt;/code&gt;, while other settings live in &lt;code&gt;~/.aws/config&lt;/code&gt;. Prefer temporary credentials from &lt;code&gt;aws login&lt;/code&gt; or IAM Identity Center.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws login&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sign in with AWS console credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws login --profile dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sign in to a named profile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws login --remote&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sign in from a host without a browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws logout --profile dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clear cached login credentials for a profile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws configure --profile dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Configure a profile with an access key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 ls --profile dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run one command as a profile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;export AWS_PROFILE=dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use a profile for the whole shell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws configure list-profiles&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List configured profiles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws configure sso&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set up an IAM Identity Center profile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws sso login --profile dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start or refresh an SSO session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws sso logout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clear cached SSO credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws sts get-caller-identity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the account and identity in use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws sts assume-role --role-arn arn --role-session-name cli&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get temporary role credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;export AWS_REGION=eu-west-1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Override the region for the shell&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="common-options"&gt;Common Options &lt;a class="headline-link" href="#common-options" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Frequently used options. Availability depends on the service and operation.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--region eu-west-1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Target a specific region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--profile dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use a named profile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--output json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the response format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--no-cli-pager&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print output instead of opening a pager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--dry-run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check permissions without acting on supported EC2 operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cli-auto-prompt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prompt for parameters interactively&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--no-paginate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Return only the first page from a paginated operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--page-size 100&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the API page size for a paginated operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--max-items 20&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limit output from a paginated operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cli-input-json file://params.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read parameters for a modeled API operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--generate-cli-skeleton&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print a parameter template for a modeled API operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--debug&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the full request and response trace&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="output-formatting-and-queries"&gt;Output Formatting and Queries &lt;a class="headline-link" href="#output-formatting-and-queries" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;--query&lt;/code&gt; option uses JMESPath and runs client side. Service-specific options such as &lt;code&gt;--filters&lt;/code&gt; run server side, which can reduce response size and improve response time for large data sets. Pipe &lt;code&gt;--output json&lt;/code&gt; into &lt;code&gt;jq&lt;/code&gt; when a query gets hard to read.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3api list-buckets --output table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Human-readable table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3api list-buckets --output text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tab-delimited text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3api list-buckets --output yaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;YAML response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3api list-buckets --query &amp;quot;Buckets[].Name&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Return one field&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-instances --query &amp;quot;Reservations[].Instances[].[InstanceId,State.Name]&amp;quot; --output text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Return several fields as columns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-instances --query &amp;quot;Reservations[].Instances[?State.Name=='running'].InstanceId&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter results client side&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-instances --filters Name=instance-state-name,Values=running&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter results server side&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-volumes --query &amp;quot;Volumes[0:5]&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Slice the result list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 wait instance-running --instance-ids i-0abc123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Block until a state is reached&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="s3-buckets-and-objects"&gt;S3 Buckets and Objects &lt;a class="headline-link" href="#s3-buckets-and-objects" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Everyday transfers with the high-level &lt;code&gt;aws s3&lt;/code&gt; commands. More examples in &lt;a href="https://linuxize.com/post/aws-s3-commands/"&gt;aws s3 commands&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 ls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all buckets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 ls s3://bucket --recursive --summarize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List objects with a size total&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 cp file.txt s3://bucket/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Upload a file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 cp s3://bucket/file.txt .&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Download a file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 cp ./dir s3://bucket/dir --recursive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Upload a directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 sync ./dir s3://bucket/dir&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Copy only new and changed files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 sync ./dir s3://bucket/dir --delete --dryrun&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview a mirror that removes stale files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 rm s3://bucket/dir/ --recursive --dryrun&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview a recursive delete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 mb s3://bucket&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a bucket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 rb s3://bucket&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove an empty bucket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws s3 presign s3://bucket/file.txt --expires-in 3600&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate a temporary download link&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="ec2-instances"&gt;EC2 Instances &lt;a class="headline-link" href="#ec2-instances" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Launch, inspect, and control instances.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-instances&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List instances and their details&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-instances --instance-ids i-0abc123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Details for one instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-instance-status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Health and scheduled events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 run-instances --image-id ami-0abc --instance-type t3.micro --key-name mykey&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Launch an instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 start-instances --instance-ids i-0abc123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start a stopped instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 stop-instances --instance-ids i-0abc123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop an instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 reboot-instances --instance-ids i-0abc123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reboot an instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 terminate-instances --instance-ids i-0abc123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permanently terminate an instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 create-tags --resources i-0abc123 --tags Key=Name,Value=web&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tag a resource&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-images --owners 099720109477 --filters &amp;quot;Name=name,Values=ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find official Ubuntu 24.04 AMIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 get-console-output --instance-id i-0abc123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read the instance console log&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="security-groups-and-key-pairs"&gt;Security Groups and Key Pairs &lt;a class="headline-link" href="#security-groups-and-key-pairs" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Network access and SSH keys for EC2. Private key files are unencrypted, so keep them readable only by your user.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-security-groups&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List security groups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 create-security-group --group-name web --description &amp;quot;Web tier&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a security group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 authorize-security-group-ingress --group-id sg-0abc --protocol tcp --port 22 --cidr 203.0.113.10/32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Allow inbound traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 revoke-security-group-ingress --group-id sg-0abc --protocol tcp --port 22 --cidr 203.0.113.10/32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove an inbound rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 delete-security-group --group-id sg-0abc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete a security group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 create-key-pair --key-name mykey --query KeyMaterial --output text &amp;gt; mykey.pem&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a key pair and save the private key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chmod 400 mykey.pem&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Restrict private key permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-key-pairs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List key pairs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 delete-key-pair --key-name mykey&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete a key pair&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-vpcs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List VPCs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-subnets --filters Name=vpc-id,Values=vpc-0abc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List subnets in a VPC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 allocate-address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reserve an elastic IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 associate-address --instance-id i-0abc123 --allocation-id eipalloc-0abc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Attach an elastic IP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="ebs-volumes-and-snapshots"&gt;EBS Volumes and Snapshots &lt;a class="headline-link" href="#ebs-volumes-and-snapshots" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Block storage and backups.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-volumes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List volumes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 create-volume --size 20 --availability-zone eu-central-1a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 attach-volume --volume-id vol-0abc --instance-id i-0abc123 --device /dev/sdf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Attach a volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 detach-volume --volume-id vol-0abc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Detach a volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 delete-volume --volume-id vol-0abc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permanently delete a volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 create-snapshot --volume-id vol-0abc --description &amp;quot;nightly&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Snapshot a volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 describe-snapshots --owner-ids self&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List your snapshots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 copy-snapshot --region eu-west-1 --source-region eu-central-1 --source-snapshot-id snap-0abc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Copy a snapshot from eu-central-1 to eu-west-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ec2 delete-snapshot --snapshot-id snap-0abc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permanently delete a snapshot&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="iam-users-and-roles"&gt;IAM Users and Roles &lt;a class="headline-link" href="#iam-users-and-roles" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Identities, policies, and access keys. Creating an access key prints its secret once, so store it securely and never commit it to version control.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam list-users&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List IAM users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam create-user --user-name dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam delete-user --user-name dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permanently delete a user after removing dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam list-roles&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List roles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam get-role --role-name deploy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show a role and its trust policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam attach-user-policy --user-name dev --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Attach a managed policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam list-attached-user-policies --user-name dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List policies attached to a user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam create-access-key --user-name dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create an access key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam list-access-keys --user-name dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List access keys and creation dates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam update-access-key --user-name dev --access-key-id AKIA123 --status Inactive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Disable a key before deleting it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam delete-access-key --user-name dev --access-key-id AKIA123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permanently delete an access key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws iam get-account-summary&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Account-wide IAM counts and limits&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="systems-manager-and-secrets"&gt;Systems Manager and Secrets &lt;a class="headline-link" href="#systems-manager-and-secrets" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Shell access without SSH, plus configuration and secret storage. The &lt;code&gt;start-session&lt;/code&gt; command needs the Session Manager plugin installed locally. Pass secret values from protected files so they do not enter shell history, and keep decrypted output out of shared logs.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ssm start-session --target i-0abc123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open a shell on an instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ssm describe-instance-information&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List instances managed by SSM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ssm send-command --instance-ids i-0abc123 --document-name AWS-RunShellScript --parameters commands=&amp;quot;uptime&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run a command on an instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ssm get-command-invocation --command-id 1a2b --instance-id i-0abc123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read the output of a sent command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ssm put-parameter --name /app/db_url --value file://db-url.txt --type SecureString&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Store an encrypted parameter from a file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ssm get-parameter --name /app/db_url --with-decryption&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read and decrypt a parameter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ssm get-parameters-by-path --path /app --recursive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List parameters under a path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws secretsmanager list-secrets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws secretsmanager get-secret-value --secret-id prod/db --query SecretString --output text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print a decrypted secret value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws secretsmanager create-secret --name prod/db --secret-string file://secret.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a secret from a file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="cloudwatch-logs-and-alarms"&gt;CloudWatch Logs and Alarms &lt;a class="headline-link" href="#cloudwatch-logs-and-alarms" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Read application and service logs from the terminal.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws logs describe-log-groups&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List log groups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws logs describe-log-streams --log-group-name /aws/lambda/fn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List streams in a group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws logs tail /aws/lambda/fn --follow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stream new log events live&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws logs tail /aws/lambda/fn --since 1h --format short&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the last hour of logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws logs filter-log-events --log-group-name /aws/lambda/fn --filter-pattern ERROR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Search log events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws logs create-log-group --log-group-name /app/web&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a log group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws logs put-retention-policy --log-group-name /app/web --retention-in-days 30&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set log retention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws logs delete-log-group --log-group-name /app/web&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permanently delete a log group and its logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws cloudwatch describe-alarms&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List alarms and their state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws cloudwatch describe-alarms --state-value ALARM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show only firing alarms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="lambda-functions"&gt;Lambda Functions &lt;a class="headline-link" href="#lambda-functions" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Deploy and invoke functions. AWS CLI version 2 expects base64 input for blob parameters by default, so literal JSON passed to &lt;code&gt;--payload&lt;/code&gt; needs &lt;code&gt;--cli-binary-format raw-in-base64-out&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws lambda list-functions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws lambda get-function --function-name fn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show configuration and code location&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws lambda invoke --function-name fn out.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Invoke a function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws lambda invoke --function-name fn --cli-binary-format raw-in-base64-out --payload '{&amp;quot;key&amp;quot;:&amp;quot;value&amp;quot;}' out.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Invoke with a JSON payload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws lambda update-function-code --function-name fn --zip-file fileb://fn.zip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deploy new code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws lambda update-function-configuration --function-name fn --timeout 30&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Change a setting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws lambda publish-version --function-name fn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Publish an immutable version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws lambda list-versions-by-function --function-name fn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List published versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws lambda delete-function --function-name fn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permanently delete a function&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="ecr-container-images"&gt;ECR Container Images &lt;a class="headline-link" href="#ecr-container-images" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Authenticate Docker against a registry with &lt;code&gt;aws ecr get-login-password --region eu-central-1&lt;/code&gt; piped into &lt;code&gt;docker login --username AWS --password-stdin 123456789012.dkr.ecr.eu-central-1.amazonaws.com&lt;/code&gt;. Container commands are in the &lt;a href="https://linuxize.com/cheatsheet/docker/"&gt;Docker cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ecr get-login-password --region eu-central-1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print a registry password for Docker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ecr describe-repositories&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List repositories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ecr create-repository --repository-name app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a repository&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ecr list-images --repository-name app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List image tags and digests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ecr describe-images --repository-name app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show image size and push date&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ecr batch-delete-image --repository-name app --image-ids imageTag=old&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete an image&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aws ecr delete-repository --repository-name app --force&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Permanently delete a repository and its images&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>aws s3 Commands: cp, sync, ls, and rm Examples</title><link>https://linuxize.com/post/aws-s3-commands/</link><pubDate>Fri, 31 Jul 2026 10:10:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/aws-s3-commands/</guid><category>aws</category><description>Practical aws s3 command examples for listing buckets, copying files, syncing directories, filtering transfers, and deleting objects safely from Linux.</description><content:encoded>&lt;p&gt;Uploading a file to Amazon S3 through the web console works fine once. The tenth time, or the first time you need to move a whole directory tree, you want it in your shell history instead. The &lt;code&gt;aws s3&lt;/code&gt; command group gives you familiar Unix-style operations for S3: &lt;code&gt;ls&lt;/code&gt; to list, &lt;code&gt;cp&lt;/code&gt; to copy, &lt;code&gt;sync&lt;/code&gt; to mirror directories, and &lt;code&gt;rm&lt;/code&gt; to delete.&lt;/p&gt;
&lt;p&gt;This guide shows practical examples of the most used &lt;code&gt;aws s3&lt;/code&gt; commands, including recursive copies, include and exclude filters, and safe deletion with &lt;code&gt;--dryrun&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites &lt;a class="headline-link" href="#prerequisites" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The examples require AWS CLI version 2 and an identity with permission to access the S3 resources you use. If the CLI is not ready yet, follow our guide on &lt;a href="https://linuxize.com/post/how-to-install-and-configure-aws-cli-on-linux/"&gt;installing and configuring the AWS CLI on Linux&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Confirm that the CLI can authenticate to your account with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts get-caller-identity&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the command prints your account ID and IAM identity, authentication is working. Individual S3 commands can still return &lt;code&gt;AccessDenied&lt;/code&gt; when that identity lacks the required bucket or object permissions.&lt;/p&gt;
&lt;p&gt;The AWS CLI has two command groups for S3. The &lt;code&gt;aws s3&lt;/code&gt; group used in this guide provides high-level file operations. The &lt;code&gt;aws s3api&lt;/code&gt; group exposes the raw API, one call per operation, and is only needed for tasks such as managing bucket policies or object versions.&lt;/p&gt;
&lt;p&gt;S3 paths use the form &lt;code&gt;s3://bucket-name/key&lt;/code&gt;. The general command structure is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 &amp;lt;subcommand&amp;gt; [ARGUMENTS] [OPTIONS]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Commands such as &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, and &lt;code&gt;sync&lt;/code&gt; take source and destination arguments. The remaining commands operate on one S3 path, except &lt;code&gt;aws s3 ls&lt;/code&gt;, which can omit the path to list every bucket.&lt;/p&gt;
&lt;h2 id="listing-buckets-and-objects"&gt;Listing Buckets and Objects &lt;a class="headline-link" href="#listing-buckets-and-objects" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;aws s3 ls&lt;/code&gt; with no arguments to list all buckets in the account:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 ls&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;2025-11-04 09:12:33 my-bucket
2026-01-15 17:40:21 my-site-backups&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To list the contents of a bucket, pass the bucket path:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 ls s3://my-bucket&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt; PRE logs/
2026-02-10 08:30:12 1048576 backup.tar.gz
2026-02-11 09:02:44 4523 notes.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Entries marked &lt;code&gt;PRE&lt;/code&gt; are prefixes, the S3 equivalent of directories. To look inside one, append it to the path with a trailing slash, for example &lt;code&gt;aws s3 ls s3://my-bucket/logs/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Add &lt;code&gt;--recursive&lt;/code&gt; to walk the whole bucket, and combine it with &lt;code&gt;--human-readable&lt;/code&gt; and &lt;code&gt;--summarize&lt;/code&gt; to get readable sizes and totals:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 ls s3://my-bucket --recursive --human-readable --summarize&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;2026-02-10 08:30:12 1.0 MiB backup.tar.gz
2026-02-11 09:02:44 4.4 KiB notes.txt
2026-02-12 06:15:09 12.7 MiB logs/app.log
Total Objects: 3
Total Size: 13.7 MiB&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The summary at the bottom shows the count and combined size of the current objects listed under the bucket or prefix. It does not include noncurrent versions in a versioned bucket.&lt;/p&gt;
&lt;h2 id="uploading-and-downloading-files-with-cp"&gt;Uploading and Downloading Files with cp &lt;a class="headline-link" href="#uploading-and-downloading-files-with-cp" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;cp&lt;/code&gt; subcommand copies files between your machine and S3, in either direction. To upload a file to a bucket:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp backup.tar.gz s3://my-bucket/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;upload: ./backup.tar.gz to s3://my-bucket/backup.tar.gz&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The object keeps its original name. To store it under a different key, spell out the full target path:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp backup.tar.gz s3://my-bucket/backups/backup-2026-02-10.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Downloading works the same way with the arguments reversed. The &lt;code&gt;.&lt;/code&gt; target saves the file into the current directory:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp s3://my-bucket/backup.tar.gz .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can also copy directly between two buckets. The transfer happens inside AWS, so the data does not pass through your machine:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp s3://my-bucket/backup.tar.gz s3://my-site-backups/backup.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="copying-directories"&gt;Copying Directories &lt;a class="headline-link" href="#copying-directories" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To copy a directory and everything under it, add &lt;code&gt;--recursive&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp ./logs s3://my-bucket/logs --recursive&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When you only want some of the files, combine &lt;code&gt;--exclude&lt;/code&gt; and &lt;code&gt;--include&lt;/code&gt;. The filters are evaluated in the order given, and the later filter wins, so the usual pattern is to exclude everything and then include what you want:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp ./logs s3://my-bucket/logs --recursive --exclude &lt;span class="s2"&gt;&amp;#34;*&amp;#34;&lt;/span&gt; --include &lt;span class="s2"&gt;&amp;#34;*.log&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This uploads only the &lt;code&gt;.log&lt;/code&gt; files and skips everything else in the directory.&lt;/p&gt;
&lt;p&gt;The most useful &lt;code&gt;cp&lt;/code&gt; options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--recursive&lt;/code&gt; - Copy all files under a directory or prefix.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--exclude&lt;/code&gt; / &lt;code&gt;--include&lt;/code&gt; - Filter files by pattern; later filters override earlier ones.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--storage-class&lt;/code&gt; - Choose the destination storage class, for example &lt;code&gt;STANDARD_IA&lt;/code&gt; for backups accessed infrequently.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--dryrun&lt;/code&gt; - Print what would be copied without transferring anything.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="streaming-to-and-from-s3"&gt;Streaming to and from S3 &lt;a class="headline-link" href="#streaming-to-and-from-s3" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;cp&lt;/code&gt; command accepts &lt;code&gt;-&lt;/code&gt; as a stand-in for standard input or output, which lets you pipe data straight to a bucket without a temporary file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pg_dump mydb &lt;span class="p"&gt;|&lt;/span&gt; gzip &lt;span class="p"&gt;|&lt;/span&gt; aws s3 cp - s3://my-bucket/backups/mydb.sql.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Reading works the same way in reverse. This prints an object to standard output where you can pipe it further:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp s3://my-bucket/backups/mydb.sql.gz - &lt;span class="p"&gt;|&lt;/span&gt; gunzip &lt;span class="p"&gt;|&lt;/span&gt; head&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="moving-and-renaming-objects-with-mv"&gt;Moving and Renaming Objects with mv &lt;a class="headline-link" href="#moving-and-renaming-objects-with-mv" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Amazon S3 does not rename an object in place. The &lt;code&gt;mv&lt;/code&gt; command copies the source to the new key and then deletes the source, so preview the operation before running it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 mv s3://my-bucket/report-draft.pdf s3://my-bucket/report-final.pdf --dryrun&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Check both paths carefully, then run the command again without &lt;code&gt;--dryrun&lt;/code&gt;. The same command can move files between your machine and S3 or between two buckets.&lt;/p&gt;
&lt;h2 id="synchronizing-directories-with-sync"&gt;Synchronizing Directories with sync &lt;a class="headline-link" href="#synchronizing-directories-with-sync" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Where &lt;code&gt;cp --recursive&lt;/code&gt; copies everything every time, &lt;code&gt;sync&lt;/code&gt; transfers files that are missing, differ in size, or have a newer source modification time. To mirror a local directory to a bucket:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 sync ./website s3://my-bucket/website&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Run it again immediately and nothing is transferred, because both sides already match. This makes &lt;code&gt;sync&lt;/code&gt; the right tool for repeated jobs such as publishing a static site or shipping nightly backups.&lt;/p&gt;
&lt;p&gt;The reverse direction downloads new and changed objects from the bucket:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 sync s3://my-bucket/website ./website&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Syncing between two buckets also works: &lt;code&gt;aws s3 sync s3://my-bucket s3://my-site-backups&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;By default, &lt;code&gt;sync&lt;/code&gt; never deletes anything. Files removed from the source remain on the target. To make the target an exact mirror, add &lt;code&gt;--delete&lt;/code&gt;, but preview the result first because deleted objects are gone for good:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 sync ./website s3://my-bucket/website --delete --dryrun&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;(dryrun) upload: website/index.html to s3://my-bucket/website/index.html
(dryrun) delete: s3://my-bucket/website/old-page.html&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Every line is prefixed with &lt;code&gt;(dryrun)&lt;/code&gt;, so nothing has happened yet. Review the &lt;code&gt;delete:&lt;/code&gt; lines, and when the plan looks right, run the same command without &lt;code&gt;--dryrun&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The same &lt;code&gt;--exclude&lt;/code&gt; and &lt;code&gt;--include&lt;/code&gt; filters from &lt;code&gt;cp&lt;/code&gt; apply here. A common one keeps repository metadata out of the bucket:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 sync ./website s3://my-bucket/website --exclude &lt;span class="s2"&gt;&amp;#34;.git/*&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Because &lt;code&gt;sync&lt;/code&gt; is idempotent, it pairs well with a scheduled job. See our guide on &lt;a href="https://linuxize.com/post/scheduling-cron-jobs-with-crontab/"&gt;scheduling cron jobs with crontab&lt;/a&gt;
if you want to run a sync every night.&lt;/p&gt;
&lt;h2 id="deleting-objects-with-rm"&gt;Deleting Objects with rm &lt;a class="headline-link" href="#deleting-objects-with-rm" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To delete a single object, pass its full path:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 rm s3://my-bucket/old-backup.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;delete: s3://my-bucket/old-backup.tar.gz&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;There is no trash bin in S3. Unless the bucket has versioning enabled, a deleted object cannot be recovered. Always test recursive deletions with &lt;code&gt;--dryrun&lt;/code&gt; first.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To delete everything under a prefix, add &lt;code&gt;--recursive&lt;/code&gt; and preview the damage before committing:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 rm s3://my-bucket/logs/ --recursive --dryrun&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the listed objects are the ones you expect, run the command again without &lt;code&gt;--dryrun&lt;/code&gt; to perform the deletion.&lt;/p&gt;
&lt;p&gt;On buckets with versioning enabled, &lt;code&gt;rm&lt;/code&gt; only inserts a delete marker; previous versions remain and continue to incur storage costs. Removing versions permanently requires the &lt;code&gt;aws s3api delete-object&lt;/code&gt; call with a version ID.&lt;/p&gt;
&lt;h2 id="creating-and-removing-buckets"&gt;Creating and Removing Buckets &lt;a class="headline-link" href="#creating-and-removing-buckets" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;mb&lt;/code&gt; (make bucket) subcommand creates a new bucket. General purpose bucket names must be unique across AWS accounts and Regions within an AWS partition, so pick something difficult to collide with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 mb s3://my-unique-bucket-name --region eu-central-1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;rb&lt;/code&gt; (remove bucket) subcommand deletes a bucket, but only when it is empty:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 rb s3://my-unique-bucket-name&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Adding &lt;code&gt;--force&lt;/code&gt; deletes the current objects in an unversioned bucket and then removes the bucket. It does not permanently delete object versions or delete markers, so removal fails when a versioned bucket still contains them. Treat &lt;code&gt;--force&lt;/code&gt; with the same caution as &lt;code&gt;rm --recursive&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="generating-temporary-download-links"&gt;Generating Temporary Download Links &lt;a class="headline-link" href="#generating-temporary-download-links" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sometimes you need to hand a file to someone without making the bucket public. The &lt;code&gt;presign&lt;/code&gt; subcommand generates a URL that grants temporary access to a single object:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 presign s3://my-bucket/report.pdf --expires-in &lt;span class="m"&gt;3600&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The command prints a long URL that anyone can use to download the object for the next hour (3600 seconds). The default lifetime is one hour, and the maximum is seven days. A URL signed with temporary credentials expires when those credentials expire, even when &lt;code&gt;--expires-in&lt;/code&gt; requests a later time.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/aws-cli/"&gt;AWS CLI cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List all buckets&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 ls&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List bucket contents&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 ls s3://bucket&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List recursively with totals&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 ls s3://bucket --recursive --summarize&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Upload a file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 cp file.txt s3://bucket/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Download a file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 cp s3://bucket/file.txt .&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Upload a directory&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 cp ./dir s3://bucket/dir --recursive&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preview renaming an object&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 mv s3://bucket/old.txt s3://bucket/new.txt --dryrun&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mirror a directory&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 sync ./dir s3://bucket/dir&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preview removing stale files during a mirror&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 sync ./dir s3://bucket/dir --delete --dryrun&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete an object&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 rm s3://bucket/file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preview deleting a prefix&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 rm s3://bucket/dir/ --recursive --dryrun&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Create a bucket&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 mb s3://bucket&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove an empty bucket&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 rb s3://bucket&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Temporary download link&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws s3 presign s3://bucket/file.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="faq"&gt;FAQ &lt;a class="headline-link" href="#faq" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What is the difference between cp &amp;ndash;recursive and sync?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;cp --recursive&lt;/code&gt; copies every file on every run. &lt;code&gt;sync&lt;/code&gt; compares both sides and transfers only new or changed files, which is faster and cheaper for repeated jobs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can I use shell wildcards in S3 paths?&lt;/strong&gt;&lt;br&gt;
No. The AWS CLI does not interpret Unix-style wildcards in an S3 path such as &lt;code&gt;s3://bucket/*.log&lt;/code&gt;. Use &lt;code&gt;--recursive&lt;/code&gt; together with &lt;code&gt;--exclude&lt;/code&gt; and &lt;code&gt;--include&lt;/code&gt; filters instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do I delete all files in a bucket?&lt;/strong&gt;&lt;br&gt;
For an unversioned bucket, preview &lt;code&gt;aws s3 rm s3://bucket --recursive --dryrun&lt;/code&gt;, then remove &lt;code&gt;--dryrun&lt;/code&gt; to empty it. The &lt;code&gt;aws s3 rb s3://bucket --force&lt;/code&gt; command can empty and remove an unversioned bucket in one step, but it fails when object versions or delete markers remain.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Make &lt;code&gt;--dryrun&lt;/code&gt; a habit before &lt;code&gt;mv&lt;/code&gt;, recursive &lt;code&gt;rm&lt;/code&gt;, or &lt;code&gt;sync --delete&lt;/code&gt;, then reuse the reviewed commands in your scripts and scheduled jobs.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/aws-s3-commands/featured_hu_541732d4103e130d.webp" medium="image" type="image/webp" width="1200" height="630"/></item><item><title>How to Install and Configure the AWS CLI on Linux</title><link>https://linuxize.com/post/how-to-install-and-configure-aws-cli-on-linux/</link><pubDate>Thu, 30 Jul 2026 09:20:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/how-to-install-and-configure-aws-cli-on-linux/</guid><category>aws</category><description>Install AWS CLI version 2 on Linux, authenticate with aws login or IAM Identity Center, manage profiles, and verify access to your AWS account.</description><content:encoded>&lt;p&gt;Clicking through the AWS console works for a one-off task, but the moment you manage instances, buckets, or DNS records regularly, you want those actions in your shell history and your scripts. The AWS CLI puts every AWS API behind a single &lt;code&gt;aws&lt;/code&gt; command, so listing instances, syncing a bucket, or rotating a key becomes a one-liner you can repeat and automate.&lt;/p&gt;
&lt;p&gt;This guide explains how to install AWS CLI version 2 on Linux, authenticate with short-term credentials, manage named profiles, and verify that your setup can access your AWS account.&lt;/p&gt;
&lt;h2 id="installing-aws-cli-version-2"&gt;Installing AWS CLI Version 2 &lt;a class="headline-link" href="#installing-aws-cli-version-2" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AWS maintains an &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" target="_blank" rel="noopener noreferrer"&gt;install script&lt;/a&gt;
that downloads, verifies, and installs the current AWS CLI release. It detects whether your Linux system uses an x86_64 or ARM processor, so the same command works on both architectures:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://awscli.amazonaws.com/v2/install.sh &lt;span class="p"&gt;|&lt;/span&gt; bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The script installs the program for your user under &lt;code&gt;~/.local/share/aws-cli&lt;/code&gt; and creates &lt;code&gt;~/.local/bin/aws&lt;/code&gt;. This avoids requiring root access. Open a new terminal after installation, then verify the version:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first part of the output should begin with &lt;code&gt;aws-cli/2.&lt;/code&gt;. The remaining version and system details depend on the current release and your Linux distribution.&lt;/p&gt;
&lt;p&gt;To install the CLI for every user instead, run the installer in system mode:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://awscli.amazonaws.com/v2/install.sh &lt;span class="p"&gt;|&lt;/span&gt; sudo bash -s -- --system&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;System mode installs the files under &lt;code&gt;/usr/local/aws-cli&lt;/code&gt; and creates the command links in &lt;code&gt;/usr/local/bin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When a newer release is available, update a per-user installation with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws update&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;sudo aws update&lt;/code&gt; if you installed the CLI in system mode.&lt;/p&gt;
&lt;h2 id="configuring-aws-cli-authentication"&gt;Configuring AWS CLI Authentication &lt;a class="headline-link" href="#configuring-aws-cli-authentication" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AWS recommends short-term credentials for people and workloads. The best configuration method depends on how your AWS account manages identities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;aws login&lt;/code&gt; when you already sign in to the AWS Management Console with an IAM or federated identity.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;aws configure sso&lt;/code&gt; when your organization uses AWS IAM Identity Center.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;aws configure&lt;/code&gt; with an IAM access key only when neither short-term method is available.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do not configure the CLI with root-user access keys. Use a non-root identity with only the permissions required for your work.&lt;/p&gt;
&lt;h3 id="signing-in-with-aws-console-credentials"&gt;Signing In with AWS Console Credentials &lt;a class="headline-link" href="#signing-in-with-aws-console-credentials" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;AWS CLI version 2.32.0 and later supports &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sign-in.html" target="_blank" rel="noopener noreferrer"&gt;&lt;code&gt;aws login&lt;/code&gt;&lt;/a&gt;
, which exchanges an existing console session for temporary credentials. Your AWS administrator must allow local developer sign-in for the identity. Start the browser-based flow with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws login&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The CLI asks for a default Region if one is not already configured, then opens your browser. Select the console session and identity you want to use. AWS stores the temporary session under &lt;code&gt;~/.aws/login/cache&lt;/code&gt; and refreshes its credentials while the session remains valid.&lt;/p&gt;
&lt;p&gt;To create or sign in to a named profile, add &lt;code&gt;--profile&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws login --profile work&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On a remote Linux server without a browser, use the cross-device flow:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws login --remote&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When the session reaches its maximum duration, run &lt;code&gt;aws login&lt;/code&gt; again. You can end it earlier with &lt;code&gt;aws logout&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="configuring-iam-identity-center"&gt;Configuring IAM Identity Center &lt;a class="headline-link" href="#configuring-iam-identity-center" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If your organization provides an AWS access portal, follow the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sso.html" target="_blank" rel="noopener noreferrer"&gt;IAM Identity Center configuration&lt;/a&gt;
instead of using &lt;code&gt;aws login&lt;/code&gt;. Run the setup wizard with a descriptive profile name:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure sso --profile work&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The wizard asks for the SSO session name, start or issuer URL, SSO Region, account, permission set, default Region, and output format. It opens a browser so you can authorize the session.&lt;/p&gt;
&lt;p&gt;Sign in again whenever the SSO session expires:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sso login --profile work&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;IAM Identity Center stores the profile settings in &lt;code&gt;~/.aws/config&lt;/code&gt; and caches its tokens under &lt;code&gt;~/.aws/sso/cache&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="configuring-an-iam-access-key"&gt;Configuring an IAM Access Key &lt;a class="headline-link" href="#configuring-an-iam-access-key" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Some legacy tools and workloads still require a long-term access key. If you cannot use temporary credentials, create the key for a dedicated IAM user with least-privilege permissions, then configure a named profile:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure --profile legacy&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;AWS Access Key ID [None]: &amp;lt;your-access-key-id&amp;gt;
AWS Secret Access Key [None]: &amp;lt;your-secret-access-key&amp;gt;
Default region name [None]: eu-central-1
Default output format [None]: json&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Choose the Region where most of your resources run. JSON is a practical default output format for scripts, while &lt;code&gt;table&lt;/code&gt; is easier to scan interactively.&lt;/p&gt;
&lt;p&gt;The CLI writes access keys to &lt;code&gt;~/.aws/credentials&lt;/code&gt; and other settings to &lt;code&gt;~/.aws/config&lt;/code&gt;.&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;Never commit access keys, paste them into scripts, or bake them into images. If a key enters Git history or another public location, deactivate it immediately and create a replacement. Prefer temporary credentials whenever the application supports them.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="verifying-the-configuration"&gt;Verifying the Configuration &lt;a class="headline-link" href="#verifying-the-configuration" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Ask AWS Security Token Service which identity the CLI resolved:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts get-caller-identity&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;{
&amp;#34;UserId&amp;#34;: &amp;#34;AROAXAMPLE:dejan&amp;#34;,
&amp;#34;Account&amp;#34;: &amp;#34;123456789012&amp;#34;,
&amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:sts::123456789012:assumed-role/Developer/dejan&amp;#34;
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The response identifies the account, IAM user, or assumed role behind the current credentials. To test a named profile, add it to the command:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts get-caller-identity --profile work&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the call succeeds, authentication works. Individual service commands can still fail when the identity lacks permission for that action.&lt;/p&gt;
&lt;h2 id="working-with-named-profiles"&gt;Working with Named Profiles &lt;a class="headline-link" href="#working-with-named-profiles" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Profiles keep settings and credentials for separate accounts or roles from interfering with each other. List the profiles currently available:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure list-profiles&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Select a profile for one command with &lt;code&gt;--profile&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 ls --profile work&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To use the same profile for the rest of the shell session, set &lt;code&gt;AWS_PROFILE&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;work&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;default&lt;/code&gt; profile is used when neither &lt;code&gt;--profile&lt;/code&gt; nor &lt;code&gt;AWS_PROFILE&lt;/code&gt; is set. A command-line &lt;code&gt;--profile&lt;/code&gt; option overrides the environment variable.&lt;/p&gt;
&lt;p&gt;On EC2 instances, ECS tasks, and other AWS compute services, attach an IAM role to the workload instead of storing access keys. For CI systems, use the platform&amp;rsquo;s OpenID Connect integration to assume an IAM role when available.&lt;/p&gt;
&lt;h2 id="running-your-first-commands"&gt;Running Your First Commands &lt;a class="headline-link" href="#running-your-first-commands" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The CLI follows a &lt;code&gt;aws &amp;lt;service&amp;gt; &amp;lt;operation&amp;gt;&lt;/code&gt; pattern. List your S3 buckets:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 ls&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;2025-11-02 14:11:20 backups-prod
2026-01-01 09:48:03 static-assets&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;List EC2 instances, trimmed down to the fields you care about with &lt;code&gt;--query&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ec2 describe-instances &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --query &lt;span class="s1"&gt;&amp;#39;Reservations[].Instances[].{ID:InstanceId,Type:InstanceType,State:State.Name}&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output table&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;-------------------------------------------------
| DescribeInstances |
+----------------------+-----------+------------+
| ID | Type | State |
+----------------------+-----------+------------+
| i-0abcd1234ef567890 | t3.small | running |
| i-0fe9876543ba21001 | t3.micro | stopped |
+----------------------+-----------+------------+&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;--query&lt;/code&gt; option takes a JMESPath expression and works on every command, which saves you from piping JSON into other tools for simple filtering. The &lt;code&gt;--output&lt;/code&gt; option switches between &lt;code&gt;json&lt;/code&gt;, &lt;code&gt;yaml&lt;/code&gt;, &lt;code&gt;text&lt;/code&gt;, and &lt;code&gt;table&lt;/code&gt; per invocation.&lt;/p&gt;
&lt;p&gt;Every service has built-in help, so &lt;code&gt;aws s3 help&lt;/code&gt; and &lt;code&gt;aws ec2 describe-instances help&lt;/code&gt; open the relevant manual pages without leaving the terminal.&lt;/p&gt;
&lt;h2 id="enabling-command-completion"&gt;Enabling Command Completion &lt;a class="headline-link" href="#enabling-command-completion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The installer includes &lt;code&gt;aws_completer&lt;/code&gt;, which suggests services, operations, and options when you press Tab. Confirm that your shell can find it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;command&lt;/span&gt; -v aws_completer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The path is usually &lt;code&gt;~/.local/bin/aws_completer&lt;/code&gt; for a per-user installation or &lt;code&gt;/usr/local/bin/aws_completer&lt;/code&gt; for a system installation.&lt;/p&gt;
&lt;p&gt;For Bash, add this line to &lt;code&gt;~/.bashrc&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.bashrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;complete&lt;/span&gt; -C &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt; -v aws_completer&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; aws&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Reload the file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For Zsh, add these lines to &lt;code&gt;~/.zshrc&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="sh"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.zshrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;sh&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;autoload bashcompinit &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; bashcompinit
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;complete&lt;/span&gt; -C &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt; -v aws_completer&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; aws&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then reload the Zsh configuration:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;aws: command not found&lt;/strong&gt;&lt;br&gt;
For a per-user installation, &lt;code&gt;~/.local/bin&lt;/code&gt; may be missing from &lt;code&gt;PATH&lt;/code&gt;. Add &lt;code&gt;export PATH=&amp;quot;$HOME/.local/bin:$PATH&amp;quot;&lt;/code&gt; to &lt;code&gt;~/.bashrc&lt;/code&gt; or &lt;code&gt;~/.zshrc&lt;/code&gt;, reload the file, and run &lt;code&gt;aws --version&lt;/code&gt; again. For a system installation, check that &lt;code&gt;/usr/local/bin&lt;/code&gt; is in &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unable to locate credentials&lt;/strong&gt;&lt;br&gt;
No authentication method is configured, or &lt;code&gt;AWS_PROFILE&lt;/code&gt; points to a profile that does not exist. Run &lt;code&gt;aws configure list&lt;/code&gt; to see where the CLI is looking and what it found.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ExpiredToken after aws login&lt;/strong&gt;&lt;br&gt;
An older access key in &lt;code&gt;~/.aws/credentials&lt;/code&gt; can take precedence over login credentials for the same profile. Run &lt;code&gt;aws configure list&lt;/code&gt;, remove the stale key entries for that profile, and sign in again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An error occurred (InvalidClientTokenId)&lt;/strong&gt;&lt;br&gt;
For an access-key profile, the key is inactive, deleted, or mistyped. Replace it in IAM and run &lt;code&gt;aws configure --profile &amp;lt;profile-name&amp;gt;&lt;/code&gt; again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An error occurred (UnauthorizedOperation) or AccessDenied&lt;/strong&gt;&lt;br&gt;
The credentials are valid, but the current identity lacks permission for that action. Ask your AWS administrator to grant the required permission through the relevant role, permission set, or IAM policy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Could not connect to the endpoint URL&lt;/strong&gt;&lt;br&gt;
Check the configured Region with &lt;code&gt;aws configure get region&lt;/code&gt;. A value such as &lt;code&gt;eu-central1&lt;/code&gt; is invalid; the correct format is &lt;code&gt;eu-central-1&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With AWS CLI version 2 installed and &lt;code&gt;aws sts get-caller-identity&lt;/code&gt; returning the expected account, you can start using service commands without storing long-lived credentials. For day-to-day bucket work, see our guide on &lt;a href="https://linuxize.com/post/aws-s3-commands/"&gt;the aws s3 commands&lt;/a&gt;
, and if you want those syncs on a schedule, our guide on &lt;a href="https://linuxize.com/post/scheduling-cron-jobs-with-crontab/"&gt;using cron to schedule jobs&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/how-to-install-and-configure-aws-cli-on-linux/featured_hu_4c28e7449944e2e3.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>How to Install Kubernetes with kubeadm on Ubuntu 26.04</title><link>https://linuxize.com/post/how-to-install-kubernetes-with-kubeadm-on-ubuntu-26-04/</link><pubDate>Wed, 29 Jul 2026 09:40:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/how-to-install-kubernetes-with-kubeadm-on-ubuntu-26-04/</guid><category>kubernetes</category><category>devops</category><category>ubuntu</category><description>Install Kubernetes 1.36 on Ubuntu 26.04 with kubeadm and containerd, configure Flannel networking, join worker nodes, and verify the cluster.</description><content:encoded>&lt;p&gt;When you outgrow a single Docker host and need to run containers across several machines with rolling updates, self-healing, and service discovery built in, Kubernetes is the standard answer. The &lt;code&gt;kubeadm&lt;/code&gt; tool provides a minimal upstream method for bootstrapping a self-managed cluster on plain Linux servers.&lt;/p&gt;
&lt;p&gt;This guide explains how to set up Kubernetes 1.36 on Ubuntu 26.04 using &lt;code&gt;kubeadm&lt;/code&gt;, &lt;code&gt;kubelet&lt;/code&gt;, and &lt;code&gt;kubectl&lt;/code&gt; from the Kubernetes apt repository, with &lt;code&gt;containerd&lt;/code&gt; as the container runtime. By the end you will have a control-plane node, one or more worker nodes, and a test workload running across the cluster.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Disable swap&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo swapoff -a&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install containerd&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt install -y containerd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add Kubernetes apt key&lt;/td&gt;
&lt;td&gt;&lt;code&gt;curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.36/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install kube tools&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt install -y kubelet kubeadm kubectl&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hold kube versions&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt-mark hold kubelet kubeadm kubectl&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Init control plane&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo kubeadm init --pod-network-cidr=10.244.0.0/16&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configure kubectl&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mkdir -p ~/.kube &amp;amp;&amp;amp; sudo cp /etc/kubernetes/admin.conf ~/.kube/config &amp;amp;&amp;amp; sudo chown $(id -u):$(id -g) ~/.kube/config&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Get nodes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kubectl get nodes&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Get pods (all namespaces)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kubectl get pods -A&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generate join command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo kubeadm token create --print-join-command&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites &lt;a class="headline-link" href="#prerequisites" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Two or more servers running Ubuntu 26.04 with at least 2 GB of RAM each. The control-plane node needs at least 2 CPUs.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://linuxize.com/post/how-to-create-a-sudo-user-on-ubuntu/"&gt;user with sudo privileges&lt;/a&gt;
on each server.&lt;/li&gt;
&lt;li&gt;Full network connectivity between the nodes and Internet access for downloading packages and container images.&lt;/li&gt;
&lt;li&gt;A stable IP address plus a unique hostname, MAC address, and product UUID on every node.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The same instructions apply to control-plane and worker nodes up to the cluster bootstrap step. Run every command on every node unless the section says otherwise.&lt;/p&gt;
&lt;p&gt;If a host or cloud firewall filters traffic between the nodes, allow the required traffic between these sources and destination ports:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Destination&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Ports&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Control plane API&lt;/td&gt;
&lt;td&gt;Cluster nodes and administrators&lt;/td&gt;
&lt;td&gt;TCP &lt;code&gt;6443&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;etcd on the control plane&lt;/td&gt;
&lt;td&gt;Control-plane nodes only&lt;/td&gt;
&lt;td&gt;TCP &lt;code&gt;2379-2380&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control-plane kubelet&lt;/td&gt;
&lt;td&gt;Control-plane components&lt;/td&gt;
&lt;td&gt;TCP &lt;code&gt;10250&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduler and controller manager&lt;/td&gt;
&lt;td&gt;Control-plane node itself&lt;/td&gt;
&lt;td&gt;TCP &lt;code&gt;10257&lt;/code&gt; and &lt;code&gt;10259&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worker kubelet&lt;/td&gt;
&lt;td&gt;Control-plane nodes&lt;/td&gt;
&lt;td&gt;TCP &lt;code&gt;10250&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kube-proxy health endpoint&lt;/td&gt;
&lt;td&gt;Node itself and load balancers that use it&lt;/td&gt;
&lt;td&gt;TCP &lt;code&gt;10256&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NodePort services&lt;/td&gt;
&lt;td&gt;Clients that need access&lt;/td&gt;
&lt;td&gt;TCP and UDP &lt;code&gt;30000-32767&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flannel VXLAN&lt;/td&gt;
&lt;td&gt;Other cluster nodes&lt;/td&gt;
&lt;td&gt;UDP &lt;code&gt;8472&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Restrict these rules to trusted cluster and administration networks. Do not expose the etcd or kubelet ports directly to the Internet.&lt;/p&gt;
&lt;h2 id="step-1-prepare-the-system"&gt;Step 1: Prepare the System &lt;a class="headline-link" href="#step-1-prepare-the-system" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The kubelet refuses to start when swap is active unless you configure it to tolerate swap. This guide uses the default behavior, so turn swap off for the current session and comment out swap entries in &lt;code&gt;/etc/fstab&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo swapoff -a
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sed -i &lt;span class="s1"&gt;&amp;#39;/[[:space:]]swap[[:space:]]/ s/^[^#]/#&amp;amp;/&amp;#39;&lt;/span&gt; /etc/fstab&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Check that no active swap devices remain:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;swapon --show&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The command should return no output.&lt;/p&gt;
&lt;p&gt;Load the kernel modules required by the container runtime and Kubernetes networking:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tee /etc/modules-load.d/k8s.conf &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;overlay
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;br_netfilter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo modprobe overlay
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo modprobe br_netfilter&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Confirm that both modules are loaded:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsmod &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;br_netfilter|overlay&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Enable the sysctl settings that allow iptables to see bridged traffic and let IP forwarding work:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo tee /etc/sysctl.d/k8s.conf &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;net.bridge.bridge-nf-call-iptables = 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;net.bridge.bridge-nf-call-ip6tables = 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;net.ipv4.ip_forward = 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sysctl --system&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Verify the two main networking settings:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl net.ipv4.ip_forward net.bridge.bridge-nf-call-iptables&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Both values should be &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="step-2-install-containerd"&gt;Step 2: Install containerd &lt;a class="headline-link" href="#step-2-install-containerd" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Kubernetes uses the Container Runtime Interface (CRI) to communicate with a container runtime. Ubuntu 26.04 provides containerd 2.x in its repositories:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install -y containerd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If Docker is already installed from the official Docker repository, the &lt;code&gt;containerd.io&lt;/code&gt; package provides the same runtime and conflicts with the &lt;code&gt;containerd&lt;/code&gt; package. Skip the install above and continue with the configuration below.&lt;/p&gt;
&lt;p&gt;Generate a complete containerd configuration, then enable the &lt;code&gt;systemd&lt;/code&gt; cgroup driver so it matches the kubelet configuration created by &lt;code&gt;kubeadm&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir -p /etc/containerd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;containerd config default &lt;span class="p"&gt;|&lt;/span&gt; sudo tee /etc/containerd/config.toml &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sed -i &lt;span class="s1"&gt;&amp;#39;s/SystemdCgroup = false/SystemdCgroup = true/&amp;#39;&lt;/span&gt; /etc/containerd/config.toml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart containerd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; containerd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Confirm that the service is running and the setting is present:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl is-active containerd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo grep &lt;span class="s1"&gt;&amp;#39;SystemdCgroup = true&amp;#39;&lt;/span&gt; /etc/containerd/config.toml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first command should print &lt;code&gt;active&lt;/code&gt;, and the second should show the enabled cgroup setting.&lt;/p&gt;
&lt;h2 id="step-3-add-the-kubernetes-apt-repository"&gt;Step 3: Add the Kubernetes apt Repository &lt;a class="headline-link" href="#step-3-add-the-kubernetes-apt-repository" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Kubernetes publishes a separate package repository for every minor release. This guide follows the supported &lt;code&gt;v1.36&lt;/code&gt; series, and apt installs the newest patch release available in that repository.&lt;/p&gt;
&lt;p&gt;Install the prerequisites and download the signing key:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install -y apt-transport-https ca-certificates curl gpg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo mkdir -p -m &lt;span class="m"&gt;755&lt;/span&gt; /etc/apt/keyrings
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.36/deb/Release.key &lt;span class="p"&gt;|&lt;/span&gt; sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Add the repository:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sudo tee /etc/apt/sources.list.d/kubernetes.list&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Refresh the package index:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="step-4-install-kubelet-kubeadm-and-kubectl"&gt;Step 4: Install kubelet, kubeadm, and kubectl &lt;a class="headline-link" href="#step-4-install-kubelet-kubeadm-and-kubectl" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Install the three Kubernetes tools and pin their versions so an &lt;code&gt;apt upgrade&lt;/code&gt; does not change them by accident:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install -y kubelet kubeadm kubectl
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-mark hold kubelet kubeadm kubectl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Confirm the install:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubeadm version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubelet --version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl version --client&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;apt-mark hold&lt;/code&gt; flag is important because Kubernetes upgrades follow a specific procedure (&lt;code&gt;kubeadm upgrade&lt;/code&gt;), and a casual &lt;code&gt;apt upgrade&lt;/code&gt; could break the cluster.&lt;/p&gt;
&lt;p&gt;The kubelet may restart repeatedly at this point because it does not have a cluster configuration yet. This is expected and stops after &lt;code&gt;kubeadm init&lt;/code&gt; or &lt;code&gt;kubeadm join&lt;/code&gt; configures the node.&lt;/p&gt;
&lt;h2 id="step-5-initialize-the-control-plane"&gt;Step 5: Initialize the Control Plane &lt;a class="headline-link" href="#step-5-initialize-the-control-plane" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run the next two steps only on the control-plane node.&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;This procedure creates one control-plane node, so the cluster is not highly available. For production workloads that must survive a control-plane failure, design a multi-control-plane cluster with a load balancer and a shared &lt;code&gt;--control-plane-endpoint&lt;/code&gt; before initialization.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Pick a CIDR for the pod network that does not overlap with your host network. The example uses &lt;code&gt;10.244.0.0/16&lt;/code&gt;, which is the default for Flannel. Bootstrap the cluster:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo kubeadm init --pod-network-cidr&lt;span class="o"&gt;=&lt;/span&gt;10.244.0.0/16&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The command pulls the control-plane container images, generates certificates, writes the kubeconfig files under &lt;code&gt;/etc/kubernetes/&lt;/code&gt;, and starts the static pods for the API server, controller manager, scheduler, and etcd. When it finishes you will see a block similar to this:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.1.10:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:1234...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Copy the join command somewhere safe. The bootstrap token is a credential that allows a node to authenticate while joining the cluster, so do not publish or share it with untrusted users.&lt;/p&gt;
&lt;p&gt;Set up the kubeconfig for your sudo user so &lt;code&gt;kubectl&lt;/code&gt; works without root:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cp -i /etc/kubernetes/admin.conf &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/config
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown &lt;span class="k"&gt;$(&lt;/span&gt;id -u&lt;span class="k"&gt;)&lt;/span&gt;:&lt;span class="k"&gt;$(&lt;/span&gt;id -g&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/config&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The copied &lt;code&gt;admin.conf&lt;/code&gt; grants cluster administrator access. Keep &lt;code&gt;~/.kube/config&lt;/code&gt; private and do not distribute it as a general user credential.&lt;/p&gt;
&lt;p&gt;Verify that the API server is reachable:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get nodes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The output lists the control-plane node with a status of &lt;code&gt;NotReady&lt;/code&gt;. The status changes to &lt;code&gt;Ready&lt;/code&gt; after you install a pod network in the next step.&lt;/p&gt;
&lt;h2 id="step-6-install-a-pod-network"&gt;Step 6: Install a Pod Network &lt;a class="headline-link" href="#step-6-install-a-pod-network" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pods cannot communicate until the cluster has a network plugin. Flannel is one of the simplest options that works with the default &lt;code&gt;10.244.0.0/16&lt;/code&gt; CIDR:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Watch the system pods come up:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -n kube-flannel
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -n kube-system
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get nodes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After a minute or so, the Flannel and core system pods should report &lt;code&gt;Running&lt;/code&gt;, and the control-plane node should show &lt;code&gt;Ready&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you prefer Calico, Cilium, or another CNI plugin, install it now instead of Flannel and pass the matching &lt;code&gt;--pod-network-cidr&lt;/code&gt; value to &lt;code&gt;kubeadm init&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="step-7-join-worker-nodes"&gt;Step 7: Join Worker Nodes &lt;a class="headline-link" href="#step-7-join-worker-nodes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run this step on each worker node.&lt;/p&gt;
&lt;p&gt;Use the &lt;code&gt;kubeadm join&lt;/code&gt; command that was printed at the end of &lt;code&gt;kubeadm init&lt;/code&gt;. If you lost it or the token has expired (tokens are valid for 24 hours by default), generate a new one on the control-plane node:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo kubeadm token create --print-join-command&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then run the printed command on the worker:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo kubeadm join 192.168.1.10:6443 --token &amp;lt;token&amp;gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --discovery-token-ca-cert-hash sha256:&amp;lt;hash&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Back on the control-plane node, verify that the new node has joined:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get nodes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The output now lists the worker. It moves from &lt;code&gt;NotReady&lt;/code&gt; to &lt;code&gt;Ready&lt;/code&gt; once the kubelet finishes its registration and the network plugin reports healthy.&lt;/p&gt;
&lt;h2 id="step-8-test-the-cluster"&gt;Step 8: Test the Cluster &lt;a class="headline-link" href="#step-8-test-the-cluster" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Deploy a small workload to confirm the cluster schedules pods and that networking is working:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl create deployment nginx-test --image&lt;span class="o"&gt;=&lt;/span&gt;nginx
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl expose deployment nginx-test --port&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt; --type&lt;span class="o"&gt;=&lt;/span&gt;NodePort
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl rollout status deployment/nginx-test
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods,svc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The output shows the &lt;code&gt;nginx-test&lt;/code&gt; pod in the &lt;code&gt;Running&lt;/code&gt; state and a NodePort service with a port in the &lt;code&gt;30000-32767&lt;/code&gt; range:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;NAME READY STATUS RESTARTS AGE
pod/nginx-test-7b7bf6d9b8-8pxnf 1/1 Running 0 25s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/nginx-test NodePort 10.105.10.123 &amp;lt;none&amp;gt; 80:31234/TCP 12s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Open &lt;code&gt;http://&amp;lt;node_ip&amp;gt;:&amp;lt;nodeport&amp;gt;&lt;/code&gt; in a browser and you should see the Nginx welcome page. Tear the demo down once you confirm it works:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl delete service nginx-test
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl delete deployment nginx-test&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;kubeadm init&lt;/code&gt; fails with &amp;ldquo;container runtime is not running&amp;rdquo;&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;containerd&lt;/code&gt; is not running, or its CRI plugin is disabled. Inspect the service with &lt;code&gt;sudo systemctl status containerd --no-pager&lt;/code&gt; and check &lt;code&gt;/etc/containerd/config.toml&lt;/code&gt; for a &lt;code&gt;disabled_plugins&lt;/code&gt; entry containing &lt;code&gt;cri&lt;/code&gt;. Remove &lt;code&gt;cri&lt;/code&gt; from that list, confirm that &lt;code&gt;SystemdCgroup = true&lt;/code&gt;, and restart the service with &lt;code&gt;sudo systemctl restart containerd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nodes stay &lt;code&gt;NotReady&lt;/code&gt; after init&lt;/strong&gt;&lt;br&gt;
The pod network is not installed or the CNI pods are crashing. Run &lt;code&gt;kubectl get pods -n kube-flannel&lt;/code&gt; and &lt;code&gt;kubectl logs -n kube-flannel daemonset/kube-flannel-ds --tail=50&lt;/code&gt; to inspect Flannel. Confirm that the &lt;code&gt;--pod-network-cidr&lt;/code&gt; passed to &lt;code&gt;kubeadm init&lt;/code&gt; matches the CIDR expected by the CNI plugin.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cgroup driver mismatch warning in kubelet logs&lt;/strong&gt;&lt;br&gt;
The kubelet uses &lt;code&gt;systemd&lt;/code&gt; and the runtime uses &lt;code&gt;cgroupfs&lt;/code&gt;, or vice versa. Edit &lt;code&gt;/etc/containerd/config.toml&lt;/code&gt;, set &lt;code&gt;SystemdCgroup = true&lt;/code&gt;, and restart &lt;code&gt;containerd&lt;/code&gt;. Restart the kubelet with &lt;code&gt;sudo systemctl restart kubelet&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;The connection to the server localhost:8080 was refused&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;kubectl&lt;/code&gt; is reading the wrong kubeconfig. Run &lt;code&gt;kubectl config view&lt;/code&gt; to confirm the current context, and make sure &lt;code&gt;~/.kube/config&lt;/code&gt; exists for the user running the command. On the control-plane node, copy &lt;code&gt;/etc/kubernetes/admin.conf&lt;/code&gt; to &lt;code&gt;~/.kube/config&lt;/code&gt; and fix ownership.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Worker join times out&lt;/strong&gt;&lt;br&gt;
The control-plane host is not reachable from the worker on TCP port &lt;code&gt;6443&lt;/code&gt;, or the token has expired. Confirm the route and firewall rules, then run &lt;code&gt;sudo kubeadm token create --print-join-command&lt;/code&gt; on the control plane to generate a fresh join command.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Nginx NodePort does not respond&lt;/strong&gt;&lt;br&gt;
The workload can be healthy while a host or cloud firewall blocks the assigned NodePort. Read the port from &lt;code&gt;kubectl get service nginx-test&lt;/code&gt;, then allow that TCP port only from the client network that needs access.&lt;/p&gt;
&lt;h2 id="faq"&gt;FAQ &lt;a class="headline-link" href="#faq" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Do I still need Docker?&lt;/strong&gt;&lt;br&gt;
No. Kubernetes communicates with container runtimes through the CRI, and &lt;code&gt;containerd&lt;/code&gt; is enough for this cluster. Kubernetes 1.24 removed the built-in Docker integration known as dockershim. If you also want to build images on the same host, install Docker as a separate tool. See &lt;a href="https://linuxize.com/post/how-to-install-docker-on-ubuntu-26-04/"&gt;How to Install Docker on Ubuntu 26.04&lt;/a&gt;
for the build environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why is swap disabled?&lt;/strong&gt;&lt;br&gt;
The kubelet refuses to start by default when it detects active swap. Kubernetes can use swap with an explicit kubelet configuration, but disabling it keeps this installation aligned with the default behavior.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can I run a single-node cluster on the control plane?&lt;/strong&gt;&lt;br&gt;
Yes. Remove the control-plane taint with &lt;code&gt;kubectl taint nodes --all node-role.kubernetes.io/control-plane-&lt;/code&gt;. After that, the scheduler places workload pods on the control-plane node.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do I upgrade Kubernetes later?&lt;/strong&gt;&lt;br&gt;
Follow the kubeadm node upgrade procedure and move through one minor version at a time. The process includes upgrading &lt;code&gt;kubeadm&lt;/code&gt;, running &lt;code&gt;kubeadm upgrade plan&lt;/code&gt; and &lt;code&gt;kubeadm upgrade apply&lt;/code&gt;, then upgrading the kubelet and kubectl. The package holds prevent these components from changing during a routine &lt;code&gt;apt upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="next-steps"&gt;Next Steps &lt;a class="headline-link" href="#next-steps" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You now have a working Kubernetes cluster on Ubuntu 26.04. From here you can deploy applications with manifests or Helm charts, set up an ingress controller, and add storage classes that match your environment. For a single-node lab on the same host, an alternative is to start with &lt;code&gt;k3s&lt;/code&gt; or &lt;code&gt;minikube&lt;/code&gt; and migrate to a &lt;code&gt;kubeadm&lt;/code&gt; cluster as your needs grow.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/how-to-install-kubernetes-with-kubeadm-on-ubuntu-26-04/featured_hu_768004ad5f191962.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>update-alternatives Command on Ubuntu and Debian</title><link>https://linuxize.com/post/update-alternatives-command/</link><pubDate>Mon, 27 Jul 2026 09:10:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/update-alternatives-command/</guid><category>linux commands</category><category>ubuntu</category><category>debian</category><description>Use update-alternatives on Ubuntu and Debian to list, register, switch, and remove program alternatives, with automatic and manual mode examples.</description><content:encoded>&lt;p&gt;When several installed programs provide the same command, you need a reliable way to choose which one runs by default. Hard-coding paths in scripts or rebuilding symbolic links by hand makes that choice difficult to maintain.&lt;/p&gt;
&lt;p&gt;On Ubuntu, Debian, and their derivatives, the &lt;code&gt;update-alternatives&lt;/code&gt; command manages these selections through symbolic links in &lt;code&gt;/etc/alternatives&lt;/code&gt;. This guide explains how to inspect alternative groups, switch programs interactively or from a script, register new choices, and return a group to automatic mode.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How It Works &lt;a class="headline-link" href="#how-it-works" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;update-alternatives&lt;/code&gt; maintains link groups. Each group has a generic command name and one or more registered program paths. For example, the &lt;code&gt;java&lt;/code&gt; group controls which installed Java runtime &lt;code&gt;/usr/bin/java&lt;/code&gt; starts.&lt;/p&gt;
&lt;p&gt;The generic command is not linked directly to the selected program. Instead, &lt;code&gt;/usr/bin/java&lt;/code&gt; points to &lt;code&gt;/etc/alternatives/java&lt;/code&gt;, which points to the active Java binary. You can read our &lt;a href="https://linuxize.com/post/how-to-create-symbolic-links-in-linux-using-the-ln-command/"&gt;symbolic links guide&lt;/a&gt;
for more about this two-step link structure.&lt;/p&gt;
&lt;p&gt;Each group operates in one of two modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Automatic mode&lt;/strong&gt; selects the registered alternative with the highest priority.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manual mode&lt;/strong&gt; keeps the administrator&amp;rsquo;s selection until it is changed explicitly or becomes invalid.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The command stores its administrative state under &lt;code&gt;/var/lib/dpkg/alternatives&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="syntax"&gt;Syntax &lt;a class="headline-link" href="#syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The general command syntax is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;update-alternatives [OPTIONS] COMMAND&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Commands that change an alternative group require &lt;code&gt;sudo&lt;/code&gt;. Listing and displaying alternatives does not.&lt;/p&gt;
&lt;h2 id="list-alternative-groups"&gt;List Alternative Groups &lt;a class="headline-link" href="#list-alternative-groups" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To see every master alternative group registered on the system, run:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;update-alternatives --get-selections&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;awk auto /usr/bin/mawk
editor auto /bin/nano
pager auto /bin/more
vi auto /usr/bin/vim.basic&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The second column shows whether the group is in &lt;code&gt;auto&lt;/code&gt; or &lt;code&gt;manual&lt;/code&gt; mode. The final column contains the selected program path. Your groups and paths will differ according to the packages installed on your system.&lt;/p&gt;
&lt;p&gt;To list only the registered paths for one group, pass its name to &lt;code&gt;--list&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;update-alternatives --list java&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;/usr/lib/jvm/java-17-openjdk-amd64/bin/java
/usr/lib/jvm/java-21-openjdk-amd64/bin/java&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This example has Java 17 and Java 21 registered. If the named group does not exist, the command reports that no alternatives are registered for it.&lt;/p&gt;
&lt;h2 id="display-an-alternative"&gt;Display an Alternative &lt;a class="headline-link" href="#display-an-alternative" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To see all registered options for a specific alternative and which one is currently active:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;update-alternatives --display java&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;java - auto mode
link best version is /usr/lib/jvm/java-21-openjdk-amd64/bin/java
link currently points to /usr/lib/jvm/java-21-openjdk-amd64/bin/java
link java is /usr/bin/java
slave java.1.gz is /usr/share/man/man1/java.1.gz
/usr/lib/jvm/java-17-openjdk-amd64/bin/java - priority 1711
slave java.1.gz: /usr/lib/jvm/java-17-openjdk-amd64/man/man1/java.1.gz
/usr/lib/jvm/java-21-openjdk-amd64/bin/java - priority 2111
slave java.1.gz: /usr/lib/jvm/java-21-openjdk-amd64/man/man1/java.1.gz&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The output lists each registered path with its priority. In &lt;code&gt;auto&lt;/code&gt; mode, the highest priority wins. The &lt;code&gt;slave&lt;/code&gt; lines show related files that follow the same selection, in this case the &lt;code&gt;java&lt;/code&gt; manual page.&lt;/p&gt;
&lt;h2 id="switch-between-alternatives"&gt;Switch Between Alternatives &lt;a class="headline-link" href="#switch-between-alternatives" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To choose interactively from the registered options, run:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo update-alternatives --config java&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;There are 2 choices for the alternative java (providing /usr/bin/java).
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/lib/jvm/java-21-openjdk-amd64/bin/java 2111 auto mode
1 /usr/lib/jvm/java-17-openjdk-amd64/bin/java 1711 manual mode
2 /usr/lib/jvm/java-21-openjdk-amd64/bin/java 2111 manual mode
Press &amp;lt;enter&amp;gt; to keep the current choice[*], or type selection number: 1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Type the number of a manual choice and press Enter to pin that version. Selecting &lt;code&gt;0&lt;/code&gt; keeps or restores automatic mode, while pressing Enter without a number keeps the current choice.&lt;/p&gt;
&lt;p&gt;When a group is in manual mode, a package installation can register another choice but will not replace your valid selection.&lt;/p&gt;
&lt;h2 id="set-an-alternative-noninteractively"&gt;Set an Alternative Noninteractively &lt;a class="headline-link" href="#set-an-alternative-noninteractively" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;--set&lt;/code&gt; command changes an alternative without displaying a menu, which makes it useful in provisioning scripts. Use &lt;code&gt;--list&lt;/code&gt; as shown above to copy the exact path, then pass it to &lt;code&gt;--set&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo update-alternatives --set java /usr/lib/jvm/java-17-openjdk-amd64/bin/java&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The selected group enters manual mode. The path must already be registered in that group.&lt;/p&gt;
&lt;p&gt;Alternative groups are independent unless their provider registered related files as slave links. For example, switching the &lt;code&gt;java&lt;/code&gt; group does not necessarily switch &lt;code&gt;javac&lt;/code&gt;. Use &lt;code&gt;--display&lt;/code&gt; to check which links belong to a group.&lt;/p&gt;
&lt;h2 id="register-a-new-alternative"&gt;Register a New Alternative &lt;a class="headline-link" href="#register-a-new-alternative" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you install a program outside the package manager, you can register it with &lt;code&gt;--install&lt;/code&gt;. Assume two releases of a program are installed at &lt;code&gt;/opt/acme-tool-1.0/bin/acme-tool&lt;/code&gt; and &lt;code&gt;/opt/acme-tool-2.0/bin/acme-tool&lt;/code&gt;. Confirm that both executable paths exist before registering them:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -l /opt/acme-tool-1.0/bin/acme-tool /opt/acme-tool-2.0/bin/acme-tool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Register both releases under the same &lt;code&gt;acme-tool&lt;/code&gt; group:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo update-alternatives --install /usr/local/bin/acme-tool acme-tool /opt/acme-tool-1.0/bin/acme-tool &lt;span class="m"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo update-alternatives --install /usr/local/bin/acme-tool acme-tool /opt/acme-tool-2.0/bin/acme-tool &lt;span class="m"&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The arguments are:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--install LINK NAME PATH PRIORITY&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LINK&lt;/code&gt; is the path where the generic command link will be created (&lt;code&gt;/usr/local/bin/acme-tool&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NAME&lt;/code&gt; is the alternative group name (&lt;code&gt;acme-tool&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PATH&lt;/code&gt; is the actual binary (&lt;code&gt;/opt/acme-tool-1.0/bin/acme-tool&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PRIORITY&lt;/code&gt; is the numeric weight used in &lt;code&gt;auto&lt;/code&gt; mode (higher wins).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this example, automatic mode selects version 2.0 because it has the higher priority.&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;Do not use &lt;code&gt;update-alternatives&lt;/code&gt; to replace &lt;code&gt;/usr/bin/python3&lt;/code&gt; on Ubuntu or Debian. System tools depend on the distribution&amp;rsquo;s default Python interpreter. Use versioned commands, virtual environments, &lt;code&gt;pyenv&lt;/code&gt;, or a separate command under &lt;code&gt;/usr/local/bin&lt;/code&gt; instead.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="remove-an-alternative"&gt;Remove an Alternative &lt;a class="headline-link" href="#remove-an-alternative" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before removing a registered path, display the group and confirm the exact path:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;update-alternatives --display acme-tool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then deregister the path:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo update-alternatives --remove acme-tool /opt/acme-tool-1.0/bin/acme-tool&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The command removes the path from the alternatives database but does not delete the program itself. If you remove the active path, the group returns to automatic mode and selects the best remaining alternative.&lt;/p&gt;
&lt;h2 id="reset-to-auto-mode"&gt;Reset to Auto Mode &lt;a class="headline-link" href="#reset-to-auto-mode" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you manually pinned an alternative and want to go back to automatic selection by priority:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo update-alternatives --auto java&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The system returns to the highest-priority option.&lt;/p&gt;
&lt;h2 id="switch-the-editor-alternative"&gt;Switch the Editor Alternative &lt;a class="headline-link" href="#switch-the-editor-alternative" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;editor&lt;/code&gt; alternative provides the system-wide &lt;code&gt;/usr/bin/editor&lt;/code&gt; command. Programs that invoke this path follow the selected alternative, while tools such as &lt;code&gt;sensible-editor&lt;/code&gt; may honor user-specific settings and environment variables first. To switch the system editor choice:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo update-alternatives --config editor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Select an installed editor such as &lt;code&gt;vim.basic&lt;/code&gt; from the list. Applications with their own editor setting do not necessarily follow this choice. Git, for example, checks &lt;code&gt;GIT_EDITOR&lt;/code&gt;, &lt;code&gt;core.editor&lt;/code&gt;, &lt;code&gt;VISUAL&lt;/code&gt;, and &lt;code&gt;EDITOR&lt;/code&gt; before using its compiled default.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List all alternative groups&lt;/td&gt;
&lt;td&gt;&lt;code&gt;update-alternatives --get-selections&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List paths in one group&lt;/td&gt;
&lt;td&gt;&lt;code&gt;update-alternatives --list NAME&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Display group details&lt;/td&gt;
&lt;td&gt;&lt;code&gt;update-alternatives --display NAME&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Choose interactively&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo update-alternatives --config NAME&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Select a path noninteractively&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo update-alternatives --set NAME PATH&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Return to automatic mode&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo update-alternatives --auto NAME&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Register a path&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo update-alternatives --install LINK NAME PATH PRIORITY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deregister a path&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo update-alternatives --remove NAME PATH&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;no alternatives for NAME&lt;/code&gt;&lt;/strong&gt;
The group is not registered. Check the available names with &lt;code&gt;update-alternatives --get-selections&lt;/code&gt;. Install a package that provides the group or register an existing executable with &lt;code&gt;--install&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;alternative path ... does not exist&lt;/code&gt;&lt;/strong&gt;
The path passed to &lt;code&gt;--install&lt;/code&gt; must already exist. Check it with &lt;code&gt;ls -l PATH&lt;/code&gt;, then correct the path or install the program before trying again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A regular file blocks the alternatives link&lt;/strong&gt;
Do not immediately add &lt;code&gt;--force&lt;/code&gt;. Check which package owns the path with &lt;code&gt;dpkg -S /path/to/command&lt;/code&gt;, and back up locally installed files before replacing them with an alternatives-managed link.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;--config&lt;/code&gt; for interactive changes, &lt;code&gt;--set&lt;/code&gt; for scripts, and &lt;code&gt;--auto&lt;/code&gt; when you want priority-based selection again. For a practical example with multiple JDKs, see &lt;a href="https://linuxize.com/post/how-to-check-java-version/"&gt;How to Check Java Version&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/update-alternatives-command/featured_hu_63fd47dfcb6ed134.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>How to Convert MP4 to MP3 with ffmpeg</title><link>https://linuxize.com/post/convert-mp4-to-mp3-with-ffmpeg/</link><pubDate>Sun, 26 Jul 2026 08:20:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/convert-mp4-to-mp3-with-ffmpeg/</guid><category>ffmpeg</category><description>Convert MP4 video to MP3 audio from the Linux command line with ffmpeg, including quality settings, lossless extraction, trimming, and batch conversion.</description><content:encoded>&lt;p&gt;A recorded lecture, a podcast published as video, a concert clip you only ever listen to: sometimes all you want from an MP4 is its audio track. &lt;code&gt;ffmpeg&lt;/code&gt; does this in one command, with full control over the output quality.&lt;/p&gt;
&lt;p&gt;This guide shows how to convert MP4 to MP3 with &lt;code&gt;ffmpeg&lt;/code&gt;, pick sensible quality settings, extract audio without any quality loss, and convert files in bulk.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites &lt;a class="headline-link" href="#prerequisites" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You need &lt;code&gt;ffmpeg&lt;/code&gt; installed. On Ubuntu, Debian, and derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install ffmpeg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;These commands install both &lt;code&gt;ffmpeg&lt;/code&gt; and &lt;code&gt;ffprobe&lt;/code&gt;. For version-specific instructions, see our guides on installing ffmpeg on &lt;a href="https://linuxize.com/post/how-to-install-ffmpeg-on-ubuntu-20-04/"&gt;Ubuntu&lt;/a&gt;
and &lt;a href="https://linuxize.com/post/how-to-install-ffmpeg-on-debian-10/"&gt;Debian&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="converting-mp4-to-mp3"&gt;Converting MP4 to MP3 &lt;a class="headline-link" href="#converting-mp4-to-mp3" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The simplest form gives &lt;code&gt;ffmpeg&lt;/code&gt; an input, selects the LAME MP3 encoder, and names the output file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ffmpeg -i video.mp4 -c:a libmp3lame audio.mp3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This decodes the audio track from &lt;code&gt;video.mp4&lt;/code&gt;, encodes it as MP3 with default settings, and writes &lt;code&gt;audio.mp3&lt;/code&gt;. The video stream is dropped automatically, since an MP3 file cannot contain one.&lt;/p&gt;
&lt;p&gt;For better control, the recommended form adds two options:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ffmpeg -i video.mp4 -vn -c:a libmp3lame -q:a &lt;span class="m"&gt;2&lt;/span&gt; audio.mp3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-vn&lt;/code&gt; flag explicitly discards the video stream, &lt;code&gt;-c:a libmp3lame&lt;/code&gt; selects the LAME MP3 encoder, and &lt;code&gt;-q:a 2&lt;/code&gt; selects variable bitrate (VBR) quality level 2. This level typically averages around 190 kb/s, although the actual bitrate depends on the audio.&lt;/p&gt;
&lt;h2 id="choosing-the-quality"&gt;Choosing the Quality &lt;a class="headline-link" href="#choosing-the-quality" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The MP3 encoder accepts a VBR quality scale from 0 (best) to 9 (smallest). These approximate bitrates vary with the source:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-q:a 0&lt;/code&gt; - Around 245 kb/s; highest quality VBR, for music you care about.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q:a 2&lt;/code&gt; - Around 190 kb/s; the common sweet spot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q:a 5&lt;/code&gt; - Around 130 kb/s; fine for speech and podcasts.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q:a 7&lt;/code&gt; - Around 100 kb/s; small files, audible compression on music.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you need a constant bitrate instead, for example for a device that struggles with VBR, use &lt;code&gt;-b:a&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ffmpeg -i video.mp4 -vn -c:a libmp3lame -b:a 192k audio.mp3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Keep in mind that encoding cannot add quality back: if the source audio is a 96 kb/s stream, encoding it at 320 kb/s only produces a larger file, not a better-sounding one.&lt;/p&gt;
&lt;h2 id="extracting-audio-without-quality-loss"&gt;Extracting Audio Without Quality Loss &lt;a class="headline-link" href="#extracting-audio-without-quality-loss" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Converting to MP3 always re-encodes, which costs a small amount of quality. If you only need the original audio track, check its codec before deciding whether to convert it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ffprobe -v error -select_streams a:0 -show_entries &lt;span class="nv"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;codec_name -of &lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;noprint_wrappers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1:nokey&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; video.mp4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;aac&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;AAC audio is common in MP4 files and can be copied into an &lt;code&gt;.m4a&lt;/code&gt; container without re-encoding:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ffmpeg -i video.mp4 -map 0:a:0 -c:a copy audio.m4a&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-map 0:a:0&lt;/code&gt; option selects the first audio stream, and &lt;code&gt;-c:a copy&lt;/code&gt; moves the compressed audio without decoding or encoding it. The audio data remains unchanged, and the operation usually finishes much faster than an MP3 conversion. If &lt;code&gt;ffprobe&lt;/code&gt; reports another codec, use a compatible container or convert the audio instead.&lt;/p&gt;
&lt;h2 id="converting-part-of-a-file"&gt;Converting Part of a File &lt;a class="headline-link" href="#converting-part-of-a-file" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To convert only a section, combine the conversion with a start time and a duration:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ffmpeg -ss 00:05:30 -i video.mp4 -t 00:06:30 -vn -c:a libmp3lame -q:a &lt;span class="m"&gt;2&lt;/span&gt; clip.mp3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-ss&lt;/code&gt; option starts at 5:30, and &lt;code&gt;-t 00:06:30&lt;/code&gt; converts the next six minutes and thirty seconds, ending at 12:00. This is handy for pulling one song out of a concert recording or one answer out of a long interview.&lt;/p&gt;
&lt;h2 id="batch-converting-multiple-files"&gt;Batch Converting Multiple Files &lt;a class="headline-link" href="#batch-converting-multiple-files" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ffmpeg&lt;/code&gt; takes one input at a time, so converting a directory of MP4 files uses a small &lt;a href="https://linuxize.com/post/bash-for-loop/"&gt;bash for loop&lt;/a&gt;
:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;shopt&lt;/span&gt; -s nullglob
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; f in *.mp4&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ffmpeg -n -i &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -vn -c:a libmp3lame -q:a &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;%.mp4&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.mp3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;nullglob&lt;/code&gt; setting skips the loop when the directory contains no MP4 files. The &lt;code&gt;${f%.mp4}&lt;/code&gt; expansion strips the &lt;code&gt;.mp4&lt;/code&gt; extension so each MP3 keeps the original filename, while &lt;code&gt;-n&lt;/code&gt; prevents existing files from being overwritten. The quotes around the variables keep filenames with spaces intact.&lt;/p&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Unknown encoder &amp;rsquo;libmp3lame&amp;rsquo;&lt;/strong&gt;&lt;br&gt;
Your &lt;code&gt;ffmpeg&lt;/code&gt; build lacks the LAME MP3 encoder, which happens with some minimal or codec-restricted packages. Check for it with &lt;code&gt;ffmpeg -hide_banner -encoders | grep -w libmp3lame&lt;/code&gt;, then install an FFmpeg package that includes the encoder.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output file has no sound&lt;/strong&gt;&lt;br&gt;
The source may carry multiple audio tracks and the wrong one was picked. Inspect the file with &lt;code&gt;ffprobe -hide_banner video.mp4&lt;/code&gt;, then select the track explicitly with &lt;code&gt;-map&lt;/code&gt;, for example &lt;code&gt;-map 0:a:1&lt;/code&gt; for the second audio stream.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Could not write the M4A output header&lt;/strong&gt;&lt;br&gt;
The source audio codec is not compatible with the M4A container. Use a container that supports the original codec, or replace &lt;code&gt;-c:a copy&lt;/code&gt; with &lt;code&gt;-c:a aac -b:a 192k&lt;/code&gt; to create a compatible M4A file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The output file already exists&lt;/strong&gt;&lt;br&gt;
FFmpeg asks before replacing an existing file. Use a different output name, add &lt;code&gt;-n&lt;/code&gt; to keep the existing file, or add &lt;code&gt;-y&lt;/code&gt; only when you intend to overwrite it.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One command covers the everyday case: &lt;code&gt;ffmpeg -i video.mp4 -vn -c:a libmp3lame -q:a 2 audio.mp3&lt;/code&gt;, with &lt;code&gt;-q:a&lt;/code&gt; trading size against quality. For more conversion, compression, and inspection examples, see our &lt;a href="https://linuxize.com/post/ffmpeg-command-in-linux/"&gt;&lt;code&gt;ffmpeg&lt;/code&gt; command guide&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/convert-mp4-to-mp3-with-ffmpeg/featured_hu_6c2ecd86779650c2.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>How to Find Which Process Is Using a Port in Linux</title><link>https://linuxize.com/post/how-to-find-which-process-is-using-a-port/</link><pubDate>Sat, 25 Jul 2026 07:30:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/how-to-find-which-process-is-using-a-port/</guid><category>networking</category><category>linux commands</category><description>Find the Linux process listening on a TCP or UDP port with ss, lsof, fuser, or netstat, then inspect and stop it safely.</description><content:encoded>&lt;p&gt;You start a service, and it refuses to launch with an error like &amp;ldquo;bind: address already in use&amp;rdquo;. Something is already holding the port, but the message does not tell you what. Before you can fix it, you need to map the port back to a process, find its PID, and decide whether to stop it. Linux gives you several tools for this, and each one answers the question in a slightly different way.&lt;/p&gt;
&lt;p&gt;This guide shows how to find the process using a port with &lt;code&gt;ss&lt;/code&gt;, &lt;code&gt;lsof&lt;/code&gt;, &lt;code&gt;fuser&lt;/code&gt;, and &lt;code&gt;netstat&lt;/code&gt;, and how to stop it once you have the PID.&lt;/p&gt;
&lt;p&gt;If you need an inventory of every service accepting connections instead of one specific port, see the guide on &lt;a href="https://linuxize.com/post/check-listening-ports-linux/"&gt;checking listening ports in Linux&lt;/a&gt;
. Note that &lt;code&gt;127.0.0.1:8080&lt;/code&gt; and &lt;code&gt;0.0.0.0:8080&lt;/code&gt; collide, because binding to all interfaces includes the &lt;a href="https://linuxize.com/post/what-is-localhost/"&gt;loopback address&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For printable quick references, see the &lt;a href="https://linuxize.com/cheatsheet/ss/"&gt;ss cheatsheet&lt;/a&gt;
, &lt;a href="https://linuxize.com/cheatsheet/lsof/"&gt;lsof cheatsheet&lt;/a&gt;
, and &lt;a href="https://linuxize.com/cheatsheet/netstat/"&gt;netstat cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Find a TCP listener with ss&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo ss -ltnp 'sport = :80'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find a UDP socket with ss&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo ss -lunp 'sport = :53'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find a TCP listener with lsof&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo lsof -nP -iTCP:80 -sTCP:LISTEN&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find processes with fuser&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo fuser -v 80/tcp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find a TCP listener with netstat&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo netstat -ltnp | grep ':80 '&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inspect a process&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ps -fp PID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop an unmanaged process&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo kill PID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Send SIGTERM with fuser&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo fuser -k -TERM 80/tcp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="finding-the-process-with-ss"&gt;Finding the Process with ss &lt;a class="headline-link" href="#finding-the-process-with-ss" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://linuxize.com/post/ss-command-in-linux/"&gt;&lt;code&gt;ss&lt;/code&gt;&lt;/a&gt;
command is the standard choice on current Linux distributions. It comes from the &lt;code&gt;iproute2&lt;/code&gt; package and supports filters that match an exact port without piping the output through another command.&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ss -ltnp &lt;span class="s1"&gt;&amp;#39;sport = :80&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:((&amp;#34;nginx&amp;#34;,pid=1433,fd=6),(&amp;#34;nginx&amp;#34;,pid=1432,fd=6))
LISTEN 0 511 [::]:80 [::]:* users:((&amp;#34;nginx&amp;#34;,pid=1433,fd=6),(&amp;#34;nginx&amp;#34;,pid=1432,fd=6))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Run the command with &lt;code&gt;sudo&lt;/code&gt; so &lt;code&gt;ss&lt;/code&gt; can show process details for sockets owned by other users. The options provide the following information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt; - Show only listening sockets.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Show TCP sockets.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt; - Print numeric port numbers instead of resolving service names.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; - Show the process that owns each socket.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;sport = :80&lt;/code&gt; expression matches local port 80 exactly, so it does not also return ports such as 8080. In the output above, &lt;code&gt;nginx&lt;/code&gt; holds the port. The &lt;code&gt;Process&lt;/code&gt; column lists two process IDs because the master process, &lt;code&gt;1432&lt;/code&gt;, opened the socket and passed it to its worker, &lt;code&gt;1433&lt;/code&gt;. Either PID leads you back to the same service. The two rows show that &lt;code&gt;nginx&lt;/code&gt; listens on both IPv4 and IPv6.&lt;/p&gt;
&lt;p&gt;UDP sockets do not use the TCP &lt;code&gt;LISTEN&lt;/code&gt; state. To check a UDP port, replace &lt;code&gt;-t&lt;/code&gt; with &lt;code&gt;-u&lt;/code&gt;. For example, the following command identifies the process bound to UDP port 53:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ss -lunp &lt;span class="s1"&gt;&amp;#39;sport = :53&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
UNCONN 0 0 0.0.0.0:53 0.0.0.0:* users:((&amp;#34;dnsmasq&amp;#34;,pid=902,fd=4))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;UNCONN&lt;/code&gt; state is normal for a UDP server because UDP does not establish connections before exchanging data.&lt;/p&gt;
&lt;h2 id="finding-the-process-with-lsof"&gt;Finding the Process with lsof &lt;a class="headline-link" href="#finding-the-process-with-lsof" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://linuxize.com/post/lsof-command-in-linux/"&gt;&lt;code&gt;lsof&lt;/code&gt;&lt;/a&gt;
command lists open files, including network sockets. Use numeric output and restrict the result to TCP listeners on the port:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lsof -nP -iTCP:80 -sTCP:LISTEN&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 1432 root 6u IPv4 28319 0t0 TCP *:80 (LISTEN)
nginx 1433 www-data 6u IPv4 28319 0t0 TCP *:80 (LISTEN)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-nP&lt;/code&gt; options prevent hostname and service-name lookups, while &lt;code&gt;-iTCP:80&lt;/code&gt; selects TCP port 80 and &lt;code&gt;-sTCP:LISTEN&lt;/code&gt; excludes established connections. The output reports the command, PID, user, and file descriptor. Here &lt;code&gt;lsof&lt;/code&gt; gives you the same two &lt;code&gt;nginx&lt;/code&gt; processes that &lt;code&gt;ss&lt;/code&gt; reported, but it also shows the user each one runs as, which is useful when a master process drops privileges for its workers.&lt;/p&gt;
&lt;p&gt;For UDP port 53, use this form:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lsof -nP -iUDP:53&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The pattern is the same, except that &lt;code&gt;-iUDP:53&lt;/code&gt; selects the UDP port and there is no state filter, because UDP sockets never enter the &lt;code&gt;LISTEN&lt;/code&gt; state.&lt;/p&gt;
&lt;h2 id="finding-the-process-with-fuser"&gt;Finding the Process with fuser &lt;a class="headline-link" href="#finding-the-process-with-fuser" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you want a PID without the full socket table, &lt;code&gt;fuser&lt;/code&gt; provides a short command. Pass the port number followed by the protocol:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo fuser 80/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;80/tcp: 1432 1433&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You get the PID list and nothing else, which makes the plain form easy to pass to another command. To include the user, access type, and command name, add the &lt;code&gt;-v&lt;/code&gt; option:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo fuser -v 80/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt; USER PID ACCESS COMMAND
80/tcp: root 1432 F.... nginx
www-data 1433 F.... nginx&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The port appears once on the first row, and every process below it belongs to that same port. The &lt;code&gt;ACCESS&lt;/code&gt; column describes how each process uses the socket, where &lt;code&gt;F&lt;/code&gt; marks it as open for writing.&lt;/p&gt;
&lt;p&gt;You must specify &lt;code&gt;tcp&lt;/code&gt; or &lt;code&gt;udp&lt;/code&gt; because the same numeric port can be used by both protocols.&lt;/p&gt;
&lt;h2 id="finding-the-process-with-netstat"&gt;Finding the Process with netstat &lt;a class="headline-link" href="#finding-the-process-with-netstat" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On older systems you may still find &lt;a href="https://linuxize.com/post/netstat-command-in-linux/"&gt;&lt;code&gt;netstat&lt;/code&gt;&lt;/a&gt;
, part of the &lt;code&gt;net-tools&lt;/code&gt; package. Use it as a fallback when &lt;code&gt;ss&lt;/code&gt; is not available:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo netstat -ltnp &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;&amp;#39;:80 &amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1432/nginx: master&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The last column ties PID &lt;code&gt;1432&lt;/code&gt; to the &lt;code&gt;nginx&lt;/code&gt; master process, and &lt;code&gt;netstat&lt;/code&gt; truncates that name if it grows too long. Unlike &lt;code&gt;ss&lt;/code&gt; and &lt;code&gt;lsof&lt;/code&gt;, it reports a single process per socket rather than the whole group. The space after &lt;code&gt;:80&lt;/code&gt; in the filter prevents it from matching a longer port number such as 8080. For a UDP port, use &lt;code&gt;-lunp&lt;/code&gt; instead of &lt;code&gt;-ltnp&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="inspecting-and-stopping-the-process"&gt;Inspecting and Stopping the Process &lt;a class="headline-link" href="#inspecting-and-stopping-the-process" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once you have the PID, confirm what started the process before stopping it. The following &lt;a href="https://linuxize.com/post/ps-command-in-linux/"&gt;&lt;code&gt;ps&lt;/code&gt;&lt;/a&gt;
command shows the full command and its parent PID:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps -fp &lt;span class="m"&gt;1432&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;UID PID PPID C STIME TTY TIME CMD
root 1432 1 0 07:10 ? 00:00:00 nginx: master process /usr/sbin/nginx&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A service manager or container runtime may own the process. In that case, stop it through its manager so it does not immediately start again. For example, stop an Nginx systemd service with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl stop nginx&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;Make sure you understand what the process does before stopping it. Terminating a database or another production service to free a port can interrupt active work or cause data loss.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For an unmanaged process, send &lt;code&gt;SIGTERM&lt;/code&gt; with &lt;code&gt;kill&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo &lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="m"&gt;1432&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;SIGTERM&lt;/code&gt; asks the process to shut down cleanly. If the process ignores it, you can use &lt;code&gt;sudo kill -KILL 1432&lt;/code&gt; as a last resort, but &lt;code&gt;SIGKILL&lt;/code&gt; gives it no opportunity to save state or remove temporary files. For more detail about signals, see the guide on &lt;a href="https://linuxize.com/post/how-to-kill-a-process-in-linux/"&gt;how to kill a process in Linux&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;After inspecting the verbose &lt;code&gt;fuser&lt;/code&gt; output, you can send &lt;code&gt;SIGTERM&lt;/code&gt; to every process using the TCP port:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo fuser -k -TERM 80/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The explicit &lt;code&gt;-TERM&lt;/code&gt; matters because &lt;code&gt;fuser -k&lt;/code&gt; sends &lt;code&gt;SIGKILL&lt;/code&gt; by default.&lt;/p&gt;
&lt;h2 id="confirming-the-port-is-free"&gt;Confirming the Port Is Free &lt;a class="headline-link" href="#confirming-the-port-is-free" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run the same &lt;code&gt;ss&lt;/code&gt; query after stopping the process:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ss -ltnp &lt;span class="s1"&gt;&amp;#39;sport = :80&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If no socket row appears below the header, nothing is listening on TCP port 80 in the current network namespace. If you changed a service configuration instead of stopping it, start the service again and check the new port with the same command.&lt;/p&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The port appears but the process name is missing&lt;/strong&gt;&lt;br&gt;
Run the command with &lt;code&gt;sudo&lt;/code&gt;. Without root privileges, these tools may not be able to read details for sockets owned by another user.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ss returns nothing but the application still reports a conflict&lt;/strong&gt;&lt;br&gt;
Check that you are using the correct protocol. Use &lt;code&gt;-lunp&lt;/code&gt; for UDP instead of &lt;code&gt;-ltnp&lt;/code&gt; for TCP. The listener may also be inside another network namespace or container, so run the check in the same environment as the application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The process starts again after you stop it&lt;/strong&gt;&lt;br&gt;
A service manager or container runtime is restarting it. Stop or reconfigure the systemd service, Docker container, or other supervisor instead of repeatedly killing its PID.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Several PIDs appear for the same port&lt;/strong&gt;&lt;br&gt;
Some servers use a master process with several workers that share one socket. Other applications can use the &lt;code&gt;SO_REUSEPORT&lt;/code&gt; option. Identify the parent service and manage the group instead of stopping one worker at a time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;netstat: command not found&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;net-tools&lt;/code&gt; package is not installed on many current distributions. Use &lt;code&gt;ss&lt;/code&gt; instead.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;ss&lt;/code&gt; first when you need the process behind a specific port, then turn to &lt;code&gt;lsof&lt;/code&gt; or &lt;code&gt;fuser&lt;/code&gt; when you need a different view. Inspect the PID and its manager before stopping anything, especially on a production system.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/how-to-find-which-process-is-using-a-port/featured_hu_bc6efb012febea0f.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>CIDR Notation and Subnetting Explained</title><link>https://linuxize.com/post/cidr-notation-and-subnetting-explained/</link><pubDate>Fri, 24 Jul 2026 10:50:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/cidr-notation-and-subnetting-explained/</guid><category>networking</category><description>CIDR notation defines IP network size with a prefix length. This guide explains subnet masks, address ranges, host counts, and practical IPv4 subnetting.</description><content:encoded>&lt;p&gt;When you assign a static address, configure a firewall rule, or divide a private network, you will encounter values such as &lt;code&gt;192.168.10.0/24&lt;/code&gt;. The address identifies the network, while the number after the slash tells you how much of the address is fixed and how much remains available for hosts.&lt;/p&gt;
&lt;p&gt;This guide explains how CIDR prefixes map to subnet masks, how to find network and broadcast addresses, and how to divide an IPv4 block into smaller subnets.&lt;/p&gt;
&lt;p&gt;For instant calculations and a visual binary split, use the &lt;a href="https://linuxize.com/tools/subnet-calculator/"&gt;subnet calculator&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="what-cidr-notation-means"&gt;What CIDR Notation Means &lt;a class="headline-link" href="#what-cidr-notation-means" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CIDR stands for Classless Inter-Domain Routing. It replaced the older class-based system with variable-length prefixes, allowing networks to be sized and routed more precisely.&lt;/p&gt;
&lt;p&gt;An IPv4 CIDR block contains an address followed by a slash and a prefix length:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;192.168.10.0/24&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;An IPv4 address contains 32 bits. The &lt;code&gt;/24&lt;/code&gt; prefix means the first 24 bits identify the network, leaving 8 bits for addresses inside that network. A longer prefix fixes more network bits and creates a smaller block. A shorter prefix leaves more host bits and creates a larger block.&lt;/p&gt;
&lt;p&gt;The prefix can range from &lt;code&gt;/0&lt;/code&gt;, which covers the entire IPv4 address space, to &lt;code&gt;/32&lt;/code&gt;, which identifies one address. CIDR notation is used for both network allocation and routing, so the same format can describe a LAN subnet, a firewall source range, or a single host route.&lt;/p&gt;
&lt;h2 id="network-bits-and-host-bits"&gt;Network Bits and Host Bits &lt;a class="headline-link" href="#network-bits-and-host-bits" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To see the &lt;code&gt;/24&lt;/code&gt; boundary, write the address and mask in binary:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Address: 11000000.10101000.00001010.00000000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Mask: 11111111.11111111.11111111.00000000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;------ network ------&amp;gt;&amp;lt;-- host --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Every &lt;code&gt;1&lt;/code&gt; in the mask belongs to the network prefix. Every &lt;code&gt;0&lt;/code&gt; leaves a bit that can vary within the block. Because &lt;code&gt;/24&lt;/code&gt; leaves 8 host bits, the block contains &lt;code&gt;2^8&lt;/code&gt;, or 256, addresses.&lt;/p&gt;
&lt;p&gt;The network portion stays constant for every address in the block. Only the last 8 bits change, producing the range &lt;code&gt;192.168.10.0&lt;/code&gt; through &lt;code&gt;192.168.10.255&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="convert-a-cidr-prefix-to-a-subnet-mask"&gt;Convert a CIDR Prefix to a Subnet Mask &lt;a class="headline-link" href="#convert-a-cidr-prefix-to-a-subnet-mask" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A subnet mask expresses the same boundary as a CIDR prefix, but in dotted-decimal form. A &lt;code&gt;/24&lt;/code&gt; has 24 one bits followed by 8 zero bits:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11111111.11111111.11111111.00000000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;255.255.255.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Prefixes that end on an octet boundary are easy to recognize: &lt;code&gt;/8&lt;/code&gt; is &lt;code&gt;255.0.0.0&lt;/code&gt;, &lt;code&gt;/16&lt;/code&gt; is &lt;code&gt;255.255.0.0&lt;/code&gt;, and &lt;code&gt;/24&lt;/code&gt; is &lt;code&gt;255.255.255.0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For a prefix such as &lt;code&gt;/26&lt;/code&gt;, the first two bits of the final octet also belong to the network:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11111111.11111111.11111111.11000000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;255.255.255.192&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The binary value &lt;code&gt;11000000&lt;/code&gt; equals 192, so &lt;code&gt;/26&lt;/code&gt; maps to &lt;code&gt;255.255.255.192&lt;/code&gt;. The remaining six host bits provide &lt;code&gt;2^6&lt;/code&gt;, or 64, total addresses per subnet.&lt;/p&gt;
&lt;h2 id="calculate-the-number-of-addresses-and-hosts"&gt;Calculate the Number of Addresses and Hosts &lt;a class="headline-link" href="#calculate-the-number-of-addresses-and-hosts" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a normal IPv4 subnet, calculate the total number of addresses with this formula:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Total addresses = 2^(32 - prefix length)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A &lt;code&gt;/27&lt;/code&gt; leaves five host bits, so it contains &lt;code&gt;2^5 = 32&lt;/code&gt; addresses. The first address is normally reserved as the network address, and the last is the broadcast address, leaving 30 addresses for host interfaces.&lt;/p&gt;
&lt;p&gt;Two prefixes need separate treatment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;/31&lt;/code&gt; contains two addresses. On a point-to-point link, &lt;a href="https://www.rfc-editor.org/rfc/rfc3021.html" target="_blank" rel="noopener noreferrer"&gt;RFC 3021&lt;/a&gt;
treats both as host addresses because that link has no need for a separate network or broadcast address.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;/32&lt;/code&gt; contains one address and represents a host route, not a conventional multi-host subnet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The familiar &lt;code&gt;total minus 2&lt;/code&gt; rule therefore applies to conventional IPv4 subnets from &lt;code&gt;/0&lt;/code&gt; through &lt;code&gt;/30&lt;/code&gt;, not blindly to every prefix.&lt;/p&gt;
&lt;h2 id="find-the-network-and-broadcast-addresses"&gt;Find the Network and Broadcast Addresses &lt;a class="headline-link" href="#find-the-network-and-broadcast-addresses" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Consider the address &lt;code&gt;192.168.10.34/27&lt;/code&gt;. A &lt;code&gt;/27&lt;/code&gt; mask is &lt;code&gt;255.255.255.224&lt;/code&gt;, which creates blocks of 32 addresses in the final octet:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;0-31, 32-63, 64-95, 96-127, 128-159, 160-191, 192-223, 224-255&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The address &lt;code&gt;.34&lt;/code&gt; falls in the &lt;code&gt;32-63&lt;/code&gt; block. That gives us:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Network address: &lt;code&gt;192.168.10.32&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;First usable address: &lt;code&gt;192.168.10.33&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Last usable address: &lt;code&gt;192.168.10.62&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Broadcast address: &lt;code&gt;192.168.10.63&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find the block size by subtracting the changing mask octet from 256. For &lt;code&gt;/27&lt;/code&gt;, &lt;code&gt;256 - 224 = 32&lt;/code&gt;. Starting at zero, count in increments of 32 until you find the range that contains the address.&lt;/p&gt;
&lt;p&gt;On Linux, the &lt;a href="https://linuxize.com/post/linux-ip-command/"&gt;&lt;code&gt;ip&lt;/code&gt; command&lt;/a&gt;
displays each interface address together with its CIDR prefix:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip -brief address&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.168.10.34/27&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The output shows that &lt;code&gt;eth0&lt;/code&gt; uses the &lt;code&gt;/27&lt;/code&gt; network calculated above.&lt;/p&gt;
&lt;h2 id="subnet-a-24-network-into-26-blocks"&gt;Subnet a /24 Network into /26 Blocks &lt;a class="headline-link" href="#subnet-a-24-network-into-26-blocks" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Suppose you have &lt;code&gt;192.168.10.0/24&lt;/code&gt; and need four equal networks. Moving from &lt;code&gt;/24&lt;/code&gt; to &lt;code&gt;/26&lt;/code&gt; borrows two host bits for subnetting. Two borrowed bits produce &lt;code&gt;2^2 = 4&lt;/code&gt; subnets.&lt;/p&gt;
&lt;p&gt;Each &lt;code&gt;/26&lt;/code&gt; contains 64 total addresses and 62 conventional host addresses:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subnet&lt;/th&gt;
&lt;th&gt;Usable host range&lt;/th&gt;
&lt;th&gt;Broadcast&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;192.168.10.0/26&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;192.168.10.1&lt;/code&gt; to &lt;code&gt;192.168.10.62&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;192.168.10.63&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;192.168.10.64/26&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;192.168.10.65&lt;/code&gt; to &lt;code&gt;192.168.10.126&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;192.168.10.127&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;192.168.10.128/26&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;192.168.10.129&lt;/code&gt; to &lt;code&gt;192.168.10.190&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;192.168.10.191&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;192.168.10.192/26&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;192.168.10.193&lt;/code&gt; to &lt;code&gt;192.168.10.254&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;192.168.10.255&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The subnet boundaries increase by 64 because &lt;code&gt;/26&lt;/code&gt; leaves six host bits and &lt;code&gt;2^6 = 64&lt;/code&gt;. A network address must start on one of these boundaries. For example, &lt;code&gt;192.168.10.64/26&lt;/code&gt; is valid, but &lt;code&gt;192.168.10.70/26&lt;/code&gt; is an address inside that network rather than the network identifier.&lt;/p&gt;
&lt;h2 id="combine-networks-with-route-aggregation"&gt;Combine Networks with Route Aggregation &lt;a class="headline-link" href="#combine-networks-with-route-aggregation" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CIDR also lets routers summarize adjacent networks into one larger route. For example, these four &lt;code&gt;/24&lt;/code&gt; networks are contiguous:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;192.168.0.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;192.168.1.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;192.168.2.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;192.168.3.0/24&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;They can be advertised as the single route &lt;code&gt;192.168.0.0/22&lt;/code&gt;. A &lt;code&gt;/22&lt;/code&gt; contains 1024 addresses, exactly the same total as four &lt;code&gt;/24&lt;/code&gt; blocks.&lt;/p&gt;
&lt;p&gt;Aggregation works only when the networks are contiguous and aligned on the larger prefix boundary. The four networks from &lt;code&gt;192.168.1.0/24&lt;/code&gt; through &lt;code&gt;192.168.4.0/24&lt;/code&gt; cannot form one &lt;code&gt;/22&lt;/code&gt;, even though their total size is the same, because the range does not start on a &lt;code&gt;/22&lt;/code&gt; boundary.&lt;/p&gt;
&lt;h2 id="cidr-notation-in-ipv6"&gt;CIDR Notation in IPv6 &lt;a class="headline-link" href="#cidr-notation-in-ipv6" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;IPv6 uses CIDR prefixes over a 128-bit address. For example:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2001:db8:1234:5600::/64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;/64&lt;/code&gt; prefix fixes the first 64 bits and leaves the remaining 64 bits for the interface identifier. A &lt;code&gt;/64&lt;/code&gt; is the common size for an IPv6 LAN, especially when Stateless Address Autoconfiguration (SLAAC) is used, although routing prefixes can have other lengths.&lt;/p&gt;
&lt;p&gt;IPv6 has no broadcast address. Multicast replaces broadcast behavior, and all-zero or all-one values are legal within address fields unless a specific rule says otherwise. See the &lt;a href="https://linuxize.com/post/ip4-vs-ip6/"&gt;IPv4 vs IPv6 comparison&lt;/a&gt;
for the broader differences between the protocols.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prefix&lt;/th&gt;
&lt;th&gt;Subnet mask&lt;/th&gt;
&lt;th style="text-align: right"&gt;Total addresses&lt;/th&gt;
&lt;th style="text-align: right"&gt;Conventional usable hosts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.0.0.0&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;16,777,216&lt;/td&gt;
&lt;td style="text-align: right"&gt;16,777,214&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.0.0&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;65,536&lt;/td&gt;
&lt;td style="text-align: right"&gt;65,534&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/20&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.240.0&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;4,096&lt;/td&gt;
&lt;td style="text-align: right"&gt;4,094&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/22&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.252.0&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;1,024&lt;/td&gt;
&lt;td style="text-align: right"&gt;1,022&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/24&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.0&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;256&lt;/td&gt;
&lt;td style="text-align: right"&gt;254&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/25&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.128&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;128&lt;/td&gt;
&lt;td style="text-align: right"&gt;126&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/26&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.192&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;64&lt;/td&gt;
&lt;td style="text-align: right"&gt;62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/27&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.224&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;32&lt;/td&gt;
&lt;td style="text-align: right"&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/28&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.240&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;16&lt;/td&gt;
&lt;td style="text-align: right"&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/29&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.248&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;8&lt;/td&gt;
&lt;td style="text-align: right"&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/30&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.252&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;4&lt;/td&gt;
&lt;td style="text-align: right"&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/31&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.254&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;2&lt;/td&gt;
&lt;td style="text-align: right"&gt;2 on point-to-point links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.255&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: right"&gt;1&lt;/td&gt;
&lt;td style="text-align: right"&gt;1 host route&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The CIDR prefix tells you exactly where the network bits end and the host bits begin. Once you can convert that boundary to a mask and block size, you can calculate ranges, divide networks, and check firewall rules without relying on the old address classes.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/cidr-notation-and-subnetting-explained/featured_hu_46840b6d13fe43eb.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>mount Cheatsheet</title><link>https://linuxize.com/cheatsheet/mount/</link><pubDate>Fri, 24 Jul 2026 07:45:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/mount/</guid><description>Quick reference for the mount command: mount and unmount filesystems, mount options, UUID and label mounts, network shares, and /etc/fstab entries</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="basic-syntax"&gt;Basic Syntax &lt;a class="headline-link" href="#basic-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Core &lt;code&gt;mount&lt;/code&gt; and &lt;code&gt;umount&lt;/code&gt; command forms.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mount DEVICE DIR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Attach a device to a mount point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mount -t TYPE DEVICE DIR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount with an explicit filesystem type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mount -o OPTIONS DEVICE DIR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount with a comma-separated option list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mount DIR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount an entry already defined in &lt;code&gt;/etc/fstab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mount -a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount &lt;code&gt;/etc/fstab&lt;/code&gt; filesystems except &lt;code&gt;noauto&lt;/code&gt; entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;umount DIR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Detach the filesystem mounted at &lt;code&gt;DIR&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Most mount operations require root privileges, so prefix them with &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="list-mounted-filesystems"&gt;List Mounted Filesystems &lt;a class="headline-link" href="#list-mounted-filesystems" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Inspect what is currently mounted and where.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all mounts using the legacy display; prefer &lt;code&gt;findmnt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;findmnt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show mounts as a readable tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;findmnt /dev/sdb1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show where a specific device is mounted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;findmnt -t ext4,xfs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List only the given filesystem types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;findmnt --fstab --verify&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;/etc/fstab&lt;/code&gt; for errors before rebooting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cat /proc/mounts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read active mounts in the current mount namespace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lsblk -f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List block devices with type, label, and UUID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;df -hT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show mounted filesystems with type and free space&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="common-mount-options"&gt;Common Mount Options &lt;a class="headline-link" href="#common-mount-options" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Values passed to &lt;code&gt;-o&lt;/code&gt; or listed in the fourth &lt;code&gt;/etc/fstab&lt;/code&gt; field.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;defaults&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Common defaults are &lt;code&gt;rw,suid,dev,exec,auto,nouser,async&lt;/code&gt;; exact defaults vary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ro&lt;/code&gt; / &lt;code&gt;rw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount read-only or read-write&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;noexec&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Block execution of binaries on the filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nosuid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ignore setuid and setgid bits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nodev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ignore device files on the filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;noatime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip access-time updates, which reduces disk writes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sync&lt;/code&gt; / &lt;code&gt;async&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write synchronously or let the kernel buffer writes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;noauto&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip this entry during &lt;code&gt;mount -a&lt;/code&gt; and at boot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;user&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Allow a non-root user to mount; implies &lt;code&gt;noexec,nosuid,nodev&lt;/code&gt; unless overridden&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nofail&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Continue booting when the device is missing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;uid=1000,gid=1000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set owner and group on filesystems without Unix permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;remount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Change options on an already mounted filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;sudo mount -o remount,rw /&lt;/code&gt; remounts the root filesystem read-write.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="mount-by-uuid-or-label"&gt;Mount by UUID or Label &lt;a class="headline-link" href="#mount-by-uuid-or-label" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Device names such as &lt;code&gt;/dev/sdb1&lt;/code&gt; can change between boots, so identify the filesystem instead.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lsblk -f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the UUID and label of every filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo blkid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print device type, label, and UUID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo blkid /dev/sdb1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the attributes of one device&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount UUID=1a2b3c4d-... /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount by filesystem UUID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount LABEL=backup /mnt/backup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount by filesystem label&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount -U 1a2b3c4d-... /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Short form of the UUID lookup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount -L backup /mnt/backup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Short form of the label lookup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo e2label /dev/sdb1 backup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set a label on an ext2, ext3, or ext4 filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Prefer &lt;code&gt;UUID=&lt;/code&gt; or &lt;code&gt;LABEL=&lt;/code&gt; for persistent local mounts in &lt;code&gt;/etc/fstab&lt;/code&gt; because device names can change.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="filesystem-types"&gt;Filesystem Types &lt;a class="headline-link" href="#filesystem-types" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Values for &lt;code&gt;-t&lt;/code&gt; and for the third &lt;code&gt;/etc/fstab&lt;/code&gt; field.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ext4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Widely used general-purpose Linux filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;xfs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;High-performance journaling filesystem, default on RHEL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;btrfs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Copy-on-write filesystem with snapshots and subvolumes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vfat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;FAT32, used by USB drives and EFI system partitions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;exfat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Large-file FAT variant for USB drives and SD cards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ntfs3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;In-kernel NTFS driver available on supported kernels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;iso9660&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Optical disc and ISO image filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tmpfs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;In-memory filesystem backed by RAM and swap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nfs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Network File System share&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cifs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SMB or Windows network share&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;auto&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Let &lt;code&gt;mount&lt;/code&gt; detect the type&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="network-and-special-mounts"&gt;Network and Special Mounts &lt;a class="headline-link" href="#network-and-special-mounts" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Mount forms beyond a plain local partition.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount -t nfs server:/srv/data /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount an NFS export&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount -t cifs //server/share /mnt/share -o username=user&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount a Windows or Samba share&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount -t cifs //server/share /mnt/share -o credentials=/etc/smb-credentials&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount CIFS with a credentials file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sshfs user@host:/remote/dir /mnt/remote&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount a remote directory over SSH&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount -o loop image.iso /mnt/iso&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount an ISO image through a loop device&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount --bind /src /dst&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expose an existing directory at a second path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount --rbind /src /dst&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bind a directory together with its submounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount -t tmpfs -o size=512M tmpfs /mnt/ram&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a 512 MB RAM-backed filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Keep CIFS credentials outside project directories and version control. Protect the file with &lt;code&gt;sudo chmod 600 /etc/smb-credentials&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="unmounting"&gt;Unmounting &lt;a class="headline-link" href="#unmounting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Detach a filesystem and deal with a busy mount point.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo umount /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unmount by mount point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo umount /dev/sdb1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unmount by device (obsolete; use the mount point)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo umount -R /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unmount a mount point and everything below it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo umount -l /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lazy unmount: detach now, release when no longer in use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo umount -f /mnt/share&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Force an unmount, mainly for unreachable network shares&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo umount -a -t nfs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unmount every NFS filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lsof +f -- /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List open files under the mount point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fuser -mv /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show processes and users holding the mount point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo fuser -km /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kill every process using the mount point; destructive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Review &lt;code&gt;fuser -mv&lt;/code&gt; output before using &lt;code&gt;fuser -km&lt;/code&gt;. Use lazy or forced unmounts only when a normal unmount cannot work: &lt;code&gt;-f&lt;/code&gt; can lose unwritten data, while &lt;code&gt;-l&lt;/code&gt; hides the path before all references are released.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="persistent-mounts-in-etcfstab"&gt;Persistent Mounts in /etc/fstab &lt;a class="headline-link" href="#persistent-mounts-in-etcfstab" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each line has six space-separated fields.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Device&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UUID=&lt;/code&gt;, &lt;code&gt;LABEL=&lt;/code&gt;, a device path, or a remote share&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Mount point&lt;/td&gt;
&lt;td&gt;Existing directory, or &lt;code&gt;none&lt;/code&gt; for swap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Type&lt;/td&gt;
&lt;td&gt;Filesystem type, such as &lt;code&gt;ext4&lt;/code&gt;, &lt;code&gt;nfs&lt;/code&gt;, or &lt;code&gt;cifs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Options&lt;/td&gt;
&lt;td&gt;Comma-separated mount options, or &lt;code&gt;defaults&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Dump&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt; in nearly all cases; &lt;code&gt;1&lt;/code&gt; marks the filesystem for &lt;code&gt;dump&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. Pass&lt;/td&gt;
&lt;td&gt;Order of &lt;code&gt;fsck&lt;/code&gt; at boot: &lt;code&gt;1&lt;/code&gt; for root, &lt;code&gt;2&lt;/code&gt; for others, &lt;code&gt;0&lt;/code&gt; to skip&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; &lt;code&gt;UUID=1a2b3c4d-... /mnt/data ext4 defaults,nofail 0 2&lt;/code&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo findmnt --fstab --verify&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Validate the file before rebooting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount -a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply mountable entries after validating &lt;code&gt;/etc/fstab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl daemon-reload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Regenerate the systemd mount units after an edit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo mount /mnt/data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount one entry using only its mount point&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use &lt;code&gt;nofail&lt;/code&gt; only for optional mounts. Add &lt;code&gt;_netdev&lt;/code&gt; when a network-backed filesystem is not recognized as network-dependent from its type.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Common mount errors and what to check.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;target is busy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find the holder with &lt;code&gt;fuser -mv DIR&lt;/code&gt; or &lt;code&gt;lsof +f -- DIR&lt;/code&gt;, then close it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unknown filesystem type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install the required helper or driver, such as &lt;code&gt;ntfs-3g&lt;/code&gt;, &lt;code&gt;nfs-common&lt;/code&gt; or &lt;code&gt;nfs-utils&lt;/code&gt;, or &lt;code&gt;cifs-utils&lt;/code&gt;; confirm kernel support for exFAT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wrong fs type, bad option, bad superblock&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Confirm the type with &lt;code&gt;lsblk -f&lt;/code&gt; and check &lt;code&gt;dmesg&lt;/code&gt;. If repair is needed, unmount it and use the correct filesystem checker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mount point does not exist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create the directory first with &lt;code&gt;sudo mkdir -p DIR&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;permission denied&lt;/code&gt; on CIFS&lt;/td&gt;
&lt;td&gt;Verify credentials and server share permissions; &lt;code&gt;uid=&lt;/code&gt; and &lt;code&gt;gid=&lt;/code&gt; only control local ownership&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;special device does not exist&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recheck the UUID with &lt;code&gt;blkid&lt;/code&gt;; the device name may have changed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Files are hidden after mounting&lt;/td&gt;
&lt;td&gt;The mounted filesystem covers existing directory contents; unmount it and inspect the underlying path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boot drops to emergency mode&lt;/td&gt;
&lt;td&gt;Remount root with &lt;code&gt;mount -o remount,rw /&lt;/code&gt;, fix the bad &lt;code&gt;/etc/fstab&lt;/code&gt; line, and validate it; add &lt;code&gt;nofail&lt;/code&gt; only if the mount is optional&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use these guides and cheatsheets for complete storage workflows.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-mount-and-unmount-file-systems-in-linux/"&gt;How to Mount and Unmount File Systems in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Full guide to &lt;code&gt;mount&lt;/code&gt; and &lt;code&gt;umount&lt;/code&gt; with practical examples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/etc-fstab-file/"&gt;Understanding the /etc/fstab File in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Field-by-field breakdown of persistent mount entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-mount-an-nfs-share-in-linux/"&gt;How to Mount an NFS Share in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Install the client, mount a share, and troubleshoot errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-mount-cifs-windows-share-on-linux/"&gt;How to Mount a Windows Share on Linux Using CIFS&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Credentials files, ownership, and permissions for SMB shares&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-mount-iso-file-on-linux/"&gt;How to Mount ISO File on Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Loop devices and the graphical mounting method&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-use-sshfs-to-mount-remote-directories-over-ssh/"&gt;How to Use SSHFS to Mount Remote Directories over SSH&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Mount a remote directory and browse it like a local one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/df/"&gt;df Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Check free space on mounted filesystems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/fdisk/"&gt;fdisk Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Partition a disk before creating a filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>SSH Connection Refused: Causes and Fixes</title><link>https://linuxize.com/post/fix-ssh-connection-refused/</link><pubDate>Thu, 23 Jul 2026 14:20:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/fix-ssh-connection-refused/</guid><category>ssh</category><description>Fix the SSH "Connection refused" error by checking the destination, listening port, OpenSSH service or socket, firewall rules, and port forwarding.</description><content:encoded>&lt;p&gt;You try to log in and SSH stops immediately with &lt;code&gt;connect to host example.com port 22: Connection refused&lt;/code&gt;. The failure happens before SSH checks your key or password, so changing authentication settings will not fix it.&lt;/p&gt;
&lt;p&gt;An immediate refusal means the target address has no process listening on that port, or a firewall or network device actively rejected the request. The usual causes are a stopped SSH server, the wrong host or port, a listener bound to another address, a firewall reject rule, or port forwarding to the wrong machine. A connection that hangs and then times out is different because no response came back.&lt;/p&gt;
&lt;p&gt;This guide starts with checks you can run from the client, then moves to the SSH service, listening port, firewall, and network path on the server.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/ssh/"&gt;SSH cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Confirm the destination address&lt;/td&gt;
&lt;td&gt;&lt;code&gt;getent ahosts example.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show SSH connection details&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ssh -vvv user@example.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test the default SSH port&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nc -vz example.com 22&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check for a listener on port 22&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo ss -ltnp 'sport = :22'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show the effective SSH port and addresses&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo sshd -T | grep -E '^(port|listenaddress) '&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check SSH on Ubuntu or Debian&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl status ssh.service ssh.socket&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check SSH on Fedora or RHEL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl status sshd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check UFW rules&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo ufw status numbered&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check firewalld services&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo firewall-cmd --list-services&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="confirm-the-host-and-port-from-the-client"&gt;Confirm the Host and Port from the Client &lt;a class="headline-link" href="#confirm-the-host-and-port-from-the-client" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before changing the server, confirm that the hostname resolves to the address you expect:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;getent ahosts example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the result points to an old server or the wrong public address, correct the DNS record or connect to the intended IP address directly. Reaching the wrong host can produce a refusal even when SSH is working on the real server.&lt;/p&gt;
&lt;p&gt;Next, run SSH with verbose output:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -vvv user@example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The relevant lines look like this:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;debug1: Connecting to example.com [203.0.113.10] port 22.
ssh: connect to host example.com port 22: Connection refused&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The client resolved &lt;code&gt;example.com&lt;/code&gt; to &lt;code&gt;203.0.113.10&lt;/code&gt; and received an immediate refusal from port 22. You can test the TCP port without starting an SSH login:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nc -vz example.com &lt;span class="m"&gt;22&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the server uses a custom port, test and connect to that port instead:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nc -vz example.com &lt;span class="m"&gt;2222&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -p &lt;span class="m"&gt;2222&lt;/span&gt; user@example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A hostname can also have separate IPv4 and IPv6 addresses. Test each address family when one DNS record may point to the wrong server:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -4 user@example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -6 user@example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The remaining checks require access to the server through a cloud console, virtual machine console, physical terminal, or another management channel.&lt;/p&gt;
&lt;h2 id="check-whether-ssh-is-listening"&gt;Check Whether SSH Is Listening &lt;a class="headline-link" href="#check-whether-ssh-is-listening" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The listening socket is the quickest way to tell whether the server can accept SSH connections on port 22. Run this command on the server:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ss -ltnp &lt;span class="s1"&gt;&amp;#39;sport = :22&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A working listener appears as either &lt;code&gt;sshd&lt;/code&gt; or &lt;code&gt;systemd&lt;/code&gt;, depending on whether the distribution runs the daemon continuously or uses socket activation. If the command returns nothing, no process is accepting connections on port 22.&lt;/p&gt;
&lt;p&gt;To see the port and addresses from the effective OpenSSH configuration, run:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sshd -T &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;^(port|listenaddress) &amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Typical output looks like this:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;port 22
listenaddress [::]:22
listenaddress 0.0.0.0:22&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The output shows that SSH is configured for port 22 on all IPv6 and IPv4 addresses. If it reports another port, connect with the &lt;code&gt;-p&lt;/code&gt; option and verify that the firewall allows that port. See our guide on &lt;a href="https://linuxize.com/post/how-to-change-ssh-port-in-linux/"&gt;changing the SSH port&lt;/a&gt;
if you need to correct the configuration.&lt;/p&gt;
&lt;h2 id="check-the-ssh-service-or-socket"&gt;Check the SSH Service or Socket &lt;a class="headline-link" href="#check-the-ssh-service-or-socket" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Linux distributions use different systemd unit names for OpenSSH. Ubuntu and Debian use &lt;code&gt;ssh.service&lt;/code&gt;, while Fedora, RHEL, and their derivatives use &lt;code&gt;sshd.service&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;On Ubuntu and Debian, check the service:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl status ssh.service&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Ubuntu 22.10 and later use &lt;code&gt;ssh.socket&lt;/code&gt; by default, so check that unit as well:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl status ssh.socket&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When &lt;code&gt;ssh.socket&lt;/code&gt; is active and owns port 22, &lt;code&gt;ssh.service&lt;/code&gt; may remain inactive until a client connects. In that setup, an inactive service alone does not indicate a problem. If the socket is disabled or stopped, enable it and start it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now ssh.socket&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On systems without &lt;code&gt;ssh.socket&lt;/code&gt;, enable and start the service instead:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now ssh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On Fedora, RHEL, and derivatives, check and start &lt;code&gt;sshd&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl status sshd
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now sshd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the unit reports &lt;code&gt;failed&lt;/code&gt;, validate the SSH server configuration:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sshd -t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;No output means the configuration passed the test. If OpenSSH prints an error, correct the reported line before restarting the unit. You can also inspect the current boot logs on Ubuntu and Debian:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo journalctl -u ssh.service -u ssh.socket -b&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For Fedora and RHEL, use the &lt;code&gt;sshd&lt;/code&gt; unit name:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo journalctl -u sshd -b&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="install-the-openssh-server"&gt;Install the OpenSSH Server &lt;a class="headline-link" href="#install-the-openssh-server" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some minimal installations include the SSH client but not the server. If &lt;code&gt;systemctl&lt;/code&gt; reports that the SSH unit does not exist, install the &lt;code&gt;openssh-server&lt;/code&gt; package.&lt;/p&gt;
&lt;h3 id="ubuntu-debian-and-derivatives"&gt;Ubuntu, Debian, and Derivatives &lt;a class="headline-link" href="#ubuntu-debian-and-derivatives" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Update the package index and install the server package:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install openssh-server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The package normally starts the appropriate SSH service or socket during installation. Check port 22 again with &lt;code&gt;ss&lt;/code&gt; instead of assuming that the listener started successfully.&lt;/p&gt;
&lt;h3 id="fedora-rhel-and-derivatives"&gt;Fedora, RHEL, and Derivatives &lt;a class="headline-link" href="#fedora-rhel-and-derivatives" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install the server package, then enable and start &lt;code&gt;sshd&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install openssh-server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now sshd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="check-the-listening-address"&gt;Check the Listening Address &lt;a class="headline-link" href="#check-the-listening-address" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SSH can run normally but listen only on the loopback interface or one private address. In that case, a local connection works while connections to other server addresses are refused.&lt;/p&gt;
&lt;p&gt;Review the &lt;code&gt;listenaddress&lt;/code&gt; lines from &lt;code&gt;sshd -T&lt;/code&gt;. A value such as &lt;code&gt;127.0.0.1:22&lt;/code&gt; accepts only local IPv4 connections. OpenSSH reads its main configuration from &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; and may also read files under &lt;code&gt;/etc/ssh/sshd_config.d/&lt;/code&gt;. A listener on a &lt;a href="https://linuxize.com/post/what-is-localhost/"&gt;loopback address&lt;/a&gt;
is reachable from the server itself and from nowhere else.&lt;/p&gt;
&lt;p&gt;Before changing &lt;code&gt;Port&lt;/code&gt; or &lt;code&gt;ListenAddress&lt;/code&gt;, keep console access open and validate the new configuration with &lt;code&gt;sudo sshd -t&lt;/code&gt;. On Ubuntu systems using socket activation, the socket must also reload the generated listening configuration. The port-change guide linked above covers the service and socket steps in order.&lt;/p&gt;
&lt;h2 id="check-the-firewall"&gt;Check the Firewall &lt;a class="headline-link" href="#check-the-firewall" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A firewall is less likely to cause an immediate refusal than a missing listener. Rules that silently drop traffic usually end with &lt;code&gt;Connection timed out&lt;/code&gt;, while an explicit &lt;code&gt;REJECT&lt;/code&gt; rule can return &lt;code&gt;Connection refused&lt;/code&gt;. Check the firewall after confirming the service and port.&lt;/p&gt;
&lt;p&gt;If the server uses UFW, list its rules with numbers:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ufw status numbered&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Allow the standard OpenSSH profile when SSH uses port 22:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ufw allow OpenSSH&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For a custom port, allow the exact TCP port instead:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo ufw allow 2222/tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On a server using firewalld, first check the services allowed in the active zone:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --list-services&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Add SSH to both the runtime and permanent configurations if it is missing:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --add-service&lt;span class="o"&gt;=&lt;/span&gt;ssh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo firewall-cmd --permanent --add-service&lt;span class="o"&gt;=&lt;/span&gt;ssh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For a custom port, use &lt;code&gt;--add-port=2222/tcp&lt;/code&gt; in both commands. Our &lt;a href="https://linuxize.com/post/how-to-setup-a-firewall-with-ufw-on-ubuntu-24-04/"&gt;UFW firewall guide&lt;/a&gt;
explains how to review and manage rules in more detail.&lt;/p&gt;
&lt;h2 id="check-port-forwarding-and-external-firewalls"&gt;Check Port Forwarding and External Firewalls &lt;a class="headline-link" href="#check-port-forwarding-and-external-firewalls" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If SSH works from the same machine or local network but fails from the internet, the OpenSSH listener may already be correct. Check that the router or virtualization platform forwards the external port to the server&amp;rsquo;s current private address and SSH port.&lt;/p&gt;
&lt;p&gt;The same issue can occur with a virtual machine, container, load balancer, or cloud firewall. Confirm that public DNS points to the expected system and that each forwarding rule uses the same port you pass to &lt;code&gt;ssh&lt;/code&gt;. Cloud firewall rules often drop traffic and cause a timeout, but an edge device that rejects the request or forwards it to the wrong host can produce a refusal.&lt;/p&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Connection refused started after an SSH configuration change&lt;/strong&gt;&lt;br&gt;
Run &lt;code&gt;sudo sshd -t&lt;/code&gt; and correct every reported error. On Ubuntu with socket activation, reload systemd and restart &lt;code&gt;ssh.socket&lt;/code&gt; after a valid &lt;code&gt;Port&lt;/code&gt; or &lt;code&gt;ListenAddress&lt;/code&gt; change, then verify the listener with &lt;code&gt;ss&lt;/code&gt; before closing console access.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SSH works with localhost but not the server address&lt;/strong&gt;&lt;br&gt;
Check the effective &lt;code&gt;ListenAddress&lt;/code&gt; values and the firewall rules for the external interface. A listener restricted to &lt;code&gt;127.0.0.1&lt;/code&gt; or &lt;code&gt;::1&lt;/code&gt; cannot accept remote connections.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IPv4 works but IPv6 is refused&lt;/strong&gt;&lt;br&gt;
The server may have an AAAA record without an IPv6 listener. Compare &lt;code&gt;ssh -4&lt;/code&gt; and &lt;code&gt;ssh -6&lt;/code&gt;, then correct the DNS record or configure SSH to listen on the intended IPv6 address.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only one client address is refused&lt;/strong&gt;&lt;br&gt;
A source-specific firewall rule or a tool such as Fail2ban may be rejecting that address. Review the firewall rules and, if Fail2ban is installed, check the SSH jail with &lt;code&gt;sudo fail2ban-client status sshd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SSH reaches the server but reports Permission denied&lt;/strong&gt;&lt;br&gt;
The network path and listener are working, and the failure has moved to authentication. Follow the &lt;a href="https://linuxize.com/post/fix-ssh-permission-denied-publickey/"&gt;SSH Permission denied (publickey) guide&lt;/a&gt;
instead.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once the port test succeeds, SSH should move on to host-key verification or authentication. Before exposing the restored service to the internet, review our &lt;a href="https://linuxize.com/post/ssh-hardening-best-practices/"&gt;SSH hardening best practices&lt;/a&gt;
and restrict firewall access where possible.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/fix-ssh-connection-refused/featured_hu_6253d7bc6f917ca6.webp" medium="image" type="image/webp" width="1200" height="630"/></item><item><title>Dockerfile COPY vs ADD: Which to Use</title><link>https://linuxize.com/post/dockerfile-copy-vs-add/</link><pubDate>Wed, 22 Jul 2026 10:25:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/dockerfile-copy-vs-add/</guid><category>docker</category><description>Compare Dockerfile COPY and ADD for local files, build stages, remote URLs, Git repositories, and tar extraction, with clear guidance on when to use each.</description><content:encoded>&lt;p&gt;When a Docker image needs application code, configuration, or a release archive, both &lt;code&gt;COPY&lt;/code&gt; and &lt;code&gt;ADD&lt;/code&gt; can place files in the image. For an ordinary local file, &lt;code&gt;COPY app.py /app/&lt;/code&gt; and &lt;code&gt;ADD app.py /app/&lt;/code&gt; produce the same result, but the instructions differ once archives, remote sources, or build stages are involved.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;COPY&lt;/code&gt; for local files and artifacts from other build stages. Use &lt;code&gt;ADD&lt;/code&gt; when you want automatic tar extraction or need BuildKit to fetch a remote HTTP or Git source. This guide compares both instructions and explains which one fits each case.&lt;/p&gt;
&lt;h2 id="what-copy-does"&gt;What COPY Does &lt;a class="headline-link" href="#what-copy-does" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;COPY&lt;/code&gt; takes files or directories from the build context and places them at a destination inside the image:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="dockerfile"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-sky-100 text-sky-700 dark:bg-sky-900 dark:text-sky-300"&gt;dockerfile&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; requirements.txt /app/&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; src/ /app/src/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;An archive copied this way stays an archive, and a source path cannot point outside the build context. Two options cover common permission needs by setting ownership and mode as the files are copied:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="dockerfile"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-sky-100 text-sky-700 dark:bg-sky-900 dark:text-sky-300"&gt;dockerfile&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; --chown&lt;span class="o"&gt;=&lt;/span&gt;appuser:appgroup --chmod&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;644&lt;/span&gt; config.yml /app/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;COPY&lt;/code&gt; can also read from a named context, another image, or an earlier stage in a multi-stage build. The &lt;code&gt;--from&lt;/code&gt; option is commonly used to move compiled artifacts into a smaller production image:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="dockerfile"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-sky-100 text-sky-700 dark:bg-sky-900 dark:text-sky-300"&gt;dockerfile&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; --from&lt;span class="o"&gt;=&lt;/span&gt;builder /app/target/server /usr/local/bin/server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="what-add-does"&gt;What ADD Does &lt;a class="headline-link" href="#what-add-does" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For local files and directories, &lt;code&gt;ADD&lt;/code&gt; behaves much like &lt;code&gt;COPY&lt;/code&gt;. It also understands local tar archives, remote URLs, and Git repository sources.&lt;/p&gt;
&lt;p&gt;When the source is a local tar archive, either uncompressed or compressed with gzip, bzip2, or xz, &lt;code&gt;ADD&lt;/code&gt; extracts it into the destination instead of copying the archive file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="dockerfile"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-sky-100 text-sky-700 dark:bg-sky-900 dark:text-sky-300"&gt;dockerfile&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt; rootfs.tar.gz /&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Docker detects an archive from its contents, not its filename. A file named &lt;code&gt;rootfs.tar.gz&lt;/code&gt; that does not contain a recognized tar archive is copied without an extraction error. When you need the archive itself inside the image, use &lt;code&gt;COPY&lt;/code&gt;, or use &lt;code&gt;ADD --unpack=false&lt;/code&gt; with Dockerfile syntax 1.17 or later.&lt;/p&gt;
&lt;p&gt;For remote sources, &lt;code&gt;ADD&lt;/code&gt; can download an HTTP or HTTPS URL. BuildKit supports &lt;code&gt;--checksum&lt;/code&gt; so the build fails if the downloaded content does not match the expected SHA-256 digest. Here is a checksum-verified download:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="dockerfile"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-sky-100 text-sky-700 dark:bg-sky-900 dark:text-sky-300"&gt;dockerfile&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# syntax=docker/dockerfile:1&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt; --checksum&lt;span class="o"&gt;=&lt;/span&gt;sha256:24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/linux-0.01.tar.gz &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /tmp/linux-0.01.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Remote tar archives are downloaded without extraction by default. Dockerfile syntax 1.17 added &lt;code&gt;--unpack=true&lt;/code&gt; for builds that should download and extract a remote tar archive in one instruction.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ADD&lt;/code&gt; can also clone a Git repository from an HTTPS or SSH address. A branch, tag, commit, or subdirectory can be selected in the URL, and &lt;code&gt;--checksum&lt;/code&gt; can pin a Git source to a commit. These behaviors are covered in the official &lt;a href="https://docs.docker.com/reference/dockerfile/#add" target="_blank" rel="noopener noreferrer"&gt;Dockerfile ADD reference&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="key-differences"&gt;Key Differences &lt;a class="headline-link" href="#key-differences" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source or behavior&lt;/th&gt;
&lt;th&gt;COPY&lt;/th&gt;
&lt;th&gt;ADD&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Local files and directories&lt;/td&gt;
&lt;td&gt;Copies them&lt;/td&gt;
&lt;td&gt;Copies them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local tar archive&lt;/td&gt;
&lt;td&gt;Keeps the archive&lt;/td&gt;
&lt;td&gt;Extracts it by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remote HTTP or HTTPS URL&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;Downloads it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remote Git repository&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;Clones it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checksum for a remote source&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--checksum&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remote tar extraction&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--unpack=true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build stage, named context, or image&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--from&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="choosing-between-copy-and-add"&gt;Choosing Between COPY and ADD &lt;a class="headline-link" href="#choosing-between-copy-and-add" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;COPY&lt;/code&gt; for application source code, configuration, static assets, and other ordinary files from the build context. It states the intent directly and ensures that an archive remains intact. &lt;code&gt;COPY --from&lt;/code&gt; is also the correct choice for moving artifacts between build stages or importing files from another image.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;ADD&lt;/code&gt; when its source-aware behavior is part of the task. Local tar extraction is useful for assembling a root filesystem or installing a vendored release archive without storing the compressed archive in its own image layer.&lt;/p&gt;
&lt;p&gt;For example, this instruction extracts a local application archive directly into &lt;code&gt;/opt/app/&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="dockerfile"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-sky-100 text-sky-700 dark:bg-sky-900 dark:text-sky-300"&gt;dockerfile&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt; app-1.4.2-dist.tar.gz /opt/app/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For remote artifacts, current &lt;a href="https://docs.docker.com/build/building/best-practices/#add-or-copy" target="_blank" rel="noopener noreferrer"&gt;Docker build best practices&lt;/a&gt;
favor &lt;code&gt;ADD&lt;/code&gt; with &lt;code&gt;--checksum&lt;/code&gt; because BuildKit can cache the remote source precisely and verify its contents. A &lt;code&gt;RUN&lt;/code&gt; instruction with &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt; is still appropriate when you need custom request handling or additional processing. Keep verification, extraction, and cleanup in the same &lt;code&gt;RUN&lt;/code&gt; instruction so temporary files do not remain in a separate layer.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Choose &lt;code&gt;COPY&lt;/code&gt; for local content and multi-stage artifacts. Choose &lt;code&gt;ADD&lt;/code&gt; when you need automatic tar extraction or a checksum-verified remote source. For the complete image-building workflow, see our guide on &lt;a href="https://linuxize.com/post/how-to-build-docker-images-with-dockerfile/"&gt;building Docker images with a Dockerfile&lt;/a&gt;
, and keep the &lt;a href="https://linuxize.com/cheatsheet/docker/"&gt;Docker cheatsheet&lt;/a&gt;
nearby for the rest of the instruction set.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/dockerfile-copy-vs-add/featured_hu_9fe7b15945bda5c3.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>head Cheatsheet</title><link>https://linuxize.com/cheatsheet/head/</link><pubDate>Tue, 21 Jul 2026 13:20:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/head/</guid><description>Quick reference for showing the first lines or bytes of files and limiting command output with head in Linux</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="basic-syntax"&gt;Basic Syntax &lt;a class="headline-link" href="#basic-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Core &lt;code&gt;head&lt;/code&gt; command forms.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the first 10 lines of a file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -n 20 FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the first 20 lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -c 100 FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the first 100 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command | head -n 10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limit piped output to 10 lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -- -notes.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read a file whose name starts with &lt;code&gt;-&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="select-lines"&gt;Select Lines &lt;a class="headline-link" href="#select-lines" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Control how many lines are printed.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -n 5 /etc/passwd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the first 5 lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -n 1 data.csv&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the header row of a CSV file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -n 100 app.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview the first 100 log entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -n -5 FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show all lines except the last 5 (GNU)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -n 2 FILE1 FILE2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the first 2 lines of each file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="select-bytes"&gt;Select Bytes &lt;a class="headline-link" href="#select-bytes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Read a fixed number of bytes instead of lines.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -c 100 FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the first 100 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -c 2K FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the first 2048 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -c 1MB FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the first 1,000,000 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -c -512 FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show all bytes except the last 512 (GNU)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -c 512 disk.img &amp;gt; header.bin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Save the first 512 bytes to a file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="multiple-files-and-headers"&gt;Multiple Files and Headers &lt;a class="headline-link" href="#multiple-files-and-headers" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Control the file-name headers shown with multiple inputs.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head FILE1 FILE2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show 10 lines from each file with headers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -n 5 *.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the first 5 lines of every matched log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -q FILE1 FILE2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Suppress file-name headers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -v FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Always print a file-name header&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -n 5 FILE1 - FILE2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read files and standard input in sequence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="pipelines"&gt;Pipelines &lt;a class="headline-link" href="#pipelines" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Combine &lt;code&gt;head&lt;/code&gt; with other text-processing commands.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ls -t | head -n 5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the 5 most recently modified entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sort -nr scores.txt | head -n 10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the 10 highest numeric values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep 'ERROR' app.log | head -n 20&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the first 20 matching errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tail -n +20 FILE | head -n 11&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extract lines 20 through 30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -n 20 FILE | wc -w&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Count words in the first 20 lines&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="useful-options"&gt;Useful Options &lt;a class="headline-link" href="#useful-options" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Common GNU &lt;code&gt;head&lt;/code&gt; flags and long forms.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-n NUM&lt;/code&gt;, &lt;code&gt;--lines=NUM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the first &lt;code&gt;NUM&lt;/code&gt; lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-c NUM&lt;/code&gt;, &lt;code&gt;--bytes=NUM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the first &lt;code&gt;NUM&lt;/code&gt; bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-q&lt;/code&gt;, &lt;code&gt;--quiet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Never print file-name headers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-v&lt;/code&gt;, &lt;code&gt;--verbose&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Always print file-name headers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-z&lt;/code&gt;, &lt;code&gt;--zero-terminated&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read and write NUL-delimited items (GNU)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--help&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show command help&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show the installed version&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use &lt;code&gt;head -n 5&lt;/code&gt; instead of the obsolete &lt;code&gt;head -5&lt;/code&gt; syntax in scripts.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="nul-delimited-input"&gt;NUL-Delimited Input &lt;a class="headline-link" href="#nul-delimited-input" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Handle file names containing spaces, newlines, or other special characters.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;find . -type f -print0 | head -z -n 5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select the first 5 NUL-delimited paths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;find . -type f -print0 | head -z -n 5 | xargs -0 -r ls -l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pass the first 5 paths safely to &lt;code&gt;ls&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;printf 'one\0two\0' | head -z -n 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the first NUL-delimited item&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;-z&lt;/code&gt; option is specific to GNU &lt;code&gt;head&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Quick checks for common &lt;code&gt;head&lt;/code&gt; issues.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Only 10 lines are shown&lt;/td&gt;
&lt;td&gt;This is the default; set the count with &lt;code&gt;-n NUM&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File-name headers appear&lt;/td&gt;
&lt;td&gt;Multiple files trigger headers; add &lt;code&gt;-q&lt;/code&gt; to suppress them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Binary output looks garbled&lt;/td&gt;
&lt;td&gt;Redirect byte output to a file or inspect it with &lt;code&gt;hexdump&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;head -n -5&lt;/code&gt; fails&lt;/td&gt;
&lt;td&gt;Negative counts are a GNU feature and are not portable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Upstream command reports a broken pipe&lt;/td&gt;
&lt;td&gt;&lt;code&gt;head&lt;/code&gt; exits after collecting enough input; some producers report the closed pipe&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use these guides and cheatsheets for complete text-processing workflows.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/linux-head-command/"&gt;head Command in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Full guide to lines, bytes, files, and pipelines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/tail/"&gt;tail Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Read the end of files and follow logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/cat/"&gt;cat Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Display and combine file contents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/sort/"&gt;sort Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Order lines before selecting top results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/cheatsheet/wc/"&gt;wc Cheatsheet&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Count lines, words, and bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>lsusb, lspci, and lshw: List Hardware in Linux</title><link>https://linuxize.com/post/list-hardware-in-linux/</link><pubDate>Tue, 21 Jul 2026 09:40:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/list-hardware-in-linux/</guid><category>linux commands</category><description>Identify the hardware in a Linux machine: list USB devices with lsusb, find PCI cards and their drivers with lspci, and get a full inventory with lshw.</description><content:encoded>&lt;p&gt;Sooner or later you need to know exactly what is inside a machine: which Wi-Fi chip refuses to work, whether the system sees a plugged-in USB device at all, or what to put in a purchase order for more RAM. Three commands answer these questions from the terminal, each covering a different part of the hardware inventory: &lt;code&gt;lsusb&lt;/code&gt; for USB devices, &lt;code&gt;lspci&lt;/code&gt; for PCI devices such as network cards and GPUs, and &lt;code&gt;lshw&lt;/code&gt; for a complete inventory of everything.&lt;/p&gt;
&lt;p&gt;This guide explains how to use all three, and which one to reach for depending on the question you are asking.&lt;/p&gt;
&lt;h2 id="installing-the-tools"&gt;Installing the Tools &lt;a class="headline-link" href="#installing-the-tools" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The three commands live in three small packages, most of which are preinstalled on desktop distributions.&lt;/p&gt;
&lt;p&gt;On Ubuntu, Debian, and Derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install usbutils pciutils lshw&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On Fedora, RHEL, and Derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install usbutils pciutils lshw&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="listing-usb-devices-with-lsusb"&gt;Listing USB Devices with lsusb &lt;a class="headline-link" href="#listing-usb-devices-with-lsusb" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;lsusb&lt;/code&gt; without arguments to list every device on the USB buses:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsusb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 046d:c52b Logitech, Inc. Unifying Receiver
Bus 001 Device 003: ID 13d3:56a6 IMC Networks Integrated Camera
Bus 001 Device 002: ID 8087:0aaa Intel Corp. Bluetooth 9460/9560
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each line shows the bus and device number, then the ID in &lt;code&gt;vendor:product&lt;/code&gt; form, then a human-readable name looked up from the USB ID database. The &lt;code&gt;1d6b&lt;/code&gt; root hubs are the controllers themselves, not devices you plugged in.&lt;/p&gt;
&lt;p&gt;The classic use is answering &amp;ldquo;does the system see this thing at all&amp;rdquo;: run &lt;code&gt;lsusb&lt;/code&gt;, plug the device in, run it again, and compare. If a new line appears, the system has enumerated the device, so drivers, firmware, and application support are the next places to check. Enumeration does not prove that the device or cable is fully healthy, but it confirms that the USB host received a response. If nothing appears, try another port or cable before blaming the OS. Recent kernel messages from &lt;a href="https://linuxize.com/post/dmesg-command-in-linux/"&gt;&lt;code&gt;dmesg&lt;/code&gt;&lt;/a&gt;
show the same plug events with more detail.&lt;/p&gt;
&lt;p&gt;The tree view adds the piece the flat list lacks, which drivers claimed each device and at what speed it connected:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsusb -t&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/6p, 10000M
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 480M
|__ Port 4: Dev 2, If 0, Class=Wireless, Driver=btusb, 12M
|__ Port 5: Dev 3, If 0, Class=Video, Driver=uvcvideo, 480M
|__ Port 9: Dev 4, If 2, Class=Human Interface Device, Driver=usbhid, 12M&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A device present in &lt;code&gt;lsusb&lt;/code&gt; but showing no &lt;code&gt;Driver=&lt;/code&gt; entry here has been enumerated but has no kernel driver bound to that interface. That can indicate a missing kernel module or firmware package, although some devices are intentionally controlled by a userspace driver such as libusb. A USB 3 drive showing &lt;code&gt;480M&lt;/code&gt; instead of &lt;code&gt;5000M&lt;/code&gt; is connected through a USB 2 port or cable, a common reason external disks underperform.&lt;/p&gt;
&lt;p&gt;For full descriptors of a single device, filter by its ID and add &lt;code&gt;-v&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lsusb -v -d 046d:c52b&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The verbose output is long; without root, parts of it are hidden.&lt;/p&gt;
&lt;h2 id="listing-pci-devices-with-lspci"&gt;Listing PCI Devices with lspci &lt;a class="headline-link" href="#listing-pci-devices-with-lspci" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PCI is where the built-in hardware lives: network controllers, graphics cards, storage controllers, and sound chips. The bare command lists them all:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;00:00.0 Host bridge: Intel Corporation Device a706
00:02.0 VGA compatible controller: Intel Corporation Raptor Lake-P [Iris Xe Graphics]
00:14.3 Network controller: Intel Corporation Raptor Lake PCH CNVi WiFi
00:1f.3 Audio device: Intel Corporation Raptor Lake-P/U/H cAVS
01:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller PM9A1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The leading &lt;code&gt;00:14.3&lt;/code&gt; style address identifies the device&amp;rsquo;s slot and function, and the text after the class name identifies the chip. This is the fastest way to find out exactly which Wi-Fi or Ethernet chip a machine has, which is the first thing any driver search needs.&lt;/p&gt;
&lt;p&gt;The single most useful option is &lt;code&gt;-k&lt;/code&gt;, which shows the kernel driver bound to each device:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci -k&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;00:14.3 Network controller: Intel Corporation Raptor Lake PCH CNVi WiFi
Subsystem: Intel Corporation Device 0094
Kernel driver in use: iwlwifi
Kernel modules: iwlwifi&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Kernel modules&lt;/code&gt; lists what could drive the device, and &lt;code&gt;Kernel driver in use&lt;/code&gt; shows what actually is. For a device that normally needs a kernel driver, modules listed but no driver in use can indicate missing firmware, a blacklisted module, or a binding problem. Some PCI functions do not need their own driver, so confirm the expected behavior before treating the missing line as an error. On systems with two GPUs, &lt;code&gt;lspci -k&lt;/code&gt; is also the quick way to see which one is bound to which driver.&lt;/p&gt;
&lt;p&gt;Two more options come up regularly. &lt;code&gt;-nn&lt;/code&gt; appends the numeric &lt;code&gt;[vendor:device]&lt;/code&gt; IDs, which are what you paste into a search engine or a driver compatibility list when the text name is ambiguous:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lspci -nn &lt;span class="p"&gt;|&lt;/span&gt; grep -i network&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;00:14.3 Network controller [0280]: Intel Corporation Raptor Lake PCH CNVi WiFi [8086:51f1]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And &lt;code&gt;-s&lt;/code&gt; narrows the output to one slot, combined with &lt;code&gt;-v&lt;/code&gt; or &lt;code&gt;-vv&lt;/code&gt; for details like memory ranges, capabilities, and the current link speed of the slot:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lspci -vv -s 01:00.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="getting-a-full-inventory-with-lshw"&gt;Getting a Full Inventory with lshw &lt;a class="headline-link" href="#getting-a-full-inventory-with-lshw" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Where &lt;code&gt;lsusb&lt;/code&gt; and &lt;code&gt;lspci&lt;/code&gt; each cover one bus, &lt;code&gt;lshw&lt;/code&gt; walks everything the kernel knows: CPU, memory, firmware, disks, controllers, and the buses in between. Run it as root or the output will be incomplete. The full report is pages long, so start with the summary table:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lshw -short&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;H/W path Device Class Description
===========================================================
system ThinkPad T14 Gen 4
/0/0 memory 64KiB BIOS
/0/4 processor 13th Gen Intel Core i7-1355U
/0/13 memory 32GiB System Memory
/0/13/0 memory 16GiB SODIMM DDR5 5600 MHz
/0/13/1 memory 16GiB SODIMM DDR5 5600 MHz
/0/100/2 display Raptor Lake-P [Iris Xe Graphics]
/0/100/14.3 wlp0s20f3 network Raptor Lake PCH CNVi WiFi
/0/100/1d/0 /dev/nvme0 storage SAMSUNG MZVL21T0HCLR-00B00&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This one screen answers most inventory questions: what model the machine is, which memory modules &lt;code&gt;lshw&lt;/code&gt; detected, and what storage and network hardware is present. The two 16 GiB entries show how the detected memory is populated, but they do not confirm whether the machine has another empty slot. Check the vendor&amp;rsquo;s service manual before planning an upgrade.&lt;/p&gt;
&lt;p&gt;To dig into one category, filter by class:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lshw -C memory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lshw -C network&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The class view for memory may include per-slot details such as speed and part numbers when the system firmware exposes them. For reports, &lt;code&gt;lshw&lt;/code&gt; exports machine-readable and browsable formats:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lshw -json &amp;gt; hardware.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo lshw -sanitize -html &amp;gt; hardware.html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The JSON output preserves detailed fields for local inventory tooling. Use the sanitized HTML file when sharing a report because &lt;code&gt;-sanitize&lt;/code&gt; removes potentially sensitive values such as serial numbers and IP addresses.&lt;/p&gt;
&lt;p&gt;For completeness: CPU details have their own dedicated tools, covered in our guide on &lt;a href="https://linuxize.com/post/get-cpu-information-on-linux/"&gt;getting CPU information on Linux&lt;/a&gt;
, and &lt;code&gt;sudo dmidecode&lt;/code&gt; reads the firmware&amp;rsquo;s DMI tables directly when you need BIOS versions or serial numbers that &lt;code&gt;lshw&lt;/code&gt; summarizes.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List USB devices&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lsusb&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USB tree with drivers and speeds&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lsusb -t&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full descriptors for one USB device&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo lsusb -v -d 046d:c52b&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List PCI devices&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lspci&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCI devices with kernel drivers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lspci -k&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCI devices with numeric IDs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lspci -nn&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Details for one PCI slot&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo lspci -vv -s 01:00.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware summary table&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo lshw -short&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One hardware class in detail&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo lshw -C network&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Machine-readable inventory&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo lshw -json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sanitized HTML report&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo lshw -sanitize -html&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;lsusb&lt;/code&gt; confirms detection, &lt;code&gt;lspci -k&lt;/code&gt; connects chips to drivers, and &lt;code&gt;lshw&lt;/code&gt; turns a closed case into a readable inventory; between the three, &amp;ldquo;what hardware is this and is it working&amp;rdquo; stops requiring a screwdriver. When a device shows up in these listings but misbehaves, the kernel log usually explains why, so &lt;a href="https://linuxize.com/post/dmesg-command-in-linux/"&gt;&lt;code&gt;dmesg&lt;/code&gt;&lt;/a&gt;
is the natural next stop.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/list-hardware-in-linux/featured_hu_da0040808dad9163.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>How to Comment Out Multiple Lines in Vim</title><link>https://linuxize.com/post/vim-comment-multiple-lines/</link><pubDate>Mon, 20 Jul 2026 11:20:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/vim-comment-multiple-lines/</guid><category>vim</category><description>Comment out multiple lines in Vim with visual block mode, line ranges, or bundled gc mappings, then remove comments with the matching commands.</description><content:encoded>&lt;p&gt;Commenting out a block of lines is one of those edits you make constantly: disabling a section of a config file, switching off a function while debugging, or keeping an old approach around while testing a new one. In most editors that is select plus a single shortcut. Classic Vim has no comment shortcut out of the box, but it has three techniques that are just as fast once you know them, and recent versions ship a toggle plugin as well.&lt;/p&gt;
&lt;p&gt;This guide shows how to comment out multiple lines in Vim with visual block mode, the substitute command, and the built-in comment plugin, and how to remove the comments again with each method.&lt;/p&gt;
&lt;h2 id="commenting-with-visual-block-mode"&gt;Commenting with Visual Block Mode &lt;a class="headline-link" href="#commenting-with-visual-block-mode" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The classic answer uses visual block mode to insert a comment character at the start of every selected line:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Move the cursor to the first column of the first line you want to comment.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;Ctrl+V&lt;/code&gt; to enter visual block mode.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;j&lt;/code&gt; (or the down arrow) until every target line is selected.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;Shift+I&lt;/code&gt; to insert at the left edge of the block.&lt;/li&gt;
&lt;li&gt;Type the comment character, &lt;code&gt;#&lt;/code&gt; for shell scripts and config files.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;Esc&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On Windows, &lt;code&gt;Ctrl+V&lt;/code&gt; may be mapped to paste. If it does not start visual block mode, use &lt;code&gt;Ctrl+Q&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;#&lt;/code&gt; appears on the first line while you type, which looks like the operation failed. It did not: the moment you press &lt;code&gt;Esc&lt;/code&gt;, Vim repeats the insert on every line of the block.&lt;/p&gt;
&lt;p&gt;For languages with two-character comments, type the whole prefix in step 5, for example &lt;code&gt;//&lt;/code&gt; for C, JavaScript, and Go, or &lt;code&gt;--&lt;/code&gt; for SQL and Lua. The entire string is inserted on each line.&lt;/p&gt;
&lt;p&gt;Because this selection starts in the first column, &lt;code&gt;I&lt;/code&gt; prefixes every selected line, including empty lines. If you start the block farther to the right, Vim skips lines that end before the block&amp;rsquo;s left edge. Use the substitute method below when you want to prefix a line range regardless of line length.&lt;/p&gt;
&lt;h2 id="uncommenting-with-visual-block-mode"&gt;Uncommenting with Visual Block Mode &lt;a class="headline-link" href="#uncommenting-with-visual-block-mode" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The reverse uses the same block selection to delete a column of characters:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Place the cursor on the first comment character of the first line.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;Ctrl+V&lt;/code&gt;, then &lt;code&gt;j&lt;/code&gt; down to the last commented line.&lt;/li&gt;
&lt;li&gt;If the comment prefix is longer than one character, press &lt;code&gt;l&lt;/code&gt; once for each additional character to widen the block over the whole prefix.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;x&lt;/code&gt; or &lt;code&gt;d&lt;/code&gt; to delete the selected block on every line.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The highlighted column disappears from all lines at once. If you also inserted a space after the comment character, include it in the block before deleting.&lt;/p&gt;
&lt;h2 id="commenting-with-the-substitute-command"&gt;Commenting with the Substitute Command &lt;a class="headline-link" href="#commenting-with-the-substitute-command" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The substitute command edits a range of lines in one pass, which makes it the better tool when you already know the line numbers or when the block is large. To comment lines 10 through 20:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vi"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vi&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-vi" data-lang="vi"&gt;:10,20s/^/#/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The range &lt;code&gt;10,20&lt;/code&gt; limits the substitution to those lines, &lt;code&gt;^&lt;/code&gt; matches the empty start of each line, and the replacement inserts &lt;code&gt;#&lt;/code&gt; there. Unlike block insert, this prefixes every line in the range, including blank ones.&lt;/p&gt;
&lt;p&gt;You can also select the lines first with &lt;code&gt;V&lt;/code&gt; and a movement, then press &lt;code&gt;:&lt;/code&gt;. Vim inserts the &lt;code&gt;'&amp;lt;,'&amp;gt;&lt;/code&gt; range for you, and you complete the command:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vi"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vi&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-vi" data-lang="vi"&gt;:&amp;#39;&amp;lt;,&amp;#39;&amp;gt;s/^/#/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Other ranges work the same way: &lt;code&gt;%&lt;/code&gt; for the whole file and &lt;code&gt;.,+4&lt;/code&gt; for the current line and the four below it. If you use these often, turning on line numbers makes ranges much quicker to read off the screen; see &lt;a href="https://linuxize.com/post/how-to-show-line-numbers-in-vim/"&gt;How to Show Line Numbers in Vim&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;To uncomment, delete the leading character instead of inserting it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vi"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vi&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-vi" data-lang="vi"&gt;:10,20s/^#//&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This removes the first &lt;code&gt;#&lt;/code&gt; of each line in the range and leaves lines without one untouched. For a two-character prefix such as &lt;code&gt;//&lt;/code&gt;, escaping the slashes gets noisy, so switch the delimiter to another punctuation character:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vi"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vi&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-vi" data-lang="vi"&gt;:&amp;#39;&amp;lt;,&amp;#39;&amp;gt;s#^//##&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The substitute command accepts almost any punctuation as its separator, and using &lt;code&gt;#&lt;/code&gt; here keeps the &lt;code&gt;//&lt;/code&gt; readable. The full syntax, including flags and confirmation mode, is covered in &lt;a href="https://linuxize.com/post/vim-find-replace/"&gt;Vim Find and Replace&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="keeping-indentation-with-normal"&gt;Keeping Indentation with :normal &lt;a class="headline-link" href="#keeping-indentation-with-normal" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Both methods above put the comment character in column one. To insert it in front of the first non-blank character instead, preserving the code&amp;rsquo;s indentation profile, run a normal mode command over the range:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vi"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vi&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-vi" data-lang="vi"&gt;:&amp;#39;&amp;lt;,&amp;#39;&amp;gt;norm I#&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;:norm&lt;/code&gt; command replays its argument as keystrokes on every line in the range, and &lt;code&gt;I&lt;/code&gt; in normal mode enters insert mode at the first non-blank character, so each line gets &lt;code&gt;#&lt;/code&gt; right before its content rather than at the margin. Undo treats the whole operation as a single change, so &lt;code&gt;u&lt;/code&gt; reverts every line at once.&lt;/p&gt;
&lt;h2 id="toggling-comments-with-gc"&gt;Toggling Comments with gc &lt;a class="headline-link" href="#toggling-comments-with-gc" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modern Vim and Neovim can toggle comments with a mapping that knows each filetype&amp;rsquo;s comment syntax. Neovim 0.10 and later has it built in with no setup: select lines with &lt;code&gt;V&lt;/code&gt; and press &lt;code&gt;gc&lt;/code&gt;, or use &lt;code&gt;gcc&lt;/code&gt; for the current line and &lt;code&gt;gc&lt;/code&gt; followed by a motion, such as &lt;code&gt;gcip&lt;/code&gt; for a paragraph. Pressing &lt;code&gt;gc&lt;/code&gt; on commented lines uncomments them.&lt;/p&gt;
&lt;p&gt;Vim 9.1.0375 and later bundles a similar optional comment package. Enable it for the current session with &lt;code&gt;:packadd comment&lt;/code&gt;, or add this line to your vimrc to load it on startup:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vim"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;~/.vimrc&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vim&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-vim" data-lang="vim"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;packadd&lt;/span&gt; &lt;span class="nx"&gt;comment&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After loading the package, the &lt;code&gt;gc&lt;/code&gt; mappings work as described above and pick the right comment string automatically: &lt;code&gt;#&lt;/code&gt; in a shell script, &lt;code&gt;//&lt;/code&gt; in C, and &lt;code&gt;&amp;quot;&lt;/code&gt; in a vimrc. On older Vim versions, the widely used &lt;a href="https://github.com/tpope/vim-commentary" target="_blank" rel="noopener noreferrer"&gt;commentary.vim&lt;/a&gt;
plugin provides the same familiar mappings.&lt;/p&gt;
&lt;p&gt;If you comment code many times a day, this is the method worth adopting, since toggling with &lt;code&gt;gc&lt;/code&gt; replaces both the comment and uncomment workflows in one mapping.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/vim/"&gt;Vim cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Keys or command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Comment a block&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+V&lt;/code&gt;, select lines, &lt;code&gt;Shift+I&lt;/code&gt;, type &lt;code&gt;#&lt;/code&gt;, &lt;code&gt;Esc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uncomment a block&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+V&lt;/code&gt;, select the comment column, &lt;code&gt;x&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comment lines 10-20&lt;/td&gt;
&lt;td&gt;&lt;code&gt;:10,20s/^/#/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comment a visual selection&lt;/td&gt;
&lt;td&gt;&lt;code&gt;:'&amp;lt;,'&amp;gt;s/^/#/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uncomment lines 10-20&lt;/td&gt;
&lt;td&gt;&lt;code&gt;:10,20s/^#//&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comment after indentation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;:'&amp;lt;,'&amp;gt;norm I#&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toggle comments (Neovim 0.10+, Vim 9.1.0375+)&lt;/td&gt;
&lt;td&gt;select with &lt;code&gt;V&lt;/code&gt;, press &lt;code&gt;gc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toggle the current line&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gcc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Undo the whole operation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For an occasional block, &lt;code&gt;Ctrl+V&lt;/code&gt;, &lt;code&gt;Shift+I&lt;/code&gt;, &lt;code&gt;Esc&lt;/code&gt; is the fastest habit to build, and &lt;code&gt;:s/^/#/&lt;/code&gt; handles precise ranges and blank lines. If commenting is part of your daily editing, enable the &lt;code&gt;gc&lt;/code&gt; mappings and get toggling in both directions. For selecting larger regions to operate on, see &lt;a href="https://linuxize.com/post/vim-select-all/"&gt;How to Select All in Vim&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/vim-comment-multiple-lines/featured_hu_a720d88355e6c44c.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>What Is an Inode in Linux</title><link>https://linuxize.com/post/what-is-an-inode-in-linux/</link><pubDate>Sun, 19 Jul 2026 09:35:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/what-is-an-inode-in-linux/</guid><category>disk</category><description>An inode stores Linux file metadata, not its name or data. See how inode numbers and hard links work, then check inode usage with ls, stat, and df.</description><content:encoded>&lt;p&gt;Running out of disk space normally means that a filesystem has no free bytes left. Sometimes, however, a command fails with &amp;ldquo;No space left on device&amp;rdquo; while &lt;a href="https://linuxize.com/post/how-to-check-disk-space-in-linux-using-the-df-command/"&gt;&lt;code&gt;df -h&lt;/code&gt;&lt;/a&gt;
still shows available space. One possible cause is inode exhaustion: the filesystem can store more data, but it has no free metadata records for new files. Our guide on &lt;a href="https://linuxize.com/post/fix-no-space-left-on-device/"&gt;fixing &amp;ldquo;No space left on device&amp;rdquo; when df shows free space&lt;/a&gt;
walks through that check and the other causes of the same error.&lt;/p&gt;
&lt;p&gt;To understand why this happens, and why filenames and file contents are stored separately, you need to know what an inode is. This guide explains what an inode stores, how it relates to filenames and hard links, and how to check inode usage.&lt;/p&gt;
&lt;h2 id="what-an-inode-is"&gt;What an Inode Is &lt;a class="headline-link" href="#what-an-inode-is" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An inode (short for &amp;ldquo;index node&amp;rdquo;) is a data structure that a Unix-style filesystem uses to store metadata about a file or directory. Each file has an inode number that identifies it within that filesystem. The same number can appear on another filesystem, so an inode number is not unique across the entire system.&lt;/p&gt;
&lt;p&gt;The inode holds almost everything the system needs to know about the file, except for its name and, in the usual case, the data itself. It records:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The file type, such as a regular file, directory, or symbolic link&lt;/li&gt;
&lt;li&gt;The permissions and owner and group IDs&lt;/li&gt;
&lt;li&gt;The file size and allocated blocks&lt;/li&gt;
&lt;li&gt;The access, data modification, and status change timestamps&lt;/li&gt;
&lt;li&gt;The hard-link count, which is the number of directory entries pointing to the file&lt;/li&gt;
&lt;li&gt;The block map or extents that locate the file&amp;rsquo;s data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The exact on-disk format depends on the filesystem, but these fields are the ones you see through tools such as &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;stat&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="filenames-are-separate-from-inodes"&gt;Filenames Are Separate from Inodes &lt;a class="headline-link" href="#filenames-are-separate-from-inodes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The detail that surprises many users is that the filename is not stored in the inode. A directory contains entries that map names to inode numbers. When you open &lt;code&gt;report.txt&lt;/code&gt;, the system looks up that name in the directory, finds the inode number, reads the inode, and locates the file&amp;rsquo;s data.&lt;/p&gt;
&lt;p&gt;This separation is what makes hard links possible. A hard link is another directory entry that points to the same inode. Both names are equal, and removing one name only decreases the inode&amp;rsquo;s link count. The filesystem releases the file&amp;rsquo;s storage after the last link is removed and no process still has the file open.&lt;/p&gt;
&lt;p&gt;For a practical comparison of the two link types, see &lt;a href="https://linuxize.com/post/hard-links-vs-symbolic-links/"&gt;hard links vs symbolic links&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="viewing-inode-numbers"&gt;Viewing Inode Numbers &lt;a class="headline-link" href="#viewing-inode-numbers" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To see the inode number of a file, use the &lt;code&gt;-i&lt;/code&gt; option with &lt;code&gt;ls&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -i report.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;1310720 report.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first column, &lt;code&gt;1310720&lt;/code&gt;, is the inode number. To list inode numbers for everything in a directory, run &lt;code&gt;ls -li&lt;/code&gt;, which adds the inode number as the leftmost column of the long listing.&lt;/p&gt;
&lt;p&gt;To display the metadata associated with the inode, use the &lt;a href="https://linuxize.com/post/stat-command-in-linux/"&gt;&lt;code&gt;stat&lt;/code&gt;&lt;/a&gt;
command:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stat report.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt; File: report.txt
Size: 482 Blocks: 8 IO Block: 4096 regular file
Device: 8,1 Inode: 1310720 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1000/ linuxize) Gid: ( 1000/ linuxize)
Access: 2026-01-01 14:02:11.000000000 +0100
Modify: 2026-01-01 13:55:40.000000000 +0100
Change: 2026-01-01 13:55:40.000000000 +0100
Birth: 2026-01-01 13:55:40.000000000 +0100&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Inode&lt;/code&gt; field shows the inode number, and &lt;code&gt;Links&lt;/code&gt; shows the hard-link count. &lt;code&gt;Change&lt;/code&gt; is the status change time, commonly called ctime. It changes when inode metadata such as permissions, ownership, or the link count changes. It is not the file creation time. The separate &lt;code&gt;Birth&lt;/code&gt; field shows creation time when the filesystem supports it.&lt;/p&gt;
&lt;p&gt;The filename appears at the top because you passed it to &lt;code&gt;stat&lt;/code&gt;; it is not part of the inode.&lt;/p&gt;
&lt;h2 id="how-filesystems-allocate-inodes"&gt;How Filesystems Allocate Inodes &lt;a class="headline-link" href="#how-filesystems-allocate-inodes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Inode allocation depends on the filesystem. Ext2, ext3, and ext4 create inode tables when the filesystem is formatted. This gives the filesystem a fixed inode density, so a workload that creates millions of small files can use every inode before it uses every data block.&lt;/p&gt;
&lt;p&gt;You cannot change the inode density of an existing ext4 filesystem in place. Growing the filesystem can add block groups and more inodes, but if the filesystem cannot be expanded, the practical options are to remove unneeded files, move the workload, or recreate the filesystem with a higher inode count.&lt;/p&gt;
&lt;p&gt;XFS and Btrfs allocate inodes dynamically from available filesystem space instead of creating one fixed inode table at format time. They can still reject new files when the filesystem runs out of usable data or metadata space, but they do not have the same fixed inode-count limit as ext4.&lt;/p&gt;
&lt;h2 id="checking-inode-usage"&gt;Checking Inode Usage &lt;a class="headline-link" href="#checking-inode-usage" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To see how many inodes the filesystem containing &lt;code&gt;/var&lt;/code&gt; has and how many are free, pass the path to &lt;code&gt;df&lt;/code&gt; with the &lt;code&gt;-i&lt;/code&gt; option:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;df -i /var&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sdb1 655360 655360 0 100% /var&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;IUse%&lt;/code&gt; column is the one to watch. Here, inode usage on &lt;code&gt;/var&lt;/code&gt; is at 100 percent even though the byte-based &lt;code&gt;df -h /var&lt;/code&gt; might still report free space. The filesystem cannot create another file until an inode becomes available.&lt;/p&gt;
&lt;p&gt;A large cache, session directory, mail queue, or temporary directory is a common source of inode exhaustion. GNU &lt;code&gt;du&lt;/code&gt; can count inodes instead of bytes. The following command stays on the &lt;code&gt;/var&lt;/code&gt; filesystem, checks two directory levels, and displays the largest totals at the bottom:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo du --inodes -x -d &lt;span class="m"&gt;2&lt;/span&gt; /var 2&amp;gt;/dev/null &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sort -n &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tail -20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Repeat the command on the directory with the highest count and increase the depth if needed. For other counting methods, see the guide on &lt;a href="https://linuxize.com/post/count-files-in-directory-on-linux/"&gt;counting files in a directory&lt;/a&gt;
.&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;Do not remove files only because a directory has a high inode count. First identify which application owns the files and use its cleanup or retention policy when one is available.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After cleanup, run &lt;code&gt;df -i /var&lt;/code&gt; again to confirm that free inodes are available.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An inode connects a file&amp;rsquo;s metadata to its stored data while the directory keeps the filename separately. When a filesystem reports &amp;ldquo;No space left on device&amp;rdquo; despite having free bytes, check the affected path with &lt;code&gt;df -i&lt;/code&gt; before deciding what to remove.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/what-is-an-inode-in-linux/featured_hu_3fba85c440f62f6d.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>How to Select All in Vim: Copy, Delete, or Yank Every Line</title><link>https://linuxize.com/post/vim-select-all/</link><pubDate>Sat, 18 Jul 2026 09:15:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/vim-select-all/</guid><category>vim</category><description>Select all text in Vim with ggVG, yank every line with :%y, copy the whole file to the system clipboard, or delete all lines with :%d. No plugins required.</description><content:encoded>&lt;p&gt;Sooner or later you will need to grab the entire contents of a file open in Vim, whether to paste a config file into a support ticket, move a script into another editor, or wipe everything and start over. In most editors that is &lt;code&gt;Ctrl+A&lt;/code&gt; followed by &lt;code&gt;Ctrl+C&lt;/code&gt;. Vim does not work that way, and pressing &lt;code&gt;Ctrl+A&lt;/code&gt; increments the next number at or after the cursor instead of selecting text.&lt;/p&gt;
&lt;p&gt;The quickest way to select all text in Vim is the &lt;code&gt;ggVG&lt;/code&gt; command sequence in normal mode. This guide explains how it works and how to copy, delete, or run other commands on every line in the file, including copying the whole file to the system clipboard.&lt;/p&gt;
&lt;h2 id="selecting-all-text-with-ggvg"&gt;Selecting All Text with ggVG &lt;a class="headline-link" href="#selecting-all-text-with-ggvg" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To select all text in Vim, make sure you are in normal mode (press &lt;code&gt;Esc&lt;/code&gt; if you are not), then type &lt;code&gt;ggVG&lt;/code&gt;. The sequence is three separate commands executed one after another:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gg&lt;/code&gt; - Move the cursor to the first line of the file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;V&lt;/code&gt; - Start line-wise visual mode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;G&lt;/code&gt; - Jump to the last line, extending the selection over the whole file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every line in the file is now highlighted. From here, Vim waits for an operator: press &lt;code&gt;y&lt;/code&gt; to yank (copy) the selection, &lt;code&gt;d&lt;/code&gt; to delete it, or any other visual mode command. To cancel the selection without doing anything, press &lt;code&gt;Esc&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="copying-yanking-all-lines"&gt;Copying (Yanking) All Lines &lt;a class="headline-link" href="#copying-yanking-all-lines" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the whole file selected, press &lt;code&gt;y&lt;/code&gt; to yank it into Vim&amp;rsquo;s default register. The full sequence is &lt;code&gt;ggVGy&lt;/code&gt;. You can then paste the text elsewhere in the same Vim session with &lt;code&gt;p&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Visual mode is not required, though. If you already know you want to copy everything, the ex command &lt;code&gt;:%y&lt;/code&gt; does the same thing without touching the selection:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vi"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vi&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-vi" data-lang="vi"&gt;:%y&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;%&lt;/code&gt; range means &amp;ldquo;all lines&amp;rdquo;, so &lt;code&gt;:%y&lt;/code&gt; yanks the entire file into the default register in one step. The normal mode equivalent is &lt;code&gt;ggyG&lt;/code&gt;, which yanks from the first line to the last without entering visual mode.&lt;/p&gt;
&lt;p&gt;To duplicate the whole file below itself, run &lt;code&gt;:%y&lt;/code&gt; followed by &lt;code&gt;G&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt;: yank all lines, jump to the end, and paste.&lt;/p&gt;
&lt;h2 id="copying-all-lines-to-the-system-clipboard"&gt;Copying All Lines to the System Clipboard &lt;a class="headline-link" href="#copying-all-lines-to-the-system-clipboard" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Yanked text normally stays inside Vim. To paste the file into a browser, email, or another application, copy it to the system clipboard using the &lt;code&gt;&amp;quot;+&lt;/code&gt; register:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ggVG&amp;quot;+y&lt;/code&gt; - Select all, then yank the selection to the system clipboard&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gg&amp;quot;+yG&lt;/code&gt; - Yank all lines to the system clipboard without visual mode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:%y+&lt;/code&gt; - Yank all lines to the system clipboard with an ex command&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After any of these, paste into the other application with the regular paste shortcut for your desktop environment.&lt;/p&gt;
&lt;div class="note callout callout-info"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" &gt;
&lt;path d="M 16 3 C 8.832031 3 3 8.832031 3 16 C 3 23.167969 8.832031 29 16 29 C 23.167969 29 29 23.167969 29 16 C 29 8.832031 23.167969 3 16 3 Z M 16 5 C 22.085938 5 27 9.914063 27 16 C 27 22.085938 22.085938 27 16 27 C 9.914063 27 5 22.085938 5 16 C 5 9.914063 9.914063 5 16 5 Z M 15 10 L 15 12 L 17 12 L 17 10 Z M 15 14 L 15 22 L 17 22 L 17 14 Z "&gt;&lt;/path&gt;
&lt;/svg&gt;&lt;span class="callout-title"&gt;Info&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;The &lt;code&gt;&amp;quot;+&lt;/code&gt; register requires Vim compiled with the &lt;code&gt;+clipboard&lt;/code&gt; feature. Check with &lt;code&gt;vim --version | grep clipboard&lt;/code&gt;. If the output shows &lt;code&gt;-clipboard&lt;/code&gt;, install a build with clipboard support, such as &lt;code&gt;vim-gtk3&lt;/code&gt; on Debian and Ubuntu systems.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If installing another Vim build is not an option, you can pipe the buffer to a clipboard utility instead. On X11 systems with &lt;code&gt;xclip&lt;/code&gt; installed:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vi"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vi&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-vi" data-lang="vi"&gt;:%w !xclip -selection clipboard&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This writes the whole buffer to the &lt;code&gt;xclip&lt;/code&gt; command, which places it on the clipboard. On Wayland, use &lt;code&gt;wl-copy&lt;/code&gt; from the &lt;code&gt;wl-clipboard&lt;/code&gt; package the same way:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vi"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vi&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-vi" data-lang="vi"&gt;:%w !wl-copy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For more on registers and clipboard integration, see &lt;a href="https://linuxize.com/post/how-to-copy-cut-paste-in-vim/"&gt;How to Copy, Cut and Paste in Vim&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="deleting-all-lines"&gt;Deleting All Lines &lt;a class="headline-link" href="#deleting-all-lines" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To select everything and delete it, use &lt;code&gt;ggVGd&lt;/code&gt;, or skip visual mode with &lt;code&gt;ggdG&lt;/code&gt; (move to the first line, then delete to the last line). The fastest option is again the ex command with the &lt;code&gt;%&lt;/code&gt; range:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vi"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vi&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-vi" data-lang="vi"&gt;:%d&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All lines are removed and the file is left with a single empty line. The deleted text lands in the default register, so an accidental &lt;code&gt;:%d&lt;/code&gt; is easy to reverse: press &lt;code&gt;u&lt;/code&gt; to &lt;a href="https://linuxize.com/post/vim-undo-redo/"&gt;undo&lt;/a&gt;
, or paste the text back with &lt;code&gt;p&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To delete every line without replacing the current contents of the unnamed register, send the deleted text to the black hole register:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="vi"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;vi&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-vi" data-lang="vi"&gt;:%d _&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This preserves whatever was already available for pasting with &lt;code&gt;p&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For ranges, patterns, and more deletion commands, see &lt;a href="https://linuxize.com/post/vim-delete-line/"&gt;How to Delete Lines in Vim&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="running-other-commands-on-the-whole-file"&gt;Running Other Commands on the Whole File &lt;a class="headline-link" href="#running-other-commands-on-the-whole-file" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Selecting all text is not limited to copy and delete. With &lt;code&gt;ggVG&lt;/code&gt; active, any visual mode operator applies to the entire file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ggVG=&lt;/code&gt; - Re-indent every line (same as &lt;code&gt;gg=G&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ggVGu&lt;/code&gt; - Convert the whole file to lowercase&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ggVGU&lt;/code&gt; - Convert the whole file to uppercase&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ggVG&amp;gt;&lt;/code&gt; - Shift every line one indent level to the right&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For find and replace across the whole file, you do not need a selection at all: the substitute command takes the same &lt;code&gt;%&lt;/code&gt; range, as in &lt;code&gt;:%s/old/new/g&lt;/code&gt;. See &lt;a href="https://linuxize.com/post/vim-find-replace/"&gt;Vim Find and Replace&lt;/a&gt;
for the full syntax.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/vim/"&gt;Vim cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ggVG&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select all lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ggVGy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select all and yank (copy)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ggVGd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select all and delete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ggVG&amp;quot;+y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select all and copy to the system clipboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ggyG&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yank all lines without visual mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ggdG&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete all lines without visual mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:%y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yank all lines (ex command)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:%y+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yank all lines to the system clipboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:%d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete all lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:%d _&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete all lines without replacing the unnamed register&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gg=G&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Re-indent the whole file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:%s/old/new/g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace across the whole file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Undo the last change&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;ggVG&lt;/code&gt; when you want to see the whole-file selection before choosing an operator. When the action is already clear, the &lt;code&gt;%&lt;/code&gt; range is shorter, as in &lt;code&gt;:%y&lt;/code&gt;, &lt;code&gt;:%d&lt;/code&gt;, or &lt;code&gt;:%s/old/new/g&lt;/code&gt;. For selecting a smaller block to comment out, see &lt;a href="https://linuxize.com/post/vim-comment-multiple-lines/"&gt;How to Comment Out Multiple Lines in Vim&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/vim-select-all/featured_hu_5dde98562a666b1b.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>Email Authentication Explained: SPF, DKIM, and DMARC</title><link>https://linuxize.com/post/email-authentication-spf-dkim-dmarc/</link><pubDate>Fri, 17 Jul 2026 18:20:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/email-authentication-spf-dkim-dmarc/</guid><category>mail server</category><category>dns</category><description>SPF, DKIM, and DMARC help prevent domain spoofing. See how each check works, what DMARC alignment requires, and how to verify the DNS records with dig.</description><content:encoded>&lt;p&gt;When mail from your domain lands in spam or is rejected, authentication is one of the first things to check. &lt;a href="https://support.google.com/mail/answer/81126" target="_blank" rel="noopener noreferrer"&gt;Google&lt;/a&gt;
and &lt;a href="https://senders.yahooinc.com/best-practices/" target="_blank" rel="noopener noreferrer"&gt;Yahoo&lt;/a&gt;
require all senders to use at least SPF or DKIM, while bulk senders must use SPF, DKIM, and DMARC. These mechanisms associate mail with your domain, but they do not guarantee inbox placement on their own.&lt;/p&gt;
&lt;p&gt;This guide explains what each mechanism does, how the three work together, what the records look like, and how to verify your setup from the command line.&lt;/p&gt;
&lt;h2 id="why-email-needs-authentication"&gt;Why Email Needs Authentication &lt;a class="headline-link" href="#why-email-needs-authentication" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SMTP, the protocol that moves mail between servers, was designed without sender verification. Any server can connect to any other server and claim to send mail from &lt;code&gt;example.com&lt;/code&gt;; nothing in the protocol stops it. That is why spammers and phishers can forge the From address of any domain.&lt;/p&gt;
&lt;p&gt;Authentication closes this gap with DNS and message signing. SPF tells a receiver whether the connecting server is authorized for the envelope sender domain. DKIM associates a cryptographic signature with a signing domain. DMARC checks whether a passing SPF or DKIM identity aligns with the domain in the visible From address, then publishes the domain owner&amp;rsquo;s handling preference for failures.&lt;/p&gt;
&lt;h2 id="how-the-three-work-together"&gt;How the Three Work Together &lt;a class="headline-link" href="#how-the-three-work-together" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each mechanism covers a different part of the delivery:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SPF&lt;/strong&gt; publishes which servers may send mail for your domain. Receivers check the connecting server&amp;rsquo;s IP against the list.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DKIM&lt;/strong&gt; adds a cryptographic signature to each message. Receivers verify it against a public key in DNS to confirm that the holder of the private key signed the message and that the signed content has not changed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DMARC&lt;/strong&gt; ties the result to the visible From address, publishes a handling preference for failures, and can request reports from participating receivers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using all three gives you better spoofing protection and diagnostic data even when your sending volume is below provider bulk-sender thresholds.&lt;/p&gt;
&lt;h2 id="spf-authorizing-sending-servers"&gt;SPF: Authorizing Sending Servers &lt;a class="headline-link" href="#spf-authorizing-sending-servers" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SPF (Sender Policy Framework) is a TXT record on the domain itself listing authorized senders:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;example.com. 3600 IN TXT &amp;#34;v=spf1 mx ip4:203.0.113.10 include:_spf.google.com -all&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Reading the record left to right: &lt;code&gt;v=spf1&lt;/code&gt; identifies it as SPF, &lt;code&gt;mx&lt;/code&gt; authorizes the servers named in the domain&amp;rsquo;s MX records, &lt;code&gt;ip4:203.0.113.10&lt;/code&gt; authorizes a specific address, and &lt;code&gt;include:_spf.google.com&lt;/code&gt; pulls in another domain&amp;rsquo;s SPF list, which is how you authorize a provider such as Google Workspace to send for you.&lt;/p&gt;
&lt;p&gt;The final mechanism sets the SPF result for everything not listed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-all&lt;/code&gt; - Returns &lt;code&gt;fail&lt;/code&gt;, a clear statement that unlisted servers are not authorized.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~all&lt;/code&gt; - Returns &lt;code&gt;softfail&lt;/code&gt;, a weaker statement that the server is probably not authorized.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+all&lt;/code&gt; - Returns &lt;code&gt;pass&lt;/code&gt; for every server, which defeats the purpose of SPF.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The receiving system decides how each result affects delivery. SPF itself does not require a specific action for &lt;code&gt;fail&lt;/code&gt; or &lt;code&gt;softfail&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Two rules prevent many common SPF errors. A domain must have exactly one SPF record because multiple records produce &lt;code&gt;permerror&lt;/code&gt;. Evaluation can use at most 10 DNS-querying terms, including &lt;code&gt;include&lt;/code&gt;, &lt;code&gt;mx&lt;/code&gt;, and &lt;code&gt;a&lt;/code&gt;; chained provider records can consume that limit quickly.&lt;/p&gt;
&lt;p&gt;SPF also has a blind spot: it checks the envelope sender used during the SMTP transaction, not the From header the user sees. Ordinary forwarding often causes SPF to fail because the forwarder&amp;rsquo;s IP is not in the original sender&amp;rsquo;s record, unless the forwarder rewrites the envelope sender with Sender Rewriting Scheme (SRS). That is where DKIM helps.&lt;/p&gt;
&lt;h2 id="dkim-signing-messages"&gt;DKIM: Signing Messages &lt;a class="headline-link" href="#dkim-signing-messages" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DKIM (DomainKeys Identified Mail) uses public-key cryptography. Your mail server signs each outgoing message with a private key, adding a &lt;code&gt;DKIM-Signature&lt;/code&gt; header. Receivers fetch the matching public key from DNS and verify the signature. A valid result shows that the holder of the private key signed the message and that the signed headers and body have not changed. It does not show that the message content is trustworthy.&lt;/p&gt;
&lt;p&gt;The public key lives in a TXT record under a selector name, which allows multiple keys per domain:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;default._domainkey.example.com. 3600 IN TXT &amp;#34;v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here &lt;code&gt;default&lt;/code&gt; is the selector; the signing server puts the selector name in each signature header so receivers know which key to fetch. The &lt;code&gt;p=&lt;/code&gt; value is the base64-encoded public key, typically 2048-bit RSA.&lt;/p&gt;
&lt;p&gt;Unlike SPF, DKIM requires software on the mail server to do the signing. On a self-hosted Postfix setup this is usually handled by a milter such as OpenDKIM or by &lt;a href="https://linuxize.com/post/install-and-integrate-rspamd/"&gt;Rspamd&lt;/a&gt;
, which generates the key pair and signs outgoing mail. Hosted providers generate the keys for you and tell you which records to publish.&lt;/p&gt;
&lt;p&gt;DKIM generally survives simple forwarding because the signature travels with the message. A forwarding service, mailing list, or security gateway that changes a signed header or the message body can invalidate it.&lt;/p&gt;
&lt;h2 id="dmarc-policy-and-reporting"&gt;DMARC: Policy and Reporting &lt;a class="headline-link" href="#dmarc-policy-and-reporting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SPF and DKIM authenticate domains that are not necessarily the one shown in the From address. DMARC (Domain-Based Message Authentication, Reporting, and Conformance) adds that connection and publishes a handling preference in a TXT record at &lt;code&gt;_dmarc&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;_dmarc.example.com. 3600 IN TXT &amp;#34;v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;p=&lt;/code&gt; tag describes how the domain owner views mail that fails DMARC:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;p=none&lt;/code&gt; - Expresses no DMARC-based handling preference and is the normal starting point for monitoring.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p=quarantine&lt;/code&gt; - Says the domain owner considers failing mail suspicious. A receiver may place it in spam or apply other scrutiny.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p=reject&lt;/code&gt; - Says the domain owner considers the failed use of the domain invalid.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These values are preferences, not commands. A receiving system can use other signals when deciding whether to accept, quarantine, or reject a message. The &lt;a href="https://www.rfc-editor.org/rfc/rfc9989.html" target="_blank" rel="noopener noreferrer"&gt;current DMARC standard&lt;/a&gt;
specifically says that receivers must not reject mail solely because the sender publishes &lt;code&gt;p=reject&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A message passes DMARC when at least one of SPF or DKIM passes &lt;strong&gt;and&lt;/strong&gt; aligns. With the default relaxed alignment, the authenticated domain and the From domain must share the same organizational domain, so &lt;code&gt;bounce.example.com&lt;/code&gt; can align with &lt;code&gt;example.com&lt;/code&gt;. Strict alignment, enabled with &lt;code&gt;aspf=s&lt;/code&gt; or &lt;code&gt;adkim=s&lt;/code&gt;, requires identical domains.&lt;/p&gt;
&lt;p&gt;Alignment is the part that blocks a common spoofing technique. An attacker can pass SPF for a domain they control while displaying your domain in the From header, but the result does not align and DMARC fails.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;rua=&lt;/code&gt; tag requests aggregate XML reports from participating receivers, commonly sent daily. Reports show which systems use your domain and how their messages authenticate. Start with &lt;code&gt;p=none&lt;/code&gt;, identify legitimate services such as CRMs and monitoring tools, and fix their SPF or DKIM before considering enforcement. A report-processing service or self-hosted analyzer is easier to use than reading the raw XML. Do not treat &lt;code&gt;p=reject&lt;/code&gt; as an automatic endpoint, especially for domains whose users send through mailing lists or forwarding services.&lt;/p&gt;
&lt;h2 id="checking-your-records-with-dig"&gt;Checking Your Records with dig &lt;a class="headline-link" href="#checking-your-records-with-dig" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All three mechanisms use DNS TXT records, although DKIM also requires a working signer. You can verify what the world sees with &lt;code&gt;dig&lt;/code&gt;. Check SPF on the domain itself:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig +short example.com TXT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;&amp;#34;v=spf1 mx ip4:203.0.113.10 include:_spf.google.com -all&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The answer may include unrelated TXT records. Confirm that exactly one returned string begins with &lt;code&gt;v=spf1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;DKIM requires knowing the selector; check the record your signer uses:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig +short default._domainkey.example.com TXT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;&amp;#34;v=DKIM1; k=rsa; &amp;#34; &amp;#34;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;DNS can split a long public key into adjacent quoted strings. They form one TXT record when concatenated.&lt;/p&gt;
&lt;p&gt;And DMARC always lives at the &lt;code&gt;_dmarc&lt;/code&gt; subdomain:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig +short _dmarc.example.com TXT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;&amp;#34;v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If a record is missing from the output, receivers cannot see it either. For more query options, see our &lt;a href="https://linuxize.com/post/how-to-use-dig-command-to-query-dns-in-linux/"&gt;dig command guide&lt;/a&gt;
. For an end-to-end test, send a message to a Gmail address and use &amp;ldquo;Show original&amp;rdquo;, which displays PASS or FAIL for SPF, DKIM, and DMARC on the received message.&lt;/p&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A new TXT record does not appear&lt;/strong&gt;&lt;br&gt;
Check that you used the correct DNS host name: &lt;code&gt;@&lt;/code&gt; or the bare domain for SPF, &lt;code&gt;&amp;lt;selector&amp;gt;._domainkey&lt;/code&gt; for DKIM, and &lt;code&gt;_dmarc&lt;/code&gt; for DMARC. DNS caches may continue returning the previous answer until the record&amp;rsquo;s TTL expires.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SPF returns permerror&lt;/strong&gt;&lt;br&gt;
Look for multiple TXT records beginning with &lt;code&gt;v=spf1&lt;/code&gt; and merge them into one. If there is only one record, count its DNS-querying terms and the terms inside every &lt;code&gt;include&lt;/code&gt;; exceeding the 10-lookup limit also causes &lt;code&gt;permerror&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SPF or DKIM passes but DMARC fails&lt;/strong&gt;&lt;br&gt;
The passing identity is probably not aligned with the visible From domain. Inspect the &lt;code&gt;Authentication-Results&lt;/code&gt; header for the SPF envelope domain and the DKIM &lt;code&gt;d=&lt;/code&gt; signing domain. Configure a custom return path or DKIM signing domain under your own organizational domain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DKIM reports a body hash mismatch&lt;/strong&gt;&lt;br&gt;
Something changed the body after it was signed, often a mailing list footer, security gateway, or forwarding service. Compare a directly delivered message with the modified path, and make sure the published selector and key match the active signer.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;What the receiver checks&lt;/th&gt;
&lt;th&gt;DNS record location&lt;/th&gt;
&lt;th&gt;Example value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SPF&lt;/td&gt;
&lt;td&gt;Connecting IP against the envelope sender policy&lt;/td&gt;
&lt;td&gt;TXT at &lt;code&gt;example.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v=spf1 mx -all&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DKIM&lt;/td&gt;
&lt;td&gt;Signature against the selector&amp;rsquo;s public key&lt;/td&gt;
&lt;td&gt;TXT at &lt;code&gt;&amp;lt;selector&amp;gt;._domainkey.example.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v=DKIM1; k=rsa; p=&amp;lt;key&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DMARC&lt;/td&gt;
&lt;td&gt;SPF or DKIM alignment with the visible From domain&lt;/td&gt;
&lt;td&gt;TXT at &lt;code&gt;_dmarc.example.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;v=DMARC1; p=none; rua=mailto:...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SPF authorizes sending infrastructure, DKIM associates a valid signature with a domain, and DMARC checks alignment with the visible From address. If you run your own stack, our guides on &lt;a href="https://linuxize.com/post/install-and-configure-postfix-and-dovecot/"&gt;setting up Postfix and Dovecot&lt;/a&gt;
and &lt;a href="https://linuxize.com/post/install-and-integrate-rspamd/"&gt;integrating Rspamd&lt;/a&gt;
cover the server-side configuration, including DKIM signing. For the other record types you will meet in a DNS panel, see our &lt;a href="https://linuxize.com/post/dns-record-types-explained/"&gt;DNS record types guide&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/email-authentication-spf-dkim-dmarc/featured_hu_f89798660aa99397.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>sha256sum Cheatsheet</title><link>https://linuxize.com/cheatsheet/sha256sum/</link><pubDate>Thu, 16 Jul 2026 08:40:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/sha256sum/</guid><description>Quick reference for generating and verifying SHA-256 and MD5 checksums with sha256sum, md5sum, and related Linux hash commands</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="generate-checksums"&gt;Generate Checksums &lt;a class="headline-link" href="#generate-checksums" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Print a digest for one or more files.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha256sum file.iso&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print the SHA-256 digest of a file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha256sum file1 file2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One digest line per file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha256sum *.tar.gz &amp;gt; SHA256SUMS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Save digests to a checksum file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;printf '%s' &amp;quot;text&amp;quot; | sha256sum&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hash a string from stdin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;find dir/ -type f -exec sha256sum {} +&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hash every file in a directory tree&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="verify-checksums"&gt;Verify Checksums &lt;a class="headline-link" href="#verify-checksums" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Check files against a checksum list with &lt;code&gt;-c&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha256sum -c SHA256SUMS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verify every file in the list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha256sum -c --ignore-missing SHA256SUMS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verify only the files that are present&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep file.iso SHA256SUMS | sha256sum -c -&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verify a single file from a larger list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;echo &amp;quot;DIGEST file.iso&amp;quot; | sha256sum -c -&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compare against a pasted digest (two spaces)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha256sum -c --quiet SHA256SUMS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print failures only, skip &lt;code&gt;OK&lt;/code&gt; lines&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="useful-options"&gt;Useful Options &lt;a class="headline-link" href="#useful-options" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Flags shared by &lt;code&gt;sha256sum&lt;/code&gt;, &lt;code&gt;md5sum&lt;/code&gt;, and the other GNU hash tools.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-c&lt;/code&gt;, &lt;code&gt;--check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read digests from a file and verify them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--quiet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Do not print &lt;code&gt;OK&lt;/code&gt; for verified files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print nothing; report via exit status only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--warn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Warn about improperly formatted lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--strict&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exit non-zero when a line is badly formatted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--ignore-missing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip listed files that do not exist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--tag&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;BSD-style output, &lt;code&gt;SHA256 (file) = digest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-b&lt;/code&gt;, &lt;code&gt;--binary&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mark files with &lt;code&gt;*&lt;/code&gt; in the output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-z&lt;/code&gt;, &lt;code&gt;--zero&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;End output lines with NUL instead of newline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="scripting-and-exit-codes"&gt;Scripting and Exit Codes &lt;a class="headline-link" href="#scripting-and-exit-codes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Automate checks in scripts and CI jobs.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha256sum -c --status SHA256SUMS &amp;amp;&amp;amp; echo ok&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Branch on the verification result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha256sum -c SHA256SUMS || exit 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Abort a script on any mismatch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[ &amp;quot;$(sha256sum &amp;lt; f)&amp;quot; = &amp;quot;$(sha256sum &amp;lt; g)&amp;quot; ]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compare two files by digest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha256sum file | cut -d' ' -f1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extract the bare digest value&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="other-hash-commands"&gt;Other Hash Commands &lt;a class="headline-link" href="#other-hash-commands" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Same interface, different algorithms.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;md5sum file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;128-bit MD5; corruption checks only, not security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha1sum file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;160-bit SHA-1; legacy, avoid for new uses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sha512sum file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;512-bit SHA-2 digest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;b2sum file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;BLAKE2; fast modern alternative&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cksum -a sha256 file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unified hash tool in newer coreutils&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Quick checks for common verification problems.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Digest mismatch on a download&lt;/td&gt;
&lt;td&gt;Re-download, ideally from a different mirror&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;no properly formatted checksum lines found&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fix CRLF endings with &lt;code&gt;dos2unix&lt;/code&gt;, check the file format&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;No such file or directory&lt;/code&gt; with &lt;code&gt;-c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run from the directory that holds the listed files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Every other release fails as missing&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;--ignore-missing&lt;/code&gt; to scope the check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Digest source is untrusted&lt;/td&gt;
&lt;td&gt;Verify the GPG signature on the checksum file itself&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="related-guides"&gt;Related Guides &lt;a class="headline-link" href="#related-guides" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Full walkthroughs for checksums and signing.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guide&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/sha256sum-and-md5sum-commands/"&gt;Verify a Checksum in Linux&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Full &lt;code&gt;sha256sum&lt;/code&gt; and &lt;code&gt;md5sum&lt;/code&gt; tutorial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-encrypt-and-decrypt-files-with-gpg/"&gt;Encrypt and Decrypt Files with GPG&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Work with GPG keys and signatures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/wget-command-examples/"&gt;wget Command Examples&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Download files and checksum lists&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>What Is stdin, stdout, and stderr in Linux</title><link>https://linuxize.com/post/what-is-stdin-stdout-and-stderr-in-linux/</link><pubDate>Thu, 16 Jul 2026 08:30:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/what-is-stdin-stdout-and-stderr-in-linux/</guid><category>bash</category><category>linux commands</category><description>stdin, stdout, and stderr are Linux's three standard streams. See how file descriptors 0, 1, and 2 connect commands to terminals, files, and pipes.</description><content:encoded>&lt;p&gt;When a Linux command reads text you type, sends results to the terminal, or prints an error beside them, it is using a set of connections prepared before the program starts. These connections are standard input, standard output, and standard error, usually shortened to stdin, stdout, and stderr.&lt;/p&gt;
&lt;p&gt;The shell can connect these streams to a terminal, file, pipe, or another destination without changing the program itself. This guide explains what the three standard streams do, why they use file descriptors &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, and &lt;code&gt;2&lt;/code&gt;, and how shell redirection changes their destinations.&lt;/p&gt;
&lt;h2 id="the-three-standard-streams"&gt;The Three Standard Streams &lt;a class="headline-link" href="#the-three-standard-streams" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A process normally starts with three open file descriptors inherited from its parent. When you launch a command from an interactive shell, the shell usually connects all three to your current terminal:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stream&lt;/th&gt;
&lt;th&gt;File descriptor&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Interactive default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;stdin&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Input read by the program&lt;/td&gt;
&lt;td&gt;Terminal input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stdout&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Normal program output&lt;/td&gt;
&lt;td&gt;Terminal display&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stderr&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Errors and diagnostic messages&lt;/td&gt;
&lt;td&gt;Terminal display&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Describing stdin as the keyboard is a useful shortcut, but the program actually reads from a terminal device. The terminal handles keyboard input and passes it to the program. In a script or pipeline, stdin may instead come from a file or another command.&lt;/p&gt;
&lt;p&gt;The numbers matter because shell redirection syntax uses them. stdout and stderr both appear on the terminal by default, so they can look like one stream even though they remain separate. A script can save normal results in one file while sending errors somewhere else.&lt;/p&gt;
&lt;h2 id="seeing-stdout-and-stderr-separately"&gt;Seeing stdout and stderr Separately &lt;a class="headline-link" href="#seeing-stdout-and-stderr-separately" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following commands print one normal message and one warning:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;%s\n&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;backup complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;%s\n&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;warning: archive not found&amp;#34;&lt;/span&gt; &amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;backup complete
warning: archive not found&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Both lines appear in the same terminal, but they traveled through different streams. The first &lt;code&gt;printf&lt;/code&gt; writes to stdout. The &lt;code&gt;&amp;gt;&amp;amp;2&lt;/code&gt; redirection sends the second command&amp;rsquo;s output to stderr, which lets a script report a diagnostic without mixing it into data that another command may need to process.&lt;/p&gt;
&lt;h2 id="changing-stream-destinations"&gt;Changing Stream Destinations &lt;a class="headline-link" href="#changing-stream-destinations" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The shell sets up redirections before it starts the command. The program continues reading and writing the same file descriptors without needing to know whether they point to a terminal, file, or pipe.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;&amp;gt;&lt;/code&gt; operator sends stdout to a file, creating the file or replacing its contents:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls /etc &amp;gt; files.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Nothing appears on the terminal because the directory listing went to &lt;code&gt;files.txt&lt;/code&gt;. Since &lt;code&gt;&amp;gt;&lt;/code&gt; uses stdout when no descriptor is specified, &lt;code&gt;&amp;gt; files.txt&lt;/code&gt; and &lt;code&gt;1&amp;gt; files.txt&lt;/code&gt; have the same effect.&lt;/p&gt;
&lt;p&gt;stderr remains connected to the terminal unless you redirect descriptor &lt;code&gt;2&lt;/code&gt;. This command requests one existing path and one missing path:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls /etc /nonexistent &amp;gt; files.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;ls: cannot access &amp;#39;/nonexistent&amp;#39;: No such file or directory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The successful listing went into &lt;code&gt;files.txt&lt;/code&gt;, while the error stayed visible because it traveled through stderr. Redirect descriptor &lt;code&gt;2&lt;/code&gt; to capture it separately:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls /etc /nonexistent &amp;gt; files.txt 2&amp;gt; errors.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now normal results are in &lt;code&gt;files.txt&lt;/code&gt; and the diagnostic is in &lt;code&gt;errors.txt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To save both streams in one file using portable shell syntax, redirect stdout first and then duplicate its destination for stderr:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;command&lt;/span&gt; &amp;gt; output.log 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; expression makes file descriptor &lt;code&gt;2&lt;/code&gt; point to the current destination of file descriptor &lt;code&gt;1&lt;/code&gt;. Redirections are processed from left to right, so reversing their order produces a different result. See &lt;a href="https://linuxize.com/post/bash-redirect-stderr-stdout/"&gt;how to redirect stderr to stdout in Bash&lt;/a&gt;
for combining, appending, piping, and discarding output.&lt;/p&gt;
&lt;p&gt;Input redirection works in the other direction. The &lt;code&gt;&amp;lt;&lt;/code&gt; operator connects a file to stdin:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sort &amp;lt; names.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here &lt;code&gt;sort&lt;/code&gt; reads from &lt;code&gt;names.txt&lt;/code&gt; instead of the terminal. Many commands also accept a filename as an argument, but input redirection works for any command designed to read from stdin.&lt;/p&gt;
&lt;h2 id="how-pipes-use-the-streams"&gt;How Pipes Use the Streams &lt;a class="headline-link" href="#how-pipes-use-the-streams" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A pipe (&lt;code&gt;|&lt;/code&gt;) connects the stdout of one command to the stdin of the next, so data can move between programs without a temporary file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls /etc &lt;span class="p"&gt;|&lt;/span&gt; grep conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The stdout of &lt;code&gt;ls&lt;/code&gt; becomes the stdin of &lt;code&gt;grep&lt;/code&gt;. A regular pipe carries stdout, not stderr, so an error from &lt;code&gt;ls&lt;/code&gt; still appears on the terminal instead of passing to &lt;code&gt;grep&lt;/code&gt;. The &lt;a href="https://linuxize.com/post/linux-pipes-explained/"&gt;Linux pipes guide&lt;/a&gt;
covers longer pipelines, error handling, and &lt;code&gt;pipefail&lt;/code&gt;. To show output on the terminal while also saving it, use the &lt;a href="https://linuxize.com/post/linux-tee-command/"&gt;tee command&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/bash/"&gt;Bash cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Descriptor or syntax&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;stdin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;stdout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;stderr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command &amp;lt; file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read stdin from &lt;code&gt;file&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command &amp;gt; file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write stdout to &lt;code&gt;file&lt;/code&gt;, replacing its contents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command &amp;gt;&amp;gt; file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Append stdout to &lt;code&gt;file&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command 2&amp;gt; file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write stderr to &lt;code&gt;file&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command &amp;gt; file 2&amp;gt;&amp;amp;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write stdout and stderr to the same file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command 2&amp;gt;/dev/null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Discard stderr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cmd1 | cmd2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Connect stdout from &lt;code&gt;cmd1&lt;/code&gt; to stdin for &lt;code&gt;cmd2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a command sends data somewhere unexpected, identify whether it is using file descriptor &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, or &lt;code&gt;2&lt;/code&gt;, then read its redirections from left to right. That habit makes shell pipelines and logging commands much easier to follow.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/what-is-stdin-stdout-and-stderr-in-linux/featured_hu_27be33e5647fc0f6.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>How to Configure Networking with Netplan on Ubuntu</title><link>https://linuxize.com/post/how-to-configure-networking-with-netplan-on-ubuntu/</link><pubDate>Wed, 15 Jul 2026 10:30:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/how-to-configure-networking-with-netplan-on-ubuntu/</guid><category>networking</category><category>ubuntu</category><description>Configure Ubuntu networking with Netplan using practical YAML examples for DHCP, static IP addresses, DNS, Wi-Fi, bridges, and safe remote changes.</description><content:encoded>&lt;p&gt;Since Ubuntu 17.10, networking is configured with Netplan rather than the old &lt;code&gt;/etc/network/interfaces&lt;/code&gt; file. You write a short YAML description of how each interface should behave, and Netplan translates it into configuration for the back end that actually manages the network. This keeps the configuration in one place and makes it easy to read, but the YAML syntax trips up people who are used to the older format.&lt;/p&gt;
&lt;p&gt;This guide explains how Netplan works and how to configure DHCP, static addresses, DNS, Wi-Fi, and bridges, then how to apply the changes without locking yourself out of a remote server.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List Netplan files&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ls /etc/netplan/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show interface names&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ip link&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show the merged configuration&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo netplan get&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check configuration for errors&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo netplan generate&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apply changes with rollback&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo netplan try&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apply changes directly&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo netplan apply&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show current network state&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo netplan status&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="how-netplan-works"&gt;How Netplan Works &lt;a class="headline-link" href="#how-netplan-works" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Administrators store Netplan YAML files in &lt;code&gt;/etc/netplan&lt;/code&gt;. Netplan reads those files and generates configuration for one of two back ends, called renderers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;systemd-networkd&lt;/code&gt; - The usual renderer on Ubuntu Server. It runs without a graphical environment and suits headless machines.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NetworkManager&lt;/code&gt; - The usual renderer on Ubuntu Desktop. It handles Wi-Fi, VPNs, and interface switching, and integrates with the GNOME settings panel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you run &lt;code&gt;netplan apply&lt;/code&gt;, Netplan parses the YAML, writes back-end configuration, and tells the renderer to reload it. Syntax errors stop this process, but a valid configuration with the wrong address or route can still interrupt the connection.&lt;/p&gt;
&lt;p&gt;List the files Netplan currently reads:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls /etc/netplan/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;50-cloud-init.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The exact name depends on how the system was installed. Common names include &lt;code&gt;00-installer-config.yaml&lt;/code&gt;, &lt;code&gt;01-netcfg.yaml&lt;/code&gt;, and &lt;code&gt;50-cloud-init.yaml&lt;/code&gt;. Files are read in alphanumeric order, and later files override earlier ones, so a &lt;code&gt;90-custom.yaml&lt;/code&gt; takes precedence over &lt;code&gt;50-cloud-init.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The examples below use &lt;code&gt;/etc/netplan/99-custom.yaml&lt;/code&gt;, which loads after the common installer and cloud-init filenames. Create the file with a text editor, or edit an existing file instead if you already manage it directly:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nano /etc/netplan/99-custom.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Netplan configuration files should be readable and writable only by root. After saving the file, set the required permissions before applying changes:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chmod &lt;span class="m"&gt;600&lt;/span&gt; /etc/netplan/*.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="the-structure-of-a-netplan-file"&gt;The Structure of a Netplan File &lt;a class="headline-link" href="#the-structure-of-a-netplan-file" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every Netplan file starts with a top-level &lt;code&gt;network&lt;/code&gt; key. Under it, you can set the configuration &lt;code&gt;version&lt;/code&gt;, choose a &lt;code&gt;renderer&lt;/code&gt;, and list interfaces by type, such as &lt;code&gt;ethernets&lt;/code&gt;, &lt;code&gt;wifis&lt;/code&gt;, &lt;code&gt;bridges&lt;/code&gt;, or &lt;code&gt;vlans&lt;/code&gt;. Netplan defaults to version &lt;code&gt;2&lt;/code&gt; and the &lt;code&gt;networkd&lt;/code&gt; renderer when these keys are omitted, but keeping them explicit makes the file easier to understand:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="yaml"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;/etc/netplan/99-custom.yaml&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-orange-100 text-orange-700 dark:bg-orange-900 dark:text-orange-300"&gt;yaml&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;networkd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ethernets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ens3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dhcp4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Version &lt;code&gt;2&lt;/code&gt; is the only supported Netplan YAML format. The &lt;code&gt;renderer&lt;/code&gt; chooses the back end, and the interface name (&lt;code&gt;ens3&lt;/code&gt; here) must match a real interface on the system. Find the interface names with the &lt;a href="https://linuxize.com/post/linux-ip-command/"&gt;&lt;code&gt;ip link&lt;/code&gt;&lt;/a&gt;
command:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip link&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;YAML is sensitive to indentation, so use spaces, never tabs, and keep nested keys aligned. A single misaligned line is the most common reason a configuration does not apply.&lt;/p&gt;
&lt;h2 id="configuring-dhcp"&gt;Configuring DHCP &lt;a class="headline-link" href="#configuring-dhcp" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The example above already enables DHCP for IPv4 with &lt;code&gt;dhcp4: true&lt;/code&gt;. To also enable DHCP for IPv6, add &lt;code&gt;dhcp6&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="yaml"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;/etc/netplan/99-custom.yaml&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-orange-100 text-orange-700 dark:bg-orange-900 dark:text-orange-300"&gt;yaml&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;networkd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ethernets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ens3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dhcp4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dhcp6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is the default configuration on most fresh installs, where the router assigns the address automatically.&lt;/p&gt;
&lt;h2 id="configuring-a-static-ip-address"&gt;Configuring a Static IP Address &lt;a class="headline-link" href="#configuring-a-static-ip-address" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To assign a fixed address, disable DHCP and set the address, gateway, and nameservers manually:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="yaml"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;/etc/netplan/99-custom.yaml&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-orange-100 text-orange-700 dark:bg-orange-900 dark:text-orange-300"&gt;yaml&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;networkd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ethernets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ens3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dhcp4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;192.168.1.50&lt;/span&gt;&lt;span class="l"&gt;/24&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;default&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;via&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;192.168.1.1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;nameservers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;addresses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;8.8.8.8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;1.1.1.1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The address uses CIDR notation, so &lt;code&gt;/24&lt;/code&gt; is the equivalent of the &lt;code&gt;255.255.255.0&lt;/code&gt; netmask. The &lt;code&gt;routes&lt;/code&gt; block replaces the deprecated &lt;code&gt;gateway4&lt;/code&gt; key that older guides still use. You can assign more than one address to an interface by adding extra lines under &lt;code&gt;addresses&lt;/code&gt;. For a focused walkthrough of static addressing on both Server and Desktop, see the dedicated guide on &lt;a href="https://linuxize.com/post/how-to-configure-static-ip-address-on-ubuntu-20-04/"&gt;setting a static IP address on Ubuntu&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="configuring-wi-fi"&gt;Configuring Wi-Fi &lt;a class="headline-link" href="#configuring-wi-fi" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On a desktop or laptop, Netplan can connect to a wireless network through the &lt;code&gt;wifis&lt;/code&gt; section. Ubuntu Desktop usually uses the NetworkManager renderer:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="yaml"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;/etc/netplan/99-custom.yaml&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-orange-100 text-orange-700 dark:bg-orange-900 dark:text-orange-300"&gt;yaml&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;NetworkManager&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;wifis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;wlp2s0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dhcp4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;access-points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;MyNetwork&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;your-wifi-password&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Replace &lt;code&gt;wlp2s0&lt;/code&gt; with your wireless interface name, &lt;code&gt;MyNetwork&lt;/code&gt; with the network SSID, and the password with your own.&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;The Wi-Fi password is stored in plain text inside the Netplan file. Keep the file permissions set to &lt;code&gt;600&lt;/code&gt;, and never commit Netplan files containing credentials to version control.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="creating-a-network-bridge"&gt;Creating a Network Bridge &lt;a class="headline-link" href="#creating-a-network-bridge" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A bridge joins several interfaces into one logical network, which is useful when you run virtual machines or containers that need direct access to the physical network. The example below creates a bridge named &lt;code&gt;br0&lt;/code&gt; that takes its address from DHCP and includes the physical interface &lt;code&gt;ens3&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="yaml"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;/etc/netplan/99-custom.yaml&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-orange-100 text-orange-700 dark:bg-orange-900 dark:text-orange-300"&gt;yaml&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;networkd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ethernets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ens3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dhcp4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;bridges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;br0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interfaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;ens3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dhcp4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice that the physical interface has DHCP disabled, because the bridge now owns the address rather than the interface itself.&lt;/p&gt;
&lt;h2 id="applying-the-configuration"&gt;Applying the Configuration &lt;a class="headline-link" href="#applying-the-configuration" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After editing a file, you can check it for syntax errors before doing anything to the live network. The &lt;code&gt;generate&lt;/code&gt; command builds the back-end configuration and reports any problems:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo netplan generate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When you connect over SSH, never run &lt;code&gt;netplan apply&lt;/code&gt; blindly, because a broken configuration can drop your connection. Use &lt;code&gt;netplan try&lt;/code&gt; instead, which applies the configuration temporarily and rolls back automatically if you do not confirm it within the timeout:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo netplan try&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the connection holds and the configuration is correct, confirm it at the prompt. Confirmation makes the tested configuration permanent, so you do not need to run &lt;code&gt;netplan apply&lt;/code&gt; afterward.&lt;/p&gt;
&lt;p&gt;When you are working from a local console and want to apply the configuration directly, run:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo netplan apply&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On recent Ubuntu releases you can review the resulting state, including addresses, routes, and DNS, with the &lt;code&gt;status&lt;/code&gt; command:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo netplan status&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Verify the assigned address directly with &lt;a href="https://linuxize.com/post/linux-ip-command/"&gt;&lt;code&gt;ip addr&lt;/code&gt;&lt;/a&gt;
:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip addr show dev ens3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Changes do not take effect after &lt;code&gt;netplan apply&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Run &lt;code&gt;sudo netplan generate&lt;/code&gt; and fix any YAML error it reports. If the file is valid, confirm that the interface name matches &lt;code&gt;ip link&lt;/code&gt;, then run &lt;code&gt;sudo netplan get&lt;/code&gt; to check whether a later file overrides your settings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The configuration warns that &lt;code&gt;gateway4&lt;/code&gt; is deprecated&lt;/strong&gt;&lt;br&gt;
Replace the &lt;code&gt;gateway4&lt;/code&gt; line with a &lt;code&gt;routes&lt;/code&gt; block that uses &lt;code&gt;to: default&lt;/code&gt; and &lt;code&gt;via: gateway_ip&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wi-Fi does not connect&lt;/strong&gt;&lt;br&gt;
Make sure the renderer is set to &lt;code&gt;NetworkManager&lt;/code&gt;, the SSID is quoted exactly, and the interface name matches the output of &lt;code&gt;ip link&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The static address reverts after a reboot on a cloud instance&lt;/strong&gt;&lt;br&gt;
Cloud images often regenerate Netplan files with cloud-init. Disable that by creating &lt;code&gt;/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg&lt;/code&gt; with the content &lt;code&gt;network: {config: disabled}&lt;/code&gt;, then reboot.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Netplan centralizes Ubuntu networking in a few readable YAML files, with &lt;code&gt;systemd-networkd&lt;/code&gt; driving servers and &lt;code&gt;NetworkManager&lt;/code&gt; driving desktops. When you edit these files over SSH, reach for &lt;code&gt;sudo netplan try&lt;/code&gt; first so a mistake rolls back on its own instead of cutting off your access.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/how-to-configure-networking-with-netplan-on-ubuntu/featured_hu_f49f70224b3f04eb.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>Docker Compose Cheatsheet</title><link>https://linuxize.com/cheatsheet/docker-compose/</link><pubDate>Wed, 15 Jul 2026 09:40:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/cheatsheet/docker-compose/</guid><description>Docker Compose quick reference: lifecycle commands, Compose file directives, health checks, environment variables, profiles, scaling, and cleanup.</description><content:encoded>&lt;div class="card"&gt;
&lt;h3 id="start--stop"&gt;Start &amp;amp; Stop &lt;a class="headline-link" href="#start--stop" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Bring services up and take them down.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/docker-compose/"&gt;&lt;code&gt;docker compose up&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Create and start all services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose up -d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start in background (detached)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose up -d --build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rebuild images before starting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose up -d service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start one service and its dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose up --wait&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Detach and wait until services are running or healthy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose stop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop services without removing them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start stopped services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose restart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Restart all services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose down&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop and remove containers and networks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose down -v&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Also remove project-owned named and anonymous volumes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="inspect--logs"&gt;Inspect &amp;amp; Logs &lt;a class="headline-link" href="#inspect--logs" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Check service status and output.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose ps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List running project containers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose ps -a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all project containers, including stopped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose logs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show logs for all services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose logs -f service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Follow logs for one service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose logs --tail 100 service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show last 100 log lines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose top&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Running processes per service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose events&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stream container events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose port service 80&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Host port mapped to container port 80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose ls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List running Compose projects&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="exec--run"&gt;Exec &amp;amp; Run &lt;a class="headline-link" href="#exec--run" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run commands inside service containers.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose exec service sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open shell in a running service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose exec service command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run command in a running service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose exec -u root service sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shell as a specific user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose run --rm service command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run a one-off container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose run --rm --no-deps service sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One-off without starting dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose cp service:/path ./local&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Copy from a service container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose cp ./local service:/path&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Copy into a service container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose attach service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Attach to a service&amp;rsquo;s output&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="build--images"&gt;Build &amp;amp; Images &lt;a class="headline-link" href="#build--images" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Build, pull, and push service images.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-build-docker-images-with-dockerfile/"&gt;&lt;code&gt;docker compose build&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Build all service images&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose build service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build one service image&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose build --no-cache&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build without layer cache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose pull&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pull service images&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose push&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Push service images to a registry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose images&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List images used by services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create containers without starting them&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose watch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sync files and rebuild on changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="compose-file-basics"&gt;Compose File Basics &lt;a class="headline-link" href="#compose-file-basics" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Core service directives in &lt;a href="https://linuxize.com/post/docker-compose/"&gt;docker-compose.yml&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;services:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Top-level map of containers to run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;image: postgres:16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run an existing image&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;build: .&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build from a Dockerfile in a path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;command: [&amp;quot;npm&amp;quot;, &amp;quot;run&amp;quot;, &amp;quot;dev&amp;quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Override the image default command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;entrypoint: [&amp;quot;/entrypoint.sh&amp;quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Override the image entrypoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ports: [&amp;quot;8080:80&amp;quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Publish host port 8080 to container port 80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;volumes: [&amp;quot;db_data:/var/lib/postgresql/data&amp;quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mount a named volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;environment: [&amp;quot;DEBUG=1&amp;quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set environment variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;env_file: .env.local&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Load variables from a file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;container_name: myapp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed container name (prevents scaling)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="health--startup-order"&gt;Health &amp;amp; Startup Order &lt;a class="headline-link" href="#health--startup-order" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Control dependency order and restart behavior.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directive&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;depends_on: [db]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start db before this service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;depends_on: {db: {condition: service_healthy}}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wait until db passes its health check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;healthcheck: {test: [&amp;quot;CMD&amp;quot;, &amp;quot;pg_isready&amp;quot;]}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Define a health probe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;interval&lt;/code&gt;, &lt;code&gt;timeout&lt;/code&gt;, &lt;code&gt;retries&lt;/code&gt;, &lt;code&gt;start_period&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Health check timing fields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;restart: &amp;quot;no&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Never restart (default)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;restart: always&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Always restart&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;restart: on-failure&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Restart on non-zero exit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;restart: unless-stopped&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Restart unless manually stopped&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="environment-variables"&gt;Environment Variables &lt;a class="headline-link" href="#environment-variables" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Pass configuration into services. Keep &lt;code&gt;.env&lt;/code&gt; files out of version control; use Compose secrets for sensitive data.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;environment: [&amp;quot;API_KEY=${API_KEY}&amp;quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Interpolate from the shell or &lt;code&gt;.env&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${VAR:-default}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use default when VAR is unset or empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${VAR:?message}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fail with message when VAR is unset or empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;env_file: .env.local&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Load variables from a specific file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Loaded automatically from the project directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose --env-file .env.prod up -d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use an alternate env file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Render final config with variables resolved&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="projects--files"&gt;Projects &amp;amp; Files &lt;a class="headline-link" href="#projects--files" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Compose looks for &lt;code&gt;compose.yaml&lt;/code&gt; first; &lt;code&gt;docker-compose.yml&lt;/code&gt; is still supported.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose -f compose.prod.yaml up -d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use a specific file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose -f base.yml -f override.yml up -d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Merge files; later files can add, merge, or override values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose -p myproject up -d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the project name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;COMPOSE_FILE=base.yml:override.yml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Default files via environment variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;COMPOSE_PROJECT_NAME=myproject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Default project name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Validate and print the merged config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose config --services&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List service names&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show Compose version&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="profiles--scaling"&gt;Profiles &amp;amp; Scaling &lt;a class="headline-link" href="#profiles--scaling" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run optional services and multiple replicas.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;profiles: [&amp;quot;debug&amp;quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Assign a service to a profile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose --profile debug up -d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start with a profile enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;COMPOSE_PROFILES=debug,test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable profiles via environment variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose up -d --scale worker=3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run 3 replicas of a service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose up -d --no-deps service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start or update one service without its dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose up -d --force-recreate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recreate containers even without changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3 id="cleanup"&gt;Cleanup &lt;a class="headline-link" href="#cleanup" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Remove what a project created.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose down&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove containers and networks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://linuxize.com/post/how-to-remove-docker-images-containers-volumes-and-networks/"&gt;&lt;code&gt;docker compose down -v&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Also remove project-owned named and anonymous volumes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose down --rmi all&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Also remove images&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose down --remove-orphans&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove containers for removed services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose rm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove stopped service containers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker compose stop service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop a single service&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</content:encoded></item><item><title>tree Command in Linux: Display Directory Structure</title><link>https://linuxize.com/post/tree-command-in-linux/</link><pubDate>Mon, 13 Jul 2026 08:40:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/tree-command-in-linux/</guid><category>linux commands</category><description>The tree command lists directories recursively as an indented tree. This guide covers installation, depth limits, filtering, sizes, and saving the output.</description><content:encoded>&lt;p&gt;The &lt;a href="https://linuxize.com/post/how-to-list-files-in-linux-using-the-ls-command/"&gt;&lt;code&gt;ls&lt;/code&gt; command&lt;/a&gt;
shows the contents of one directory at a time. When you want to see how a whole project is laid out, running &lt;code&gt;ls&lt;/code&gt; in every subdirectory gets old fast. The &lt;code&gt;tree&lt;/code&gt; command solves this by listing a directory and everything below it as an indented tree, so you can take in the entire hierarchy at a glance.&lt;/p&gt;
&lt;p&gt;This guide explains how to install &lt;code&gt;tree&lt;/code&gt; and use it to display directory structures, limit depth, filter files, show sizes, and save the output to a file.&lt;/p&gt;
&lt;h2 id="installing-tree"&gt;Installing tree &lt;a class="headline-link" href="#installing-tree" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;tree&lt;/code&gt; is a small utility that is not installed by default on most distributions, but it is available in the standard repositories.&lt;/p&gt;
&lt;p&gt;On Ubuntu, Debian, and derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install tree&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On Fedora, RHEL, and derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install tree&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Once installed, verify the version:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="basic-usage"&gt;Basic Usage &lt;a class="headline-link" href="#basic-usage" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The general syntax of the &lt;code&gt;tree&lt;/code&gt; command is as follows:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree [OPTIONS] [DIRECTORY]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When invoked without arguments, &lt;code&gt;tree&lt;/code&gt; lists the current directory recursively. For example, running it inside a small Node.js project produces output like this:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;.
├── package.json
├── README.md
└── src
├── app.js
└── utils
└── helpers.js
3 directories, 4 files&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each level of nesting is indented and connected with line-drawing characters, so &lt;code&gt;helpers.js&lt;/code&gt; is clearly inside &lt;code&gt;src/utils&lt;/code&gt;. The report line at the bottom counts everything in the listing, and since tree 2.1 that count includes the starting directory itself.&lt;/p&gt;
&lt;p&gt;To list a different directory, pass its path as an argument:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree /etc/nginx&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="limiting-the-depth"&gt;Limiting the Depth &lt;a class="headline-link" href="#limiting-the-depth" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On a large directory the default recursive listing can print thousands of lines. The &lt;code&gt;-L&lt;/code&gt; option limits how many levels deep &lt;code&gt;tree&lt;/code&gt; descends:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -L &lt;span class="m"&gt;2&lt;/span&gt; /var/log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With &lt;code&gt;-L 2&lt;/code&gt;, &lt;code&gt;tree&lt;/code&gt; shows the contents of &lt;code&gt;/var/log&lt;/code&gt; and one level of subdirectories, then stops. This is usually the first option to reach for when a plain &lt;code&gt;tree&lt;/code&gt; floods the terminal.&lt;/p&gt;
&lt;h2 id="showing-hidden-files"&gt;Showing Hidden Files &lt;a class="headline-link" href="#showing-hidden-files" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Like &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;tree&lt;/code&gt; skips hidden files by default. Use &lt;code&gt;-a&lt;/code&gt; to include entries that start with a dot:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -a&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;.
├── .env
├── .git
│ ├── config
│ └── HEAD
├── package.json
├── README.md
└── src
├── app.js
└── utils
└── helpers.js
4 directories, 7 files&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice that &lt;code&gt;.env&lt;/code&gt; and the &lt;code&gt;.git&lt;/code&gt; directory now show up in the listing. Combining &lt;code&gt;-a&lt;/code&gt; with &lt;code&gt;-L 1&lt;/code&gt; is a quick way to audit what actually lives in a directory, dotfiles included.&lt;/p&gt;
&lt;h2 id="listing-directories-only"&gt;Listing Directories Only &lt;a class="headline-link" href="#listing-directories-only" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you only care about the folder structure and not the files, use &lt;code&gt;-d&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;.
└── src
└── utils
3 directories&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The files are gone and only the directory skeleton remains, which is handy for documenting a project layout.&lt;/p&gt;
&lt;h2 id="displaying-file-sizes"&gt;Displaying File Sizes &lt;a class="headline-link" href="#displaying-file-sizes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-s&lt;/code&gt; option prints the size of each file in bytes. In practice you will almost always use &lt;code&gt;-h&lt;/code&gt; instead, which prints the sizes in human-readable units:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -h&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;[4.0K] .
├── [ 412] package.json
├── [1.2K] README.md
└── [4.0K] src
├── [3.4K] app.js
└── [4.0K] utils
└── [ 890] helpers.js
3 directories, 4 files&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The size shown next to a directory is the size of the directory entry itself, not its contents. To get cumulative directory sizes, add &lt;code&gt;--du&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree --du -h&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With &lt;code&gt;--du&lt;/code&gt;, each directory reports the total size of everything inside it, similar to the &lt;a href="https://linuxize.com/post/du-command-in-linux/"&gt;&lt;code&gt;du&lt;/code&gt; command&lt;/a&gt;
. This option reads the full hierarchy before printing, so it can take time and consume extra memory on a large directory tree.&lt;/p&gt;
&lt;h2 id="filtering-by-pattern"&gt;Filtering by Pattern &lt;a class="headline-link" href="#filtering-by-pattern" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-P&lt;/code&gt; option lists only files that match a wildcard pattern. Quote the pattern so the shell does not expand it first:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -P &lt;span class="s2"&gt;&amp;#34;*.js&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Directories are still shown even when they contain no matching files. Add &lt;code&gt;--prune&lt;/code&gt; to remove the empty branches:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -P &lt;span class="s2"&gt;&amp;#34;*.js&amp;#34;&lt;/span&gt; --prune&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;.
└── src
├── app.js
└── utils
└── helpers.js
3 directories, 2 files&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Only the JavaScript files and the directories that lead to them remain. The patterns follow the same rules as shell globs; see our guide to &lt;a href="https://linuxize.com/post/linux-wildcards-and-globbing/"&gt;Linux wildcards and globbing&lt;/a&gt;
for the full syntax.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-I&lt;/code&gt; option does the opposite and excludes matching entries. Multiple patterns are separated with &lt;code&gt;|&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -I &lt;span class="s2"&gt;&amp;#34;node_modules|.git&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is the most common &lt;code&gt;tree&lt;/code&gt; invocation in day-to-day work, since it hides the noise of dependency and VCS directories. In tree 2.0 and later you can also pass &lt;code&gt;--gitignore&lt;/code&gt; to skip everything that the project&amp;rsquo;s &lt;code&gt;.gitignore&lt;/code&gt; files exclude.&lt;/p&gt;
&lt;h2 id="printing-full-paths"&gt;Printing Full Paths &lt;a class="headline-link" href="#printing-full-paths" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default each entry shows only its own name. The &lt;code&gt;-f&lt;/code&gt; option prints the full path prefix instead:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -f src&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;src
├── src/app.js
└── src/utils
└── src/utils/helpers.js
2 directories, 2 files&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Full paths are useful in saved listings because each entry keeps its context even when you view the output away from the original directory.&lt;/p&gt;
&lt;h2 id="sorting-the-output"&gt;Sorting the Output &lt;a class="headline-link" href="#sorting-the-output" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Entries are sorted alphabetically by default. The most useful alternatives are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-t&lt;/code&gt; - Sort by last modification time, oldest first.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-r&lt;/code&gt; - Reverse the current sort order.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt; - Sort version strings naturally, so &lt;code&gt;file2&lt;/code&gt; comes before &lt;code&gt;file10&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--sort=size&lt;/code&gt; - Sort by file size.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that &lt;code&gt;-t&lt;/code&gt; places the oldest entries first, which is the opposite of what &lt;code&gt;ls -t&lt;/code&gt; does. To see the most recently modified files at the top of each directory, combine it with &lt;code&gt;-r&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -t -r&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="saving-the-output-to-a-file"&gt;Saving the Output to a File &lt;a class="headline-link" href="#saving-the-output-to-a-file" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;-o&lt;/code&gt; option writes the tree to a file instead of the terminal:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -o structure.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The line-drawing characters are UTF-8 by default. If the file is destined for an environment that cannot render them, force plain ASCII connectors:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree --charset&lt;span class="o"&gt;=&lt;/span&gt;ascii -o structure.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;tree&lt;/code&gt; can also emit structured formats directly: &lt;code&gt;-J&lt;/code&gt; produces JSON, &lt;code&gt;-X&lt;/code&gt; produces XML, and &lt;code&gt;-H &amp;lt;baseHref&amp;gt;&lt;/code&gt; produces a browsable HTML listing:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tree -J -L &lt;span class="m"&gt;2&lt;/span&gt; &amp;gt; structure.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tree&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List the current directory recursively&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tree -L 2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limit the listing to two levels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tree -a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Include hidden files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tree -d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Directories only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tree -h --du&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Human-readable cumulative sizes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tree -P &amp;quot;*.js&amp;quot; --prune&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only files matching a pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tree -I &amp;quot;node_modules|.git&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exclude matching entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tree -f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Print full paths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tree -o file.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Write the output to a file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tree -J&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Output JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;tree&lt;/code&gt; command turns a nested directory hierarchy into a single readable listing, and options such as &lt;code&gt;-L&lt;/code&gt;, &lt;code&gt;-I&lt;/code&gt;, and &lt;code&gt;--du&lt;/code&gt; keep the output focused on what you actually need. If you want the same tree-style view for running processes instead of files, take a look at the &lt;a href="https://linuxize.com/post/pstree-command-in-linux/"&gt;pstree command&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/tree-command-in-linux/featured_hu_a9fffca12294665e.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>How to Encrypt and Decrypt Files with GPG</title><link>https://linuxize.com/post/how-to-encrypt-and-decrypt-files-with-gpg/</link><pubDate>Sun, 12 Jul 2026 11:30:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/how-to-encrypt-and-decrypt-files-with-gpg/</guid><category>security</category><description>Encrypt files with GPG using a passphrase or a key pair, share encrypted files with other people, protect whole directories, and decrypt safely in scripts.</description><content:encoded>&lt;p&gt;Sooner or later you end up with a file that should not sit around in plain text: a database dump with customer data, a document with credentials, or a backup you want to park on cloud storage you do not fully trust. Encrypting the file before it leaves your machine solves the problem, and GPG is the standard tool for the job on Linux.&lt;/p&gt;
&lt;p&gt;GnuPG (GNU Privacy Guard), invoked as &lt;code&gt;gpg&lt;/code&gt;, implements the OpenPGP standard. It supports two ways of encrypting a file: symmetric encryption, where a single passphrase both locks and unlocks the file, and public key encryption, where anyone can encrypt a file for you but only your private key can decrypt it.&lt;/p&gt;
&lt;p&gt;This guide explains how to encrypt and decrypt files with &lt;code&gt;gpg&lt;/code&gt; using both methods, how to exchange encrypted files with other people, and how to handle encryption in scripts.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Encrypt with a passphrase&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpg -c file&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrypt to a file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpg -o file -d file.gpg&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generate a key pair&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpg --full-generate-key&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List public keys&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpg --list-keys&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Export your public key&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpg --armor --export you@example.com &amp;gt; public.asc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Import someone&amp;rsquo;s public key&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpg --import public.asc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encrypt for a recipient&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpg -e -r name@example.com file&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sign and encrypt&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpg -s -e -r name@example.com file&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encrypt a directory&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tar czf - dir | gpg -c -o dir.tar.gz.gpg&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decrypt a directory&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gpg -d dir.tar.gz.gpg | tar xzf -&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="installing-gnupg"&gt;Installing GnuPG &lt;a class="headline-link" href="#installing-gnupg" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;GnuPG is preinstalled on nearly all Linux distributions because the package managers themselves depend on it. Verify that it is available:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;gpg (GnuPG) 2.4.4
libgcrypt 1.10.3&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Your version numbers may differ, but any current GnuPG 2.x release supports the commands used in this guide.&lt;/p&gt;
&lt;p&gt;If the command is missing, install the &lt;code&gt;gnupg&lt;/code&gt; package with &lt;code&gt;sudo apt install gnupg&lt;/code&gt; on Ubuntu, Debian, and Derivatives, or &lt;code&gt;sudo dnf install gnupg2&lt;/code&gt; on Fedora, RHEL, and Derivatives.&lt;/p&gt;
&lt;h2 id="encrypting-a-file-with-a-passphrase"&gt;Encrypting a File with a Passphrase &lt;a class="headline-link" href="#encrypting-a-file-with-a-passphrase" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Symmetric encryption is the simplest option: one passphrase encrypts the file, and the same passphrase decrypts it. There are no keys to generate or exchange, which makes it a good fit for encrypting your own backups or sending a file to someone you can share a passphrase with over a separate channel.&lt;/p&gt;
&lt;p&gt;Use the &lt;code&gt;-c&lt;/code&gt; (&lt;code&gt;--symmetric&lt;/code&gt;) option:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg -c database-backup.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;gpg&lt;/code&gt; prompts for a passphrase, asks you to repeat it, and writes the encrypted result to &lt;code&gt;database-backup.sql.gpg&lt;/code&gt;. The original file is left in place. Before removing it, decrypt the encrypted copy to a temporary file and compare the two files:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg -o /tmp/database-backup.sql -d database-backup.sql.gpg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cmp database-backup.sql /tmp/database-backup.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;cmp&lt;/code&gt; command prints nothing when the files are identical. After a successful comparison, remove the temporary copy and the original plaintext file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm /tmp/database-backup.sql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm database-backup.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Pick a long passphrase. The encryption is only as strong as the passphrase protecting it, and a short or reused one undoes the benefit of encrypting at all.&lt;/p&gt;
&lt;p&gt;By default the output is a binary file. If you need to paste the encrypted content into an email or a ticket, add &lt;code&gt;-a&lt;/code&gt; (&lt;code&gt;--armor&lt;/code&gt;) to produce ASCII text instead:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg -c -a notes.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This writes &lt;code&gt;notes.txt.asc&lt;/code&gt;, a plain text file that survives copy and paste. You can also choose the cipher explicitly with &lt;code&gt;--cipher-algo AES256&lt;/code&gt; if a policy requires a specific algorithm; run &lt;code&gt;gpg --version&lt;/code&gt; to see which ciphers your build supports.&lt;/p&gt;
&lt;h2 id="decrypting-a-file"&gt;Decrypting a File &lt;a class="headline-link" href="#decrypting-a-file" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To decrypt, pass the encrypted file to &lt;code&gt;gpg&lt;/code&gt; with &lt;code&gt;-d&lt;/code&gt; (&lt;code&gt;--decrypt&lt;/code&gt;) and use &lt;code&gt;-o&lt;/code&gt; to name the output file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg -o database-backup.sql -d database-backup.sql.gpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;gpg&lt;/code&gt; asks for the passphrase and writes the decrypted file. Without &lt;code&gt;-o&lt;/code&gt;, the &lt;code&gt;-d&lt;/code&gt; option prints the decrypted content to standard output, which is useful when you only want to look at a small encrypted text file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg -d notes.txt.asc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you decrypt the same file again a moment later, you may not be prompted for the passphrase. That is not a bug: &lt;code&gt;gpg-agent&lt;/code&gt; caches passphrases for a few minutes. To clear the cache immediately, reload the agent:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg-connect-agent reloadagent /bye&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="generating-a-gpg-key-pair"&gt;Generating a GPG Key Pair &lt;a class="headline-link" href="#generating-a-gpg-key-pair" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Public key encryption removes the shared-passphrase problem. You publish your public key, anyone can use it to encrypt files for you, and only your private key can decrypt them. The private key never leaves your machine.&lt;/p&gt;
&lt;p&gt;Generate a key pair with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg --full-generate-key&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The command walks you through a few prompts: the key type (the default is fine), the expiration date, and your name and email address. Finally, it asks for a passphrase that protects the private key on disk. When the process finishes, list your keys to confirm:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg --list-keys&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;pub ed25519 2026-01-01 [SC] [expires: 2029-01-01]
1A2B3C4D5E6F7A8B9C0D1E2F3A4B5C6D7E8F9A0B
uid [ultimate] Alice Example &amp;lt;alice@example.com&amp;gt;
sub cv25519 2026-01-01 [E] [expires: 2029-01-01]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The long hexadecimal string is the key fingerprint. It uniquely identifies the key, and other people use it to verify that a key really belongs to you.&lt;/p&gt;
&lt;h2 id="exchanging-public-keys"&gt;Exchanging Public Keys &lt;a class="headline-link" href="#exchanging-public-keys" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To let someone encrypt files for you, export your public key in ASCII format and send it to them:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg --armor --export alice@example.com &amp;gt; alice-public.asc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When you receive a public key from someone else, import it into your keyring:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg --import bob-public.asc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;gpg: key 9F8E7D6C5B4A3F2E: public key &amp;#34;Bob Example &amp;lt;bob@example.com&amp;gt;&amp;#34; imported
gpg: Total number processed: 1
gpg: imported: 1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before you trust an imported key, compare its fingerprint with the owner over a separate channel, such as a video call or an already-verified chat:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg --fingerprint bob@example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If the fingerprints match, you can certify the key so &lt;code&gt;gpg&lt;/code&gt; stops warning you about it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg --sign-key bob@example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="encrypting-a-file-for-a-recipient"&gt;Encrypting a File for a Recipient &lt;a class="headline-link" href="#encrypting-a-file-for-a-recipient" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the recipient&amp;rsquo;s public key imported, encrypt a file for them using &lt;code&gt;-e&lt;/code&gt; (&lt;code&gt;--encrypt&lt;/code&gt;) and &lt;code&gt;-r&lt;/code&gt; (&lt;code&gt;--recipient&lt;/code&gt;):&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg -e -r bob@example.com report.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This writes &lt;code&gt;report.pdf.gpg&lt;/code&gt;, which only Bob&amp;rsquo;s private key can decrypt. If you have not certified Bob&amp;rsquo;s key yet, &lt;code&gt;gpg&lt;/code&gt; shows a warning:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;gpg: 9F8E7D6C5B4A3F2E: There is no assurance this key belongs to the named user
Use this key anyway? (y/N)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Answer &lt;code&gt;y&lt;/code&gt; only if you have verified the fingerprint as described above. To silence the warning permanently, certify the key with &lt;code&gt;--sign-key&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can name several recipients, and each of them will be able to decrypt the same file. Include yourself if you want to keep a readable copy:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg -e -r bob@example.com -r alice@example.com report.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Without &lt;code&gt;-r alice@example.com&lt;/code&gt; in that command, even you, the person who encrypted the file, could not decrypt the result.&lt;/p&gt;
&lt;h2 id="signing-and-verifying-encrypted-files"&gt;Signing and Verifying Encrypted Files &lt;a class="headline-link" href="#signing-and-verifying-encrypted-files" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Encryption hides the content, but it does not prove who created the file. Anyone with Bob&amp;rsquo;s public key can encrypt a file for him. Adding a signature with &lt;code&gt;-s&lt;/code&gt; (&lt;code&gt;--sign&lt;/code&gt;) closes that gap:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg -s -u alice@example.com -e -r bob@example.com report.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-u&lt;/code&gt; (&lt;code&gt;--local-user&lt;/code&gt;) option selects Alice&amp;rsquo;s signing key explicitly, which matters if you have more than one private key. &lt;code&gt;gpg&lt;/code&gt; asks for the private key passphrase, then signs and encrypts in one pass. When Bob decrypts the file, &lt;code&gt;gpg&lt;/code&gt; verifies the signature automatically:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg -o report.pdf -d report.pdf.gpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;gpg: encrypted with cv25519 key, ID 9F8E7D6C5B4A3F2E, created 2026-01-01
&amp;#34;Bob Example &amp;lt;bob@example.com&amp;gt;&amp;#34;
gpg: Signature made Thu 01 Jan 2026 11:42:10 CET
gpg: using EDDSA key 1A2B3C4D5E6F7A8B9C0D1E2F3A4B5C6D7E8F9A0B
gpg: Good signature from &amp;#34;Alice Example &amp;lt;alice@example.com&amp;gt;&amp;#34; [full]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Good signature&lt;/code&gt; line confirms both that the file came from Alice and that it was not modified after signing. If the file was altered in transit, &lt;code&gt;gpg&lt;/code&gt; reports a bad signature instead. For verifying plain downloads rather than encrypted files, checksums are often enough; see our guide on the &lt;a href="https://linuxize.com/post/sha256sum-and-md5sum-commands/"&gt;sha256sum and md5sum commands&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="encrypting-a-directory"&gt;Encrypting a Directory &lt;a class="headline-link" href="#encrypting-a-directory" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;gpg&lt;/code&gt; encrypts single files, not directories. The usual pattern is to pack the directory with &lt;a href="https://linuxize.com/post/how-to-create-and-extract-archives-using-the-tar-command-in-linux/"&gt;&lt;code&gt;tar&lt;/code&gt;&lt;/a&gt;
and encrypt the archive in one pipeline:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tar czf - project/ &lt;span class="p"&gt;|&lt;/span&gt; gpg -c -o project.tar.gz.gpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;tar&lt;/code&gt; command writes a compressed archive to standard output, and &lt;code&gt;gpg&lt;/code&gt; encrypts the stream into &lt;code&gt;project.tar.gz.gpg&lt;/code&gt; without ever writing an unencrypted archive to disk.&lt;/p&gt;
&lt;p&gt;To restore the directory, reverse the pipeline:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg -d project.tar.gz.gpg &lt;span class="p"&gt;|&lt;/span&gt; tar xzf -&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The same pattern works with &lt;code&gt;-e -r name@example.com&lt;/code&gt; in place of &lt;code&gt;-c&lt;/code&gt; when you are encrypting the archive for someone else.&lt;/p&gt;
&lt;h2 id="decrypting-in-scripts"&gt;Decrypting in Scripts &lt;a class="headline-link" href="#decrypting-in-scripts" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Backup jobs and deploy scripts cannot type a passphrase interactively. For those cases, store the passphrase in a file and point &lt;code&gt;gpg&lt;/code&gt; at it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gpg --batch --yes --pinentry-mode loopback &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --passphrase-file /root/.backup-pass &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -o backup.sql -d backup.sql.gpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;--batch&lt;/code&gt; option disables all interactive prompts, &lt;code&gt;--yes&lt;/code&gt; overwrites the output file if it exists, and &lt;code&gt;--pinentry-mode loopback&lt;/code&gt; allows the passphrase to come from the file instead of the interactive pinentry dialog. GPG reads only the first line of the passphrase file. The same options work with &lt;code&gt;-c&lt;/code&gt; for encrypting.&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;A passphrase file is a credential. Restrict it with &lt;code&gt;chmod 600&lt;/code&gt;, keep it outside your repository, and add it to &lt;code&gt;.gitignore&lt;/code&gt; so it never lands in version control. Avoid passphrase files when public key encryption fits the job. Scripts need no passphrase to encrypt with &lt;code&gt;-e -r&lt;/code&gt; because that operation uses only the recipient&amp;rsquo;s public key.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;gpg: decryption failed: No secret key&lt;/strong&gt;&lt;br&gt;
The file was encrypted for a key that is not in your keyring. This often happens when someone encrypts a file with their own key instead of yours, or when you moved to a new machine without migrating your private key. Run &lt;code&gt;gpg --list-packets file.gpg | head&lt;/code&gt; to see which key ID the file was encrypted for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;gpg: public key decryption failed: Inappropriate ioctl for device&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;gpg&lt;/code&gt; could not open a passphrase prompt, which is common over SSH or in minimal shells. Tell it which terminal to use and retry:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;GPG_TTY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;tty&lt;span class="k"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Add the line to &lt;code&gt;~/.bashrc&lt;/code&gt; to make it permanent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;gpg does not ask for the passphrase&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;gpg-agent&lt;/code&gt; has cached it. This is expected behavior; run &lt;code&gt;gpg-connect-agent reloadagent /bye&lt;/code&gt; to clear the cache, for example before stepping away from a shared machine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no assurance this key belongs to the named user&lt;/strong&gt;&lt;br&gt;
The recipient&amp;rsquo;s key is imported but not certified. Verify the fingerprint with the owner, then run &lt;code&gt;gpg --sign-key name@example.com&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;gpg -c&lt;/code&gt; with a strong passphrase when you are protecting your own files, and key-based encryption with &lt;code&gt;-e -r&lt;/code&gt; when files move between people, adding &lt;code&gt;-s&lt;/code&gt; when the recipient needs proof of who sent them. For TLS certificates and encrypting data in transit rather than files at rest, see our guide on &lt;a href="https://linuxize.com/post/how-to-use-openssl/"&gt;how to use OpenSSL&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/how-to-encrypt-and-decrypt-files-with-gpg/featured_hu_faa33d9e092f6f3c.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>strace Command in Linux: Trace System Calls</title><link>https://linuxize.com/post/strace-command-in-linux/</link><pubDate>Sat, 11 Jul 2026 10:15:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/strace-command-in-linux/</guid><category>linux commands</category><description>Use the strace command to trace system calls and signals on Linux, debug why a program fails, find missing files, and measure where a process spends its time.</description><content:encoded>&lt;p&gt;A program exits with a vague error, or hangs, and the logs say nothing useful. Before guessing, you can watch exactly what the program asks the kernel to do. Every time a process opens a file, reads a socket, or allocates memory, it makes a system call, and &lt;code&gt;strace&lt;/code&gt; records each one along with its arguments and return value. That trace often reveals the real problem in seconds: a config file the program looked for in the wrong place, a permission denied on a socket, or a call that blocks forever.&lt;/p&gt;
&lt;p&gt;This guide explains how to trace a command with &lt;code&gt;strace&lt;/code&gt;, attach to a running process, filter the calls you care about, and read the output to find the failing call.&lt;/p&gt;
&lt;h2 id="installing-strace"&gt;Installing strace &lt;a class="headline-link" href="#installing-strace" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;strace&lt;/code&gt; is not always installed by default, so add it from your distribution&amp;rsquo;s repositories.&lt;/p&gt;
&lt;p&gt;On Ubuntu, Debian, and Derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install strace&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On Fedora, RHEL, and Derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install strace&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="tracing-a-command"&gt;Tracing a Command &lt;a class="headline-link" href="#tracing-a-command" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The general syntax is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strace [OPTIONS] COMMAND [ARGS]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The simplest use is to run a command under &lt;code&gt;strace&lt;/code&gt;, which prints every system call the program makes to standard error. Trace a small command such as &lt;code&gt;whoami&lt;/code&gt; to see the shape of the output:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strace whoami&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;execve(&amp;#34;/usr/bin/whoami&amp;#34;, [&amp;#34;whoami&amp;#34;], 0x7ffd... /* 25 vars */) = 0
brk(NULL) = 0x55d3...
openat(AT_FDCWD, &amp;#34;/etc/ld.so.cache&amp;#34;, O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, &amp;#34;/lib/x86_64-linux-gnu/libc.so.6&amp;#34;, O_RDONLY|O_CLOEXEC) = 3
...
openat(AT_FDCWD, &amp;#34;/etc/passwd&amp;#34;, O_RDONLY|O_CLOEXEC) = 3
write(1, &amp;#34;dejan\n&amp;#34;, 6) = 6
exit_group(0) = ?
+++ exited with 0 +++&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each line is one system call: the name, its arguments in parentheses, and the return value after the &lt;code&gt;=&lt;/code&gt;. A return of &lt;code&gt;3&lt;/code&gt; from &lt;code&gt;openat&lt;/code&gt; is a file descriptor, meaning the open succeeded; a return of &lt;code&gt;-1&lt;/code&gt; carries an error name such as &lt;code&gt;ENOENT&lt;/code&gt;. Notice the program opened &lt;code&gt;/etc/passwd&lt;/code&gt; to look up the user name, then &lt;code&gt;write&lt;/code&gt; sent the result to file descriptor 1, which is standard output.&lt;/p&gt;
&lt;h2 id="reading-failed-calls"&gt;Reading Failed Calls &lt;a class="headline-link" href="#reading-failed-calls" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The reason to reach for &lt;code&gt;strace&lt;/code&gt; is usually a failure, and failures are easy to spot because the return value is &lt;code&gt;-1&lt;/code&gt; followed by the error code. Suppose a program cannot start and you trace it:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strace ./myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A failing line looks like this:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;openat(AT_FDCWD, &amp;#34;/etc/myapp/config.yaml&amp;#34;, O_RDONLY) = -1 ENOENT (No such file or directory)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This single line tells you the program expected its config at &lt;code&gt;/etc/myapp/config.yaml&lt;/code&gt; and the file is not there. A &lt;code&gt;-1 EACCES&lt;/code&gt; instead would mean the file exists but the process lacks permission. For a short trace, scan for &lt;code&gt;-1&lt;/code&gt; to find failed calls. With a noisy program, use &lt;code&gt;-Z&lt;/code&gt; to print only calls that returned an error:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strace -Z ./myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Not every failed call is the root cause. Programs commonly probe several paths before finding a file, so read the calls around the failure and look for the last relevant error before the program exits.&lt;/p&gt;
&lt;h2 id="filtering-the-calls-you-care-about"&gt;Filtering the Calls You Care About &lt;a class="headline-link" href="#filtering-the-calls-you-care-about" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A full trace is noisy. When you only care about file access, limit the trace to the relevant calls with &lt;code&gt;-e trace=&lt;/code&gt;. To see just the file-opening calls, trace &lt;code&gt;openat&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strace -e &lt;span class="nv"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openat ./myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can name a category instead of individual calls. The &lt;code&gt;%file&lt;/code&gt; category covers every call that takes a filename, and &lt;code&gt;%network&lt;/code&gt; covers network-related calls:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strace -e &lt;span class="nv"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%file ./myapp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strace -e &lt;span class="nv"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%network ./myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This focus turns a flood of output into the handful of lines that matter for the question you are asking.&lt;/p&gt;
&lt;h2 id="attaching-to-a-running-process"&gt;Attaching to a Running Process &lt;a class="headline-link" href="#attaching-to-a-running-process" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a process is already running, perhaps stuck or pinning the CPU, attach to it by PID with &lt;code&gt;-p&lt;/code&gt; instead of starting a new program. First find the PID with the &lt;a href="https://linuxize.com/post/ps-command-in-linux/"&gt;ps command&lt;/a&gt;
, then attach:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo strace -p &lt;span class="m"&gt;2841&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;strace&lt;/code&gt; begins printing the calls the live process makes from that moment on. You may not need &lt;code&gt;sudo&lt;/code&gt; when the process belongs to your user, but Linux capabilities and the &lt;code&gt;kernel.yama.ptrace_scope&lt;/code&gt; setting can impose additional restrictions. Press &lt;code&gt;Ctrl+C&lt;/code&gt; to detach and leave the process running. For a hung process, attaching usually shows it parked in a single blocking call such as &lt;code&gt;read&lt;/code&gt; or &lt;code&gt;futex&lt;/code&gt;, which points straight at what it is waiting for.&lt;/p&gt;
&lt;h2 id="following-child-processes"&gt;Following Child Processes &lt;a class="headline-link" href="#following-child-processes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default &lt;code&gt;strace&lt;/code&gt; follows only the process it started. Programs that fork workers, such as shells or servers, do their real work in children that the trace would miss. Add &lt;code&gt;-f&lt;/code&gt; to follow forks so the children are traced too:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strace -f ./server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Each line is then prefixed with the PID that made the call, so you can tell the parent and its children apart.&lt;/p&gt;
&lt;h2 id="summarizing-system-call-time"&gt;Summarizing System Call Time &lt;a class="headline-link" href="#summarizing-system-call-time" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Beyond individual calls, &lt;code&gt;strace&lt;/code&gt; can profile where a program spends its time in the kernel. The &lt;code&gt;-c&lt;/code&gt; flag suppresses the per-call output and prints a summary table when the program exits:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strace -c ./myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
41.23 0.004812 18 267 read
22.10 0.002579 10 251 12 openat
15.04 0.001755 14 125 mmap
...
------ ----------- ----------- --------- --------- ----------------
100.00 0.011670 843 14 total&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The table ranks system calls by total time, shows how many times each was called, and counts how many returned an error. The 12 &lt;code&gt;openat&lt;/code&gt; errors show that some file lookups failed, but programs often probe optional paths as part of normal operation. Inspect the individual calls before treating the count as a problem.&lt;/p&gt;
&lt;h2 id="saving-a-trace-to-a-file"&gt;Saving a Trace to a File &lt;a class="headline-link" href="#saving-a-trace-to-a-file" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Traces scroll fast, so for anything non-trivial write the output to a file with &lt;code&gt;-o&lt;/code&gt; and read it afterward:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strace -o trace.log -f ./myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This keeps &lt;code&gt;strace&lt;/code&gt; output separate from the program&amp;rsquo;s own output and gives you a file to grep, for example &lt;code&gt;grep ENOENT trace.log&lt;/code&gt; to list every missing-file error at once.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Trace a command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;strace ./app&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trace only failed calls&lt;/td&gt;
&lt;td&gt;&lt;code&gt;strace -Z ./app&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trace only file calls&lt;/td&gt;
&lt;td&gt;&lt;code&gt;strace -e trace=%file ./app&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trace network calls&lt;/td&gt;
&lt;td&gt;&lt;code&gt;strace -e trace=%network ./app&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attach to a running process&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo strace -p PID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow child processes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;strace -f ./app&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Summarize call time and errors&lt;/td&gt;
&lt;td&gt;&lt;code&gt;strace -c ./app&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write trace to a file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;strace -o trace.log ./app&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use focused filters and read the calls around a failure instead of treating every error as the cause. For another view of open files and sockets on a running process, use the &lt;a href="https://linuxize.com/post/lsof-command-in-linux/"&gt;lsof command&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/strace-command-in-linux/featured_hu_1ce61c076380bd34.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>How to Manage Node.js Processes with PM2</title><link>https://linuxize.com/post/how-to-manage-nodejs-processes-with-pm2/</link><pubDate>Fri, 10 Jul 2026 09:20:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/how-to-manage-nodejs-processes-with-pm2/</guid><category>nodejs</category><category>linux commands</category><description>How to install PM2, run and manage Node.js processes with clustering, zero-downtime reloads, log rotation, and systemd integration that survives reboots.</description><content:encoded>&lt;p&gt;A Node.js app can run fine with &lt;code&gt;node app.js&lt;/code&gt; during development, but production needs something that can restart crashes, collect logs, and come back after a reboot. A single Node.js process runs one event loop, so busy services can hit a single-process ceiling before the server itself is out of capacity. PM2 is a Node.js process manager that covers those operational pieces: it restarts crashed apps, captures stdout and stderr into rotated log files, runs networked apps in cluster mode across CPU cores, and survives a reboot through a systemd unit. The CLI is short enough to learn in an afternoon, and it covers everything from local development to a multi-server fleet.&lt;/p&gt;
&lt;p&gt;This guide explains how to install PM2 on Linux, start and manage Node.js processes, set up clustering for multi-core servers, and persist the process list across reboots.&lt;/p&gt;
&lt;h2 id="install-pm2"&gt;Install PM2 &lt;a class="headline-link" href="#install-pm2" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PM2 is published as an npm package. PM2 7 requires Node.js 18 or newer. With Node.js already installed, add PM2 globally:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo npm install -g pm2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If your projects use pnpm, &lt;code&gt;pnpm add -g pm2&lt;/code&gt; installs the same package. See the &lt;a href="https://linuxize.com/post/pnpm-command/"&gt;pnpm command guide&lt;/a&gt;
for its global install setup.&lt;/p&gt;
&lt;p&gt;Confirm the version:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;7.0.3&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;pm2&lt;/code&gt; command is now on &lt;code&gt;$PATH&lt;/code&gt; for every user. PM2 stores per-user state under &lt;code&gt;~/.pm2&lt;/code&gt;, so each Linux user has an isolated process list, log directory, and pid file.&lt;/p&gt;
&lt;h2 id="start-an-application"&gt;Start an Application &lt;a class="headline-link" href="#start-an-application" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The simplest invocation starts a single Node.js process and gives it a name you can refer to later:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 start app.js --name myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;[PM2] Starting /home/sara/myapp/app.js in fork_mode (1 instance)
[PM2] Done.
┌────┬───────┬─────────┬───────┬──────┬──────────┬────────┐
│ id │ name │ mode │ pid │ ↺ │ status │ cpu │
├────┼───────┼─────────┼───────┼──────┼──────────┼────────┤
│ 0 │ myapp │ fork │ 12345 │ 0 │ online │ 0% │
└────┴───────┴─────────┴───────┴──────┴──────────┴────────┘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;--name&lt;/code&gt; flag is optional but worth setting on every start: PM2 falls back to the script filename otherwise, and &amp;ldquo;myapp&amp;rdquo; is easier to type than &amp;ldquo;server&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pm2 start&lt;/code&gt; also accepts npm scripts. If your &lt;code&gt;package.json&lt;/code&gt; has &lt;code&gt;&amp;quot;start&amp;quot;: &amp;quot;node app.js&amp;quot;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 start npm --name myapp -- start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;--&lt;/code&gt; separator is required so PM2 stops parsing flags and passes the remainder to npm.&lt;/p&gt;
&lt;h2 id="inspect-processes"&gt;Inspect Processes &lt;a class="headline-link" href="#inspect-processes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pm2 ls&lt;/code&gt; (or &lt;code&gt;pm2 list&lt;/code&gt;) prints the current process table:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 ls&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;┌────┬─────────┬─────────┬─────────┬─────────┬──────────┬────────┐
│ id │ name │ mode │ pid │ uptime │ status │ memory │
├────┼─────────┼─────────┼─────────┼─────────┼──────────┼────────┤
│ 0 │ myapp │ fork │ 12345 │ 3m │ online │ 64.0mb │
│ 1 │ worker │ fork │ 12346 │ 1m │ online │ 42.0mb │
└────┴─────────┴─────────┴─────────┴─────────┴──────────┴────────┘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For per-process detail, including environment variables, restart count, and log paths, ask for a detailed view:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 show myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The output also reports the script path, the working directory, and the last few exit codes, which together cover most &amp;ldquo;why is it restarting&amp;rdquo; investigations.&lt;/p&gt;
&lt;h2 id="read-logs"&gt;Read Logs &lt;a class="headline-link" href="#read-logs" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PM2 captures stdout and stderr into log files under &lt;code&gt;~/.pm2/logs&lt;/code&gt;. The streaming view is the fastest way to see what is happening right now:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 logs myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;0|myapp | App listening on http://127.0.0.1:3000
0|myapp | request from 127.0.0.1 GET /&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The prefix combines the PM2 id with the app name, which matters in cluster mode where multiple instances share a name. Add &lt;code&gt;--lines 100&lt;/code&gt; to start from the last 100 lines, or &lt;code&gt;--err&lt;/code&gt; to tail only stderr.&lt;/p&gt;
&lt;p&gt;For long-lived apps, install the log rotation module:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 install pm2-logrotate
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 &lt;span class="nb"&gt;set&lt;/span&gt; pm2-logrotate:max_size 10M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 &lt;span class="nb"&gt;set&lt;/span&gt; pm2-logrotate:retain &lt;span class="m"&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The settings cap each log file at 10 MB and keep seven rotated copies, which is enough to investigate problems without filling the disk.&lt;/p&gt;
&lt;h2 id="restart-reload-and-stop"&gt;Restart, Reload, and Stop &lt;a class="headline-link" href="#restart-reload-and-stop" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Three verbs cover most lifecycle work:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 restart myapp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 reload myapp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 stop myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;restart&lt;/code&gt; kills and respawns the process. It is the fastest option but drops in-flight requests.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;reload&lt;/code&gt; is the zero-downtime variant. PM2 starts the new process, waits until it reports ready, and only then terminates the old one. It only works in cluster mode (more below), so the listening socket can be passed across processes.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;stop&lt;/code&gt; shuts the process down but keeps the entry in the table, so a later &lt;code&gt;pm2 start myapp&lt;/code&gt; brings it back without re-typing the script path. To remove the entry completely, use &lt;code&gt;pm2 delete myapp&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="run-in-cluster-mode"&gt;Run in Cluster Mode &lt;a class="headline-link" href="#run-in-cluster-mode" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A single Node.js process runs one event loop. On multi-core servers, PM2&amp;rsquo;s cluster mode forks the application into multiple processes that share the listening socket:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 start app.js -i &lt;span class="m"&gt;4&lt;/span&gt; --name myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Pass &lt;code&gt;max&lt;/code&gt; instead of a number to spawn one process per logical CPU:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 start app.js -i max --name myapp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Cluster mode requires the application to handle being one of several processes. Most HTTP frameworks (Express, Fastify, Koa) work out of the box because Node.js handles the socket distribution. Code that uses in-process state (counters, caches, WebSocket session maps) needs an external store such as Redis or a sticky-session mechanism for the cluster to behave correctly.&lt;/p&gt;
&lt;h2 id="manage-multiple-apps-with-an-ecosystem-file"&gt;Manage Multiple Apps with an Ecosystem File &lt;a class="headline-link" href="#manage-multiple-apps-with-an-ecosystem-file" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For more than a single app, switch from CLI flags to a configuration file:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 ecosystem&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The command writes &lt;code&gt;ecosystem.config.js&lt;/code&gt; in the current directory. Edit it to list your apps:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="js"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;ecosystem.config.js&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-yellow-100 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-300"&gt;js&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;apps&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;api&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./api/server.js&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;max&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;exec_mode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cluster&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;production&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;worker&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./worker/index.js&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;production&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Start everything at once:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 start ecosystem.config.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The file is the right place to record per-environment overrides, log paths, memory limits (&lt;code&gt;max_memory_restart: &amp;quot;512M&amp;quot;&lt;/code&gt;), and cron-style restart schedules. Commit it alongside the application.&lt;/p&gt;
&lt;h2 id="survive-a-reboot"&gt;Survive a Reboot &lt;a class="headline-link" href="#survive-a-reboot" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PM2 does not start itself at boot. To make it do so, generate a systemd unit:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 startup systemd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sara --hp /home/sara&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Run the printed command exactly as shown. It installs and enables a systemd unit named &lt;code&gt;pm2-&amp;lt;user&amp;gt;.service&lt;/code&gt;. Then save the current process list so PM2 knows what to start:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 save&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After a reboot, the systemd unit launches PM2 as your user, which resurrects each saved app. Verify the unit is enabled:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl status pm2-sara&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;● pm2-sara.service - PM2 process manager
Loaded: loaded (/etc/systemd/system/pm2-sara.service; enabled; preset: enabled)
Active: active (running)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="monitor-resources"&gt;Monitor Resources &lt;a class="headline-link" href="#monitor-resources" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For an at-a-glance view of CPU and memory per app, run the built-in dashboard:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pm2 monit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The terminal UI shows a live process list with CPU and memory graphs, plus a log tail per app. Press &lt;code&gt;q&lt;/code&gt; to quit.&lt;/p&gt;
&lt;p&gt;For programmatic access, &lt;code&gt;pm2 jlist&lt;/code&gt; prints the same data as JSON, which feeds into your own dashboards or monitoring scripts.&lt;/p&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;pm2: command not found&lt;/code&gt; after install&lt;/strong&gt;&lt;br&gt;
npm&amp;rsquo;s global bin directory is not on &lt;code&gt;$PATH&lt;/code&gt;. Run &lt;code&gt;npm config get prefix&lt;/code&gt; and add &lt;code&gt;&amp;lt;prefix&amp;gt;/bin&lt;/code&gt; to &lt;code&gt;$PATH&lt;/code&gt;, or install Node.js through the official NodeSource setup, which places npm under &lt;code&gt;/usr/bin&lt;/code&gt; by default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Process keeps restarting&lt;/strong&gt;&lt;br&gt;
The script crashes on startup. Run &lt;code&gt;pm2 logs myapp --err&lt;/code&gt; to see the most recent stderr output, then fix the underlying error. Use &lt;code&gt;pm2 show myapp&lt;/code&gt; for the restart count.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;pm2 reload&lt;/code&gt; falls back to restart&lt;/strong&gt;&lt;br&gt;
Reload only works in cluster mode. Add &lt;code&gt;-i 2&lt;/code&gt; (or more) when starting the app, and the next reload will be zero-downtime.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Install PM2 globally&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo npm install -g pm2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Start an app&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pm2 start app.js --name myapp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List processes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pm2 ls&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stream logs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pm2 logs myapp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restart&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pm2 restart myapp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero-downtime reload&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pm2 reload myapp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pm2 stop myapp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete from list&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pm2 delete myapp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cluster mode (4 instances)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pm2 start app.js -i 4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Save process list&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pm2 save&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generate systemd unit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pm2 startup systemd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="faq"&gt;FAQ &lt;a class="headline-link" href="#faq" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Should I use PM2 in a Docker container?&lt;/strong&gt;&lt;br&gt;
Usually no. Containers already provide isolation, and an orchestrator (Docker, systemd, Kubernetes) restarts crashed containers. Running PM2 inside hides crashes from the orchestrator and makes the container harder to debug.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Does PM2 support TypeScript?&lt;/strong&gt;&lt;br&gt;
Yes. Either compile to JavaScript first and point PM2 at the compiled file, or use &lt;code&gt;--interpreter ts-node&lt;/code&gt; when starting. Compiling is faster at runtime and simpler in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do I pass environment variables to a PM2 app?&lt;/strong&gt;&lt;br&gt;
Add an &lt;code&gt;env&lt;/code&gt; block to the ecosystem file, or prefix the CLI invocation: &lt;code&gt;NODE_ENV=production pm2 start app.js&lt;/code&gt;. The ecosystem file is the durable option.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PM2 turns a Node.js process into a managed service with one short command, and the ecosystem file scales the same workflow to many apps on the same server. Pair it with cluster mode for multi-core HTTP services, generate the systemd unit so reboots do not take the site down, and the rest is operational hygiene.&lt;/p&gt;
&lt;p&gt;For related setup, see our guides on &lt;a href="https://linuxize.com/post/how-to-install-node-js-on-ubuntu-22-04/"&gt;installing Node.js on Ubuntu&lt;/a&gt;
and &lt;a href="https://linuxize.com/post/how-to-deploy-a-nodejs-application-on-ubuntu-26-04/"&gt;deploying a Node.js application on Ubuntu 26.04&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/how-to-manage-nodejs-processes-with-pm2/featured_hu_a6720331c2e439aa.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>Bash Parameter Expansion: Defaults, Substrings, and Replacement</title><link>https://linuxize.com/post/bash-parameter-expansion/</link><pubDate>Thu, 09 Jul 2026 09:40:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/bash-parameter-expansion/</guid><category>bash</category><description>Bash parameter expansion handles default values, substrings, string length, pattern trimming, search and replace, and case conversion, all inside the shell.</description><content:encoded>&lt;p&gt;Most Bash scripts call &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, or &lt;code&gt;cut&lt;/code&gt; for jobs the shell can do by itself. Stripping an extension from a filename, providing a default when a variable is empty, or replacing part of a string are all built into the &lt;code&gt;${...}&lt;/code&gt; syntax, run in the current process, and cost no fork to an external program. The syntax is dense, which is why many people never move past &lt;code&gt;${var}&lt;/code&gt;, but there are only a handful of patterns to learn.&lt;/p&gt;
&lt;p&gt;This guide explains Bash parameter expansion: default values, length, substrings, prefix and suffix trimming, search and replace, and case conversion, with practical examples of each.&lt;/p&gt;
&lt;h2 id="the-basic-form"&gt;The Basic Form &lt;a class="headline-link" href="#the-basic-form" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;${var}&lt;/code&gt; expands to the value of &lt;code&gt;var&lt;/code&gt;, exactly like &lt;code&gt;$var&lt;/code&gt;. The braces become mandatory when the variable name would otherwise run into the surrounding text:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;report&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_final.txt&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;report_final.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Without braces, Bash would look for a variable named &lt;code&gt;file_final&lt;/code&gt;. Everything else in this guide builds on this form by adding an operator inside the braces.&lt;/p&gt;
&lt;h2 id="default-values"&gt;Default Values &lt;a class="headline-link" href="#default-values" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;:-&lt;/code&gt; operator substitutes a fallback when a variable is unset or empty:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Deploying to &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;staging&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Deploying to staging&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The variable itself is not modified; the default only applies to this one expansion. To also assign the fallback to the variable, use &lt;code&gt;:=&lt;/code&gt; instead:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;: &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LOG_DIR&lt;/span&gt;&lt;span class="p"&gt;:=/var/log/myapp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$LOG_DIR&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;/var/log/myapp&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The leading &lt;code&gt;:&lt;/code&gt; is the null command; it evaluates its arguments and does nothing else, which makes it the idiomatic way to trigger the assignment. This pattern is common at the top of scripts to give every configuration variable a sane default.&lt;/p&gt;
&lt;p&gt;Two related operators round out the family. &lt;code&gt;:?&lt;/code&gt; aborts the script with a message when the variable is missing, which turns a silent misconfiguration into a loud one:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;: &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;:?API_KEY must be set&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;bash: API_KEY: API_KEY must be set&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And &lt;code&gt;:+&lt;/code&gt; is the inverse of &lt;code&gt;:-&lt;/code&gt;: it expands to a value only when the variable is set and non-empty, which is useful for building optional command arguments:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PROXY&lt;/span&gt;&lt;span class="p"&gt;:+--proxy &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$PROXY&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; https://example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When &lt;code&gt;PROXY&lt;/code&gt; is empty, the expansion vanishes entirely and &lt;code&gt;curl&lt;/code&gt; runs without the option.&lt;/p&gt;
&lt;p&gt;Each operator also exists without the colon (&lt;code&gt;-&lt;/code&gt;, &lt;code&gt;=&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;). The colon versions treat an empty string the same as an unset variable; the colon-free versions act only when the variable is truly unset. In practice, the colon versions are what you want nearly all the time.&lt;/p&gt;
&lt;p&gt;Defaults work on positional parameters too, which makes optional script arguments trivial:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This uses the first argument if given and the current directory otherwise; see our guide on &lt;a href="https://linuxize.com/post/bash-script-arguments/"&gt;Bash script arguments&lt;/a&gt;
for the wider context.&lt;/p&gt;
&lt;h2 id="string-length"&gt;String Length &lt;a class="headline-link" href="#string-length" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;${#var}&lt;/code&gt; expands to the length of the value in characters:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;s3cretPass&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;10&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A common use is input validation, such as rejecting a password shorter than a minimum inside an &lt;a href="https://linuxize.com/post/bash-if-else-statement/"&gt;if statement&lt;/a&gt;
. For arrays, the same syntax with &lt;code&gt;[@]&lt;/code&gt; counts elements instead: &lt;code&gt;${#files[@]}&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="substrings"&gt;Substrings &lt;a class="headline-link" href="#substrings" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;${var:offset:length}&lt;/code&gt; form extracts a substring. Offsets count from zero, and the length is optional:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;2026-01-01&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;4&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;5&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;2026
01-01&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first expansion takes four characters starting at position zero; the second takes everything from position five onward.&lt;/p&gt;
&lt;p&gt;Negative offsets count from the end of the string, but they require a space or parentheses so Bash does not confuse the syntax with the &lt;code&gt;:-&lt;/code&gt; default operator:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;backup-2026.tar.gz&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="p"&gt;: -6&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;tar.gz&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A negative length means &amp;ldquo;stop that many characters before the end&amp;rdquo; rather than a count, so &lt;code&gt;${var:1:-1}&lt;/code&gt; trims one character from each side. Negative lengths require Bash 4.2 or later.&lt;/p&gt;
&lt;h2 id="trimming-prefixes-and-suffixes"&gt;Trimming Prefixes and Suffixes &lt;a class="headline-link" href="#trimming-prefixes-and-suffixes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Four operators remove a pattern from the front or the back of the value. &lt;code&gt;#&lt;/code&gt; removes the shortest match from the front, &lt;code&gt;##&lt;/code&gt; the longest match from the front, &lt;code&gt;%&lt;/code&gt; the shortest match from the back, and &lt;code&gt;%%&lt;/code&gt; the longest match from the back. The patterns are globs, the same wildcards used for filenames.&lt;/p&gt;
&lt;p&gt;The classic use is pulling filenames apart:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/var/www/site/index.backup.html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;%/*&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;%.*&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;##*.&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;index.backup.html
/var/www/site
/var/www/site/index.backup
html&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first two replicate the &lt;code&gt;basename&lt;/code&gt; and &lt;code&gt;dirname&lt;/code&gt; commands: &lt;code&gt;##*/&lt;/code&gt; deletes the longest match of &amp;ldquo;anything followed by a slash&amp;rdquo; from the front, and &lt;code&gt;%/*&lt;/code&gt; deletes the shortest &amp;ldquo;slash followed by anything&amp;rdquo; from the back. The last two split at the final dot, so &lt;code&gt;%.*&lt;/code&gt; strips one extension while &lt;code&gt;##*.&lt;/code&gt; keeps only the extension.&lt;/p&gt;
&lt;p&gt;The shortest/longest distinction matters exactly when the pattern can match at more than one place. With the file above, &lt;code&gt;${path%.*}&lt;/code&gt; removes only &lt;code&gt;.html&lt;/code&gt;, while &lt;code&gt;${path%%.*}&lt;/code&gt; would remove &lt;code&gt;.backup.html&lt;/code&gt; as well.&lt;/p&gt;
&lt;p&gt;Renaming files in a loop shows the pattern in action. For bulk changes, preview the commands first:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; f in *.jpeg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;mv -- %q %q\n&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;%.jpeg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.jpg&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After checking the generated commands, run the rename:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; f in *.jpeg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mv -- &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;%.jpeg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.jpg&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Each name has its &lt;code&gt;.jpeg&lt;/code&gt; suffix trimmed and &lt;code&gt;.jpg&lt;/code&gt; appended, with no &lt;code&gt;sed&lt;/code&gt; in sight. The &lt;code&gt;--&lt;/code&gt; tells &lt;code&gt;mv&lt;/code&gt; that option parsing is done, which protects filenames that begin with a dash.&lt;/p&gt;
&lt;h2 id="search-and-replace"&gt;Search and Replace &lt;a class="headline-link" href="#search-and-replace" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;${var/pattern/replacement}&lt;/code&gt; form replaces the first match of a glob pattern, and doubling the first slash replaces all matches:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;csv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;one,two,three&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;/,/;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;//,/;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;one;two,three
one;two;three&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Anchors are available: &lt;code&gt;${var/#pattern/replacement}&lt;/code&gt; replaces only a match at the start of the string, and &lt;code&gt;${var/%pattern/replacement}&lt;/code&gt; only at the end. Omitting the replacement deletes the match:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;//,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;onetwothree&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Keep in mind the pattern is a glob, not a regular expression: &lt;code&gt;*&lt;/code&gt; and &lt;code&gt;?&lt;/code&gt; work, but &lt;code&gt;.&lt;/code&gt; is a literal dot and there are no &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;^&lt;/code&gt; operators. When you genuinely need regular expressions, that is the job of &lt;code&gt;sed&lt;/code&gt; or the &lt;code&gt;=~&lt;/code&gt; operator; for everything simpler, the expansion is faster and has no quoting headaches. Our &lt;a href="https://linuxize.com/post/bash-string-manipulation/"&gt;Bash string manipulation&lt;/a&gt;
guide compares these approaches side by side.&lt;/p&gt;
&lt;h2 id="changing-case"&gt;Changing Case &lt;a class="headline-link" href="#changing-case" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Bash 4 added case conversion operators: &lt;code&gt;^^&lt;/code&gt; uppercases the value, &lt;code&gt;,,&lt;/code&gt; lowercases it, and the single forms &lt;code&gt;^&lt;/code&gt; and &lt;code&gt;,&lt;/code&gt; convert only the first character:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;alice&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;^&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;^^&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;header&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CONTENT-TYPE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Alice
ALICE
content-type&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lowercasing is the standard trick for case-insensitive comparisons: normalize both sides with &lt;code&gt;,,&lt;/code&gt; and compare the results. Most current Linux distributions ship Bash 5, and Bash 4 is enough for these operators. Availability is mainly a concern in scripts that must also run on macOS&amp;rsquo;s ancient default Bash 3.2, where they are missing.&lt;/p&gt;
&lt;h2 id="indirect-expansion"&gt;Indirect Expansion &lt;a class="headline-link" href="#indirect-expansion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;${!var}&lt;/code&gt; expands to the value of the variable whose name is stored in &lt;code&gt;var&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;staging_host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;staging.example.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;production_host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;prod.example.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;staging&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;env&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_host&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="p"&gt;!ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;staging.example.com&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Indirection occasionally saves the day in configuration-driven scripts, but if you find yourself using it often, an &lt;a href="https://linuxize.com/post/bash-arrays/"&gt;associative array&lt;/a&gt;
is usually the cleaner tool.&lt;/p&gt;
&lt;h2 id="combining-with-positional-parameters"&gt;Combining with Positional Parameters &lt;a class="headline-link" href="#combining-with-positional-parameters" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All the operators work on &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, and friends, and the substring form even works on &lt;code&gt;$@&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:?usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt; command [args...]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;shift_args&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="p"&gt;@:&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first line insists on at least one argument and prints a usage message otherwise; the second collects every argument after the first into an array. These two lines are the skeleton of most subcommand-style scripts.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For a printable quick reference, see the &lt;a href="https://linuxize.com/cheatsheet/bash/"&gt;Bash cheatsheet&lt;/a&gt;
.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Expansion&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var:-default}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Value, or &lt;code&gt;default&lt;/code&gt; if unset or empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var:=default}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same, and assigns the default to &lt;code&gt;var&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var:?message}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Value, or exit with &lt;code&gt;message&lt;/code&gt; if unset or empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var:+word}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;word&lt;/code&gt; only if &lt;code&gt;var&lt;/code&gt; is set and non-empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${#var}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Length of the value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var:2:5}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Five characters starting at offset 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var: -3}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Last three characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var#pattern}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove shortest matching prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var##pattern}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove longest matching prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var%pattern}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove shortest matching suffix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var%%pattern}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remove longest matching suffix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var/old/new}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace first match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var//old/new}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace all matches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var/#old/new}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace match at start only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var/%old/new}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replace match at end only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var^^}&lt;/code&gt; / &lt;code&gt;${var,,}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Uppercase / lowercase the value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${var^}&lt;/code&gt; / &lt;code&gt;${var,}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Uppercase / lowercase the first character&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;${!var}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Value of the variable named by &lt;code&gt;var&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Parameter expansion replaces a surprising share of the &lt;code&gt;sed | awk | cut&lt;/code&gt; pipelines found in everyday scripts, with defaults via &lt;code&gt;:-&lt;/code&gt; and &lt;code&gt;:=&lt;/code&gt;, filename surgery via &lt;code&gt;#&lt;/code&gt; and &lt;code&gt;%&lt;/code&gt;, and replacement via &lt;code&gt;//&lt;/code&gt; covering the bulk of real cases. The patterns pair naturally with the string techniques in our &lt;a href="https://linuxize.com/post/bash-string-manipulation/"&gt;Bash string manipulation&lt;/a&gt;
guide, and with &lt;code&gt;set -u&lt;/code&gt; from the &lt;a href="https://linuxize.com/post/bash-set-command/"&gt;Bash set command&lt;/a&gt;
, where a well-placed &lt;code&gt;${var:-}&lt;/code&gt; marks a variable as intentionally optional.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/bash-parameter-expansion/featured_hu_a2b5ebbf7649af63.webp" medium="image" type="image/webp" width="1200" height="675"/></item><item><title>smartctl Command in Linux: Check Disk Health with SMART</title><link>https://linuxize.com/post/smartctl-command-in-linux/</link><pubDate>Wed, 08 Jul 2026 09:40:00 +0200</pubDate><author>hello@linuxize.com (Linuxize)</author><guid>https://linuxize.com/post/smartctl-command-in-linux/</guid><category>disk</category><category>linux commands</category><description>Use smartctl in Linux to check SMART health, read disk attributes, run self-tests, troubleshoot USB enclosures, and monitor NVMe wear.</description><content:encoded>&lt;p&gt;Disks rarely die without warning. Long before a drive stops responding, it usually accumulates reallocated sectors, read errors, or climbing temperatures, and the drive itself keeps count through SMART (Self-Monitoring, Analysis and Reporting Technology). The &lt;code&gt;smartctl&lt;/code&gt; command reads those counters, so the question &amp;ldquo;is this disk failing?&amp;rdquo; gets an answer based on the drive&amp;rsquo;s own bookkeeping instead of guesswork.&lt;/p&gt;
&lt;p&gt;This guide explains how to use &lt;code&gt;smartctl&lt;/code&gt; to check drive health, read the attributes that actually predict failure, run self-tests, and keep an eye on NVMe wear.&lt;/p&gt;
&lt;h2 id="smartctl-syntax"&gt;smartctl Syntax &lt;a class="headline-link" href="#smartctl-syntax" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The basic syntax is:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;smartctl [OPTIONS] DEVICE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;DEVICE&lt;/code&gt; is normally a whole disk such as &lt;code&gt;/dev/sda&lt;/code&gt;, &lt;code&gt;/dev/sdb&lt;/code&gt;, or &lt;code&gt;/dev/nvme0&lt;/code&gt;, not a mounted directory. Most checks need root because &lt;code&gt;smartctl&lt;/code&gt; sends commands directly to the drive. If you are not sure which device names your disks have, run &lt;code&gt;lsblk&lt;/code&gt; first.&lt;/p&gt;
&lt;h2 id="installing-smartctl"&gt;Installing smartctl &lt;a class="headline-link" href="#installing-smartctl" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;smartctl&lt;/code&gt; is part of the &lt;code&gt;smartmontools&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;On Ubuntu, Debian, and Derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install smartmontools&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On Fedora, RHEL, and Derivatives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install smartmontools&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After installation, run &lt;code&gt;smartctl&lt;/code&gt; with &lt;code&gt;sudo&lt;/code&gt; unless your distribution has granted your user direct access to storage devices.&lt;/p&gt;
&lt;h2 id="checking-whether-a-drive-supports-smart"&gt;Checking Whether a Drive Supports SMART &lt;a class="headline-link" href="#checking-whether-a-drive-supports-smart" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start with the identity summary:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo smartctl -i /dev/sda&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Model Family: Samsung based SSDs
Device Model: Samsung SSD 870 EVO 1TB
Serial Number: S6PTNM0T812345A
Firmware Version: SVT02B6Q
User Capacity: 1,000,204,886,016 bytes [1.00 TB]
SMART support is: Available - device has SMART capability.
SMART support is: Enabled&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Besides confirming SMART support, this output gives you the model and serial number, which you will want when matching a physical drive to a device name or claiming a warranty. In the rare case SMART is available but disabled, enable it with &lt;code&gt;sudo smartctl -s on /dev/sda&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="checking-overall-health"&gt;Checking Overall Health &lt;a class="headline-link" href="#checking-overall-health" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The quickest check is the drive&amp;rsquo;s own verdict:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo smartctl -H /dev/sda&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;SMART overall-health self-assessment test result: PASSED&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A &lt;code&gt;FAILED&lt;/code&gt; result means the drive predicts its own failure within 24 hours and warranty replacement is justified; back up immediately.&lt;/p&gt;
&lt;div class="note callout callout-warning"&gt;
&lt;div class="callout-header"&gt;&lt;svg role="img" aria-hidden="true" class="callout-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"&gt;
&lt;path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm-.5-5h1c.276 0 .5.224.5.5v1c0 .276-.224.5-.5.5h-1c-.276 0-.5-.224-.5-.5v-1c0-.276.224-.5.5-.5zm0-8h1c.276 0 .5.224.5.5V8l-.5 3-1 .5L9 8V5.5c0-.276.224-.5.5-.5z"&gt;&lt;/path&gt;
&lt;/svg&gt;
&lt;span class="callout-title"&gt;Warning&lt;/span&gt;&lt;/div&gt;
&lt;div class="callout-body"&gt;Do not read &lt;code&gt;PASSED&lt;/code&gt; as &amp;ldquo;healthy&amp;rdquo;. The overall verdict flips only when an attribute crosses the manufacturer&amp;rsquo;s failure threshold, and drives regularly corrupt data while still technically passing. The attributes in the next section tell the real story, and no SMART output replaces working backups.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="reading-smart-attributes"&gt;Reading SMART Attributes &lt;a class="headline-link" href="#reading-smart-attributes" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The attribute table is where failure announces itself early:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo smartctl -A /dev/sda&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
5 Reallocated_Sector_Ct 0x0033 100 100 010 Pre-fail Always - 0
9 Power_On_Hours 0x0032 097 097 000 Old_age Always - 11284
12 Power_Cycle_Count 0x0032 099 099 000 Old_age Always - 413
177 Wear_Leveling_Count 0x0013 099 099 000 Pre-fail Always - 8
187 Reported_Uncorrect 0x0032 100 100 000 Old_age Always - 0
194 Temperature_Celsius 0x0022 067 052 000 Old_age Always - 33
197 Current_Pending_Sector 0x0032 100 100 000 Old_age Always - 0
198 Offline_Uncorrectable 0x0030 100 100 000 Old_age Offline - 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Two number systems live in this table. &lt;code&gt;VALUE&lt;/code&gt; is a normalized score where higher is better; the drive flags failure when it drops to &lt;code&gt;THRESH&lt;/code&gt;. &lt;code&gt;RAW_VALUE&lt;/code&gt; is the actual count, and for the attributes that matter, the raw count is what you read.&lt;/p&gt;
&lt;p&gt;Four attributes predict failure well, and their healthy raw value is zero:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Reallocated_Sector_Ct&lt;/code&gt; (5) - Sectors the drive has retired and remapped to spares. A handful may stay stable for years, but a count that grows between checks is the classic sign of a dying disk.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Reported_Uncorrect&lt;/code&gt; (187) - Errors the drive could not correct internally. Any nonzero value correlates strongly with failure.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Current_Pending_Sector&lt;/code&gt; (197) - Sectors the drive could not read and is waiting to remap. Pending sectors mean data in those spots is already at risk.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Offline_Uncorrectable&lt;/code&gt; (198) - Confirmed unreadable sectors found during offline scanning.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note the raw values now, check again in a week, and treat growth in any of these four as your cue to replace the drive. Temperature (194) is worth a glance too: sustained operation above roughly 50°C shortens drive life, and a spike often points at a failed case fan.&lt;/p&gt;
&lt;h2 id="running-self-tests"&gt;Running Self-Tests &lt;a class="headline-link" href="#running-self-tests" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Attributes are passive bookkeeping; self-tests actively exercise the drive. The test runs inside the drive&amp;rsquo;s firmware, so you can keep using the system while it works. Start with the short test, which takes a couple of minutes:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo smartctl -t short /dev/sda&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===
Sending command: &amp;#34;Execute SMART Short self-test routine immediately in off-line mode&amp;#34;.
Testing has begun.
Please wait 2 minutes for test to complete.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The long test (&lt;code&gt;-t long&lt;/code&gt;) reads the entire surface and takes from under an hour on an SSD to many hours on a large hard drive; it is the right choice when a short test passes but you still suspect the drive. Check the results once the wait time has passed:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo smartctl -l selftest /dev/sda&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error
# 1 Short offline Completed without error 00% 11284 -
# 2 Extended offline Completed without error 00% 10102 -&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A failed entry lists the LBA of the first error, which is the drive telling you exactly where it can no longer read. At that point the useful response is replacement, not repair; filesystem-level checks like &lt;a href="https://linuxize.com/post/fsck-command-in-linux/"&gt;&lt;code&gt;fsck&lt;/code&gt;&lt;/a&gt;
fix filesystem structures, not failing hardware underneath them.&lt;/p&gt;
&lt;h2 id="checking-nvme-drives"&gt;Checking NVMe Drives &lt;a class="headline-link" href="#checking-nvme-drives" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;NVMe drives report health through a different log format, and &lt;code&gt;smartctl -a&lt;/code&gt; presents the main fields directly:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo smartctl -a /dev/nvme0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="output"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;output&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-output" data-lang="output"&gt;=== START OF SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED
Critical Warning: 0x00
Temperature: 41 Celsius
Available Spare: 100%
Available Spare Threshold: 10%
Percentage Used: 3%
Data Units Written: 18,536,442 [9.49 TB]
Media and Data Integrity Errors: 0
Error Information Log Entries: 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Three fields carry the signal. &lt;code&gt;Percentage Used&lt;/code&gt; is the drive&amp;rsquo;s own wear estimate against its rated endurance, so 3% after a year of use projects decades of life, while a value racing toward 100% on a young drive means the workload is chewing through it. &lt;code&gt;Available Spare&lt;/code&gt; falling toward its threshold plays the role reallocated sectors play on SATA drives. &lt;code&gt;Media and Data Integrity Errors&lt;/code&gt; should be zero, full stop.&lt;/p&gt;
&lt;h2 id="checking-drives-in-usb-enclosures"&gt;Checking Drives in USB Enclosures &lt;a class="headline-link" href="#checking-drives-in-usb-enclosures" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;USB adapters often hide the drive behind a bridge chip, and &lt;code&gt;smartctl&lt;/code&gt; reports &lt;code&gt;Unknown USB bridge&lt;/code&gt; instead of SMART data. Most bridges pass SMART through when asked explicitly:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo smartctl -a -d sat /dev/sdb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-d sat&lt;/code&gt; option tells &lt;code&gt;smartctl&lt;/code&gt; to tunnel ATA commands through the bridge. If that fails, &lt;code&gt;-d sntasmedia&lt;/code&gt; or &lt;code&gt;-d sntjmicron&lt;/code&gt; handle common NVMe-to-USB chips, and some cheap enclosures simply do not pass SMART at all.&lt;/p&gt;
&lt;h2 id="continuous-monitoring-with-smartd"&gt;Continuous Monitoring with smartd &lt;a class="headline-link" href="#continuous-monitoring-with-smartd" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;smartmontools&lt;/code&gt; package also ships &lt;code&gt;smartd&lt;/code&gt;, a daemon that polls your drives and warns you instead of waiting for you to remember. A single line in &lt;code&gt;/etc/smartd.conf&lt;/code&gt; covers all drives:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="txt"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"&gt;&lt;/path&gt;
&lt;polyline points="14 2 14 8 20 8"&gt;&lt;/polyline&gt;
&lt;/svg&gt;&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;/etc/smartd.conf&lt;/span&gt;&lt;span class="px-2 py-0.5 rounded text-xs font-medium bg-gray-200 text-gray-700 dark:bg-slate-600 dark:text-slate-300"&gt;txt&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-txt" data-lang="txt"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DEVICESCAN -a -o on -S on -s (S/../.././02|L/../../6/03) -m root -M exec /usr/share/smartmontools/smartd-runner&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This monitors all detected devices, runs a short self-test daily at 02:00 and a long test on Saturdays at 03:00, and reports problems to root&amp;rsquo;s mail. Enable it with:&lt;/p&gt;
&lt;div class="code-block relative my-4 rounded-lg overflow-hidden border border-gray-200 dark:border-slate-700" data-lang="bash" data-prompt="$"&gt;
&lt;div class="code-header flex items-center justify-between px-4 py-2 bg-gray-50 dark:bg-slate-800/80 border-b border-gray-200 dark:border-slate-700"&gt;
&lt;div class="flex items-center gap-2"&gt;&lt;svg class="w-4 h-4 text-gray-500 dark:text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;
&lt;polyline points="4 17 10 11 4 5"&gt;&lt;/polyline&gt;
&lt;line x1="12" y1="19" x2="20" y2="19"&gt;&lt;/line&gt;
&lt;/svg&gt;
&lt;span class="text-sm text-gray-600 dark:text-slate-400 font-medium"&gt;Terminal&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now smartd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Distribution packages ship a commented default config that is close to this already, so often you only need to enable the service.&lt;/p&gt;
&lt;h2 id="troubleshooting"&gt;Troubleshooting &lt;a class="headline-link" href="#troubleshooting" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Permission denied or operation not permitted&lt;/strong&gt;&lt;br&gt;
Run the command with &lt;code&gt;sudo&lt;/code&gt;. &lt;code&gt;smartctl&lt;/code&gt; needs direct device access, and an unprivileged shell usually cannot send SMART commands to a disk.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SMART support is disabled&lt;/strong&gt;&lt;br&gt;
If &lt;code&gt;smartctl -i&lt;/code&gt; says SMART is available but disabled, turn it on with &lt;code&gt;sudo smartctl -s on /dev/sda&lt;/code&gt;, replacing &lt;code&gt;/dev/sda&lt;/code&gt; with the correct device.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unknown USB bridge&lt;/strong&gt;&lt;br&gt;
Try the SAT passthrough driver with &lt;code&gt;sudo smartctl -a -d sat /dev/sdb&lt;/code&gt;. If that fails on an NVMe-to-USB enclosure, try &lt;code&gt;-d sntasmedia&lt;/code&gt; or &lt;code&gt;-d sntjmicron&lt;/code&gt;. Some adapters do not expose SMART data at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No such device or wrong disk shown&lt;/strong&gt;&lt;br&gt;
Confirm the device path with &lt;code&gt;lsblk&lt;/code&gt; before running &lt;code&gt;smartctl&lt;/code&gt;. SATA disks usually appear as &lt;code&gt;/dev/sdX&lt;/code&gt;, while NVMe drives usually appear as &lt;code&gt;/dev/nvme0&lt;/code&gt; or &lt;code&gt;/dev/nvme0n1&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="quick-reference"&gt;Quick Reference &lt;a class="headline-link" href="#quick-reference" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Identify drive and SMART support&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo smartctl -i /dev/sda&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overall pass/fail verdict&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo smartctl -H /dev/sda&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attribute table&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo smartctl -A /dev/sda&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full ATA disk report&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo smartctl -x /dev/sda&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NVMe health&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo smartctl -a /dev/nvme0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Start a short self-test&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo smartctl -t short /dev/sda&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Start a full-surface test&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo smartctl -t long /dev/sda&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;View self-test results&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo smartctl -l selftest /dev/sda&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drive behind a USB adapter&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo smartctl -a -d sat /dev/sdb&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="headline-link" href="#conclusion" aria-hidden="true"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A monthly &lt;code&gt;smartctl -A&lt;/code&gt; glance at reallocated, pending, and uncorrectable counts, or &lt;code&gt;smartd&lt;/code&gt; doing the same automatically, converts most disk failures from surprises into scheduled replacements. When the numbers start moving, copy the data off first and experiment second; a drive that is reallocating sectors owes you nothing. For checking the filesystems that live on top of healthy drives, see our guide on the &lt;a href="https://linuxize.com/post/fsck-command-in-linux/"&gt;fsck command&lt;/a&gt;
.&lt;/p&gt;</content:encoded><media:content url="https://linuxize.com/post/smartctl-command-in-linux/featured_hu_4efd877508bf1b96.webp" medium="image" type="image/webp" width="1200" height="675"/></item></channel></rss>