Course outline · 0% complete

0/29 lessons0%

Course overview →

Making things: mkdir and touch

lesson 2-3 · ~8 min · 6/29

Creating directories and files

Every project starts the same way: create a directory skeleton, drop in some starter files, begin working. Doing that with commands instead of clicks means the whole setup can be scripted (unit 8) and repeated identically on any machine, including servers, where clicking is not an option.

These commands have been on loan since lesson 1-2. Here is what they actually do:

CommandMeaningBehavior
mkdir namemake directoryCreates one directory. Fails if the parent does not exist.
mkdir -p a/b/cmake with parentsCreates the whole chain in one go, and stays quiet if parts already exist.
touch nameupdate timestampCreates an empty file, or if it already exists, updates its last-modified time.

Both commands accept several names at once, as in touch a.txt b.txt c.txt.

Building a site skeleton without cd

A single mkdir -p builds two directories under site/, one touch drops files into them, and ls reads each directory by path, so the shell never has to move.

mkdir -p site/css site/js
touch site/index.html site/css/style.css
ls site
ls site/css

Output

css
index.html
js
style.css

The important trick is that ls accepts a path argument. ls site lists the contents of site from wherever you happen to be standing, so inspecting a directory does not require descending into it first.

Two ls flags worth knowing now

  • ls -a: show all entries, including hidden ones. Any name starting with a dot (like .bashrc) is hidden from plain ls. That's the entire hiding mechanism, just a naming convention. You'll meet these "dotfiles" properly in unit 7.
  • ls -l: long format. One line per entry with permissions, owner, size, and date. The permission string at the start (like -rw-r--r--) is decoded in unit 6.

Flags combine: ls -la shows everything, in detail.

Hidden files are just names that start with a dot

This example creates one ordinary file and one hidden file. Plain ls shows only the visible one, while ls -a reveals both. The output is narrowed to the interesting line with grep, the tool that headlines unit 4.

mkdir demo
cd demo
touch visible.txt .secret
ls
ls -a | grep secret

Output

visible.txt
.secret

Hiding here is purely a naming convention. A leading dot in the filename is the entire mechanism, and no special attribute or permission is involved, which is why ls -a can show these files without needing any extra privilege.

What -p actually does

In mkdir -p app/src/utils, the -p flag creates the missing parent directories along the way: app first, then app/src, then app/src/utils, all from one command. It also stays quiet when some of them already exist, which is what makes it safe to re-run. Without -p, mkdir fails as soon as it is asked for app/src/utils while app does not exist.

The p stands for parents, not for two things people reasonably guess:

  • It does not print each directory as it is created. mkdir is silent on success, like most Unix tools. The flag for narration is -v (verbose).
  • It has nothing to do with permissions or privacy. New directories take their mode from your umask, and changing that is chmod's job (unit 6).

Building a project skeleton in one go

A whole project skeleton, created and then listed, with two directories, two files, and no cd anywhere. A single mkdir -p handles both directories because it accepts several paths at once, a single touch creates both files for the same reason, and two ls calls read the results by path.

mkdir -p app/src app/docs
touch app/readme.md app/src/main.py
ls app
ls app/src

Output

docs
readme.md
src
main.py

What makes this scriptable

  • mkdir -p app/src app/docs makes both directories in one command, creating the shared app parent along the way.
  • touch takes several paths at once too, so both files come from one line.
  • Nothing here needs cd. Every path is relative to where you already stand, which is what makes these lines safe to paste into a script.
  • ls app lists docs, readme.md, and src in alphabetical order, which is ls's default. main.py appears only under ls app/src, since that is where it lives.