首页 > 解决方案 > 使用子进程捕获 jupyter-notebook 标准输出

问题描述

我正在创建一个工具,允许用户在 AWS 服务器上运行带有 pyspark 的 jupyter-notebook,并将端口转发到他们的 localhost 以连接到笔记本。

我一直在使用 subprocess.Popen ssh 进入远程服务器并启动 pyspark shell/notebook,但我无法避免让它将所有内容打印到终端。我想每行执行一个操作来检索端口号。

例如,运行这个(按照这里最流行的答案:从 subprocess.communicate() 读取流输入

command = "jupyter-notebook"
con = subprocess.Popen(['ssh', node, command], stdout=subprocess.PIPE, bufsize=1)

with con.stdout:
    for line in iter(con.stdout.readline, b''):
        print(line),
con.wait()

这将忽略上下文管理器,并且该con部分开始打印标准输出,以便立即打印到终端

[I 16:13:20.783 NotebookApp] [nb_conda_kernels] enabled, 0 kernels found
[I 16:13:21.031 NotebookApp] JupyterLab extension loaded from /home/*****/miniconda3/envs/aws/lib/python3.7/site-packages/jupyterlab
[I 16:13:21.031 NotebookApp] JupyterLab application directory is /data/data0/home/*****/miniconda3/envs/aws/share/jupyter/lab
[I 16:13:21.035 NotebookApp] [nb_conda] enabled
...
...
...

当我调用如下所示的随机脚本而不是“jupyter-notebook”(其中command="bash random_script.sh")时,我可以让上下文管理器运行

# random_script.sh
for i in $(seq 1 100)
do
    echo "some output: $i"
    sleep 2
done

这符合预期,我实际上可以在with语句中的每行执行一个操作。jupyter 版本是否有一些根本不同的东西可以防止这种行为发生类似的情况?

标签: python-2.7sshsubprocessjupyter-notebook

解决方案


事实证明,这个问题与 jupyter 生成的控制台输出实际上是到 STDERR 而不是 stdout 的事实有关。我不确定为什么。但无论如何,这种变化完全解决了这个问题:

con = subprocess.Popen(['ssh', node, command], 
                       stdout=subprocess.PIPE, 
                       stderr=subprocess.STDOUT,  # <-- redirect stderr to stdout
                       bufsize=1)

推荐阅读