Tools: The "Everything is a File" Tour of Linux (2026)

Tools: The "Everything is a File" Tour of Linux (2026)

Two tools that will save you more than any tutorial

What even is /etc

DNS redirection or how I broke Google with one line

/etc/resolv.conf: the file that keeps rewriting itself

/etc/passwd and /etc/shadow: the user accounts are just a text file

/etc/ssh/sshd_config: watching bots try your front door

/etc/fstab: the file that can stop your machine from booting

/proc: the folder that is not actually on disk

Routing: where packets actually go

/dev: the devices that are not devices

/boot: where the kernel lives

/var/log: the system's diary

/etc/systemd/system/ writing a service that survives crashes

PATH why commands vanish when you break one variable

Permissions

Environment variables

Terminal shortcuts worth memorizing now

References I wanted to overcome my command line phobia and join the 4% club of human bots who don't panic when they see the terminal, typing away in their plain terminal. I wanted to feel like a hacker. Not the movie kind with three keyboards and cascading green text, but the kind who actually understands what their computer is doing. So I googled "How to learn Linux" and landed on the most mundane, beige documentation website I have ever seen in my life. I dropped into forums next, expecting a more human approach. The first post I found had someone saying "just build your own kernel." I just wanted to learn things, not go on a spiritual journey. People told me Linux had a learning curve. Except this curve was a cliff. If you want a 12-minute brush through Linux basics before diving into the weird stuff, Fireship made a video for exactly that. Before we go into a rabbit hole, I will suggest to try all of this on a VPS, a VM, or a Docker container. Not your main machine. The reason is simple: some of what I will show you involves deliberately breaking things. Try to understand the command before copying, because imagine copying rm -rf /. But if you are HIM, nobody is stopping you. On a throwaway container? You type exit, spin up a fresh one, and try again. Freedom to destroy without consequences is genuinely how you learn Linux fastest. Before anything else: man and tldr. These are your cheat codes. man is the built-in Linux manual. Every command, every system file, every config format has one. When you wonder what a flag does or what a file is for, man has the answer written by the people who built the thing. The problem with man is density. It was written by engineers for engineers. Enter tldr, a community-written alternative that gives you just the practical common cases. tldr gives you five useful examples instead of fifty pages of specification. Use tldr when you want to quickly understand what something does. Use man when you need the full picture. If man is the textbook, tldr is the cheat sheet your classmate scribbled the night before the exam. One more habit worth building early: when something fails, read the actual error message before googling. "Permission denied" means permissions. "No such file or directory" means the path is wrong or the file doesn't exist. "Command not found" means it is not installed or not in your PATH. Linux error messages are not trying to confuse you. They are telling you what happened. /etc is where Linux keeps its brain. Configuration for almost everything the system does lives here in plain text files you can open with any editor. I spent the first hour just running ls /etc and opening random files, and breaking things up. That felt like finding an unlocked door in a building I thought was sealed. The one thing I tried in /etc was /etc/hosts. I wanted to reach my local dev server by a name instead of 127.0.0.1:3000. Opening the file: I added one line at the bottom and saved: It worked immediately. No restart, no daemon reload. The file is read fresh on every single lookup because this check happens before Linux even thinks about asking a DNS server anything. Then I had an idea. What if I pointed instagram.com at localhost? This is poor man's parental control. All of Meta's infrastructure, the entire DNS system, bypassed by one line in a text file on your machine. The whole internet is the fallback. This file runs first. Imagine making your friend slowly lose their mind on a shared Linux machine, redirect their most visited sites to 127.0.0.1 in /etc/hosts. They will restart their wifi three times, blame their ISP, factory reset their router, and spend an hour in a chat with customer support before anyone thinks to check a text file. Once I understood /etc/hosts, I wanted to know what happened when a hostname was not found there. That fallback is /etc/resolv.conf, which holds the actual DNS server address the system asks. I had edited this on my machine and my changes kept vanishing. Now I understood why. systemd-resolved is a local DNS middleman running at 127.0.0.53. It manages this file and rewrites it whenever it restarts. Let's break the internet: The machine is still connected to the network. It just cannot resolve any names because it is asking a DNS server that does not exist. apt update fails, curl fails, package installs fail. The network is fine, only name resolution is dead. This is what a misconfigured DNS server looks like from the inside. The permanent fix without the file fighting back is editing systemd-resolved's own config: I heard that everything in Linux is treated as a file, from hardware device to system configurations, just a file. This in itself was surprising to me, till I started exploring it through /etc/passwd Seven colon-separated fields per line: username, password placeholder, user ID, group ID, comment, home directory, login shell. The x in the second field means the actual password hash is stored in /etc/shadow, which only root can read. The 9 fields are username, encrypted password, last change, minimum age, maximum age, warning, activity, expiration and reserved. $6$ means SHA-512. The rounds=4096 deliberately makes hashing slow. Slow hashing means brute-force attacks take longer. Your password is protected partly by intentional computational expense. Now the interesting part. Every account with /usr/sbin/nologin as its login shell cannot open an interactive session. Try to SSH in as www-data and the connection closes immediately. No password prompt, no shell, nothing. These accounts exist only so the processes running as them have a numeric user identity for permissions. They are not meant for humans to log into. Now, i wanted to try breaking it and hence, changed my login shell to /bin/false in /etc/passwd. When i tried to connect in a new terminal, the session closes the instant the shell starts because /bin/false exits immediately with a failure code. My account exists, password is correct, the SSH connection succeeds, but I am immediately disconnected. I have locked yourself out without deleting the account or changing the password. I fixed the current session by changing /bin/false back to /bin/bash. On any internet-facing VPS, run this after it has been up for a day: On a fresh VPS after few hours, that number is usually in the thousands. Automated bots scan every IP address on the internet looking for open port 22 and trying common username and password combinations. root, admin, ubuntu, 123456. Constantly, from everywhere. All SSH behavior is controlled by /etc/ssh/sshd_config: You would see a file with multiple lines with Port info, permits and authentications. Two lines that matter immediately: Setting PasswordAuthentication no means SSH only accepts key-based authentication. The bots still knock but there is nothing to brute-force. No password means no attack surface. PermitRootLogin no means even with valid root credentials, nobody SSHs directly into root. Want to watch the bots in real time: Run that for five minutes on a fresh VPS. The attempts come in constantly from IP addresses across dozens of countries. It is mildly unsettling and also clarifying. This is just what the internet is like all the time. After disabling passwords: Whenever the bots try a password, the server tells them 'NO', not even letting them trying the password to authenticate. /etc/fstab is read at boot. Linux mounts everything listed here. USB drives, additional partitions, network shares. Get an entry wrong and the machine may not boot. UUID is used instead of the device name because the name might change but the UUID won't. This acts as the Aadhar Number of the device. 'broken-entry-here' is a string of text without the columns. When the mount command encounters it, it has no idea what the device is, and where it should be mounted. Now test without rebooting: This command is essentially the dry run of the boot process. Error. Exactly what you would get on boot if you saved this and restarted. Fix it by removing or commenting out the broken line, then run mount -a again to confirm it passes. The rule: always test with mount -a before rebooting when you touch /etc/fstab. Always. A bad fstab entry drops you into recovery mode or an emergency shell with no obvious explanation. Keep a mental note that this file exists and kills boots if you get it wrong. /proc is a virtual filesystem. There are no files here stored on disk anywhere. When you read something from /proc, the kernel generates the content on the spot from its own live internal data. It is a window into running system state, not stored data. Run it twice, ten seconds apart. The numbers change. Because it is live. The flags like vmx, aes and sse which details the CPU capability the processor supports. vmx means hardware virtualization is available. If you try to run KVM and it refuses, check for this flag. aes means the CPU has built-in AES hardware acceleration. Disk encryption and TLS are genuinely faster because of this single flag. sse/avx means CPU has Streaming SIMD Extensions which can boost performance for heavy computations, and video encoding. The per-process data is where things get interesting. Every running process gets its own directory: fd/ lists every file descriptor the process has open right now. Log files, sockets, pipes, all of it as symlinks. environ has the exact environment variables the process launched with. cmdline shows the full command that started it. status has memory use, current state, which user it runs as. The kernel stores command arguments separated by null bytes (\0) to avoid confusion with spaces inside arguments. tr swaps those null spaces to make it readable. When you delete a file while a process holds it open, the data stays on disk. The file is gone from ls but the space is allocated until the process releases its file descriptor. In Linux, file is a link to a block of data, you are only removing the name. If the process has file descriptor open, data block will be kept alive. By redirecting to the FD in /proc, you're telling the kernel to wipe the actual data blocks while leaving the 'ghost' handle intact.

Find these with lsof | grep deleted. Fix without restarting the process: That truncates the held-open file to zero bytes through the process's own descriptor. Disk space reclaimed, process uninterrupted. The routing table is what your machine consults before sending any packet. It decides which network interface and which gateway to use. The default line handles everything. It says "for any destination I don't have a specific rule for, send it to 192.168.1.1." That is your router. Every internet-bound packet passes through that rule. Delete it and watch what happens: The machine is still on the network. It just cannot reach anything outside the local subnet because there is no default route. This is one of the first things to check when a server cannot reach the internet. The default route may simply not exist, perhaps because a VPN misconfigured it, or because someone ran ip route flush without knowing what it did. One line is the complete answer about which interface and gateway any packet would use to reach any destination. /dev/null, /dev/zero, /dev/random all live in the same directory as actual hardware. They have the same character device type marker. None of them are physical hardware. /dev/null is a black hole. Write anything to it, and it is gone silently. Read from it, you get immediate end-of-file. This is what command > /dev/null 2>&1 does: stdout goes to the black hole, 2>&1 sends stderr to wherever stdout is going (also the black hole).The numbers represent 'streams.' 1 is standard output (normal text), and 2 is standard error. 2>&1 means, take all the errors and send them into the same pipe where the normal text is going. Since that pipe leads to /dev/null, the command becomes perfectly silent. /dev/zero produces infinite zero bytes. Good for filling disks or creating blank test files: fallocate is instant because it just tells the filesystem to reserve the space without actually writing anything to the disk. dd if=/dev/zero forces the CPU to actually churn out millions of zeros and write them one by one. /dev/urandom produces cryptographically random bytes collected from hardware entropy: The thing that made this concrete for me: the same read() system call your code uses to open a text file reads random bytes from /dev/urandom. Same interface but completely different behavior underneath. That is the "everything is a file" idea became real. vmlinuz is the compressed Linux kernel (vm = virtual machine, z- compressed like .zip). The actual operating system, stored as a file. initrd.img is a temporary RAM filesystem that acts as a bridge, which loads before the real filesystem mounts at boot. grub/ has the bootloader that lets you choose between operating systems. That file is the kernel build configuration. Every driver, every feature, listed. Most of it is cryptic without context but searching it teaches you what the kernel actually supports. The only advice here: do not delete anything from /boot. Deleting vmlinuz means the computer cannot boot at all. Recovery requires a live USB. This is the one folder in the filesystem where curiosity should not turn into experiments. Consider /etc is the brain and /proc is the nervous system, /boot is the heart of Linux. /var/log is where the machine writes what happened. Everything. auth.log records every login, failed or successful. syslog is the general system log. kern.log has kernel messages. dpkg.log records every package installed or removed and when. Some logs are plain text files you can cat like syslog, while others live in the journal/ directory stores logs in a binary format to make them searchable and faster to filter. The journalctl command is used to read these binary logs. When something breaks, look for the log file for the specific thing that broke. It almost always contains the exact error. If logs kept growing forever, they’d fill your entire disk. Linux uses a tool called logrotate that periodically takes the old log, compresses it in the .gz files, and eventually deletes it Systemd starts everything on boot and manages services. Unit files in /etc/systemd/system/ tell it what to run. I wanted a script running on boot that restarted if it crashed. Cron can run on boot with @reboot but has no crash recovery. A service file does: After=network.target line is a safety check that tells Linux to not start this app until the network is actually up.By default, system services want to run as root and can be a security risk. If the app gets hacked, User= makes sure the attacker is trapped in the user account and doesn't get access to keys. WorkingDirectory ensures that if the code looks for a file in ./config, it's looking in the right folder. Restart=on-failure is the important line. The process crashes, it comes back in 5 seconds because of RestartSec=5 which can be adjusted. You stop it with systemctl stop. The distinction between a crash and an intentional stop is handled automatically. Logs for this service: PATH tells the shell where to look for executables. When you type ls, the shell searches every directory in PATH until it finds a file named ls. If PATH is wrong, every command fails. Everything is gone. The binaries still exist on disk but the shell just lost its map. It can be fixed with: Why this matters beyond the experiment: cron jobs run with a stripped PATH by default. If your script calls something in /usr/local/bin and cron's PATH does not include that directory, the cron job silently fails with "command not found" while the exact same script works fine in your terminal. Set PATH explicitly in your crontab: If you’re ever unsure where a command is actually coming from, use which. Running which ls shows the exact path the shell found. It also helps to verify if the map is working. Permissions in theory is chmod, rwx, octal numbers. In practice I kept getting them wrong until I broke something on purpose. The file exists and the content is correct, but newly created files have no execute permission. Check with: No x anywhere. Add it: Now the more interesting break. Remove execute from ls itself: ls still exists on disk. It just cannot be executed. From the shell's perspective it might as well not be there. Fix: The three positions: owner, group, others mean the same permissions behave differently depending on who runs the command. When your web server returns 403 errors and logs say "permission denied," this is why. The files exist, the server is running, but www-data does not have the permission to read them. For a file: +x means you can run it; But for a directory: +x means you can view it using cd.

Linux works on Principle of Least Privilege(PoLP), hence avoid the temptation to run chmod 777. A friend set a variable in ~/.bashrc. It worked in his terminal. His systemd service couldn't see it which is followed by hours of debugging. Every process inherits environment variables from its parent. The terminal is started by the login process, which sources ~/.bashrc, which sets your variables. Systemd (PID 1) starts services. Systemd never read your ~/.bashrc. The variables your terminal has, the service has never heard of. Your terminal reads ~/.bashrc and /etc/profile and has everything you configured. A cron job reads almost nothing. PATH is /usr/bin:/bin. Your tools in /usr/local/bin are invisible. A systemd service reads only what you explicitly declare in its unit file under [Service]. For services, declare variables in the unit file: For cron, set PATH at the top of the crontab or use absolute paths everywhere. For your own sessions, ~/.bashrc works. The confusion only happens when you expect one environment to be visible in another. In Linux, explicit is better than implicit. If a service needs a variable, tell the service directly. Ctrl+R searches command history interactively. Start typing any part of a command you ran before. This is faster than retyping long paths. cd - goes to the last directory you were in. Jump between two locations without retyping either path. !! repeats the last command. The classic use is sudo !! when you forgot sudo. Ctrl+A and Ctrl+E jump to the start and end of the current line. Ctrl+W deletes the last word backwards. These three reduce terminal frustration noticeably. When a config file edit breaks something and you want to know exactly what changed: diff /etc/nginx/nginx.conf.backup /etc/nginx/nginx.conf. Keep backups before editing important files. cp nginx.conf nginx.conf.bak takes two seconds. I found two resources that can be helpful in the learning curve of Linux: Linux Journey : This has organized learning path that breaks down the complexities of the Linux operating system into digestible stages. Bandit : It is wargame designed to teach the fundamentals of the Linux command line. Visually looks boring, but is really interesting to follow through. Fireship: Linux in 100 Seconds : start here if you haven't Linux man pages : every file and command has one tldr pages : install with apt install tldr, use it for every new command Arch Wiki : the best Linux documentation on the internet, works for all distros regardless of what you're running explainshell.com : paste any command and it breaks down every flag visually The filesystem docs : official kernel documentation Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ man ls man chmod man 5 passwd # the 5 means file format manual, not the command man resolv.conf # the config file itself has a man page man ls man chmod man 5 passwd # the 5 means file format manual, not the command man resolv.conf # the config file itself has a man page man ls man chmod man 5 passwd # the 5 means file format manual, not the command man resolv.conf # the config file itself has a man page -weight: 500;">apt -weight: 500;">install tldr tldr ls tldr chmod -weight: 500;">apt -weight: 500;">install tldr tldr ls tldr chmod -weight: 500;">apt -weight: 500;">install tldr tldr ls tldr chmod nano /etc/hosts nano /etc/hosts nano /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost 127.0.0.1 localhost ::1 localhost ip6-localhost 127.0.0.1 localhost ::1 localhost ip6-localhost 127.0.0.1 myapp.local 127.0.0.1 myapp.local 127.0.0.1 myapp.local nano /etc/hosts # add: 127.0.0.1 instagram.com nano /etc/hosts # add: 127.0.0.1 instagram.com nano /etc/hosts # add: 127.0.0.1 instagram.com ping instagram.com ping instagram.com ping instagram.com PING instagram.com (127.0.0.1) 56 bytes of data. PING instagram.com (127.0.0.1) 56 bytes of data. PING instagram.com (127.0.0.1) 56 bytes of data. cat /etc/resolv.conf cat /etc/resolv.conf cat /etc/resolv.conf # This file is managed by man:systemd-resolved(8). Do not edit. nameserver 127.0.0.53 # This file is managed by man:systemd-resolved(8). Do not edit. nameserver 127.0.0.53 # This file is managed by man:systemd-resolved(8). Do not edit. nameserver 127.0.0.53 echo "nameserver 0.0.0.0" > /etc/resolv.conf ping google.com echo "nameserver 0.0.0.0" > /etc/resolv.conf ping google.com echo "nameserver 0.0.0.0" > /etc/resolv.conf ping google.com ping: google.com: Temporary failure in name resolution ping: google.com: Temporary failure in name resolution ping: google.com: Temporary failure in name resolution # Fix it immediately echo "nameserver 8.8.8.8" > /etc/resolv.conf # Fix it immediately echo "nameserver 8.8.8.8" > /etc/resolv.conf # Fix it immediately echo "nameserver 8.8.8.8" > /etc/resolv.conf nano /etc/systemd/resolved.conf # under [Resolve]: # DNS=1.1.1.1 # FallbackDNS=8.8.8.8 -weight: 500;">systemctl -weight: 500;">restart systemd-resolved nano /etc/systemd/resolved.conf # under [Resolve]: # DNS=1.1.1.1 # FallbackDNS=8.8.8.8 -weight: 500;">systemctl -weight: 500;">restart systemd-resolved nano /etc/systemd/resolved.conf # under [Resolve]: # DNS=1.1.1.1 # FallbackDNS=8.8.8.8 -weight: 500;">systemctl -weight: 500;">restart systemd-resolved cat /etc/passwd cat /etc/passwd cat /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin saumya:x:1001:1001::/home/saumya:/bin/bash # the above is in the form of name:password:UID:GID:GECOS:directory:shell (root:x:0:0:root:/root:/bin/bash) root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin saumya:x:1001:1001::/home/saumya:/bin/bash # the above is in the form of name:password:UID:GID:GECOS:directory:shell (root:x:0:0:root:/root:/bin/bash) root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin saumya:x:1001:1001::/home/saumya:/bin/bash # the above is in the form of name:password:UID:GID:GECOS:directory:shell (root:x:0:0:root:/root:/bin/bash) -weight: 600;">sudo cat /etc/shadow | grep saumya -weight: 600;">sudo cat /etc/shadow | grep saumya -weight: 600;">sudo cat /etc/shadow | grep saumya saumya:$6$rounds=4096$saltstring$hashedpassword:19820:0:99999:7::: # 9 fields separated by ':' saumya:$6$rounds=4096$saltstring$hashedpassword:19820:0:99999:7::: # 9 fields separated by ':' saumya:$6$rounds=4096$saltstring$hashedpassword:19820:0:99999:7::: # 9 fields separated by ':' nano /etc/passwd # find your line, change /bin/bash to /bin/false nano /etc/passwd # find your line, change /bin/bash to /bin/false nano /etc/passwd # find your line, change /bin/bash to /bin/false grep "Failed password" /var/log/auth.log | wc -l grep "Failed password" /var/log/auth.log | wc -l grep "Failed password" /var/log/auth.log | wc -l nano /etc/ssh/sshd_config nano /etc/ssh/sshd_config nano /etc/ssh/sshd_config PasswordAuthentication no PermitRootLogin no PasswordAuthentication no PermitRootLogin no PasswordAuthentication no PermitRootLogin no tail -f /var/log/auth.log tail -f /var/log/auth.log tail -f /var/log/auth.log -weight: 500;">systemctl -weight: 500;">restart sshd grep "Failed password" /var/log/auth.log | tail -5 # bots still try, still fail, but now they fail faster -weight: 500;">systemctl -weight: 500;">restart sshd grep "Failed password" /var/log/auth.log | tail -5 # bots still try, still fail, but now they fail faster -weight: 500;">systemctl -weight: 500;">restart sshd grep "Failed password" /var/log/auth.log | tail -5 # bots still try, still fail, but now they fail faster cat /etc/fstab cat /etc/fstab cat /etc/fstab # in the order # file system, mount point, type, options, dump and pass UUID=abc123 / ext4 defaults 0 1 UUID=def456 /boot ext4 defaults 0 2 tmpfs /tmp tmpfs defaults 0 0 # in the order # file system, mount point, type, options, dump and pass UUID=abc123 / ext4 defaults 0 1 UUID=def456 /boot ext4 defaults 0 2 tmpfs /tmp tmpfs defaults 0 0 # in the order # file system, mount point, type, options, dump and pass UUID=abc123 / ext4 defaults 0 1 UUID=def456 /boot ext4 defaults 0 2 tmpfs /tmp tmpfs defaults 0 0 nano /etc/fstab # add at the bottom: broken-entry-here nano /etc/fstab # add at the bottom: broken-entry-here nano /etc/fstab # add at the bottom: broken-entry-here mount: /: can't find broken-entry-here. mount: /: can't find broken-entry-here. mount: /: can't find broken-entry-here. cat /proc/meminfo cat /proc/meminfo cat /proc/meminfo cat /proc/cpuinfo | grep "flags" | head -1 cat /proc/cpuinfo | grep "flags" | head -1 cat /proc/cpuinfo | grep "flags" | head -1 # Find something running ps aux | grep nginx # Say it's PID 1234 ls /proc/1234/ # Find something running ps aux | grep nginx # Say it's PID 1234 ls /proc/1234/ # Find something running ps aux | grep nginx # Say it's PID 1234 ls /proc/1234/ cmdline cwd environ exe fd maps mem net -weight: 500;">status cmdline cwd environ exe fd maps mem net -weight: 500;">status cmdline cwd environ exe fd maps mem net -weight: 500;">status cat /proc/1234/cmdline | tr '\0' ' ' ls -la /proc/1234/fd/ cat /proc/1234/cmdline | tr '\0' ' ' ls -la /proc/1234/fd/ cat /proc/1234/cmdline | tr '\0' ' ' ls -la /proc/1234/fd/ > /proc/1234/fd/4 > /proc/1234/fd/4 > /proc/1234/fd/4 ip route show ip route show ip route show default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.100 metric 100 # local lane 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100 default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.100 metric 100 # local lane 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100 default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.100 metric 100 # local lane 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100 ip route del default ping google.com ip route del default ping google.com ip route del default ping google.com connect: Network is unreachable connect: Network is unreachable connect: Network is unreachable ip route add default via 192.168.1.1 # put it back # Most useful debugging command for routing ip route get 8.8.8.8 ip route add default via 192.168.1.1 # put it back # Most useful debugging command for routing ip route get 8.8.8.8 ip route add default via 192.168.1.1 # put it back # Most useful debugging command for routing ip route get 8.8.8.8 8.8.8.8 via 192.168.1.1 dev eth0 src 192.168.1.100 8.8.8.8 via 192.168.1.1 dev eth0 src 192.168.1.100 8.8.8.8 via 192.168.1.1 dev eth0 src 192.168.1.100 # Silence all output but still check if it worked some_noisy_command > /dev/null 2>&1 echo $? # 0 means success, anything else means it failed # Silence all output but still check if it worked some_noisy_command > /dev/null 2>&1 echo $? # 0 means success, anything else means it failed # Silence all output but still check if it worked some_noisy_command > /dev/null 2>&1 echo $? # 0 means success, anything else means it failed fallocate -l 500M bigfile # faster for large files # or the /dev/zero version: dd if=/dev/zero of=bigfile bs=1M count=500 df -h # watch disk fill up rm bigfile fallocate -l 500M bigfile # faster for large files # or the /dev/zero version: dd if=/dev/zero of=bigfile bs=1M count=500 df -h # watch disk fill up rm bigfile fallocate -l 500M bigfile # faster for large files # or the /dev/zero version: dd if=/dev/zero of=bigfile bs=1M count=500 df -h # watch disk fill up rm bigfile cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 24 echo # or the cleaner version: openssl rand -base64 18 cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 24 echo # or the cleaner version: openssl rand -base64 18 cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 24 echo # or the cleaner version: openssl rand -base64 18 vmlinuz-5.15.0-91-generic initrd.img-5.15.0-91-generic grub/ config-5.15.0-91-generic vmlinuz-5.15.0-91-generic initrd.img-5.15.0-91-generic grub/ config-5.15.0-91-generic vmlinuz-5.15.0-91-generic initrd.img-5.15.0-91-generic grub/ config-5.15.0-91-generic cat /boot/config-$(uname -r) | grep CONFIG_EXT4 cat /boot/config-$(uname -r) | grep CONFIG_EXT4 cat /boot/config-$(uname -r) | grep CONFIG_EXT4 CONFIG_EXT4_FS=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS=y ls /var/log ls /var/log ls /var/log auth.log syslog kern.log dpkg.log nginx/ -weight: 500;">apt/ journal/ auth.log syslog kern.log dpkg.log nginx/ -weight: 500;">apt/ journal/ auth.log syslog kern.log dpkg.log nginx/ -weight: 500;">apt/ journal/ tail -f /var/log/syslog # live system events journalctl -u nginx -f # live logs for a specific -weight: 500;">service journalctl -xe # recent journal with explanations journalctl --since "1 hour ago" # last hour of everything tail -f /var/log/syslog # live system events journalctl -u nginx -f # live logs for a specific -weight: 500;">service journalctl -xe # recent journal with explanations journalctl --since "1 hour ago" # last hour of everything tail -f /var/log/syslog # live system events journalctl -u nginx -f # live logs for a specific -weight: 500;">service journalctl -xe # recent journal with explanations journalctl --since "1 hour ago" # last hour of everything nano /etc/systemd/system/myapp.-weight: 500;">service nano /etc/systemd/system/myapp.-weight: 500;">service nano /etc/systemd/system/myapp.-weight: 500;">service [Unit] Description=My app After=network.target [Service] Type=simple User=saumya WorkingDirectory=/home/saumya/app ExecStart=/usr/bin/node server.js Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target [Unit] Description=My app After=network.target [Service] Type=simple User=saumya WorkingDirectory=/home/saumya/app ExecStart=/usr/bin/node server.js Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target [Unit] Description=My app After=network.target [Service] Type=simple User=saumya WorkingDirectory=/home/saumya/app ExecStart=/usr/bin/node server.js Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target -weight: 500;">systemctl daemon-reload -weight: 500;">systemctl -weight: 500;">enable myapp -weight: 500;">systemctl -weight: 500;">start myapp -weight: 500;">systemctl -weight: 500;">status myapp -weight: 500;">systemctl daemon-reload -weight: 500;">systemctl -weight: 500;">enable myapp -weight: 500;">systemctl -weight: 500;">start myapp -weight: 500;">systemctl -weight: 500;">status myapp -weight: 500;">systemctl daemon-reload -weight: 500;">systemctl -weight: 500;">enable myapp -weight: 500;">systemctl -weight: 500;">start myapp -weight: 500;">systemctl -weight: 500;">status myapp journalctl -u myapp -f journalctl -u myapp -f journalctl -u myapp -f export PATH="" ls export PATH="" ls export PATH="" ls bash: ls: command not found bash: ls: command not found bash: ls: command not found export PATH=/usr/bin:/bin:/usr/sbin:/sbin ls # back export PATH=/usr/bin:/bin:/usr/sbin:/sbin ls # back export PATH=/usr/bin:/bin:/usr/sbin:/sbin ls # back PATH=/usr/local/bin:/usr/bin:/bin * * * * * /home/saumya/myscript.sh PATH=/usr/local/bin:/usr/bin:/bin * * * * * /home/saumya/myscript.sh PATH=/usr/local/bin:/usr/bin:/bin * * * * * /home/saumya/myscript.sh echo '#!/bin/bash echo "this ran"' > myscript.sh ./myscript.sh echo '#!/bin/bash echo "this ran"' > myscript.sh ./myscript.sh echo '#!/bin/bash echo "this ran"' > myscript.sh ./myscript.sh bash: ./myscript.sh: Permission denied bash: ./myscript.sh: Permission denied bash: ./myscript.sh: Permission denied ls -la myscript.sh # -rw-r--r-- 1 saumya saumya 30 myscript.sh ls -la myscript.sh # -rw-r--r-- 1 saumya saumya 30 myscript.sh ls -la myscript.sh # -rw-r--r-- 1 saumya saumya 30 myscript.sh chmod +x myscript.sh ./myscript.sh # this ran chmod +x myscript.sh ./myscript.sh # this ran chmod +x myscript.sh ./myscript.sh # this ran chmod -x /bin/ls ls chmod -x /bin/ls ls chmod -x /bin/ls ls bash: /bin/ls: Permission denied bash: /bin/ls: Permission denied bash: /bin/ls: Permission denied chmod +x /bin/ls chmod +x /bin/ls chmod +x /bin/ls chown -R www-data:www-data /var/www/html chmod -R 755 /var/www/html chown -R www-data:www-data /var/www/html chmod -R 755 /var/www/html chown -R www-data:www-data /var/www/html chmod -R 755 /var/www/html [Service] Environment=NODE_ENV=production EnvironmentFile=/etc/myapp/.env [Service] Environment=NODE_ENV=production EnvironmentFile=/etc/myapp/.env [Service] Environment=NODE_ENV=production EnvironmentFile=/etc/myapp/.env - Linux Journey : This has organized learning path that breaks down the complexities of the Linux operating system into digestible stages. - Bandit : It is wargame designed to teach the fundamentals of the Linux command line. Visually looks boring, but is really interesting to follow through. - Fireship: Linux in 100 Seconds : -weight: 500;">start here if you haven't - Linux man pages : every file and command has one - tldr pages : -weight: 500;">install with -weight: 500;">apt -weight: 500;">install tldr, use it for every new command - Arch Wiki : the best Linux documentation on the internet, works for all distros regardless of what you're running - explainshell.com : paste any command and it breaks down every flag visually - The filesystem docs : official kernel documentation