Covers beginner to senior level. Each question includes the answer. Questions marked π₯ are commonly asked in real interviews.
Q1 π₯ Why is cd a shell builtin and not an external program?
Every Linux process has its own working directory stored in the kernel. When a shell runs an external command, it forks a child process. The child can call
chdir()to change its own working directory, but this change only affects the child β the parent shell remains unchanged. Since the whole point ofcdis to change the shell's working directory, it must run inside the shell process itself usingchdir()directly. That's what a builtin is.type cd # cd is a shell builtin /usr/bin/cd # this exists but is useless as a standalone program
Q2. What syscall does cd use internally?
chdir(path)β changes the calling process's working directory. On success returns 0; on failure returns -1 with errno set (ENOENT, ENOTDIR, EACCES, etc.). The shell then updates$PWDand$OLDPWD.
Q3 π₯ What are $PWD and $OLDPWD?
$PWDβ current working directory, maintained by the shell (not the kernel). Updated bycdon every successful directory change.$OLDPWDβ the previous working directory, set bycdbefore changing to the new one. Used bycd -.The kernel also tracks the real (physical) path.
$PWDmay differ if symlinks are involved βpwd -Pasks the kernel for the real path.
Q4. What is the difference between a shell builtin and an external command?
A builtin runs inside the shell process (no fork). An external command forks a child process, execs the binary, and returns. Builtins are necessary for commands that must affect the shell's own state:
cd(cwd),export(environment),set(shell options),source(run in current shell), etc.
Q5. What does cd with no argument do? Why?
Goes to
$HOME. POSIX specifies thatcdwith no operand is equivalent tocd $HOME.$HOMEis set at login by PAM from/etc/passwd.
Q6. What does cd - do?
Changes to the previous directory (
$OLDPWD) and prints the destination. Togglingcd -repeatedly alternates between two directories.
Q7. How do you go two levels up?
cd ../.. cd ../../ # same
Q8. What does cd ~username do?
Changes to that user's home directory (read from
/etc/passwd). Requires execute permission on the target directory.cd ~root # /root cd ~alice # /home/alice
Q9 π₯ What is the difference between cd -L and cd -P?
-L(default, logical): follows the logical path. Symlink names are preserved in$PWD.-P(physical): resolves all symlinks.$PWDreflects the real filesystem path.ln -s /var/log /tmp/logs cd /tmp/logs && pwd # /tmp/logs (logical) cd -P /tmp/logs && pwd # /var/log (physical)Affects
cd ..behavior: logical..goes to/tmp; physical..goes to/var.
Q10. What does cd . do?
Nothing β stays in the current directory. But it does re-evaluate
$PWDfrom the kernel, which can fix a stale$PWDif the directory was deleted and re-created, or if$PWDwas manually corrupted.
Q11 π₯ You're in /tmp/link (a symlink to /var/log). You run cd ... Where are you?
/tmpβ not/var. The default-Lmode preserves the logical path.cd ..goes to the logical parent of/tmp/link, which is/tmp.To get to
/var(the real parent), usecd -P ..while in the symlinked directory.
Q12. How do you find the real (physical) path of your current directory when symlinks are involved?
pwd -P # shell builtin: asks kernel for real path realpath . # external command: resolves all symlinks readlink -f . # another option
Q13. Can $PWD lie to you? How?
Yes β in two ways:
$PWDpreserves symlink names (logical path) even though the kernel knows the real path.$PWDcan be directly overwritten:PWD=/fake/path. After this,pwdshows the fake path butpwd -Pshows the truth.Run
cd .to resync$PWDfrom the kernel.
Q14 π₯ What's the bug in this script?
#!/bin/bash
cd /tmp/workdir
rm -rf *If
cd /tmp/workdirfails (directory doesn't exist), the script continues and runsrm -rf *in whatever directory the script was called from β potentially deleting everything in the caller's working directory.Fix:
cd /tmp/workdir || exit 1 rm -rf *Or with
set -eat the top, a failedcdexits the script immediately.
Q15 π₯ How do you temporarily change directory in a script and return afterwards?
Three approaches:
# 1. Subshell (safest β parent unaffected automatically) (cd /tmp && do_something) # 2. pushd/popd pushd /tmp > /dev/null do_something popd > /dev/null # 3. Save and restore original=$(pwd) cd /tmp do_something cd "$original"
Q16. How do you make a script always run relative to its own location?
#!/bin/bash script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$script_dir" # Now ./config, ./lib, etc. are relative to the scriptThis works even if the script is called from a different directory.
Q17 π₯ Why doesn't this work?
$(cd /tmp)
$(...)runs in a subshell. Thecdchanges the subshell's working directory, but the subshell exits immediately after. The parent shell's cwd is unchanged. This is a no-op.
cdmust be called directly in the current shell (not in a subshell, pipe, or xargs) to have any effect.
Q18. How do you handle a path with spaces in a script?
Always quote the variable:
dir="my documents" cd "$dir" # β quotes prevent word splitting cd $dir # β word splits: tries cd "my" "documents"
Q19. What is $CDPATH and when is it useful?
A colon-separated list of directories. When
cdreceives a relative path that doesn't exist locally, it searches each$CDPATHentry in order.export CDPATH=".:$HOME:$HOME/projects" cd myapp # searches ./myapp, ~/myapp, ~/projects/myappUseful for developers who jump between project directories frequently. Always put
.first to prefer local directories.
Q20. What's the danger of $CDPATH in scripts?
If the user has
$CDPATHset, a script'scd configmight go to~/projects/configinstead of./config. Always useunset CDPATHor explicit relative paths (cd ./config) in scripts.
Q21. What environment variable does cd - use?
$OLDPWDβ set bycdto the previous working directory before each directory change.cd /var/log # OLDPWD = (previous cwd), PWD = /var/log cd /etc # OLDPWD = /var/log, PWD = /etc cd - # uses OLDPWD β goes to /var/log
Q22 π₯ You deleted a directory you were currently in. What happens and how do you recover?
The shell still shows the old
$PWD(stale). The kernel still has the inode open so some operations may work, others won't. You'll see errors like "No such file or directory" on most operations.Recovery:
cd # go home β always works cd /tmp # or any known good directory
Q23. How do you cd to the output of a command?
cd "$(git rev-parse --show-toplevel)" # git repo root cd "$(dirname "$(which python3)")" # python3 binary's directory cd "$(find . -type d -name "src" | head -1)"The
$()subshell captures stdout; the outercdruns in the current shell.
Q24. What's the difference between these two?
cd /tmp && ls
(cd /tmp && ls)
cd /tmp && lsβ changes the current shell's directory to/tmp, then lists it. After this command, your shell is in/tmp.(cd /tmp && ls)β runs in a subshell. Lists/tmpbut the parent shell's cwd is unchanged.
Q25 π₯ A junior developer's deploy script fails randomly. The script does cd $DEPLOY_DIR and then rm -rf *. What could go wrong and how would you fix it?
Several problems:
- If
$DEPLOY_DIRis unset or empty,cdgoes to$HOME, thenrm -rf *deletes everything in home.- If
$DEPLOY_DIRdoesn't exist,cdfails silently (withoutset -e), andrm -rf *runs in the current directory.rm -rf *doesn't remove hidden files (dotfiles).Fix:
set -e set -u # error on unset variables cd "${DEPLOY_DIR:?DEPLOY_DIR is not set}" || exit 1 rm -rf ./* # more explicit; consider rm -rf "${DEPLOY_DIR:?}"/* instead
Q26. How does cd handle the path resolution according to POSIX?
POSIX specifies this algorithm for
cd path:
- If path begins with
/, use it as-is.- If path is
.or starts with./or../, use$PWD/path.- Otherwise, search
$CDPATHentries in order.- Call
chdir()with the resolved path.- Update
$PWD(logical or physical depending on-L/-P).
Q27. What is the directory stack and which commands manage it?
A LIFO stack of directories maintained by the shell. Commands:
pushd dirβ cd to dir and push current to stackpopdβ return to top of stackdirsβ show stack contentsdirs -vβ show with index numbersdirs -cβ clear stackpushd +Nβ rotate stack (bash/zsh)In zsh,
setopt AUTO_PUSHDmakes everycdautomatically push to the stack β giving you a full navigation history.
Q28. You need execute but not read permission on a directory. What can and can't you do?
chmod 111 /secret # execute only, no read cd /secret # β can enter the directory ls /secret # β Permission denied (need r to list) cat /secret/file.txt # β can access files IF you know the nameExecute (
x) on a directory = permission to traverse/enter and stat known files. Read (r) on a directory = permission to list filenames. They are completely independent.
Q29 π₯ Why does cd in a shell function affect the caller, but cd in a script doesn't?
Shell functions run in the current shell process β they share the shell's state including cwd, variables, and environment. A
cdinside a function changes the calling shell's directory.A script runs in a separate child process (fork + exec). Its
cdonly affects the child. When the script exits, the parent shell's cwd is unchanged.Exception: if you
source(. script.sh) a script, it runs in the current shell β socdinside it DOES affect your shell.
Q30. What is zoxide and how does it improve on cd?
zoxideis a smartercdwritten in Rust. It tracks which directories you visit and how often (frecency = frequency + recency). You can jump to any previously visited directory by typing part of its name:z proj # jumps to ~/projects/myapp if you've been there before zi proj # interactive fuzzy selection with fzfIt learns your patterns over time and improves. Drop-in replacement:
eval "$(zoxide init bash)"addszas an alias.
See also:
README.mdΒ·examples.mdΒ·edge-cases.md