Python
Executable
Check
Programming
Scripting

Test if executable exists in Python?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Python programs often rely on external tools such as git, ffmpeg, docker, or psql. Before launching those commands, it is worth checking whether the executable is available so you can produce a clear error message instead of a late FileNotFoundError.

Use shutil.which for Commands on PATH

For most cases, shutil.which is the right answer. It searches the directories listed in PATH and returns the full executable path when it finds a match.

python
1from shutil import which
2
3for command in ["git", "python3", "ffmpeg"]:
4    path = which(command)
5    if path:
6        print(f"{command} found at {path}")
7    else:
8        print(f"{command} is not available")

This approach is cross-platform and respects the current environment. On Windows it also understands executable extensions such as .exe, .bat, and .cmd through the PATHEXT mechanism, so it is usually better than manually splitting PATH.

Handle Explicit Paths Separately

If the user passes an absolute or relative path, which is not enough. In that case you want to verify two things:

  1. the file exists
  2. the file is executable for the current process
python
1from pathlib import Path
2import os
3from shutil import which
4
5def executable_exists(target: str) -> bool:
6    candidate = Path(target)
7
8    if candidate.parent != Path(".") or candidate.is_absolute():
9        return candidate.is_file() and os.access(candidate, os.X_OK)
10
11    return which(target) is not None
12
13
14for target in ["git", "/bin/ls", "./scripts/deploy.sh"]:
15    print(target, executable_exists(target))

That helper covers both common input styles: command names and explicit file paths.

Turn the Check into a Useful Error

A boolean is often not enough. In real applications it is better to return the resolved path or raise a descriptive exception that explains what dependency is missing.

python
1from shutil import which
2
3def require_executable(command: str) -> str:
4    path = which(command)
5    if path is None:
6        raise RuntimeError(
7            f"Required executable '{command}' was not found in PATH. "
8            "Install it and retry."
9        )
10    return path
11
12
13git_path = require_executable("git")
14print(f"Using {git_path}")

This keeps the failure close to program startup instead of letting the application run half way through a workflow before crashing.

Avoid Probing by Running the Command

Some code samples use subprocess.run and treat a failed launch as proof that the executable is missing. That works, but it is usually the wrong first choice because it is slower and may trigger side effects.

python
1import subprocess
2
3def try_launch(command: str) -> bool:
4    try:
5        completed = subprocess.run(
6            [command, "--version"],
7            check=False,
8            stdout=subprocess.PIPE,
9            stderr=subprocess.PIPE,
10            text=True,
11        )
12        return completed.returncode == 0
13    except FileNotFoundError:
14        return False

This pattern is only useful when the command exists but you also want to validate that it is callable and not broken in the current environment. For a pure existence check, which is cleaner.

Common Pitfalls

The most common mistake is confusing a file that exists with a file that is executable. Path.exists() only tells you the file is present. It says nothing about permissions, mount options, or whether the file is actually runnable.

Another issue is assuming that the parent shell and the Python process share the same PATH. In containerized environments, virtual environments, and GUI applications, the Python process may see a very different environment. Always check from inside Python if Python is the process that will launch the command.

Windows introduces its own edge cases. A command like python may resolve to python.exe, and a script may launch through .bat or .cmd. Manual path scanning often misses those rules, while shutil.which already handles them correctly.

Finally, do not use the check as a substitute for proper error handling. An executable may exist during startup and disappear later because the environment changed. You should still catch FileNotFoundError or OSError around the actual subprocess call.

Summary

  • Use shutil.which when you need to find a command on PATH.
  • If the input may be a file path, combine Path.is_file with os.access(..., os.X_OK).
  • Prefer returning a resolved path or raising a clear startup error.
  • Avoid launching a command just to test existence unless you also need a health check.
  • Keep real subprocess error handling in place even after performing a pre-check.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.