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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值