Chapter 03Lesson 03~50 minutes

Absolute Paths, Relative Paths, and Path Expansion

A path written in a command is not always the path a program receives. The shell can expand variables, tildes, command substitutions, and wildcard patterns before the kernel resolves the resulting pathname.

BeginnerPath resolutionShell expansion

Learning objectives

By the end of this lesson

  • Distinguish absolute paths from paths resolved relative to a process working directory.
  • Explain dot, dot-dot, home, and symbolic-link behavior without relying on visual intuition.
  • Identify major Bash expansion stages that can transform command arguments.
  • Use quoting to control parameter expansion, word splitting, and pathname expansion.
  • Canonicalize and validate paths before performing consequential operations.

1. Pathnames identify objects through a directory hierarchy

A pathname is a sequence of components separated by /. The kernel resolves components through directories until it reaches the target object or an error. The object may be a regular file, directory, symbolic link, socket, device, or another filesystem type.

From shell expression to resolved object
flowchart TD
  X["Typed path expression"] --> E["Shell expansions"]
  E --> A["Argument passed to command"]
  A --> B{"Begins with slash?"}
  B -->|"yes"| R["Start at root directory"]
  B -->|"no"| C["Start at process working directory"]
  R --> K["Kernel resolves components and links"]
  C --> K
  K --> O["Filesystem object or error"]

2. Absolute and relative paths

PathStarting pointExample meaning
AbsoluteFilesystem root //etc/ssh/sshd_config names the same pathname from any working directory
RelativeCurrent working directoryconfig/app.env depends on where the process is running
Home-relative shell expressionExpanded by the shell first~/logs normally becomes a path under the current user’s home

Absolute paths improve clarity but can reduce portability when a workspace moves. Relative paths improve portability inside a known project root but become dangerous when that root is not established. Robust automation combines a verified root with derived, quoted paths.

3. Special components: dot, dot-dot, and repeated slashes

.

Current directory component

./script.sh explicitly names a file in the current directory and bypasses ordinary PATH search.

..

Parent directory component

Resolution moves to the parent of the current directory component, subject to filesystem and symbolic-link semantics.

/

Root and separator

A leading slash selects the root. Repeated slashes are generally treated as one, although portable code should avoid depending on special implementation cases.

Trailing slash

Directory expectation

A trailing slash can require the target to resolve as a directory and can change command behavior.

Textual simplification is not full resolution

Removing .. components as strings can be wrong when symbolic links are involved. Use filesystem-aware tools such as realpath when canonical physical resolution is required.

4. The shell can transform a path before execution

Bash performs several expansion stages. The exact rules are detailed, but the operational model is essential:

01Brace expansion

logs/{app,worker} can generate multiple words before variable expansion.

02Tilde expansion

An unquoted leading ~ can become a home-directory path.

03Parameter, command, and arithmetic expansion

$HOME, $(pwd), and $((n+1)) produce text.

04Word splitting

Unquoted expansion results may split into multiple arguments based on IFS.

05Pathname expansion

Unquoted wildcard patterns can become matching filenames.

06Quote removal

Syntactic quotes are removed before the external command receives its argument vector.

workspace="$HOME/devops academy"

# One argument because the expansion is quoted.
printf '<%s>\n' "$workspace"

# Potentially multiple arguments because the expansion is unquoted.
# Do not use this form for path variables.
printf '<%s>\n' $workspace

# Tilde expansion occurs here:
printf 'home expression: %s\n' ~

# Quoted tilde is literal text, not a home expansion:
printf 'literal: %s\n' "~"

5. Quoting controls shell interpretation

FormExpansion behaviorTypical path use
UnquotedParameter expansion followed by splitting and globbingUse only when multiple words or patterns are intentionally required
Double quotesAllows parameter and command expansion but suppresses ordinary splitting and globbing"$root/config file"
Single quotesTreats nearly all enclosed characters literallyFixed strings such as '*.log' when the asterisk must remain literal
BackslashEscapes one following character in many contextsUseful for short literals, less maintainable for complex paths

The safest default is simple: quote every parameter expansion that should remain one argument. Exceptions such as intentional arrays, pattern expansion, and arithmetic should be explicit and reviewed.

6. Pathname expansion and wildcard patterns

lab="$HOME/devops-academy/linux/chapter03/lesson03/globs"
mkdir -p -- "$lab"
printf '%s\n' alpha beta > "$lab/app.log"
printf '%s\n' gamma > "$lab/worker.log"
printf '%s\n' hidden > "$lab/.audit.log"
printf '%s\n' text > "$lab/readme.txt"

cd -- "$lab" || exit 1
printf 'Unquoted pattern expands to matching non-hidden names:\n'
printf '  %s\n' *.log

printf 'Quoted pattern remains literal:\n'
printf '  %s\n' '*.log'

printf 'Explicit hidden-name pattern:\n'
printf '  %s\n' .*.log

By default, a leading dot must be matched explicitly. A pattern with no match may remain literal unless shell options such as nullglob or failglob change behavior. Scripts must define and verify the intended rule.

7. Canonicalization and target validation

realpath resolves components and symbolic links according to its options. readlink -f offers similar behavior on many GNU/Linux systems, but portability and missing-target behavior differ.

course_root="$HOME/devops-academy/linux"
requested="$course_root/chapter03/lesson03"

root_real=$(realpath -e -- "$course_root") || exit 1
target_real=$(realpath -m -- "$requested") || exit 1

printf 'root=%s\n' "$root_real"
printf 'target=%s\n' "$target_real"

case "$target_real" in
  "$root_real"|"$root_real"/*)
    printf 'Target is inside the approved course root.\n'
    ;;
  *)
    printf 'Refusing target outside course root: %s\n' "$target_real" >&2
    exit 1
    ;;
esac
Containment checks require a separator boundary

A simple prefix test can confuse /srv/app with /srv/application. Match either the root itself or the root followed by /.

8. Hands-on lab: observe expansion and resolution

lab="$HOME/devops-academy/linux/chapter03/lesson03"
root="$lab/path lab"
mkdir -p -- "$root/real/releases/v1" "$root/reports"
ln -sfn -- "real/releases/v1" "$root/current"
printf 'version=1\n' > "$root/real/releases/v1/app.env"

cd -- "$root" || exit 1
{
  printf '=== working directory ===\n'
  printf 'logical=%s\n' "$(pwd -L)"
  printf 'physical=%s\n' "$(pwd -P)"

  printf '\n=== path forms ===\n'
  printf 'absolute=%s\n' "$root/current/app.env"
  printf 'relative=%s\n' "current/app.env"
  printf 'canonical=%s\n' "$(realpath -e -- current/app.env)"

  printf '\n=== argument boundaries ===\n'
  printf 'quoted argument: <%s>\n' "$root"
  printf 'literal glob: <%s>\n' '*.env'

  printf '\n=== matches under current release ===\n'
  for file in current/*.env; do
    [ -e "$file" ] || continue
    printf '%s -> %s\n' "$file" "$(realpath -e -- "$file")"
  done
} > "$lab/path-report.txt"

less "$lab/path-report.txt"

Verification checklist

9. Common path-handling mistakes

Using unquoted path variables

Whitespace and wildcard characters can create multiple arguments or unexpected matches. Quote expansions intended as one path.

Trusting a visual path without resolving links

A logical path can traverse symbolic links to another location. Use physical resolution when containment or security depends on the true target.

Assuming a wildcard always matches

Default unmatched-pattern behavior may pass the literal pattern to a command. Guard matches or select explicit shell options.

Building commands with eval

Re-parsing constructed text introduces injection and quoting hazards. Use arrays and direct argument passing instead.

10. Knowledge check

Question 1. At what point is a relative path anchored?

Question 2. Why does "$path" usually behave more safely than $path?

Question 3. Why is removing .. components as plain text not a reliable canonicalization method?

11. Summary

Absolute paths begin at root; relative paths begin at a process’s current directory. Before the kernel resolves a pathname, Bash may expand tildes, variables, substitutions, and wildcard patterns. Quote path variables by default, canonicalize when physical location matters, and validate that resolved targets remain inside an approved root.

Next lesson

Command History, Completion, Aliases, and Help Systems

You will make interactive work faster while controlling the persistence, security, and reproducibility risks of shell conveniences.

12. Further reading

  • GNU Bash Reference Manual — shell expansions, quoting, filename expansion, and shell options.
  • Linux manual pages for path_resolution, realpath, readlink, glob, and symlink.
  • POSIX pathname resolution and Shell Command Language specifications.
  • GNU Coreutils manuals for realpath, readlink, dirname, basename, and stat.
  • Filesystem Hierarchy Standard — conventional absolute system paths.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.