Complete guide to Python's os.posix_spawn function covering process creation, file actions, spawn attributes, and practical examples.
Last modified April 11, 2025
This comprehensive guide explores Python’s os.posix_spawn function, a POSIX-compliant process creation mechanism. We’ll cover file actions, spawn attributes, and practical examples for efficient process spawning.
The os.posix_spawn function creates a new process executing a specified program. It’s more efficient than fork-exec on some systems.
Key parameters: path (program to execute), argv (argument list), env (environment), file_actions (file operations), and spawn attributes (process characteristics).
The simplest use of os.posix_spawn launches a program with given arguments. This example runs the ’ls’ command to list directory contents.
basic_spawn.py
import os
pid = os.posix_spawn( “/bin/ls”, [“ls”, “-l”, “/tmp”], os.environ )
_, status = os.waitpid(pid, 0) print(f"Process {pid} exited with status {status}")
This creates a new process running ’ls -l /tmp’. The parent waits for the child to complete using os.waitpid. The environment is inherited from the parent.
Note that the first argument in argv should match the program name (convention).
You can specify custom environment variables when spawning a process. This example sets a special environment for the child process.
custom_env.py
import os
custom_env = os.environ.copy() custom_env[“MODE”] = “DEBUG” custom_env[“LOG_LEVEL”] = “VERBOSE”
pid = os.posix_spawn( “/usr/bin/env”, [“env”], custom_env )
_, status = os.waitpid(pid, 0) print(f"Process completed with status {status}")
The child process runs ’env’ which displays its environment. We see our custom variables MODE and LOG_LEVEL in the output.
Environment variables are passed as a dictionary. Always copy os.environ first to avoid modifying the parent’s environment.
File actions allow modifying file descriptors before program execution. This example redirects stdout to a file.
redirect_output.py
import os
file_actions = os.posix_spawn_file_actions() file_actions.addopen(1, “output.txt”, os.O_WRONLY | os.O_CREAT, 0o644) file_actions.addclose(2) # Close stderr
pid = os.posix_spawn( “/bin/ls”, [“ls”, “-l”, “/”], os.environ, file_actions=file_actions )
os.waitpid(pid, 0) print(“Output written to output.txt”)
This redirects stdout (fd 1) to output.txt and closes stderr (fd 2). The ls output goes to the file instead of the terminal.
File actions must be created before spawning and can include open, close, and dup2 operations.
Spawn attributes control process characteristics. This example creates a new process group for the child process.
process_group.py
import os
spawn_attrs = os.posix_spawnattr() spawn_attrs.setflags(os.POSIX_SPAWN_SETPGROUP) spawn_attrs.setpgroup(0) # Create new process group
pid = os.posix_spawn( “/bin/sleep”, [“sleep”, “10”], os.environ, spawn_attrs=spawn_attrs )
print(f"Created process {pid} in new process group") os.waitpid(pid, 0)
The child process (sleep) runs in its own process group. This is useful for process management and signal handling.
Attributes can control signal handling, scheduling, and other process characteristics.
This example demonstrates using both file actions and spawn attributes to create a process with customized characteristics.
combined_features.py
import os
file_actions = os.posix_spawn_file_actions() file_actions.addopen(1, “out.log”, os.O_WRONLY | os.O_CREAT, 0o644) file_actions.adddup2(1, 2) # Redirect stderr to stdout
spawn_attrs = os.posix_spawnattr() spawn_attrs.setflags(os.POSIX_SPAWN_SETPGROUP) spawn_attrs.setpgroup(0)
pid = os.posix_spawn( “/bin/bash”, [“bash”, “-c”, “echo ‘Output’; echo ‘Error’ >&2”], os.environ, file_actions=file_actions, spawn_attrs=spawn_attrs )
os.waitpid(pid, 0) print(“Both output and error written to out.log”)
The bash command’s output and error streams are redirected to out.log. The process runs in its own process group.
This shows how to combine multiple features of posix_spawn for advanced process control.
Proper error handling is crucial when spawning processes. This example shows how to handle various spawn failures.
error_handling.py
import os import errno
try: # Attempt to spawn non-existent program pid = os.posix_spawn( “/nonexistent/program”, [“program”], os.environ ) except OSError as e: if e.errno == errno.ENOENT: print(“Program not found”) elif e.errno == errno.EACCES: print(“Permission denied”) else: print(f"Spawn failed: {e}")
try: # Invalid file action file_actions = os.posix_spawn_file_actions() file_actions.addopen(1, “/root/protected”, os.O_WRONLY, 0o644) pid = os.posix_spawn( “/bin/true”, [“true”], os.environ, file_actions=file_actions ) except PermissionError: print(“Cannot open protected file”)
The first attempt fails because the program doesn’t exist. The second fails due to permission issues with file actions.
Always handle potential errors when spawning processes, especially with file operations or privileged paths.
Spawn attributes can control signal handling in the child process. This example resets signal handlers to defaults.
signal_handling.py
import os import signal
spawn_attrs = os.posix_spawnattr() spawn_attrs.setsigdefault({signal.SIGINT: signal.SIG_DFL}) spawn_attrs.setflags(os.POSIX_SPAWN_SETSIGDEF)
pid = os.posix_spawn( “/bin/bash”, [“bash”, “-c”, “echo ‘Running…’; sleep 10; echo ‘Done’”], os.environ, spawn_attrs=spawn_attrs )
print(f"Process {pid} running - Ctrl-C will terminate it") os.waitpid(pid, 0)
The child process resets SIGINT to default behavior, making it interruptible with Ctrl-C. Without this, it might inherit parent’s signal handlers.
Signal handling attributes are particularly important for long-running or interactive child processes.
Path security: Validate executable paths to prevent command injection
Environment sanitization: Carefully control environment variables
File descriptor handling: Close unnecessary FDs in the child
Privilege separation: Consider dropping privileges in child
Error handling: Handle all possible spawn failures
Use absolute paths: For both executable and file actions
Clean environments: Pass only necessary environment variables
Resource limits: Set appropriate limits via spawn attributes
Signal management: Explicitly set signal handling
Error checking: Validate all inputs before spawning
My 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.