Module: commands
Purpose: Run external shell commands and capture the status code and output.
Python Version: 1.4
Description:
Note: This module is made obsolete by the subprocess module.
There are 3 functions in the
commands module for working with external commands. The functions are shell-aware and return the output or status code from the command. getstatusoutput():
The function getstatusoutput() runs a command via the shell and returns the exit code and the text output (stdout and stderr combined). The exit codes are the same as for the C function
wait() or os.wait(). The code is a 16-bit number. The low byte contains the signal number that killed the process. When the signal is zero, the high byte is the exit status of the program. If a core file was produced, the high bit of the low byte is set.from commands import *
def run_command(cmd):
print 'Running: "%s"' % cmd
status, text = getstatusoutput(cmd)
exit_code = status >> 8
signal_num = status % 256
print 'Signal: %d' % signal_num
print 'Exit : %d' % exit_code
print 'Core? : %s' % bool(exit_code / 256)
print 'Output:'
print text
run_command('ls -l *.py')
run_command('ls -l *.notthere')
run_command('echo "WAITING TO BE KILLED"; read input')
This example runs 2 commands which exit normally, and a third which blocks waiting to be killed from another shell. (Don't simply use Ctrl-C as the interpreter will intercept that signal. Use
ps and grep in another window to find the read process and send it a signal with kill.)$ python commands_getstatusoutput.py
Running: "ls -l *.py"
Signal: 0
Exit : 0
Core? : False
Output:
-rw-r--r-- 1 dhellman dhellman 1191 Oct 21 09:41 __init__.py
-rw-r--r-- 1 dhellman dhellman 1321 Oct 21 09:48 commands_getoutput.py
-rw-r--r-- 1 dhellman dhellman 1265 Oct 21 09:50 commands_getstatus.py
-rw-r--r-- 1 dhellman dhellman 1626 Oct 21 10:10 commands_getstatusoutput.py
Running: "ls -l *.notthere"
Signal: 0
Exit : 1
Core? : False
Output:
ls: *.notthere: No such file or directory
Running: "echo "WAITING TO BE KILLED"; read input"
Signal: 1
Exit : 0
Core? : False
Output:
WAITING TO BE KILLED
In this example, I used "kill -HUP $PID" to kill the
read process.getoutput():
If the exit code is not useful for your application, you can use
getoutput() to receive only the text output from the command.from commands import *
text = getoutput('ls -l *.py')
print 'ls -l *.py:'
print text
text = getoutput('ls -l *.notthere')
print 'ls -l *.py:'
print text
$ python commands_getoutput.py
ls -l *.py:
-rw-r--r-- 1 dhellman dhellman 1191 Oct 21 09:41 __init__.py
-rw-r--r-- 1 dhellman dhellman 1321 Oct 21 09:48 commands_getoutput.py
-rw-r--r-- 1 dhellman dhellman 1265 Oct 21 09:50 commands_getstatus.py
-rw-r--r-- 1 dhellman dhellman 1626 Oct 21 10:10 commands_getstatusoutput.py
ls -l *.py:
ls: *.notthere: No such file or directory
getstatus():
Contrary to what you might expect,
getstatus() does not run a command and return the status code. Instead, it's argument is a filename which is combined with "ls -ld" to build a command to be run by getoutput(). The text output of the command is returned.from commands import *
status = getstatus('commands_getstatus.py')
print 'commands_getstatus.py:', status
status = getstatus('notthere.py')
print 'notthere.py:', status
status = getstatus('$filename')
print '$filename:', status
As you notice from the output, the $ character in the argument to the last call is escaped so the environment variable name is not expanded.
$ python commands_getstatus.py
commands_getstatus.py: -rw-r--r-- 1 dhellman dhellman 1387 Oct 21 10:19 commands_getstatus.py
notthere.py: ls: notthere.py: No such file or directory
$filename: ls: $filename: No such file or directory
References:
Python Module of the Week Home
Download Sample Code
Technorati Tags:
python, PyMOTW
4 comments:
I really like your PyMOTW series, but I don't understand why cover the commands module if it is deprecated?
(More so if it is for such an antiquated version of Python).
Having it in the documentation might be good if someone happens to see some code using it, but I see no reason teaching its use.
That's a reasonable point. I decided to go ahead and cover it because the module is still present in Python 2.5 and my goal has been to work through all of the current modules. Since existing code might still use it, understanding how it works can be valuable.
Extra tip to go with use of 'commands' module. Under the covers it uses the popen() call. When the subsequent descriptor is closed and the system pclose() is called, it will wait for the exit status of the subprocess created. To get the exit status popen() would in general use the wait4() or equivalent system call, which relies on the parent process being able to receive a SIGCHLD signal when the subprocess exits. If for some reason you have set up the SIGCHLD signal to be ignored, the popen() call will fail and the close of the descriptor will as a result throw a Python exception.
This isn't universal though, as on MacOS X it looks like you can ignore SIGCHLD and it still works. Ignore SIGCHLD on Linux though and it will definitely fail.
Thanks, Graham, that's an excellent tip!
Post a Comment