打印Python subprocess.Popen执行的命令
我有一个脚本,它可以自动在多个git仓库中修改作者信息。
def filter_history(old, new, name, repoPath):
command = """--env-filter '
an="$GIT_AUTHOR_NAME"
am="$GIT_AUTHOR_EMAIL"
cn="$GIT_COMMITTER_NAME"
cm="$GIT_COMMITTER_EMAIL"
if [[ "$GIT_COMMITTER_NAME" = "|old|" ]]
then
cn="|name|"
cm="|new|"
fi
if [[ "$GIT_AUTHOR_NAME" = "|old|" ]]
then
an="|name|"
am="|new|"
fi
export GIT_AUTHOR_NAME="$an"
export GIT_AUTHOR_EMAIL="$am"
export GIT_COMMITTER_NAME="$cn"
export GIT_COMMITTER_EMAIL="$cm"
'
"""
#DO string replace
command = command.replace("|old|", old)
command = command.replace("|new|", new)
command = command.replace("|name|", name)
print "git filter-branch -f " + command
process = subprocess.Popen(['git filter-branch -f', command],cwd=os.path.dirname(repoPath), shell=True)
process.wait()
这个命令执行得很好,但告诉我在仓库历史中没有任何变化。不过,如果我把打印出来的命令(应该就是正在执行的命令)放到一个shell脚本里执行,它就能正常改变历史。我觉得这个命令可能没有被正确执行。有没有办法让我看到子进程模块到底执行了什么命令呢?
2 个回答
2
如果你的应用程序在Windows环境下运行,正如下面这个回答所说的,subprocess模块有一个不太为人所知的功能,叫做subprocess.list2cmdline
,你可以用它。这个subprocess.list2cmdline
可以把一系列的参数转换成命令行字符串,使用的规则和微软的C运行时是一样的。
如果你使用的是Python 3.3以上的版本,你还可以直接通过subprocess对象获取参数列表,方法是使用.args
:
import subprocess
process = subprocess.Popen(...)
subprocess.list2cmdline(process.args)
从Python 3.8开始,你还可以使用shlex.join()
这个函数:
不过要记住,subprocess是通过进程间通信(IPC)来工作的,所以最好的方法就是直接查看args
列表,因为这些参数会被传递给被调用程序的argv
。
5
当你使用 shell = True
时,subprocess.Popen
会期待第一个参数是一个字符串。如果可以的话,最好不要使用 shell = True
,因为这样可能会带来 安全风险(请查看警告)。
如果你不使用 shell = True
,或者使用 shell = False
,那么 subprocess.Popen
就会期待一个参数列表。你可以通过 shlex.split
从一个字符串生成这个参数列表:
import shlex
import subprocess
def filter_history(old, new, name, repoPath):
"""Change author info
"""
# http://help.github.com/change-author-info/
# http://stackoverflow.com/a/3880493/190597
command = """git filter-branch -f --env-filter '
an="$GIT_AUTHOR_NAME"
am="$GIT_AUTHOR_EMAIL"
cn="$GIT_COMMITTER_NAME"
cm="$GIT_COMMITTER_EMAIL"
if [[ "$GIT_COMMITTER_NAME" = "{old}" ]]
then
cn="{name}"
cm="{new}"
fi
if [[ "$GIT_AUTHOR_NAME" = "{old}" ]]
then
an="{name}"
am="{new}"
fi
export GIT_AUTHOR_NAME="$an"
export GIT_AUTHOR_EMAIL="$am"
export GIT_COMMITTER_NAME="$cn"
export GIT_COMMITTER_EMAIL="$cm"
'
""".format(old = old, new = new, name = name)
process = subprocess.Popen(
shlex.split(command),
cwd = os.path.dirname(repoPath))
process.communicate()