Linux and the Terminal
The idea
Picture a giant filing cabinet. Each drawer is a directory (a folder that holds files or other folders). Drawers hold smaller folders, which hold more folders, all the way down to the papers: your files. The very front of the cabinet is the root, written /. An absolute path is the full chain of drawers from the front of the cabinet to one paper: /home/you/notes/today.txt means front, then home, then you, then notes, then the paper today.txt. A relative path starts from the drawer you already have open, so notes/today.txt means "the today.txt in the notes drawer right here." Three shortcuts: . is the open drawer, .. is the drawer that holds it, and ~ is your home drawer.
The terminal is a control room for that cabinet. Instead of clicking icons, you type a short written order, called a command, press Enter, and the computer carries it out. That sounds slower, but it pays off: a typed order can be repeated, saved in a file, and chained with other orders, and every server you will ever support is run this way.
Setup: on Windows, run wsl --install in PowerShell to install WSL2 (Windows Subsystem for Linux 2), restart, then open the Ubuntu app. On macOS and Linux, just open Terminal. On Windows, keep your course files inside the Linux side, under your home folder (~), and not under /mnt/c/, which is your Windows drive seen from Linux: it is slower and mixes up file permissions. Everything you type in this course runs in a shell, the program inside the terminal that reads your orders. On Ubuntu it is called bash.
Moving around: pwd, ls, and cd
The Go programs you write later will run from this control room, so the orders come first. Three commands tell you where you are and how to move:
pwd # print working directory: shows your current folder
ls # list: shows what is in the current folder
cd projects # change directory: walk into the "projects" drawer
cd .. # walk up one level, to the parent folder
cd . # walk nowhere: "." is the drawer you already have open
cd ~ # jump to your home drawer from anywhere
cd - # jump back to the drawer you were in a moment ago
clear # wipe the screen clean (Ctrl+L does the same)
exit # close the terminal session
pwd prints a path such as /home/you. If cd says No such file or directory, the drawer is not in the one you have open, so check with ls.
Two flags (options that change how a command works) make ls more useful:
ls -a # -a also shows hidden files, whose names start with a dot
ls -lh # -l is the long listing; -h prints sizes people can read, like 4.0K
ls -R # -R lists the folder and every folder inside it, level by level
Flags can be glued together: ls -lha means ls -l -h -a.
Making, copying, moving, and deleting
echo prints the text you give it, and cat prints a whole file on the screen:
mkdir notes # make directory: create a new folder
mkdir -p a/b/c # -p creates the whole chain of folders in one go
touch todo.txt # create an empty file named todo.txt
echo "hi" > todo.txt # echo prints text; with > it puts that text in the file
cat todo.txt # prints: hi
cp todo.txt backup.txt # copy: duplicate a file
cp -r notes notes2 # -r copies a folder and everything inside it
mv todo.txt done.txt # move: rename or relocate a file
rm -i done.txt # remove: delete a file (-i asks you first)
rmdir notes2 # remove directory: delete an empty folder
rm -r a # -r removes a folder and everything inside it
rmdir refuses a folder that has things in it, but rm -r does not. Neither has an undo. cat can also take several files and prints them one after the other. mv and cp overwrite an existing file of the same name without asking, so use cp -i and mv -i when you are unsure. And never run rm -rf / or rm -rf ~: -f (force) removes without asking, and those two erase everything.
If a name contains a space, wrap it in quotes, otherwise the shell sees two separate names:
touch "my notes.txt" # one file called: my notes.txt
touch my notes.txt # two files: my and notes.txt
Wildcards
Typing every file name gets old. A wildcard is a pattern the shell fills in with every matching name before the command even runs.
ls *.txt # * matches any run of characters: a.txt, b.txt, report.txt
ls ?.txt # ? matches exactly one character: a.txt, b.txt, but not report.txt
ls [ab].txt # [ab] matches one character from the list: a.txt and b.txt
cp *.txt backup/ # copy every .txt file into the backup folder
rm *.tmp # delete every .tmp file: check with ls *.tmp first
The shell does the matching, not ls or cp. If you run echo *.txt you see a.txt b.txt, the names the shell filled in. Two things follow. A wildcard only matches names that exist, and a pattern that matches nothing is passed along unchanged. And when a command needs to receive the * itself, such as find . -name "*.log" in the next lesson, you quote it so the shell leaves it alone.
Standard output and standard error
Every command has two places to print: standard output for its normal results and standard error for its complaints. Both show up on your screen, so they look the same, but they are separate streams. > only captures the first one.
ls /nonexistent > out.txt # the complaint still appears on screen; out.txt stays empty
ls /nonexistent 2> err.txt # 2> sends the complaint to a file instead
ls /nonexistent 2>/dev/null # /dev/null is a bin that swallows everything: hide the complaint
ls a.txt /nonexistent > both.txt 2>&1 # 2>&1 sends errors to the same place as normal output
ls: cannot access '/nonexistent': No such file or directory is the complaint here, printed on standard error. 2>/dev/null is how you silence noise you have already decided to ignore, such as Permission denied lines when searching the whole disk. Use it carefully, because it also hides real problems.
Editing files with nano
Almost everything from here on needs you to write text into a file: scripts, notes, programs. echo ... > works for one line, but for real editing you need an editor. nano is a simple one that runs inside the terminal.
nano notes.txt
nano opens the file (creating it if it does not exist) and you just type. The commands are listed along the bottom of the screen, where ^ means the Ctrl key. Press Ctrl+O, then Enter, to save ("write out"). Press Ctrl+X to exit; if there are unsaved changes it asks whether to save them. Ctrl+W searches for text. If you prefer a graphical editor, Visual Studio Code works well with WSL2: from a folder, run code . and it opens that folder.
Write plain text files only, not Word documents. Files saved from Windows Notepad can carry hidden carriage-return characters at the end of every line (written \r), which break scripts in confusing ways, so use nano or VS Code for anything you will run.
Pipes and redirects
A pipe is a conveyor belt from one machine to the next: what the left command prints becomes what the right command reads. A redirect sends that printed output into a file instead of the screen.
ls | sort # pipe: list files, then sort the lines alphabetically
ls > files.txt # redirect: overwrite files.txt with the listing
ls >> files.txt # redirect: append the listing to files.txt instead
sort puts lines in alphabetical order. After the two redirects, files.txt holds the listing once from > and again from >>.
Permissions
Permissions are keys and badges for each door. Every file has an owner, a group, and rules for who may read (r), write (w), or execute (x, run as a program) it. ls -l shows ten characters like -rw-r--r--. The first is the type (- for a file, d for a drawer). Then come three letters each for the owner, the group, and everyone else. So -rw-r--r-- is a file the owner can read and write, and everyone else can only read.
ls -l # long listing: permissions, owner, size per file
chmod u+x script.sh # u = you, the owner; +x = add the execute badge
After chmod u+x, the owner's letters change from rw- to rwx. To run a script file that has the execute badge, put ./ in front of its name, which means "the file right here": ./script.sh. Without the badge, run it through the shell instead: sh script.sh.
Some actions are reserved for the administrator, whom Linux calls root. sudo runs one command with that power, asks for your password (nothing shows as you type), and is how you install software: sudo apt update refreshes Ubuntu's list of available programs, and sudo apt install tree installs one called tree. Only use sudo when a command tells you it needs it, and read the command twice first.
Getting help and working faster
Forgot what a command does? Read its man page (manual page: the built-in instructions).
man ls # opens the manual for ls; press q to quit
history # lists the orders you gave earlier; the up arrow recalls them
which ls prints where a program lives on disk, which answers "is this installed?" (it prints nothing when it is not).
The shell's error messages are short but precise. Three you will meet constantly:
command not found: you misspelled the command, or the program is not installed.No such file or directory: the path is wrong. Check your spelling, check where you are withpwd, and check the folder withls.Permission denied: you are not allowed to read, write or run that file. Look atls -l, and do not reach forsudounless you understand why.
Two keys save time. Tab completes a name you have started typing. Ctrl+C stops a command that is still running.
Common mistakes
rmhas no trash can. The file is gone, so check withpwdandlsfirst, and userm -iwhile learning.rm -rdeletes a whole folder at once. Read the path twice before pressing Enter.>overwrites the whole file; use>>to add to it.cd ..goes up one level;cd .stays where you are.- Linux commands and file names are case-sensitive.
- Forgetting quotes around a name with a space, so the shell splits it into two names.
- Running
rm *orrm *.txtwithout first runninglswith the same pattern to see exactly what it will hit. - Expecting
>to capture error messages. Those need2>. - Editing scripts in a word processor instead of nano or VS Code.
Try it
- Open your terminal (Windows: the Ubuntu app after WSL2). Run
pwd. You see a path starting with/, like/home/you. - Run
cd ~, thenpwd. You are in your home drawer. Runcd .., thenpwd: one level up. Runcd ., thenpwd: the same path as before. - Run
cd ~, thenls,ls -a, andls -lh.ls -aadds names starting with a dot. In the long listing, each line starts with permission letters like-rw-r--r--(a file, where the owner can read and write and everyone else can only read) ordrwxr-xr-x(a drawer). - Run
mkdir -p practice/a/b, thencd practice/a/b, thenpwd. The path now ends inpractice/a/b. - Run
cd ~/practice, thenecho "hello" > hello.txtandcat hello.txt. You seehello. - Run
cp hello.txt copy.txt,mv copy.txt renamed.txt, thenls. You seea,hello.txt, andrenamed.txt. - Run
cp -r a backup, thenls. You now also seebackup. Runls | sort: the same names in alphabetical order. - Run
ls > list.txt, thenls >> list.txt, thencat list.txt. The listing appears twice, because>>added to the file. - Run
chmod u+x hello.txt, thenls -l. The permission letters forhello.txtnow includex. - Run
rm -i renamed.txtand answery. Then runrm -r backup, thenls. Both names are gone. - Run
historyto see your earlier orders. Typecatwith no file name: it waits for typing. Press Ctrl+C to stop it. Typecd ~/praand press Tab: it completes topractice. - Run
man ls, skim it, pressqto quit. Thencd ~to return home. - Run
cd ~/practice, thentouch a.txt b.txt c.md. Runls *.txt,ls ?.txtandecho *.mdand compare what each prints. Then runmkdir stashandcp *.txt stash/, andls stash. - Run
ls /nonexistentand read the complaint. Then runls /nonexistent 2> err.txt(the screen stays quiet),cat err.txt, andls /nonexistent 2>/dev/null. - Run
nano hello.sh, typeecho hi, press Ctrl+O then Enter to save, and Ctrl+X to exit. Then runsh hello.sh, andcat hello.shto see the file you wrote. - Run
touch "my notes.txt", thenls my notes.txtand read the two complaints, thenls "my notes.txt"with the quotes.