Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在运行git命令时获取子进程stdout?_Python_Git_Subprocess - Fatal编程技术网

Python 如何在运行git命令时获取子进程stdout?

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

我有一个用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 != "":
            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)