在Python中运行Bash命令
在本地机器上,我运行一个python脚本,其中包含这一行在Python中运行Bash命令,python,bash,Python,Bash,在本地机器上,我运行一个python脚本,其中包含这一行 bashCommand = "cwm --rdf test.rdf --ntriples > test.nt" os.system(bashCommand) 这个很好用 然后我在服务器上运行相同的代码,得到以下错误消息 'import site' failed; use -v for traceback Traceback (most recent call last): File "/usr/bin/cwm", line 48,
bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
os.system(bashCommand)
这个很好用
然后我在服务器上运行相同的代码,得到以下错误消息
'import site' failed; use -v for traceback
Traceback (most recent call last):
File "/usr/bin/cwm", line 48, in <module>
from swap import diag
ImportError: No module named swap
“导入站点”失败;使用-v进行回溯
回溯(最近一次呼叫最后一次):
文件“/usr/bin/cwm”,第48行,在
从交换导入诊断
ImportError:没有名为swap的模块
因此,我当时所做的是插入一个print bash命令
,该命令在使用os.system()
当然,我再次得到错误(由os.system(bashCommand)
引起),但在该错误之前,它会在终端中打印命令。然后,我只是复制了输出,并复制粘贴到终端,点击回车键,它就工作了
有人知道发生了什么吗?用subprocess调用它
import subprocess
subprocess.Popen("cwm --rdf test.rdf --ntriples > test.nt")
您收到的错误似乎是因为服务器上没有交换模块,您应该在服务器上安装交换,然后再次运行脚本不要使用os.system
。它已被弃用,取而代之的是。来自:“此模块打算替换几个较旧的模块和功能:os.system
,os.spawn
”
比如你的情况:
bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
import subprocess
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()
根据错误,服务器上缺少名为swap的包。这/usr/bin/cwm
需要它。如果您使用的是Ubuntu/Debian,请使用aptitude安装Pythonswap
。您可以使用bash程序,参数-c用于执行命令:
bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
output = subprocess.check_output(['bash','-c', bashCommand])
您可以使用子流程
,但我始终觉得这不是一种“Pythonic”的方式。所以我创建了Sultan(无耻的插件),它使运行命令行函数变得简单
蟒蛇式的方法是使用
subprocess.Popen
获取一个列表,其中第一个元素是要运行的命令,后跟任何命令行参数
例如:
import subprocess
args = ['echo', 'Hello!']
subprocess.Popen(args) // same as running `echo Hello!` on cmd line
args2 = ['echo', '-v', '"Hello Again"']
subprocess.Popen(args2) // same as running 'echo -v "Hello Again!"` on cmd line
也可以使用“os.popen”。
例如:
输出:
total 16
drwxr-xr-x 2 root root 4096 ago 13 21:53 .
drwxr-xr-x 4 root root 4096 ago 13 01:50 ..
-rw-r--r-- 1 root root 1278 ago 13 21:12 bot.py
-rw-r--r-- 1 root root 77 ago 13 21:53 test.py
None
为了在一定程度上扩展前面的答案,这里有一些通常被忽略的细节
- 首选
subprocess.run()
oversubprocess.check\u call()
和朋友oversubprocess.call()
oversubprocess.Popen()
overos.system()
overos.Popen()
- 理解并可能使用
text=True
,即universal\u newlines=True
- 理解
shell=True
或shell=False
的含义,以及它如何改变报价和shell便利设施的可用性
- 了解
sh
和Bash之间的区别
- 了解子流程如何与其父流程分离,并且通常不能更改父流程
- 避免将Python解释器作为Python的子进程运行
下面将更详细地介绍这些主题
首选subprocess.run()
或subprocess.check\u call()
subprocess.Popen()
函数是一个低级的工作,但要正确使用它很困难,最终会复制/粘贴多行代码。。。在标准库中已经方便地作为一组用于各种目的的高级包装函数存在,下面将详细介绍这些函数
这里有一段来自:
调用子流程的推荐方法是对它可以处理的所有用例使用run()
函数。对于更高级的用例,可以直接使用底层的Popen
接口
不幸的是,这些包装函数的可用性在不同的Python版本中有所不同
subprocess.run()
正式引入Python 3.5。这意味着要替换以下所有内容
- Python2.7/3.1中引入了
subprocess.check_output()
。它基本上相当于subprocess.run(…,check=True,stdout=subprocess.PIPE)。stdout
- Python2.5中引入了
子流程.check_call()
。它基本上相当于子流程。run(…,check=True)
subprocess.call()
是在Python 2.4的原始subprocess
模块()中引入的。它基本上相当于子流程.run(…).returncode
高级API vssubprocess.Popen()
重构和扩展的子流程.run()
比它所取代的旧的遗留函数更具逻辑性和通用性。它返回一个对象,该对象具有各种方法,允许您从已完成的子流程中检索退出状态、标准输出以及一些其他结果和状态指示器
subprocess.run()
是一种方法,如果您只需要一个程序来运行并将控制权返回给Python。对于更复杂的场景(后台进程,可能带有Python父程序的交互式I/O),您仍然需要使用subprocess.Popen()
,并自己处理所有管道。这需要对所有运动部件有一个相当复杂的理解,不应轻率地进行。较简单的表示(可能仍在运行)流程,在子流程的剩余生命周期中,需要从代码中管理该流程
也许应该强调的是,仅仅subprocess.Popen()
只会创建一个进程。如果不考虑这一点,则会有一个子流程与Python并行运行,因此是一个“后台”流程。如果它不需要进行输入、输出或与您协调,那么它可以与您的Python程序并行地执行有用的工作
避免os.system()
和os.popen()
自time eternal(好吧,自Python 2.5以来)以来,已包含建议优先选择子流程
,而不是os.system()
:
子程序
total 16
drwxr-xr-x 2 root root 4096 ago 13 21:53 .
drwxr-xr-x 4 root root 4096 ago 13 01:50 ..
-rw-r--r-- 1 root root 1278 ago 13 21:12 bot.py
-rw-r--r-- 1 root root 77 ago 13 21:53 test.py
None
normal = subprocess.run([external, arg],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
check=True,
text=True)
print(normal.stdout)
convoluted = subprocess.run([external, arg],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
check=True)
# You have to know (or guess) the encoding
print(convoluted.stdout.decode('utf-8'))
# XXX AVOID THIS BUG
buggy = subprocess.run('dig +short stackoverflow.com')
# XXX AVOID THIS BUG TOO
broken = subprocess.run(['dig', '+short', 'stackoverflow.com'],
shell=True)
# XXX DEFINITELY AVOID THIS
pathological = subprocess.run(['dig +short stackoverflow.com'],
shell=True)
correct = subprocess.run(['dig', '+short', 'stackoverflow.com'],
# Probably don't forget these, too
check=True, text=True)
# XXX Probably better avoid shell=True
# but this is nominally correct
fixed_but_fugly = subprocess.run('dig +short stackoverflow.com',
shell=True,
# Probably don't forget these, too
check=True, text=True)
cmd = '''while read -r x;
do ping -c 3 "$x" | grep 'round-trip min/avg/max'
done <hosts.txt'''
# Trivial but horrible
results = subprocess.run(
cmd, shell=True, universal_newlines=True, check=True)
print(results.stdout)
# Reimplement with shell=False
with open('hosts.txt') as hosts:
for host in hosts:
host = host.rstrip('\n') # drop newline
ping = subprocess.run(
['ping', '-c', '3', host],
text=True,
stdout=subprocess.PIPE,
check=True)
for line in ping.stdout.split('\n'):
if 'round-trip min/avg/max' in line:
print('{}: {}'.format(host, line))
subprocess.run('''
# This for loop syntax is Bash only
for((i=1;i<=$#;i++)); do
# Arrays are Bash-only
array[i]+=123
done''',
shell=True, check=True,
executable='/bin/bash')
subprocess.run('cd /tmp', shell=True)
subprocess.run('pwd', shell=True) # Oops, doesn't print /tmp
subprocess.run('cd /tmp; pwd', shell=True)
os.environ['foo'] = 'bar'
subprocess.run('echo "$foo"', shell=True, env={'foo': 'bar'})
#!/usr/bin/env python
import subprocess
with open('test.nt', 'wb', 0) as file:
subprocess.check_call("cwm --rdf test.rdf --ntriples".split(),
stdout=file)
#!/usr/bin/env python
import subprocess
subprocess.check_call("cwm --rdf test.rdf --ntriples > test.nt",
shell=True)
#!/usr/bin/env python
import subprocess
subprocess.check_call('program <(command) <(another-command)',
shell=True, executable='/bin/bash')