"command not found" for Your Own Scripts - PATH and chmod
What You'll Learn
- Why only your own script says
command not found - How to tell
command not foundfromPermission denied - How to work through
./,chmod +x, PATH, andhash -rin order
Quick Summary
command not found means the shell could not find that command on your PATH. For your own scripts, fix it in this order:
- Run it from the current dir with
./script.sh(a bare name only searches PATH) - Add the execute bit with
chmod +x script.sh - Add the directory to PATH for everyday use (
~/binor~/.local/bin) - Clear the path cache with
hash -rafter moving or replacing it
Assumptions
- Shell: bash (the default on Ubuntu / Debian)
- Target: a
.shscript you wrote, or a command you built yourself - zsh works the same way; only details like
hash -rdiffer
Why does only my own script say command not found?
Conclusion: bash looks for a bare command name only in the directories listed in PATH. The current directory is not on PATH by default, so typing
script.shfinds nothing.
When you type script.sh, bash resolves it in this order:
- Shell functions, aliases, and builtins
- Paths already cached in
hash - The directories listed in the
PATHenvironment variable (front to back)
If script.sh is in none of the PATH directories, you get command not found even when the file sits right in front of you.
$ ls script.sh $ script.sh bash: script.sh: command not found
Leaving the current directory (.) off PATH is a deliberate safety default. If . were at the front of PATH, an attacker could drop a malicious file named like a real command (ls) into a directory you cd into, and you would run it by accident. So a script "right here" must be named explicitly.
How is command not found different from Permission denied?
Conclusion:
command not foundmeans "not located";Permission deniedmeans "located, but no execute permission." The message tells you which way to look.
These two have different causes and different fixes.
| Message | Meaning | Main fix |
|---|---|---|
command not found |
No such command on PATH | Use ./ / add to PATH |
Permission denied |
File exists but has no execute bit | chmod +x |
bad interpreter |
Wrong shebang path / CRLF endings | Fix shebang / dos2unix |
# The path is right, but there is no execute permission $ ./script.sh bash: ./script.sh: Permission denied
If adding ./ changes the error to Permission denied, the PATH problem is solved and the next issue is permissions. If you see bad interpreter, the shebang or line endings are at fault, so read Fixing "bad interpreter".
Run it with ./ first
Conclusion: Run a script in the current directory with
./script.sh. The./is an explicit path that skips the PATH search entirely.
# NG: only PATH is searched, so it is not found $ script.sh bash: script.sh: command not found # OK: name the file in the current directory directly $ ./script.sh Hello
If it lives elsewhere, use an absolute or relative path instead.
$ /home/alice/tools/script.sh $ ~/tools/script.sh $ bash script.sh # passing it to bash works even without the execute bit
Passing the script to an interpreter (bash script.sh) runs it even without execute permission. This is handy for temporarily separating a "PATH problem" from a "permission problem."
What happens without execute permission?
Conclusion: Without the execute bit,
./script.shstops withPermission denied. Grant it withchmod +x.
Newly created, downloaded, or copied scripts often lose their execute permission.
$ ls -l script.sh -rw-r--r-- 1 alice alice 42 Jun 6 10:00 script.sh $ ./script.sh bash: ./script.sh: Permission denied
-rw-r--r-- has no x (execute bit). Add it.
$ chmod +x script.sh $ ls -l script.sh -rwxr-xr-x 1 alice alice 42 Jun 6 10:00 script.sh $ ./script.sh Hello
chmod 777 is unnecessary and dangerous. If you only need to run the file, chmod +x (or chmod 755) is enough. Making it world-writable with 777 is a security risk.
How do I add my own directory to PATH?
Conclusion: To avoid typing
./every time, add your script directory toPATH. Putexport PATHin~/.bashrcto make it permanent.
First, check the current PATH.
$ echo $PATH /usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
Add the directory where you keep scripts (for example ~/bin).
# For this session only (current shell) $ export PATH="$HOME/bin:$PATH"
To make it permanent, append it to ~/.bashrc (or ~/.profile for login shells).
# Add to the end of ~/.bashrc export PATH="$HOME/bin:$PATH"
# Reload it into the current shell $ source ~/.bashrc $ which script.sh /home/alice/bin/script.sh $ script.sh # runs without ./ Hello
~/bin and ~/.local/bin
Ubuntu's default ~/.profile adds ~/bin and ~/.local/bin to PATH at login if they exist. Drop your scripts in either one and PATH often works with no extra config (you may need to log in again for it to take effect).
PATH entries are separated by :, and position sets priority. With $HOME/bin:$PATH your script wins; with $PATH:$HOME/bin existing commands win. To avoid accidentally shadowing a system command of the same name, append at the end.
Still not found, or grabbing the old binary?
Conclusion: bash caches the path of a command once it finds it (
hash). Right after you move or replace a script, it may grab the old path. Clear the cache withhash -r.
When PATH and permissions look right but behavior is wrong, use type to see what bash actually intends to run and from where.
$ type -a script.sh script.sh is /home/alice/bin/script.sh
If type points at an old location, or a command you deleted still runs, the cache is stale.
# Clear the cached command paths $ hash -r # Check again $ type -a script.sh
which searches the PATH on the filesystem, but type reports how bash actually resolves the name, including aliases, functions, builtins, and the hash cache. For diagnosis, type -a is the reliable choice.