File & directory commands
ls, cd, cp, mv, rm, mkdir, touch, ln — with output.
Almost everything you do on a Linux server involves moving around the filesystem and manipulating files, so this small set of commands becomes second nature fast. Each one does exactly one thing, and they combine into everything else. We will go through them one at a time, with the real output you would see — because the fastest way to learn a command is to run it and read what it prints.
ls — list directory contents
ls lists what is in a directory. On its own it prints names in columns; the flags are where it gets useful. -l gives the long format (one file per line, with permissions, owner, size, and date); -a shows hidden files (those starting with a dot); -h makes sizes human-readable (K, M, G); and -t sorts by time. You will type ls -lah constantly — long, all, human-readable.
$ lsconfig.yml data logs server.py$ ls -lahtotal 24Kdrwxr-xr-x 4 deploy deploy 4.0K Jul 3 10:14 .drwxr-xr-x 6 deploy deploy 4.0K Jul 3 09:02 ..-rw-r--r-- 1 deploy deploy 512 Jul 3 10:14 config.ymldrwxr-xr-x 2 deploy deploy 4.0K Jul 3 10:10 datadrwxr-xr-x 2 deploy deploy 4.0K Jul 3 10:12 logs-rwxr-xr-x 1 deploy deploy 1.2K Jul 3 10:14 server.py# │ │ │ │ │ └ date/time └ name# │ │ │ │ └ size (human-readable)# │ │ └owner └group# │ └ link count# └ type + permissions (d = directory, - = file)
pwd, cd — where you are, and moving
pwd ("print working directory") answers "where am I?" and cd ("change directory") moves you. cd with a path goes there; cd with nothing goes to your home; cd .. goes up one level; and cd - jumps back to the previous directory you were in. These plus ls are the loop you run all day: list, move, list again.
$ pwd/home/deploy/app$ cd /var/log # go to an absolute path$ pwd/var/log$ cd - # jump back to where I just was/home/deploy/app$ cd .. # up one level$ pwd/home/deploy
mkdir, rmdir, touch — create things
mkdir makes a directory; with -p it makes a whole path of nested directories at once (and does not error if they already exist). touch creates an empty file, or updates a file’s timestamp if it already exists. rmdir removes an empty directory (you will usually use rm -r instead, below).
$ mkdir logs$ mkdir -p project/src/api # creates project, project/src, and project/src/api all at once$ touch project/src/api/main.py # create an empty file$ ls -R projectproject:srcproject/src:apiproject/src/api:main.py
cp, mv, rm — copy, move, remove
cp copies a file (cp source dest); to copy a directory and everything in it, add -r (recursive). mv both moves and renames — mv old.txt new.txt renames, mv file.txt dir/ moves it into a directory. rm deletes a file; rm -r deletes a directory and its contents. There is no undo and no recycle bin, so rm is the command to respect most.
$ cp config.yml config.yml.bak # make a backup copy$ cp -r data data-archive # copy a whole directory (recursive)$ mv server.py app.py # rename$ mv app.py project/src/ # move into a directory$ rm config.yml.bak # delete a file$ rm -r data-archive # delete a directory and everything in it
ln — links
ln -s creates a symbolic link — a pointer to another file or directory, like a shortcut. Symlinks are everywhere in Linux: /usr/bin/python often points at python3.11, and config directories use them to switch between versions. ls -l shows a symlink with an arrow to its target. (A "hard link" without -s is a second name for the same data; symlinks are what you use day to day.)
$ ln -s /opt/app/config/prod.yml current.yml # current.yml now points at prod.yml$ ls -l current.ymllrwxrwxrwx 1 deploy deploy 27 Jul 3 10:20 current.yml -> /opt/app/config/prod.yml# ^ the leading "l" means it is a symlink; the arrow shows the target