execution of Linux commands in Python.

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

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/KusanoNEU/article/details/79964307
个人分类: python
上一篇refactoring in python[note 1]
下一篇python learning notes
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭