我正在使用 subprocess.Popen
调用,在另一个问题中,我发现自己误解了 Python 如何为命令行生成参数。
我的问题
有没有办法找出实际的命令行是什么?
示例代码:
proc = subprocess.popen(....)
print "the commandline is %s" % proc.getCommandLine()
你该如何编写getCommandLine
函数?
我正在使用 subprocess.Popen
调用,在另一个问题中,我发现自己误解了 Python 如何为命令行生成参数。
我的问题
有没有办法找出实际的命令行是什么?
示例代码:
proc = subprocess.popen(....)
print "the commandline is %s" % proc.getCommandLine()
你该如何编写getCommandLine
函数?
proc.args
中:(参见链接)proc = subprocess.Popen(....)
print("the commandline is {}".format(proc.args))
在Python2.7中,并未保存args
,它只是传递给其他函数,如_execute_child
。因此,在这种情况下,获取命令行的最佳方法是在拥有它时将其保存:proc = subprocess.Popen(shlex.split(cmd))
print "the commandline is %s" % cmd
请注意,如果您有参数列表(例如由shlex.split(cmd)
返回的内容),则可以使用未记录的函数subprocess.list2cmdline
恢复命令行字符串cmd
。In [14]: import subprocess
In [15]: import shlex
In [16]: cmd = 'foo -a -b --bar baz'
In [17]: shlex.split(cmd)
Out[17]: ['foo', '-a', '-b', '--bar', 'baz']
In [18]: subprocess.list2cmdline(['foo', '-a', '-b', '--bar', 'baz'])
Out[19]: 'foo -a -b --bar baz'
我的问题的正确答案实际上是没有命令行。subprocess的重点在于它通过IPC执行所有操作。list2cmdline尽可能地接近,但实际上最好的方法是查看“args”列表,并知道这将成为被调用程序中的argv。
list2cmdline()
函数仅适用于兼容MS C运行时解析命令行的Windows应用程序。它将参数列表转换为传递给CreateProcess()
的字符串。在POSIX系统中,参数列表会直接传递给os.execve()
(+/- os.fsencode())。请注意,cmd.exe
使用不同的规则。 - jfs美观且可扩展的方法
我一直在使用类似于这样的东西:
#!/usr/bin/env python3
import os
import shlex
import subprocess
import sys
def run_cmd(cmd, cwd=None, extra_env=None, extra_paths=None, dry_run=False):
if extra_env is None:
extra_env = {}
newline_separator = ' \\\n'
out = []
kwargs = {}
env = os.environ.copy()
# cwd
if 'cwd' is not None:
kwargs['cwd'] = cwd
# extra_env
env.update(extra_env)
for key in extra_env:
out.append('{}={}'.format(shlex.quote(key), shlex.quote(extra_env[key])) + newline_separator)
# extra_paths
if extra_paths is not None:
path = ':'.join(extra_paths)
if 'PATH' in env:
path += ':' + env['PATH']
env['PATH'] = path
out.append('PATH="{}:${{PATH}}"'.format(':'.join(extra_paths)) + newline_separator)
# Command itself.
for arg in cmd:
out.append(shlex.quote(arg) + newline_separator)
# Print and run.
kwargs['env'] = env
print('+ ' + ' '.join(out) + ';')
if not dry_run:
subprocess.check_call(cmd, **kwargs)
run_cmd(
sys.argv[1:],
cwd='/bin',
extra_env={'ASDF': 'QW ER'},
extra_paths=['/some/path1', '/some/path2']
)
示例运行:
./a.py echo 'a b' 'c d'
输出:
+ ASDF='QW ER' \
PATH="/some/path1:/some/path2:${PATH}" \
echo \
'a b' \
'c d' \
;
a b c d
特性摘要:
sh -x
的命令中添加+
,以便用户轻易区分命令和命令输出cd
或其他额外的环境变量,就显示它们。只有在这些变量被给出时才会打印,生成最小化的shell命令。所有这些都可以使用户手动复制命令来运行命令,以避免出现错误或查看正在进行的操作。
在Python 3.5.2和Ubuntu 16.04上测试通过。具体细节请参考GitHub源代码。
如果你在POSIX操作系统上,可以通过将进程ID传递给ps
命令来查看它:
import subprocess
proc = subprocess.Popen(["ls", "-la"])
subprocess.Popen(["ps", "-p", str(proc.pid)])
输出(请参见CMD列):
PID TTY TIME CMD
7778 ttys004 0:00.01 ls -la
list2cmdline
的内容感到困惑。它期望的是一个列表而不是一个字符串。 - unutbusubprocess.Popen(cmdline)
,它可以工作。当我调用list2cmdline(cmdline)
时,它会给出一个无法工作的命令行。 - Brian Postow