Temporary Files, Hidden Files, and Directory Layout
Filesystem hygiene depends on lifecycle. Temporary work, persistent configuration, mutable state, cache, logs, runtime sockets, and application releases should not be mixed. This lesson connects safe temporary-resource creation with Linux directory conventions.
Learning objectives
By the end of this lesson
- Create race-resistant temporary files and directories with mktemp.
- Use traps to clean up temporary resources on normal and interrupted exits.
- Explain why leading-dot names are hidden by convention rather than access control.
- Map configuration, persistent state, cache, logs, runtime data, and applications to conventional locations.
- Design a user-owned application workspace with explicit lifecycle boundaries.
1. Place data according to ownership and lifecycle
A maintainable system separates what is shipped from what changes at runtime. Mixing application binaries, configuration, logs, caches, secrets, and temporary data in one directory complicates upgrades, backup policy, permissions, incident response, and cleanup.
flowchart TD A["Application or service"] --> C["Configuration"] A --> S["Persistent state"] A --> H["Cache"] A --> L["Logs"] A --> R["Runtime sockets and PID data"] A --> T["Temporary working data"] C --> ETC["/etc or user config"] S --> VAR["/var/lib or user data"] H --> CACHE["/var/cache or user cache"] L --> LOG["/var/log or journal"] R --> RUN["/run"] T --> TMP["/tmp or private temp dir"]
2. Temporary resources require unique, private names
Constructing a predictable pathname such as
/tmp/my-script.tmp creates race and collision risks.
Another user or process might create it first, replace it with a
link, or read data written with permissive defaults.
mktemp creates a unique file or directory securely
according to the requested template and current permissions.
temporary_file=$(mktemp)
temporary_dir=$(mktemp -d)
printf 'temporary file: %s\n' "$temporary_file"
printf 'temporary dir: %s\n' "$temporary_dir"
stat -c 'mode=%A owner=%U:%G type=%F path=%n' -- \
"$temporary_file" "$temporary_dir"
rm -f -- "$temporary_file"
rm -rf -- "$temporary_dir"
A command that merely prints a supposedly unique name can leave a race window. Use a tool that atomically creates the resource with restrictive access.
3. /tmp, /var/tmp, /run, and TMPDIR serve different lifecycles
/tmpGeneral temporary data, often cleared at boot or by aging
policyShared namespace; create private resources securely
/var/tmpTemporary data expected to survive reboot longerStill subject to cleanup policy; not a durable data store
/runVolatile runtime state since current bootUsually managed by system services; cleared at boot
$TMPDIRPreferred temporary base selected by environment or
applicationValidate availability and fall back deliberately
choose_tmp_base() {
local candidate=${TMPDIR:-/tmp}
if [[ -d $candidate && -w $candidate ]]; then
printf '%s\n' "$candidate"
else
printf '%s\n' /tmp
fi
}
base=$(choose_tmp_base)
work=$(mktemp -d --tmpdir="$base" devops-academy.XXXXXX)
printf 'private work directory: %s\n' "$work"
rm -rf -- "$work"
4. Clean up with a trap while preserving the real exit status
A script can exit through success, an error, or a signal. A cleanup
function registered on EXIT provides one central
removal path. It should quote variables, tolerate partially created
resources, and avoid masking the script’s original status.
#!/usr/bin/env bash
set -u
work=''
cleanup() {
status=$?
trap - EXIT INT TERM
if [[ -n $work && -d $work ]]; then
rm -rf -- "$work"
fi
exit "$status"
}
trap cleanup EXIT INT TERM
work=$(mktemp -d "${TMPDIR:-/tmp}/academy-report.XXXXXX")
printf 'alpha\n' > "$work/input.txt"
tr '[:lower:]' '[:upper:]' < "$work/input.txt" > "$work/output.txt"
cat -- "$work/output.txt"
# EXIT trap removes the private directory.
For service-grade automation, cleanup policy may retain failed evidence instead of deleting it. That decision should be explicit: clean secrets and disposable data, but preserve diagnostic artifacts when required by the runbook.
6. Conventional Linux directory roles
/etcHost-specific system configurationService configuration, repository definitions, network
policy
/usrShareable, mostly read-only system software and dataCommands, libraries, documentation
/var/libPersistent mutable service stateDatabases, package-manager state, application state
/var/logPersistent log files where file logging is usedApplication and system logs, alongside journal-based
logging
/var/cacheRegenerable cached dataPackage caches, downloaded indexes, rendered artifacts
/runVolatile runtime stateSockets, PID files, locks, service-generated state
/optAdd-on application packagesVendor or self-contained third-party software
/srvData served by system servicesSite content or protocol-specific service data
/homeUser-owned files and configurationSource checkouts, user tools, course labs
Real distributions and applications vary. Consult package documentation and service unit configuration rather than inventing arbitrary paths. The key design is separation: code, configuration, durable state, cache, logs, and runtime files have different backup and cleanup rules.
7. User-scoped configuration and XDG directories
Desktop and command-line applications increasingly follow XDG
base-directory conventions. They separate user configuration,
persistent application data, cache, and runtime state instead of
placing everything directly in $HOME.
config_home=${XDG_CONFIG_HOME:-$HOME/.config}
data_home=${XDG_DATA_HOME:-$HOME/.local/share}
cache_home=${XDG_CACHE_HOME:-$HOME/.cache}
state_home=${XDG_STATE_HOME:-$HOME/.local/state}
printf 'config=%s\n' "$config_home"
printf 'data=%s\n' "$data_home"
printf 'cache=%s\n' "$cache_home"
printf 'state=%s\n' "$state_home"
mkdir -p -- \
"$config_home/devops-academy" \
"$data_home/devops-academy" \
"$cache_home/devops-academy" \
"$state_home/devops-academy"
Human or policy-controlled settings
Back up and review changes; do not mix generated cache into this location.
Persistent application-owned content
May require backup, migration, and compatibility planning.
Regenerable acceleration data
Can normally be deleted when the application is stopped, at the cost of recomputation.
Persistent operational state
History, checkpoints, and other data that should survive but is not primary user content.
8. Virtual filesystems are interfaces, not ordinary storage
Paths such as /proc and /sys expose kernel
and device information through filesystem-like interfaces. Many
entries are generated dynamically and do not represent persistent
disk files. /dev contains device nodes and related
runtime-managed entries.
printf 'Process identity through /proc:\n'
readlink -- /proc/self/exe
cat -- /proc/self/status | head
printf '\nSelected virtual filesystem mounts:\n'
findmnt -n -o TARGET,FSTYPE /proc /sys /dev /run 2>/dev/null || true
Some virtual files are writable control interfaces. Writing to them can change kernel or device behavior immediately. Inspect documentation and use later hardening lessons before modifying such paths.
9. Hands-on lab: build a lifecycle-separated user application tree
set -u
app=academy-demo
root="$HOME/devops-academy/linux/chapter04/lesson05-layout"
rm -rf -- "$root"
mkdir -p -- "$root"
config_root=${XDG_CONFIG_HOME:-$HOME/.config}
data_root=${XDG_DATA_HOME:-$HOME/.local/share}
cache_root=${XDG_CACHE_HOME:-$HOME/.cache}
state_root=${XDG_STATE_HOME:-$HOME/.local/state}
config_dir="$config_root/$app"
data_dir="$data_root/$app"
cache_dir="$cache_root/$app"
state_dir="$state_root/$app"
mkdir -p -- "$config_dir" "$data_dir" "$cache_dir" "$state_dir"
printf 'endpoint=https://example.invalid\n' > "$config_dir/app.conf"
printf 'record-001\n' > "$data_dir/records.txt"
printf 'compiled-cache\n' > "$cache_dir/index.cache"
printf 'last_run=never\n' > "$state_dir/status"
work=$(mktemp -d "${TMPDIR:-/tmp}/${app}.XXXXXX")
trap 'rm -rf -- "$work"' EXIT
printf 'transient-build\n' > "$work/build.tmp"
{
printf 'CONFIG %s\n' "$config_dir/app.conf"
printf 'DATA %s\n' "$data_dir/records.txt"
printf 'CACHE %s\n' "$cache_dir/index.cache"
printf 'STATE %s\n' "$state_dir/status"
printf 'TEMP %s\n' "$work/build.tmp"
} > "$root/layout-report.txt"
cat -- "$root/layout-report.txt"
printf '\nTemporary object mode:\n'
stat -c '%A %U:%G %n' -- "$work" "$work/build.tmp"
Verification checklist
10. Common temporary and layout mistakes
Using a predictable filename in /tmp
This risks collisions and link attacks. Create the resource
atomically with mktemp.
Treating dotfiles as secret
Hidden display does not restrict access. Use ownership, permissions, and secret-management controls.
Writing mutable state beside installed binaries
Upgrades and read-only deployment models become fragile. Separate code from configuration and state.
Deleting diagnostic evidence unconditionally
Cleanup policy should distinguish secrets and disposable data from artifacts needed to understand a failed run.
11. Knowledge check
Question 1. Why is mktemp safer than
manually choosing /tmp/my-script.tmp?
Question 2. Does a leading dot protect a file from other users?
Question 3. Why should cache and persistent state be stored separately?
12. Chapter summary
Chapter 4 established safe filesystem manipulation and interpretation. You can create, copy, move, and remove bounded targets; inspect object types and metadata; reason about inodes and links; control shell-generated target sets; and separate temporary, configuration, state, cache, log, runtime, and application data according to lifecycle.
13. Further reading
- Filesystem Hierarchy Standard — directory purposes and placement conventions.
- GNU Coreutils manuals for mktemp, ls, cp, stat, and install.
- GNU Bash Reference Manual — traps, parameter expansion, and shell startup files.
- XDG Base Directory Specification — user configuration, data, cache, state, and runtime directories.
- Linux manual pages for tmpfile, mkstemp, proc, sysfs, tmpfs, and file-hierarchy.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.