Python 如何在运行git命令时获取子进程stdout?
我有一个用python编写的程序,其中使用了git命令。。 出于某种原因,我不想使用git python或其他替代子流程的方法。 但我目前一直在获取git clone的输出 我试过一些代码片段。有些命令可以很好地使用,比如Python 如何在运行git命令时获取子进程stdout?,python,git,subprocess,Python,Git,Subprocess,我有一个用python编写的程序,其中使用了git命令。。 出于某种原因,我不想使用git python或其他替代子流程的方法。 但我目前一直在获取git clone的输出 我试过一些代码片段。有些命令可以很好地使用,比如ping8.8.8.8,但不能使用git clone 比如说 使用线程 def log_worker(stdout): while True: last = non_block_read(stdout).strip() if last
ping8.8.8.8
,但不能使用git clone
比如说
使用线程
def log_worker(stdout):
while True:
last = non_block_read(stdout).strip()
if last != "":
print(last)
def non_block_read(output):
fd = output.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
try:
return output.read()
except:
return ''
def test():
mysql_process = subprocess.Popen(
"ping google.com",
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
thread = Thread(target=log_worker, args=[mysql_process.stdout])
thread.daemon = True
thread.start()
mysql_process.wait()
thread.join(timeout=1)
test()
或
最常见的一种
for line in iter(proc.stdout.readline, ''):
sys.stdout.write('{:.2f} {}\n'.format(
time.time() - start,
line.rstrip()
))
sys.stdout.flush()
所有这些都可以在ping google.com
上正常工作,但不能在git clone
上正常工作。
有什么办法解决这个问题吗?
提前谢谢
更新1:
实际上,我只是想得到git clone的完成百分比。不需要日志或任何日志文件。不向终端写入时,
git clone
不会向stdout或stderr输出任何内容,除非出现错误
当然,当写入终端时,它有很多输出,但输出是不断被覆盖的进度条。通常情况下,你不希望它将是一个控制字符和重复行的大混乱
但如果你真的想要,有两种选择
首先,可以使用PTY(伪TTY)。您可以使用创建PTY,然后将PTY显式地交给子进程。或者您可以使用,它处理分叉和自动连接PTY,所以您所要做的就是调用其中一个函数。或者您可以使用该模块。(目前还不完全清楚哪一个更具可移植性;
openpty
和forkpty
声称pty
更具可移植性,从概念上讲,它就是这样设计的……但它也只在Linux上进行了真正的测试。)
请注意,git
希望将PTY作为其stderr,而不是stdout
或者,大多数
git
命令都有一个--progress
标志,使它们将进度写入stderr,即使它不是终端。至少在所记录的版本中,这包括克隆
,但您当然应该检查人
以了解您的本地版本。所以,这可能就是你所需要的。(另请参见--verbose
标志。)
然而,这可能没有那么好。对我来说,当我提供一个没有附加条款帽的PTY时,我会在每一行后面加一个\r
,而不加\n
来覆盖它;当我使用--progress
选项时,git
会检测脚本运行的任何终端的termcaps,这意味着我最终会得到ANSI颜色代码以及\r
s
当然,无论哪种方式,我都会收到数百条我不感兴趣的无用线路,但我想这就是你想要的?(或者您可能想使用
universal\u newlines='\r'
将'\r'
转换为'\n'
?这有点作弊,因为这是自覆盖Unix终端输出,您假装它是经典的Mac输出…但它可以工作。)不向终端写入时,git clone
没有任何输出到stdout或stderr,除非出现错误
当然,当写入终端时,它有很多输出,但输出是不断被覆盖的进度条。通常情况下,你不希望它将是一个控制字符和重复行的大混乱
但如果你真的想要,有两种选择
首先,可以使用PTY(伪TTY)。您可以使用创建PTY,然后将PTY显式地交给子进程。或者您可以使用,它处理分叉和自动连接PTY,所以您所要做的就是调用其中一个函数。或者您可以使用该模块。(目前还不完全清楚哪一个更具可移植性;
openpty
和forkpty
声称pty
更具可移植性,从概念上讲,它就是这样设计的……但它也只在Linux上进行了真正的测试。)
请注意,git
希望将PTY作为其stderr,而不是stdout
或者,大多数
git
命令都有一个--progress
标志,使它们将进度写入stderr,即使它不是终端。至少在所记录的版本中,这包括克隆
,但您当然应该检查人
以了解您的本地版本。所以,这可能就是你所需要的。(另请参见--verbose
标志。)
然而,这可能没有那么好。对我来说,当我提供一个没有附加条款帽的PTY时,我会在每一行后面加一个\r
,而不加\n
来覆盖它;当我使用--progress
选项时,git
会检测脚本运行的任何终端的termcaps,这意味着我最终会得到ANSI颜色代码以及\r
s
当然,无论哪种方式,我都会收到数百条我不感兴趣的无用线路,但我想这就是你想要的?(或者你可能想用
universal\u newlines='\r'
将'\r'
翻译成'\n'
?这有点作弊,因为这是自覆盖Unix终端输出,你假装它是经典的Mac输出…但它能工作。)我有一个类似的问题,但我也希望实时进展,因为这是一个大型git回购,git克隆需要花费很长时间(大约5分钟)。我想向用户提供实时反馈
下面是一个Python 3.7工作示例:
# This will print stdout/stderr as it comes in
def run_shell_command_with_realtime_output(shell_command_string, working_dir='.'):
# print the command to be executed, just for fun
print("run_shell_command >", shell_command_string)
# run it, this will NOT block
sub_process = subprocess.Popen(shell_command_string,
shell=True,
cwd=working_dir, universal_newlines=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# print the stdout/stderr as it comes in
while True:
# The readline() will block until...
# it reads and returns a string that ends in a '\n',
# or until the process has ended which will result in '' string
output = sub_process.stdout.readline()
if output:
print(output.strip())
elif sub_process.poll() is not None:
break
# get the return code
return_code = sub_process.wait()
# Was there an error?
if return_code != 0:
print("FYI, the subprocess had an error, you might want to do something special...")
# return the sub_process, in case the caller wants to check exit/return codes
return sub_process
事实证明,git clone
似乎不像我们通常使用的那样写入stdout/stderr。相反,它使用了一个寻呼机,这是它更新同一行的方式,就像克隆时一样,并且%在同一行上递增
所以你需要这样称呼它
# prepare to clone the git repo
git_clone_url_with_credentials = "https://<username>:<password>@bitbucket.org/myreponame.git"
git_clone_with_progress_cmd = "git --no-pager clone --progress {}".format(git_clone_url_with_credentials)
helpers_misc.run_shell_command_with_progress(git_clone_with_progress_cmd)
#准备克隆git回购
git\u clone\u url\u和\u credentials=“https://:@bitbucket.org/myreponame.git”
git_clone_with_progress_cmd=“git--no pager clone--progress{}”。格式(git_clone_url_with_凭证)
助手\u杂项运行\u外壳\u通信
# prepare to clone the git repo
git_clone_url_with_credentials = "https://<username>:<password>@bitbucket.org/myreponame.git"
git_clone_with_progress_cmd = "git --no-pager clone --progress {}".format(git_clone_url_with_credentials)
helpers_misc.run_shell_command_with_progress(git_clone_with_progress_cmd)