Mastering the Command Line: Efficient Python Script Execution on Linux
Script execution failures in production often trace back to misunderstandings about the Linux environment—wrong interpreter, permissions, environment contamination. This concise guide outlines established best practices for running Python scripts reliably on Linux.
Python Availability and Version Control
Most current distributions (Ubuntu 22.04 LTS, CentOS 8+) ship with Python 3.x, but legacy systems (CentOS 7, RHEL 7, earlier Ubuntu releases) may default to Python 2.x. Always verify:
python3 --version # Preferred. Expect output: Python 3.10.12
If absent/incorrect:
sudo apt update && sudo apt install python3 # Debian/Ubuntu
sudo dnf install python3 # RHEL/CentOS/Fedora
Note: Avoid relying on python; on many systems this invokes Python 2.x or throws:
Command 'python' not found, did you mean:
command 'python3' from deb python3
Minimal Example: Scripting and Execution
Consider the operational need to run a maintenance script from cron. Place hello.py in /opt/scripts/:
#!/usr/bin/env python3
print("Scheduled job: Success")
Key steps:
chmod +x /opt/scripts/hello.py
/opt/scripts/hello.py
Output should resemble:
Scheduled job: Success
Shebang (#!…) enables direct execution. Use /usr/bin/env python3 for environment portability (virtualenv support, user-installed interpreters).
Passing Command-Line Arguments
Production scripts rarely run without parameters. Typical pattern:
#!/usr/bin/env python3
import sys
if len(sys.argv) < 2:
print("Usage: hello.py <username>")
exit(1)
user = sys.argv[1]
print(f"Welcome, {user}")
Invoke:
./hello.py sysadmin
Yields:
Welcome, sysadmin
Gotcha: If called from another working directory, relative file references within the script may fail. Normalize with os.path.abspath(os.path.dirname(__file__)) for robust path resolution.
Executing as a Module
When packaging as part of a collection:
python3 -m mypackage.hello
Module execution enforces import context, raising ModuleNotFoundError if the structure is not correct:
ModuleNotFoundError: No module named 'mypackage'
Useful for CI jobs or deployment hooks where import paths must be validated.
$PATH, Environment, and Permissions
To run a script globally (e.g., hello.py from any directory):
-
Place script in
$HOME/binor/usr/local/bin. -
Ensure it's executable:
chmod 755 hello.py -
Set PATH if needed:
export PATH="$HOME/bin:$PATH" -
Persist in
.bashrc,.zshrc, or profile equivalent.
Known issue: Modifying /usr/local/bin typically requires root privileges. Consider security implications for multi-user systems.
Handling Python Environments
System Python often collides with user requirements. Use venv for isolation:
python3 -m venv /opt/myjobenv
source /opt/myjobenv/bin/activate
pip install requests
python /opt/scripts/hello.py
deactivate
Only dependencies for that environment are available. Outside, system Python is unaffected.
Side note: Scripts with hardcoded /usr/bin/python3 in the shebang ignore venv activation. Prefer /usr/bin/env python3 unless you have a static, site-wide Python.
Practical Edge Cases
-
Cron jobs: Use absolute paths, set
PATHvariable explicitly. Cron runs with minimal environment; missing variables (e.g.,PYTHONPATH) result in cryptic errors. -
SELinux/AppArmor: On hardened systems,
Permission deniederror persists even with correctchmod. Audit logs clarify (/var/log/audit/audit.log,journalctl -xe). -
Line endings: Windows line endings (
^Merrors) break scripts. Convert withdos2unix:dos2unix hello.py -
Dependency drift: Pin requirements using
requirements.txtorpip freeze > requirements.txtfor recurring batch jobs.
Quick Reference Table
| Task | Command/Setting | Note |
|---|---|---|
| Check version | python3 --version | Check actual interpreter used |
| Make executable | chmod +x yourscript.py | Needed for shebang execution |
| Shebang (portable) | #!/usr/bin/env python3 | Supports venvs, user installs |
| Add to PATH | export PATH="$HOME/bin:$PATH" | Use in shell rc files |
| Create venv | python3 -m venv venvdir | Project-specific deps |
| Install package | pip install -r requirements.txt | Pin and track dependencies |
Non-Obvious Tip
Use set -euo pipefail in bash scripts that call Python code during automation. This ensures upstream failures are correctly caught, avoiding silent data corruption or missed tasks.
Linux script execution is rarely just about the command syntax—it’s about knowing system defaults, environment pitfalls, and ensuring scripts behave as expected under automation, not just interactive use. That’s what separates a reliable deployment from a flaky one.
