GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||
GeezerVison is showing zetcode.com — Python exec command - run shell commands and programs with subprocess Python exec commandlast modified October 30, 2026 Python 3.15 In this article we show how to execute shell commands and programs in Python. Running external programs
In Python, there are several ways to execute shell commands or programs. The
The os.system function
The system_fun.py
import os
status = os.system('echo hello from the shell')
print(f'status: {status}')
status = os.system('exit 3')
print(f'status: {status}, exit code: {os.waitstatus_to_exitcode(status)}')
The function returns the wait status of the process. On Unix, the exit code
is encoded in it; the $ python system_fun.py hello from the shell status: 0 status: 768, exit code: 3 The os.popen function
The read_output.py
import os
output = os.popen('ls files').read()
print(output.split())
In the example, we read the output of the $ python read_output.py ['data.txt', 'names.csv', 'notes.md', 'report.pdf'] The subprocess.run function
The version_check.py
import subprocess
result = subprocess.run(['git', '--version'], capture_output=True, text=True)
print(result)
print(f'return code: {result.returncode}')
print(f'version: {result.stdout.split()[-1]}')
The example gets the version of Git. The command is given as a list: the program name followed by its arguments. result = subprocess.run(['git', '--version'], capture_output=True, text=True)
With $ python version_check.py CompletedProcess(args=['git', '--version'], returncode=0, stdout='git version 2.34.1\n', stderr='') return code: 0 version: 2.34.1 Handling errorsA failing command does not raise an exception by default; we must check its return code. check_errors.py
import subprocess
result = subprocess.run(['ls', 'missing'], capture_output=True, text=True)
print(result.returncode, result.stderr.strip())
try:
subprocess.run(['ls', 'missing'], capture_output=True, text=True, check=True)
except subprocess.CalledProcessError as e:
print(f'command {e.cmd} failed with code {e.returncode}')
try:
subprocess.run(['nosuchcommand'])
except FileNotFoundError as e:
print(e)
The $ python check_errors.py 2 ls: cannot access 'missing': No such file or directory command ['ls', 'missing'] failed with code 2 [Errno 2] No such file or directory: 'nosuchcommand' The check_output function
The check_output_fun.py
import subprocess kernel = subprocess.check_output(['uname', '-s'], text=True).strip() print(kernel) count = subprocess.check_output(['wc', '-l', 'words.txt'], text=True) print(count.split()[0])
We get the name of the kernel and the number of lines in the
$ python check_output_fun.py Linux 7 Sending input
The send_input.py
import subprocess
words = 'sky\nforest\ncup\nwood\n'
result = subprocess.run(['sort', '-r'], input=words, capture_output=True,
text=True)
print(result.stdout, end='')
We pass four words to the $ python send_input.py wood sky forest cup Running commands in a shell
With shell_true.py
import subprocess cmd = 'sort words.txt | uniq -c | sort -rn | head -3' result = subprocess.run(cmd, shell=True, capture_output=True, text=True) print(result.stdout, end='') The pipeline finds the three most common words in the file. $ python shell_true.py
3 sky
2 forest
1 wood
Shell injection
Building a shell command from untrusted data is dangerous. The shell
interprets special characters such as injection.py
import shlex
import subprocess
filename = 'words.txt; echo INJECTED'
subprocess.run(f'wc -l {filename}', shell=True)
print('---')
subprocess.run(['wc', '-l', filename])
print('---')
subprocess.run(f'wc -l {shlex.quote(filename)}', shell=True)
print(shlex.quote(filename))
print(shlex.split('grep -n "two words" file.txt'))
The file name contains a semicolon. With $ python injection.py 7 words.txt INJECTED --- wc: 'words.txt; echo INJECTED': No such file or directory --- wc: 'words.txt; echo INJECTED': No such file or directory 'words.txt; echo INJECTED' ['grep', '-n', 'two words', 'file.txt'] Timeouts
The timeout_fun.py
import subprocess
import time
start = time.perf_counter()
try:
subprocess.run(['sleep', '10'], timeout=1)
except subprocess.TimeoutExpired as e:
print(f'{e.cmd} timed out after {e.timeout} s')
print(f'elapsed: {time.perf_counter() - start:.1f} s')
When the timeout expires, the child process is killed and
$ python timeout_fun.py ['sleep', '10'] timed out after 1 s elapsed: 1.0 s Working directory and environment
The cwd_env.py
import os
import subprocess
result = subprocess.run(['ls'], cwd='files', capture_output=True, text=True)
print(result.stdout.split())
env = os.environ | {'GREETING': 'Hello there'}
cmd = ['sh', '-c', 'echo "$GREETING from $PWD"']
result = subprocess.run(cmd, cwd='files', env=env, capture_output=True,
text=True)
print(result.stdout, end='')
We list the files of the $ python cwd_env.py ['data.txt', 'names.csv', 'notes.md', 'report.pdf'] Hello there from /home/user/python/files The Popen class
The process creation and management in the communicate_fun.py
import subprocess
proc = subprocess.Popen(['tr', 'a-z', 'A-Z'], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, text=True)
print(f'running: {proc.poll() is None}')
stdout, _ = proc.communicate(input='an old falcon\nan old owl\n')
print(stdout, end='')
print(f'return code: {proc.returncode}')
The $ python communicate_fun.py running: True AN OLD FALCON AN OLD OWL return code: 0 Reading output as it arrives
The ticker.py
import time
for i in range(1, 4):
print(f'tick {i}', flush=True)
time.sleep(0.5)
This program prints a line every half a second. stream_output.py
import subprocess
import sys
import time
start = time.perf_counter()
with subprocess.Popen([sys.executable, 'ticker.py'], stdout=subprocess.PIPE,
text=True) as proc:
for line in proc.stdout:
print(f'{time.perf_counter() - start:.1f} s: {line}', end='')
print(f'exit code: {proc.returncode}')
We run the ticker with the current Python interpreter,
$ python stream_output.py 0.0 s: tick 1 0.5 s: tick 2 1.0 s: tick 3 exit code: 0 PipelinesWe can connect processes into a pipeline without a shell by passing the output pipe of one process as the input of another. pipeline.py
import subprocess
p1 = subprocess.Popen(['sort', 'words.txt'], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['uniq', '-c'], stdin=p1.stdout, stdout=subprocess.PIPE,
text=True)
p1.stdout.close()
output, _ = p2.communicate()
p1.wait()
for line in output.splitlines():
count, word = line.split()
print(f'{word}: {count}')
The example is equivalent to the $ python pipeline.py cup: 1 forest: 2 sky: 3 wood: 1 Running processes in parallel
Since parallel.py
import subprocess
import time
start = time.perf_counter()
procs = [subprocess.Popen(['sleep', '1']) for _ in range(5)]
for proc in procs:
proc.wait()
print(f'5 processes finished in {time.perf_counter() - start:.1f} s')
Five $ python parallel.py 5 processes finished in 1.0 s Replacing the process
The replace_process.py
import os
print(f'python pid: {os.getpid()}', flush=True)
os.execvp('sh', ['sh', '-c', 'echo "shell pid: $$"'])
print('this line is never printed')
The $ python replace_process.py python pid: 139665 shell pid: 139665 Sourcesubprocess - Subprocess management - Python documentation In this article we have executed shell commands and programs in Python. AuthorMy name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming. List all Python tutorials. | ||||||||||||||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |