This is my quick reference for using Linux for doing things. I claim no originality. Mostly they are copy pasted from the internet and tested by me. An increasing proportion of those are produced by AI.
Linux koans
Everything is a file a file or a directory an inode. An inode (index node) is a representation of a sequence of data that the system can access. A file is just a list of inodes, and a directory is just a list of files.
Every command is an executable.
Every machine is a server. Some merely serve extremely slow machines (humans, aka “users”).
The \usr is not the user. It is the UNIX System Resources.
The \usr was the user, until Unix became so large that \bin overflowed and had to put the rest of them in \usr\bin. This was embarrassing for all involved, so they moved user files to \home, and pretend that \usr stands for UNIX System Resources. (here). A mistake that only took 40 years to fix.
In the beginning was the command line. The command line is just a face of the shell. What was the original face of the command line before the shell was born?
The shell reads in a stream of letters, because the user is just another file (a streaming file, named stdin). Like all streaming files, the user is eternal and inexhaustible. The shell stands, rapt in attention, afore the user file.
So when does the user ever leave? The user never leaves. The shell simply kills itself when the user types exit. The shell would rather die than to face the prospect of reading the last word from the user.
So when does the shell ever break out of its rapt attention? Whenever it sees \n, it is shaken out of its trance and interprets what the user has just said, in the interval bracketed between two \ns.
The shell has one ear and two mouths. The ear is stdin, and the mouths are stdout and stderr. The shell has a tiny brain which is only capable of interpreting the few syntactic elements of bash scripts. Everything else it wants to do, it dutifully sends a binary message into the oracular altar of the Linux kernel, from which an oceanic voice replies the answer of the kernel.
How to PATH
The PATH environment variable is a list of directories that the shell searches for commands. It is a colon-separated list of directories. For example, just about every Linux installation has a PATH variable that looks like:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binTo add things to PATH, use the export command, like export PATH="$HOME/bin:$PATH".
env # same as printenv
export VAR_NAME="value"
unset VAR_NAME
export PATH=newpath:$PATH # There is no simple way to undo this one.
# but you can try export OLD_PATH=$PATH; ...; export PATH=$OLD_PATHFor Windows, use Get-ChildItem Env:.
How to directories
Based on https://askubuntu.com/a/135679, https://serverfault.com/a/24525, man hier, Filesystem Hierarchy Standard - Wikipedia.
Where to install read-only things
/binand/sbin: binaries and superuser-binaries./usr: System-wide, read-only files installed by the OS. This directory can be remotely mounted to multiple hosts safely./usr/local: System-wide, read-only files installed byroot. And that’s why most directory names from/usrare duplicated here./opt- System-wide, read-only and bundled-up software. That is, software that does not split their files overbin,lib,share,includelike well-behaved software should./usr/binandusr/sbin: They no longer exist. Just use/binand/sbin.~/.local: the per-user counterpart of/usr/local, that is: software installed by (and for) each user. Like/usr, it has its own~/.local/share,~/.local/bin,~/.local/lib.~/.local/opt: The per-user counterpart of/opt
Requiem for /usr/bin and /usr/sbin: Originally, /bin and /lib are only for binaries and libraries required for booting, while /usr/bin and /usr/lib are for all the other executables and libraries. This is no longer true, as some binaries required for booting has over the years leaked into those two folders (if there is a way to make a mess, people will make it), so since Ubuntu 20.04, they no longer exist, to remove this mess.
How to install for local user only:
./configure --prefix=$HOME/.local
make
make installHow to install for everyone: sudo ./configure && make && make install
Where to install read-write things
Read-write things are typically configuration files, since they are read and written by both the user and binary executables.
/etc: System-wide configuration. Typically used by the OS to decide what to do when starting up, shutting down, etc.~/.config: Per-user configuration files. Although because of legacy, you keep seeing nonsense like.bashrcin your home directory instead of~/.config/.bashrc. Herercmeans “run configuration”.
Where to do read-write things
/home/username, or just~: Each user typically is only able to modify their own folder here, like~/myfile.txt./tmp: If you need to create something just for the moment, then make it here. It will be deleted when the system restarts.
Other things (you should not modify them)
/run:runtime temporary data, representing the system’s state since the last boot. It’s used for storing process IDs, lock files, and other files that are would normally be stored in/tmp. It is basically/tmpfor the machine./var: Variable data. It is somewhat like/runin that both are meant to be read-written by programs, but unlike/run, data here persists over reboots. This is often used for logging information. For example, tryvim /var/log/user.log
Modifying anything below this line may brick the system. Reading is fine though.
/lib: libraries. You should not handle it directly. Some libraries are added at OS installation, and others at program installation. If you have a broken installation, you might be asked to manually copy some files looking likelibxxx.sohere. (sostands for “shared object”.)/boot: Files required for booting. For example, the bootloader, the kernel, the initramfs (initial RAM file system)./dev: Device files. It typically looks like/dev/sda1,/dev/sda2, etc. Other than things likesda1(for harddrive) you might noticetty1andpty1’ which stand for “teletype” and “pseudo teletype”, respectively, but they are actually used as files to read whatever the user is typing from (the user is a file, see Section 1). There are some odd ones like:/dev/null, which is a “file” that you write to when you just want to throw something away (everything is a file, even a black hole…)./dev/urandom, which is a random number generator. It is preferred over/dev/random. See here./dev/zero, which is a file that you can’t write to, but you can read, but it’s filled with zeros.
/media: Mount removable medias, like USB drives and SD cards. For example, you can mount a USB at/media/usb1and another one at/media/usb2. Mounting is typically done automatically by the system when you plug it in./mnt: Mounts that are not so easily removable, like a hard drive, or a network drive. And unlike/media, mounting and unmounting is not automatic. On WSL, this typically has just one important thing:/mnt/c./srv: Static files that are served out./srv/httpwould be for static websites,/srv/ftpfor an FTP server. It is usually used only on webservers, not an end-user machine like your laptop.
Environment variables
How to control them
Use echo $X to see what the current value of X is.
For current session, use export like export EDITOR=nano.
For all sessions, add to your .bashrc or .profile. If you just want to add it to the end (not recommended, as you can end up with an archeological tell), you can do one-liner like echo "export EDITOR=nano" >> ~/.bashrc.
Common ones
PATH: path to binaries. See Section 2.EDITOR: default editor.SHELL: default shell.HOME: home directory.USER: current user.PS1: current prompt (just tryecho $PS1if it doesn’t make sense).
You can change prompts in a rather arcane language. For example, try this one:
export PS1="\[\e]0;\w\a\]\n\[\e[32m\]\u@\h \[\e[33m\]\w\[\e[0m\]\n\\$ "Cron jobs
Cron jobs are scheduled tasks that run periodically. For scheduling one-off tasks, use the at command. The name came from “Cronos”, the name of the Greek god of time. A good reference is Newbie: Intro to cron.
Quick reference
The cron job syntax is as follows (See Crontab.guru - The cron schedule expression editor):
# ┌───────────── minute (0–59)
# │ ┌───────────── hour (0–23)
# │ │ ┌───────────── day of the month (1–31)
# │ │ │ ┌───────────── month (1–12)
# │ │ │ │ ┌───────────── day of the week (0–6) (Sunday to Saturday)
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ │
# * * * * * <command to execute>
* * * * * <once a minute>
0 * * * * <once an hour at 0-th minute>
0 0 * * * <once a day at midnight>
0 0 1 * * <once a month at the midnight of the 1-th day>
0 0 1 1 * <once a year at the midnight of January 1>
* * * * 0 <once a minute every Sunday>Check that cron service is running by systemctl list-unit-files --type=service | grep "cron"
List cron jobs by crontab -l.
Creating a Cron Job
For this example, we create a job that runs every 20 seconds.
Open Crontab: Open your crontab file by typing
crontab -ein your terminal. This command opens the crontab file for the current user in the default text editor.Write Cron Job: Standard cron jobs can’t run in a smaller granularity than a minute. For a once-per-20-seconds job, you’ll need to use a workaround.
Add the following lines to your crontab:
* * * * * /path/to/script.sh
* * * * * sleep 20; ~/cronjobs/script.sh
* * * * * sleep 40; ~/cronjobs/script.sh- Script Content: Create
script.sh, have the following content:
#!/bin/bash
CRON_MESSAGE="Some message"
echo "The cron message is: $CRON_MESSAGE"Then save and close the file, and chmod +x ~/cronjobs/script.sh to make it executable.
Best Practices
- Location: Store scripts in a dedicated directory, such as
~/cronjobs, for better organization. - Script Naming: Use meaningful names for your scripts for easier identification.
- Logging: Implement logging within your scripts to capture output and errors for later review. It’s good practice to use
/var/log/cronfor logging.
Cron environment variables
Cron jobs run in a minimal environment, so any environment variable, like CRON_MESSAGE, is not accessible by the cron script. Instead, you have a few choices:
- Put it directly in the crontab file:
CRON_MESSAGE="Some message"
* * * * * /path/to/script.sh- Put it directly in the script:
#!/bin/bash
export CRON_MESSAGE="Some message"
# rest of the script follows- If the variable is defined in an external file (like ~/.bashrc, ~/.profile, or a custom configuration file), you can source that file at the beginning of your script:
#!/bin/bash
source /path/to/environment_variables_file
# rest of the script followsTroubleshooting
- Check Permissions: Ensure your script is executable and the cron daemon has the necessary permissions to run it.
- Logs: Check
/var/log/cronor relevant logs for errors.
If you’re using WSL, ensure that the cron service is running since it doesn’t start by default. Use sudo service cron start. You can configure ~/.bashrc by adding the following line: sudo service cron start, but it would make you enter the password at every login.
Alternatively, enable systemd as described at Section 6.1.
How to WSL
init vs systemd
Every Linux starts its first process with some root process. The init is the traditional and simpler one, and systemd is more modern and advanced one.
WSL by default starts with init instead of systemd, perhaps to save time and compute. This makes things annoying for some users. You can check by ps -p 1 -o comm and see what it returns.
To enable systemd, enter in your /etc/wsl.conf with:
[boot]
systemd=trueor just use cat "[boot]\nsystemd=true" >> /etc/wsl.conf.