1. os.system
out = os.system(command_to_use)
This is implemented by calling the Standard C function system(), and has the same limitations.
the return value is the exit status of the process encoded in the format specified for wait(). Note that POSIX does not specify the meaning of the return value of the C system() function, so the return value of the Python function is system-dependent.
2.os.popen(command, mode, bufsize)
return value is a file object
, which can be read or written depending on whether mode is ‘r’ (default) or ‘w’.
>>> fd = os.popen('ls', 'r')
>>> for line in fd.read().split():
... print(line)
...
a9fdd8b1224a2aa7ff63fd3a4fb20a035f8dcb2b.patch
autotest
Backups
Cache
CachedData
CachedExtensions
3.os.popen(command[, mode[, bufsize]])
Open a pipe to or from command. The return value is an open file object connected to the pipe, which can be read or written depending on whether mode is ‘r’ (default) or ‘w’. The bufsize argument has the same meaning as the corresponding argument to the built-in open() function. The exit status of the command (encoded in the format specified for wait()) is available as the return value of the close() method of the file object, except that when the exit status is zero (termination without errors), None is returned.
the communication could not be bi-directional.
>>> import os
>>> fd = os.popen('ls -la')
>>> for line in fd.read().split('\n'):
... print(line)
...
total 704
drwxr-xr-x. 25 root root 4096 Apr 16 14:36 .
dr-xr-xr-x. 32 root root 4096 Apr 16 13:59 ..
-rw-r--r-- 1 root root 6062 Mar 19 10:16 a9fdd8b1224a2aa7ff63fd3a4fb20a035f8dcb2b.patch
drwx------ 7 autotest autotest 175 Feb 10 13:05 autotest
drwxr-xr-x 2 root root 29 Mar 9 09:00 Backups
drwx------ 2 root root 267 Mar 9 09:04 Cache
drwxr-xr-x 3 root root 54 Mar 9 09:00 CachedData
drwxr-xr-x 2 root root 21 Mar 9 09:01 CachedExtensions
there are os.popen2
, os.popen3
, os.popen4
, which are obsolete - use subprocess
instead.
4.subprocess
module
aims to replace functions like os.system
, os.popen
.
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None)
This does not capture stdout or stderr by default. To do so, pass PIPE for the stdout and/or stderr arguments.
this is equivalent to subprocess.call
>>> subprocess.call(['ls', '-la'])
ls: cannot access mnt: Transport endpoint is not connected
total 704
drwxr-xr-x. 25 root root 4096 Apr 16 14:36 .
dr-xr-xr-x. 32 root root 4096 Apr 16 13:59 ..
-rw-r--r-- 1 root root 6062 Mar 19 10:16 a9fdd8b1224a2aa7ff63fd3a4fb20a035f8dcb2b.patch
drwx------ 7 autotest autotest 175 Feb 10 13:05 autotest
drwxr-xr-x 2 root root 29 Mar 9 09:00 Backups
it seems the output is directly redirect to stdout
import subprocess
cmd = ['ls', '-la']
f = subprocess.run(cmd)
print('-'* 20)
print(f.stdout)
output:
total 3680
drwxr-xr-x 2 root root 4096 Apr 16 17:02 .
drwxr-xr-x 4 root root 33 Apr 16 15:04 ..
-rw-r--r-- 1 root root 508452 Jul 19 2017 glusterfs-3.8.4-18.6.el7rhgs.x86_64.rpm
-rw-r--r-- 1 root root 71404 Jul 19 2017 glusterfs-api-3.8.4-18.6.el7rhgs.x86_64.rpm
-rw-r--r-- 1 root root 174460 Jul 19 2017 glusterfs-cli-3.8.4-18.6.el7rhgs.x86_64.rpm
-rw-r--r-- 1 root root 793156 Jul 19 2017 glusterfs-client-xlators-3.8.4-18.6.el7rhgs.x86_64.rpm
-rw-r--r-- 1 root root 116744 Jul 19 2017 glusterfs-fuse-3.8.4-18.6.el7rhgs.x86_64.rpm
-rw-r--r-- 1 root root 199768 Jul 19 2017 glusterfs-geo-replication-3.8.4-18.6.el7rhgs.x86_64.rpm
-rw-r--r-- 1 root root 369960 Jul 19 2017 glusterfs-libs-3.8.4-18.6.el7rhgs.x86_64.rpm
-rw-r--r-- 1 root root 1497232 Jul 19 2017 glusterfs-server-3.8.4-18.6.el7rhgs.x86_64.rpm
-rw-r--r-- 1 root root 94 Apr 16 17:02 sample.py
-rw------- 1 root root 12288 Apr 16 17:02 .sample.py.swp
--------------------
None
>>> import shlex
>>> command = input()
docker run --privileged=true -it --name gluster registry.access.redhat.com/rhgs3/rhgs-server-rhel7 /bin/bash
>>> cmd = shlex.split(command)
>>> cmd
['docker', 'run', '--privileged=true', '-it', '--name', 'gluster', 'registry.access.redhat.com/rhgs3/rhgs-server-rhel7', '/bin/bash']
>>> obj = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> obj.communicate("uname -r".encode())
(b'', b'the input device is not a TTY\n')
>>> obj = subprocess.Popen(['ssh', 'server2'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> obj.communicate("uname -r".encode())(b'3.10.0-693.2.1.el7.x86_64\n', b"Pseudo-terminal will not be allocated because stdin is not a terminal.\r\nWarning: Permanently added '10.66.8.206' (ECDSA) to the list of known hosts.\r\n")
>>> obj.poll()
0
the child process is dead after communicate
>>> out = subprocess.check_output(['ssh', 'server2', 'uname', '-r'])
Warning: Permanently added '10.66.8.206' (ECDSA) to the list of known hosts.
>>> out
b'3.10.0-693.2.1.el7.x86_64\n'
how to open a shell and communicate?
>>> from subprocess import Popen, PIPE
>>> child = Popen(['ssh', '-T', 'server2'], stdin=PIPE, stdout=PIPE, bufsize=0, universal_newlines=True)
>>> Warning: Permanently added '10.66.8.206' (ECDSA) to the list of known hosts.
>>> child.stdin.write(b'uname -r')
>>> child.stdin.flush()
>>> child.stdout.readline()
the child.stdout.readline()
will hang.
the reason from the doc:
Warning Use communicate() rather than .stdin.write, .stdout.read or .stderr.read to avoid deadlocks due to any of the other OS pipe buffers filling up and blocking the child process.
>>> child = Popen(['ssh', '-T', 'server2'], stdin=PIPE, stdout=PIPE, bufsize=-1, universal_newlines=True)
>>> Warning: Permanently added '10.66.8.206' (ECDSA) to the list of known hosts.
>>> child.stdin.write(b'uname -r')
>>> child.stdin.flush()
>>> child.communicate()
('3.10.0-693.2.1.el7.x86_64\n', None)
after communicate
, the child process exits. So what if I want to run multiple commands in that ssh session?
my goal here is to run a container and start GlusterFS service on it. So the subprocess must be alive after giving it commands.
# docker run --privileged=true -it --name gluster registry.access.redhat.com/rhgs3/rhgs-server-rhel7 /bin/bash
reference:
https://docs.python.org/3.6/library/subprocess.html#module-subprocess