Running System Commands in Python
Python allows interaction with the operating system by executing system commands directly from scripts using the subprocess module.
The subprocess Module
The subprocess module enables you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes.
The subprocess.run Function
- Purpose: Execute a command, wait for it to complete, and get the result.
- Returns: A
CompletedProcessinstance containing details about the executed command.
Example:
import subprocess
result = subprocess.run(["date"])
- The command is specified as a list, where the first element is the command and the subsequent elements are its arguments.
- In this example, the
datecommand displays the current date and time.
Blocking Behavior
- The parent process (your Python script) is blocked while the child process (the system command) is running.
- The script resumes execution only after the child process completes.
Example with sleep:
import subprocess
subprocess.run(["sleep", "2"])
- This command causes the script to pause for 2 seconds.
- During this time, the script is blocked and cannot perform other tasks.
Handling Command Return Codes
- The
CompletedProcessobject has areturncodeattribute. - A
returncodeof0indicates successful execution. - A non-zero
returncodeindicates an error occurred.
Example:
import subprocess
result = subprocess.run(["ls", "non_existent_file"])
print("Return code:", result.returncode)
- Since the file does not exist,
lsreturns a non-zero exit status. - You can use the
returncodeto handle errors in your script.
Executing Commands with Arguments
- Additional command-line arguments are included in the list after the command.
Example:
import subprocess
subprocess.run(["ls", "-l", "/usr"])
- This runs
lswith the-loption on the/usrdirectory.
Obtaining the Output of a System Command
To process the output of a system command within your Python script, capture it using the capture_output parameter.
Capturing Standard Output and Standard Error
- Set
capture_output=Trueinsubprocess.run()to capture the command's output. - The
stdoutandstderrattributes of theCompletedProcessobject contain the captured output.
Example:
import subprocess
result = subprocess.run(["host", "8.8.8.8"], capture_output=True)
- The
hostcommand resolves hostnames to IP addresses and vice versa. - By capturing the output, you can parse and manipulate the data.
Accessing and Decoding the Output
- The
stdoutandstderrattributes are byte strings (bytesobjects). - To convert them to standard Python strings, decode them using
decode().
Example:
output = result.stdout.decode()
print("Output:", output)
- Decoding uses UTF-8 encoding by default.
Parsing the Output
- Once decoded, you can split or parse the output as needed.
Example:
output = result.stdout.decode()
output_parts = output.split()
print("Parsed Output:", output_parts)
- This splits the output string into a list of words.
Extracting Specific Information
Extracting the Hostname from an IP Address:
import subprocess
result = subprocess.run(["host", "8.8.8.8"], capture_output=True)
output = result.stdout.decode().split()
hostname = output[-1].strip('.')
print("Hostname:", hostname)
- Retrieves the last element of the output, which is the hostname associated with the IP address.
Handling Standard Error
- If a command writes output to standard error, it is captured in the
stderrattribute.
Example:
import subprocess
result = subprocess.run(["rm", "does_not_exist"], capture_output=True)
error_output = result.stderr.decode()
print("Error Output:", error_output)
- Since the file does not exist,
rmoutputs an error message to standard error. - Capturing
stderrallows you to handle errors gracefully.
Understanding Byte Strings and Encoding
When capturing output from subprocesses, the data is returned as byte strings (bytes objects), indicated by a leading b in the output (e.g., b'output').
Why Byte Strings?
- Subprocesses communicate through byte streams, not Python strings.
- This allows for binary data and text in various encodings to be transmitted.
Decoding Byte Strings
- Use the
decode()method to convert a byte string to a Python string. - By default,
decode()uses'utf-8'encoding, which is standard for Unicode text.
Example:
byte_output = result.stdout
string_output = byte_output.decode('utf-8')