Absolute vs Relative Path Made Easy


absolute vs relative path example in Linux terminal


absolute vs relative path example in Linux terminal

Have you ever run cd reports successfully, only to get "No such file or directory" when you run the same command from another folder? The reason is simple: Linux handles absolute and relative paths differently. Once you understand how each one works, navigating the filesystem becomes much easier and path-related errors are easier to avoid.

This distinction becomes especially important in scripts and automated jobs. A relative path depends on the directory where a command starts, while an absolute path points to a fixed location. A script that works perfectly when you run it manually can fail when cron or another service runs it from a different directory.

In this guide, you'll learn how absolute and relative paths work, when to use each one, and how to check where you are in the filesystem. You'll also see practical examples with pwd, realpath, cd, and other common Linux commands.

Concept:

If you're still shaky on basic navigation, it's worth pairing this with a quick look at practical cd command tips before you dig into paths, since the two go hand in hand.

Examples


#01

What Is an Absolute Path and What Is a Relative Path?

An absolute path is a full address. It always starts at the root of the filesystem, that single / at the very top, and spells out every folder you'd need to pass through to reach a file, no matter where you're currently sitting in the terminal. A relative path, on the other hand, is directions from wherever you happen to be standing right now.

Think of it like giving someone your location. "123 Main Street, Springfield" works no matter where the other person is starting from, that's an absolute path. "Two blocks down, turn left" only makes sense if you're both starting from the same spot, that's relative. Neither one is better on its own, they're just built for different jobs.

Every time you run ls, cd, cp, or open a file in a text editor, you're feeding it one of these two path types whether you notice it or not. Getting comfortable telling them apart at a glance is what stops half the "file not found" errors before they happen. If the bigger picture of how directories nest under root is still fuzzy, our Unix file system guide is worth a read alongside this one.


#02

How Linux Tells the Two Apart

The rule Linux actually uses is simple: if a path starts with a forward slash, it's absolute. Anything else is treated as relative to your current working directory, whatever that happens to be at that moment.






LinuxTeck
linuxteck@ubuntu:~$ pwd
Sample Output
/home/linuxteck

That output from pwd (print working directory) is an absolute path. Every relative path you type is silently measured from that exact spot. So cd projects means "go into projects, starting from /home/linuxteck." Change your current folder, and that same relative command now points somewhere completely different. This is a good moment to get comfortable with how the Linux file system is structured from the ground up, since paths only make sense once the hierarchy does.

Concept:

A lot of beginners assume ~ is a relative path since it's short, but it always expands to your absolute home directory (like /home/linuxteck), so it behaves like an absolute path no matter where you run it from. Worth knowing this expansion is a shell trick, not a filesystem feature. Bash swaps ~ for your full home path before the command ever runs, the underlying kernel calls like open() and chdir() have no idea what a tilde is and never see it.


#03

Path Symbols You'll Actually Use

Symbol / Command What It Means When You'd Actually Use It
/ Filesystem root, start of every absolute path Writing a path that must work no matter where it's run from
. Your current directory Running a local script with ./script.sh
.. One directory up from where you are Stepping back out of a folder you just went into
~ Your home directory, resolved as an absolute path Jumping home from anywhere without typing the full path
pwd Prints your current absolute location Confirming exactly where you are before running something risky
realpath Converts a relative path into its absolute form Turning a fragile relative reference into a solid one for scripts

Concept:

realpath ships by default on GNU/Linux as part of coreutils, so every mainstream distro has it out of the box. On macOS or minimal environments like Alpine or a stripped down BSD, it may not be installed. On Linux and Alpine/BusyBox, readlink -f is a reliable fallback. macOS's built-in readlink doesn't support -f at all though, so on a Mac the more dependable fix is installing coreutils with Homebrew (brew install coreutils) and using grealpath instead.


#04

Absolute and Relative Paths in Practice

I. Check Where You Actually Are

Before you type any path, it helps to confirm your starting point. This is the single habit that prevents most path confusion.






LinuxTeck
linuxteck@ubuntu:~/projects$ pwd
Sample Output
/home/linuxteck/projects

II. Move With a Relative Path

You're in /home/linuxteck/projects and want to get into a subfolder. No need to spell out the whole address.






LinuxTeck
linuxteck@ubuntu:~/projects$ cd website/assets

Pair this with ls once you land in a new folder to confirm what's actually there before you go typing more paths blind.

III. Jump Home Instantly

Doesn't matter how deep you've wandered into the filesystem, this always works the same way.






LinuxTeck
linuxteck@ubuntu:/var/log/nginx$ cd ~

IV. Go Straight There With an Absolute Path

Same destination, but written so it works from literally anywhere, including from inside a script you don't fully trust yet.






LinuxTeck
linuxteck@ubuntu:~$ cd /var/log/nginx

V. Stack Multiple Dots to Climb Up

You can chain .. to hop up several levels at once instead of running cd .. over and over.






LinuxTeck
linuxteck@ubuntu:~/projects/website/assets/img$ cd ../../.. && pwd
Sample Output
/home/linuxteck/projects

Each .. steps up exactly one level: the first gets you out of img into assets, the second out of assets into website, the third out of website into projects. Three dot-dot segments, three levels up, landing back at ~/projects. If you'd rather see the whole nested structure at once instead of climbing it blind, the tree command lays it out visually in one shot.

VI. Resolve a Relative Path Into an Absolute One

When you're not sure exactly what a relative path points to, realpath will tell you the full truth.






LinuxTeck
linuxteck@ubuntu:~/projects$ realpath ./website/assets
Sample Output
/home/linuxteck/projects/website/assets

VII. Real World: Chasing a Symlink to Its True Location

Scenario: You're deep in nested project folders and one of the subfolders is actually a symlink pointing somewhere else entirely.
Problem: pwd shows you the path you typed to get there, not the real location the symlink actually resolves to.





LinuxTeck
linuxteck@ubuntu:~/projects/shared-lib$ pwd -P
Sample Output
/mnt/storage/libs/shared-lib-v2
Why it Works: pwd -P resolves symlinks and shows the actual physical absolute path, not the shortcut you followed to get there.
Production Notes: This matters most when you're troubleshooting disk usage or permissions, since the "real" location is what actually holds the files.

VIII. Search Using a Relative Starting Point

You can point find at "." to search everything under your current folder without typing the full location.






LinuxTeck
linuxteck@ubuntu:~/projects$ find . -name "*.log"

If you want a broader introduction to searching by name, type, or modification time, the find command guide covers it in more depth.

IX. Reference a File Reliably in a Cron Job

Cron jobs start from your home directory ($HOME) by default when they run from your personal user crontab, not from wherever you happen to keep your scripts. System-level cron jobs, the ones in root's crontab or dropped into /etc/cron.d, commonly start from / instead. Either way, if your script lives somewhere else and you lean on relative paths inside it, cron will look for those relative files starting from the wrong place and come up empty. This is the exact mistake I mentioned earlier.






LinuxTeck
linuxteck@ubuntu:~$ crontab -e
Sample Output
0 2 * * * /home/linuxteck/scripts/backup.sh >> /home/linuxteck/logs/backup.log 2>&1

Production Tip:

Every path inside a cron entry, and every path inside the script it calls, should be absolute. If you're running this on a VPS you don't fully control, this one habit will save you an entire evening of confused troubleshooting. It's the same reason we push absolute paths hard when we set up scripts on hosting from providers like Verpex, where jobs often run under a different shell environment than your interactive login.

X. Copy Between Two Relative Locations

Both sides of a command can be relative at once, as long as you're clear on what they're relative to.






LinuxTeck
linuxteck@ubuntu:~/projects$ cp website/config.yml ../backups/

XI. The Mistake: A Script That Only Works From One Folder

This is basically a rebuild of the exact bug that once quietly wrecked my backup job for three days straight.






LinuxTeck
linuxteck@ubuntu:~/scripts$ cat backup.sh
Sample Output
#!/bin/bash
cd ../logs
tar -czf archive.tar.gz *.log

Common Mistake:

That cd ../logs only lands in the right place when the script is launched from ~/scripts. Run it from cron, from another user's shell, or as a systemd timer, and "one directory up" means something completely different, or nothing at all. The fix is to anchor the script to its own location and build every path from there.






LinuxTeck
linuxteck@ubuntu:~/scripts$ cat backup.sh
Sample Output (Fixed)
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/../logs" || exit 1
shopt -s nullglob
log_files=(*.log)
if [ ${#log_files[@]} -eq 0 ]; then
echo "No log files found, skipping archive"
exit 0
fi
tar -czf archive.tar.gz "${log_files[@]}"

Common Mistake:

Anchoring the script to its own folder isn't enough on its own. If cd fails for any reason, permissions, a missing directory, a bad mount, bash just keeps going and runs tar in whatever directory it started in, silently archiving the wrong files. Adding || exit 1 after cd (or turning on set -e at the top of the script) stops execution the moment that happens instead of letting it fail quietly. The nullglob check matters too, since a bare *.log glob with no matching files gets passed to tar as a literal, unmatched string and throws an error instead of just archiving nothing.

If you want to go deeper into building scripts that survive being run from anywhere, our first bash script walkthrough and the guide on how bash actually looks up commands are good next stops. If that if check on the array length above looks unfamiliar, our guide to bash conditional statements breaks that syntax down.


#05

Why This Distinction Actually Matters

Nobody thinks about paths until something breaks in exactly the wrong moment. A deploy script that worked fine on your laptop suddenly can't find its own config file on the server. A cron job silently fails at 2am because the working directory it assumed just isn't there when systemd launches it. The command was never wrong, the assumption about where it would be run from was.

Once you actually internalize that a relative path is a promise about your current location, and an absolute path makes no such promise at all, you start writing scripts differently. You stop typing cd .. chains and start reaching for realpath or $(dirname "$0") without thinking twice. That single habit shift is one of the more reliable signs that someone has moved from copying commands to actually understanding the filesystem underneath them, and it's the kind of thing you'll notice matters more, not less, as you move into managing production servers where you don't always control the working directory a job starts from.

It also changes how you read documentation. Man pages and reference material lean on this distinction constantly without spelling it out, and understanding it makes the rest of the filesystem, including things like how realpath resolves symbolic links, click into place a lot faster.


Key Points

  • A path starting with / is always absolute, everything else is relative to wherever pwd currently points.
  • Use realpath when you're not sure what a relative path actually resolves to, especially around symlinks.
  • Any path used inside cron, systemd timers, or scripts triggered by another process should be absolute.
  • ~ always resolves to an absolute path even though it looks short and relative.
  • pwd -P shows the real physical location, which matters when a folder is actually a symlink.
  • Anchor scripts to their own location with $(dirname "$0") instead of assuming a fixed starting folder.
  • Chain multiple .. together (like ../../..) to climb several directory levels in one command.
  • Cron jobs start from your home directory by default in a user crontab (system crontabs often start from /), so always add || exit 1 after a cd in a script instead of assuming it succeeded.

Frequently Asked Questions

Why does my script work when I run it by hand but fail in cron?

Almost always it's a relative path problem. A user crontab doesn't start your job from wherever you normally launch it from by hand, it starts from your home directory (and a system crontab in /etc/cron.d often starts from / instead), so any "./file" or "../folder" reference points to the wrong place, or nowhere. Swap those for absolute paths and it usually just starts working.

What's the actual difference between ./script.sh and just script.sh?

./script.sh explicitly tells bash to look in your current directory. Just typing script.sh makes bash search your PATH variable instead, and unless the script's folder is listed there, it won't find it and you'll get a "command not found" even though the file is sitting right in front of you.

How do I quickly find the absolute path of a file I'm looking at?

Run realpath followed by the filename, even if you only know it by a relative reference. It'll print the full absolute path back to you instantly, symlinks resolved and all.

Does cd - always take me back to my exact previous directory?

Yes, cd - jumps you to whatever directory you were in immediately before your last cd command, and it toggles back and forth if you keep using it. Handy when you're bouncing between two folders repeatedly. Under the hood it's just reading the $OLDPWD environment variable, so if you're inside a subshell or a fresh script where $OLDPWD was never set, cd - will fail with a "not set" error instead of moving anywhere.

Why doesn't ~ expand when I put it inside quotes?

Bash only expands ~ when it's unquoted or at the very start of a word. Wrap it in double or single quotes and bash treats it as a literal tilde character instead of your home directory, which trips people up constantly in scripts. If you need quotes around the path, for spaces or variables, use "$HOME/path" instead. $HOME expands correctly inside double quotes while ~ does not.

Should I just always use absolute paths in my scripts to be safe?

For anything that might run outside your interactive shell, cron jobs, systemd services, deployment scripts, yes, absolute paths (or a path anchored to the script's own location) are worth the extra typing. For quick one off commands you're running by hand, relative paths are fine and honestly faster to type.


LinuxTeck - A Complete Linux Learning Blog
From your first terminal command to advanced sysadmin skills, every guide here is written in plain English with real examples you can run right now.

About Sharon J

Sharon J is a Linux System Administrator with strong expertise in server and system management. She turns real-world experience into practical Linux guides on Linux Teck.

View all posts by Sharon J →

Leave a Reply

Your email address will not be published.

L