Shell, explained
The shell, explained visually.
Every page takes one command apart and draws it: what each part does, where every line goes, and the trap that catches everyone. Tap any part to explore it.
$ls | grep .txt | wc -l
What does the pipe | do in the terminal?
The pipe | connects two commands: everything the first one prints becomes the input of the second. In ls | grep .txt | wc -l, ls lists the files, grep keeps only the names containing .txt, and wc -l counts what is left.
See it drawn$ls notes.txt nope.txt 2>&1 | grep nope
What does 2>&1 mean?
2>&1 sends a command's error output (stream 2, stderr) to the same place as its normal output (stream 1, stdout). Without it, errors skip the pipe and go straight to your screen, so the next command never sees them.
See it drawn$echo "buy milk" >> todo.txt
> vs >> in the terminal: overwrite or append?
> writes a command's output into a file and replaces everything that was in it. >> adds the output to the end of the file and keeps what was there. Both create the file if it does not exist yet.
See it drawn$mkdir backup && cp notes.txt backup/
&&, || and ; in the terminal: what's the difference?
All three run one command after another. && runs the next one only if the previous one succeeded (exit status 0), || only if it failed, and ; runs it no matter what happened.
See it drawn$rm "$f"
Why quote your variables: rm $f vs rm "$f"
Without quotes, bash splits a variable's value on spaces (and expands any * in it) before the command runs. With f="old notes.txt", rm $f gets two arguments, old and notes.txt, and deletes notes.txt: a different file. rm "$f" gets the one name you meant.
See it drawn$echo *.txt
What does * mean in the terminal? Globbing explained
* is a wildcard that the shell expands before the command runs: the pattern is replaced by every file name in the current folder that matches it. The command never sees the *, only the list of names.
See it drawn$find . -name "*.log" | xargs rm
find . -name "*.log" | xargs rm, explained
find lists every .log file below the current folder, one path per line. xargs reads those lines and runs rm with all of them as its arguments, so every file found is deleted. The quotes around *.log matter: they let find, not the shell, do the matching.
See it drawn$sort names.txt > names.txt
Why sort file > file empties your file
The shell sets up the > redirection before sort starts, and > empties the file straight away. When sort then opens names.txt, there is nothing left to read, so it writes nothing back. The file ends up empty.
See it drawn