funwithlinux blog

How to Fix 'No Such File or Directory' When Changing Directory with Variable in Shell Script

If you’ve ever written a shell script, chances are you’ve encountered the frustrating error: cd: no such file or directory. This error is especially common when using variables to store directory paths—a practice that’s critical for writing flexible, maintainable scripts. Whether you’re automating backups, deploying applications, or managing system tasks, variables help keep paths dynamic and reusable. But when cd fails with a "no such file or directory" message despite the path seeming correct, it’s often due to subtle issues in how variables are defined, expanded, or handled in the shell.

In this guide, we’ll demystify why this error occurs when using variables with cd, break down the most common causes, and provide step-by-step solutions to fix it. By the end, you’ll have the tools to write robust shell scripts that reliably navigate directories using variables.

2026-01

Table of Contents#

  1. Understanding the Error
  2. Common Causes of the Error
  3. Step-by-Step Solutions
  4. Advanced Scenarios
  5. Prevention Tips
  6. Conclusion
  7. References

Understanding the Error#

The error cd: no such file or directory occurs when the cd command cannot locate the path you’re trying to navigate to. When using a variable (e.g., cd "$DIR"), the root cause is almost always related to how the variable is defined, expanded, or interpreted by the shell. The shell may resolve the variable to a path that doesn’t exist, or it may misinterpret the path due to syntax issues, leading to a failed directory change.

Common Causes of the Error#

Let’s explore the most frequent reasons variables cause cd to fail, with examples of problematic scripts.

2.1 Variable Not Set or Empty#

If the variable storing the directory path is undefined or empty, cd will attempt to navigate to an empty string, resulting in the error.

Example of the Problem:

#!/bin/bash
# Variable is not set (undefined)
DIR=  # Accidentally emptied or never assigned
cd "$DIR"  # cd: no such file or directory

Here, DIR is explicitly set to an empty string. When cd "$DIR" runs, it’s equivalent to cd "", which tells cd to navigate to the current directory (if no argument is given), but in some shells (like bash), cd "" is treated as an invalid path, hence the error.

2.2 Leading/Trailing Whitespace in the Variable#

If the variable contains unintended leading or trailing spaces, the shell will interpret the path with those spaces, leading to a non-existent directory.

Example of the Problem:

#!/bin/bash
# Variable has trailing space due to incorrect assignment
DIR="/path/to/my/dir "  # Note the space at the end
cd "$DIR"  # cd: /path/to/my/dir : No such file or directory

Here, DIR includes a trailing space, so the path becomes /path/to/my/dir (with a space), which likely doesn’t exist on your system.

2.3 Unquoted Variables and Word Splitting#

In shell scripts, unquoted variables undergo word splitting and pathname expansion. This means spaces, tabs, or newlines in the variable value are treated as separators, and wildcards (e.g., *) are expanded to matching filenames. This can completely alter the intended path.

Example of the Problem:

#!/bin/bash
DIR="/path/with spaces"  # Path contains a space
cd $DIR  # Unquoted variable: word splitting occurs!

When cd $DIR runs, the shell splits /path/with spaces into two arguments: cd /path/with spaces. This is interpreted as cd /path/with spaces, which is invalid (unless there’s a directory named spaces in /path/with).

2.4 Relative Paths in Variables (Context-Dependence)#

If the variable stores a relative path (e.g., ./documents or ../parent), the path is resolved relative to the current working directory (CWD) when the script runs. If the script is executed from a different directory than expected, the relative path may not resolve correctly.

Example of the Problem:

#!/bin/bash
# Variable uses a relative path
DIR="./reports"
cd "$DIR"  # Fails if script is run from a directory without a "reports" subfolder

If you run this script from /home/user, it will try to navigate to /home/user/reports. But if you run it from /home/user/projects, it will look for /home/user/projects/reports (which may not exist).

2.5 Variable Defined in a Subshell#

Variables set inside a subshell (e.g., in a pipeline, $(...), or (...) block) are not accessible in the parent shell. If you define the directory variable in a subshell, it will be undefined when you try to use it with cd.

Example of the Problem:

#!/bin/bash
# Variable set in a subshell (using a pipeline)
echo "/path/to/dir" | read DIR  # DIR is set in a subshell
cd "$DIR"  # Fails: DIR is undefined in the parent shell!

The read DIR command runs in a subshell, so DIR is not available outside of it.

2.6 Special Characters in Paths (Spaces, Symbols)#

Paths with special characters like spaces, *, ?, or ( ) can cause issues if the variable is not properly quoted or escaped. Even with quotes, if the path itself is invalid (e.g., a space due to a typo), cd will fail.

Example of the Problem:

#!/bin/bash
# Path contains an asterisk (wildcard)
DIR="/path/with*"  # Intended to be a literal asterisk, but unquoted expansion occurs
cd "$DIR"  # If no file/directory matches "/path/with*", this fails

If there’s no directory named with*, cd will throw an error.

Step-by-Step Solutions#

Now that we’ve identified the causes, let’s fix each scenario with actionable solutions.

3.1 Check if the Variable Is Set and Non-Empty#

Always verify that the directory variable is defined and non-empty before using it with cd. Use conditional checks like [ -z "$DIR" ] to detect empty variables.

Solution:

#!/bin/bash
DIR="/valid/path/to/dir"
 
# Check if DIR is set and not empty
if [ -z "$DIR" ]; then
  echo "Error: DIR variable is not set or is empty."
  exit 1
fi
 
# Check if the path exists and is a directory
if [ ! -d "$DIR" ]; then
  echo "Error: Directory $DIR does not exist."
  exit 1
fi
 
cd "$DIR" || { echo "Failed to cd to $DIR"; exit 1; }
  • [ -z "$DIR" ] checks if DIR is empty.
  • [ ! -d "$DIR" ] checks if DIR is not a valid directory.
  • cd "$DIR" || exit 1 ensures the script exits if cd fails.

3.2 Trim Whitespace from Variables#

To remove leading/trailing spaces from a variable, use parameter expansion (bash-specific) or command-line tools like tr or sed.

Solution with Parameter Expansion:

#!/bin/bash
# Variable with leading/trailing spaces
DIR=" /path/to/dir "
 
# Trim leading spaces: ${DIR## }
# Trim trailing spaces: ${DIR%% }
TRIMMED_DIR="${DIR## }"  # Remove leading spaces
TRIMMED_DIR="${TRIMMED_DIR%% }"  # Remove trailing spaces
 
cd "$TRIMMED_DIR" || exit 1

Alternative with xargs:

TRIMMED_DIR=$(echo "$DIR" | xargs)  # xargs trims leading/trailing whitespace

3.3 Always Quote Variables When Using cd#

Always quote directory variables with double quotes ("$DIR") to prevent word splitting and pathname expansion. This preserves spaces and special characters in the path.

Solution:

#!/bin/bash
DIR="/path/with spaces"
cd "$DIR" || exit 1  # Quoted variable: path is preserved as a single argument

Quoting ensures cd receives the entire path as one argument, even if it contains spaces or special characters.

3.4 Use Absolute Paths in Variables#

To avoid context-dependent relative paths, store absolute paths in variables. Use tools like readlink -f or realpath to convert relative paths to absolute paths dynamically.

Solution with readlink:

#!/bin/bash
# Convert relative path to absolute path
RELATIVE_DIR="./reports"
ABSOLUTE_DIR=$(readlink -f "$RELATIVE_DIR")  # Resolves to /home/user/reports (for example)
 
cd "$ABSOLUTE_DIR" || exit 1
  • readlink -f resolves symlinks and relative paths to an absolute path.
  • Use realpath instead of readlink if readlink -f is unavailable (e.g., on macOS: brew install coreutils for greadlink).

3.5 Avoid Subshells When Setting Variables#

To ensure variables are accessible, avoid defining them in subshells. Use process substitution, here-strings, or shopt -s lastpipe (bash 4.2+) to set variables in the parent shell.

Solution with Here-String:

#!/bin/bash
# Avoid subshell with here-string
read DIR <<< "/path/to/dir"  # DIR is set in the parent shell
cd "$DIR" || exit 1

Solution for Command Output (No Subshell):

#!/bin/bash
# Capture command output without subshell (using process substitution)
DIR=$(pwd)  # $(pwd) runs in a subshell, but the result is assigned to DIR in the parent
cd "$DIR" || exit 1  # Works, because only the command substitution is a subshell

For pipelines, use shopt -s lastpipe (bash-specific) to run the last command in the parent shell:

#!/bin/bash
shopt -s lastpipe  # Run last command in pipeline in parent shell
echo "/path/to/dir" | read DIR  # Now DIR is set in parent shell
cd "$DIR" || exit 1

3.6 Handle Special Characters with Care#

For paths containing special characters (spaces, *, ( )), always:

  • Quote the variable to preserve the literal path.
  • Escape special characters if needed (e.g., \ for spaces, but quoting is safer).

Solution for Paths with Spaces:

#!/bin/bash
DIR="/path/with spaces"
cd "$DIR" || exit 1  # Quoting preserves the space

Solution for Paths with Wildcards:
If the path contains a literal * (e.g., /path/to/file*name), quote the variable to prevent expansion:

DIR="/path/to/file*name"
cd "$DIR" || exit 1  # Quoting treats * as a literal character

Advanced Scenarios#

4.1 Variables with Newlines or Control Characters#

Paths with newlines (rare but possible) can cause cd to fail. Use parameter expansion to remove newlines or sanitize the variable.

Example Fix:

#!/bin/bash
# Variable with a newline (e.g., from a misbehaved command)
DIR=$'path/with\nnewline'  # $'...' syntax for escape sequences
 
# Remove newlines using parameter expansion
SANITIZED_DIR="${DIR//$'\n'/}"  # Replace newlines with empty string
cd "$SANITIZED_DIR" || exit 1

4.2 Dynamic Paths with Command Substitution#

If the directory is determined dynamically (e.g., via git rev-parse --show-toplevel to find a Git repo root), ensure the command substitution doesn’t introduce extra whitespace or fail silently.

Example Fix:

#!/bin/bash
# Get Git repo root (dynamic path)
DIR=$(git rev-parse --show-toplevel 2>/dev/null)  # Suppress errors
 
# Check if command succeeded and DIR is valid
if [ -z "$DIR" ] || [ ! -d "$DIR" ]; then
  echo "Error: Not in a Git repository or repo root not found."
  exit 1
fi
 
cd "$DIR" || exit 1

Prevention Tips#

To avoid "No such file or directory" errors altogether, follow these best practices:

  1. Quote Variables Always: Use "$DIR" instead of $DIR when passing paths to cd (or any command).
  2. Use Absolute Paths: Prefer absolute paths in variables to avoid context dependence.
  3. Enable Strict Mode: Add set -euo pipefail at the top of scripts to exit on undefined variables (-u), errors (-e), and pipeline failures (-o pipefail).
    #!/bin/bash
    set -euo pipefail  # Strict mode: catch errors early!
    DIR="/path/to/dir"
    cd "$DIR"  # Fails fast if DIR is undefined or invalid
  4. Test Paths Before Using Them: Always check if [ -d "$DIR" ] before running cd "$DIR".
  5. Avoid Subshells for Variable Assignment: Define variables in the parent shell unless you explicitly need subshell isolation.

Conclusion#

The "No such file or directory" error when using cd with variables in shell scripts is almost always caused by mishandling variables—whether due to unquoted expansion, undefined variables, relative paths, or subshell scoping. By following the solutions outlined here—quoting variables, using absolute paths, validating inputs, and avoiding subshell pitfalls—you can write robust scripts that reliably navigate directories.

Remember: shell scripting requires careful attention to how variables are defined, expanded, and scoped. With these techniques, you’ll minimize errors and make your scripts more maintainable and predictable.

References#