【问题标题】:In shell pass results of "python -m SimpleSTTPServer" to pipe在 shell 中将“python -m SimpleSTTPServer”的结果传递给管道
【发布时间】:2018-10-18 01:19:00
【问题描述】:

我正在尝试将 Python CLI“SimpleHTTPServer”命令的输出发送到管道,以便对结果进行 grep。但似乎输出的第一行没有传递到管道,我不知道为什么。

这是运行命令的典型输出。第一行声明它已经启动了一个服务器,以及它正在使用的端口。然后它会在各种网络活动发生时报告它们。所以如果我运行python -m SimpleHTTPRequest 然后加载index.html 页面两次,输出如下所示:

$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
127.0.0.1 - - [07/May/2018 21:08:31] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [07/May/2018 21:08:36] "GET / HTTP/1.1" 200 -

如果我将stderr 重定向到stdout,然后发送到管道,我希望所有行都会在管道之后到达stdin。但这似乎没有发生。当我在管道之后使用sed 并让它在所有行前加上“这是标准输入:”时,输出的第一行不会出现。

$ python -m SimpleHTTPServer 2>&1 | sed "s/.*/This is stdin\:&/"
This is stdin:127.0.0.1 - - [07/May/2018 23:35:07] "GET / HTTP/1.1" 200 -
This is stdin:127.0.0.1 - - [07/May/2018 23:35:11] "GET / HTTP/1.1" 200 -

我尝试了不同的重定向选项。我可以使用1>&2stdout 重定向到stderr,这使得所有三行都显示而不传递到管道,正如预期的那样。根据this answer 的讨论,我尝试使用0>$1stdin 重定向到stdout,但这并没有将任何行发送到管道。我尝试根据this answer 将python 命令放在大括号中,但它并没有改变结果。很明显,网络活动日志正在发送到stderr,但尚不清楚第一行的去向。我还尝试在管道之后使用grep,结果相同。在所有情况下,输出的第一行都没有到达管道之后的stdin

看来,python“SimpleHTTPServer”的第一行输出不会发送到stdoutstderr,所以我不能将它传递给管道。发生了什么?


如果有人有更好的解决方法,这就是我想要做的。我想要一个单行 shell 命令,它将 (1) 使用 python SimpleHTTPServer 启动本地服务器; (2) 找出它正在使用的端口号;然后 (3) 在该本地服务器端口打开浏览器。我知道 SimpleHTTPServer 的默认端口是 8000;但如果那个已经在使用中,它会分配一个不同的,所以我需要知道这一点。我也知道我可以告诉 SimpleHTTPServer 使用哪个端口,但是如果该端口已在使用中,那么该命令将失败。我知道在 python 中你可以询问正在使用的端口,但我需要一个 shell 脚本来从不同的应用程序运行。所以我决定在启动服务器时监听命令的输出,正则表达式 4 位端口号,使其成为变量,然后使用该变量在浏览器中打开正确的端口。我希望以下内容可以正常工作,但事实并非如此。

$ port=$(python -m SimpleHTTPServer 2>&1 | grep -o '[0-9]\{4\}') ; open http://localhost:$port

【问题讨论】:

标签: python bash shell simplehttpserver


【解决方案1】:

我指的是 Python3 和模块 http.server,因为 Python2 已经走到了生命的尽头。然而,同样的情况也发生在那里。您观察到的行为与此 HTTP 服务器实现并发的方式有关,而它在调用处理客户端请求的函数 serve_forever() 之前没有刷新 stdout(参见 Lib/http/server.py)。您可以通过在Lib/http/server.py 的第 1247 行中对 print 的调用中的函数参数附加 , flush=True 来自己测试。

由于我假设您无论如何都想使用 Python3 的 HTTP 服务器,您可以使用以下 bash 脚本来完成启动 HTTP 服务器、找到其侦听端口并打开系统默认浏览器以打开的任务它:

#!/bin/bash

# Runs your server process
(python3 -m http.server &) >/dev/null 2>&1

# Adds delay, so that server started up
sleep 0.5

# Retrieves PID of the running server process
pid=$(pgrep -f "python3 -m http.server")

# Uses lsof to find the listening sockets
# -a is used to 'and' two filters
port=$(lsof -a -i -p $pid | grep -oP 'TCP.*:\K\d+')
echo "Server running on port ${port}"

# Opens the site
open "http://localhost:${port}"

请注意,之后您需要终止服务器进程。

希望,这会有所帮助!

【讨论】:

    猜你喜欢
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-10
    相关资源
    最近更新 更多