从Jupyter笔记本运行交互式命令行代码

Dim*_*old 19 cmd ipython jupyter

Ipython Jupyter Notebook中有一个有趣的选项可以直接从笔记本中执行命令行语句.例如:

! mkdir ...
! python file.py
Run Code Online (Sandbox Code Playgroud)

此外 - 此代码可以使用os以下命令运行:

import os
os.system('cmd command')
Run Code Online (Sandbox Code Playgroud)

但是如何运行交互式shell命令.例如:

!conda install package
Run Code Online (Sandbox Code Playgroud)

可能需要将来的input([Y]/N)或文件夹位置,但不接受进一步的输入.

tev*_*dar 8

假设您正在询问交互性,那么您可以尝试一些东西。

如果您想知道 Jupyter 如何知道单元格的输出何时结束:好吧,它显然不知道,它只是将任何捕获的输出转储到最近活动的单元格中:

import threading,time
a=5
threading.Thread(target=lambda:[print(a),time.sleep(20),print(a)]).start()
Run Code Online (Sandbox Code Playgroud)

(故意短于漂亮的例子,因为这只是侧面信息。当 20 秒的等待正在运行时,您有时间激活另一个单元格,也许通过发出a=6

这可用于将一些控制台代码的输出输出到屏幕,同时从主线程控制它:

import sys,threading,subprocess

proc=subprocess.Popen('/bin/sh',stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.STDOUT)
pout=proc.stdout
pin=proc.stdin

def outLoop():
    running=True
    while(running):
        line=pout.readline().decode(sys.stdout.encoding)
        print(line,end='')
        running='\n' in line
    print('Finished')

threading.Thread(target=outLoop).start()
Run Code Online (Sandbox Code Playgroud)

然后你可以发出命令,比如

pin.write(b'ls -l\n')
pin.flush()
Run Code Online (Sandbox Code Playgroud)

pin.write(b'exit\n')
pin.flush()
Run Code Online (Sandbox Code Playgroud)

即使b'ls\nexit\n'有效,这就是为什么outLoop这么长(一个简单的while(proc.poll() is None)-print(...)循环会比它获取所有输出更快完成。

然后整个事情可以自动化为:

while(proc.poll() is None):
    inp=bytearray(input('something: ')+'\n',sys.stdin.encoding)
    if(proc.poll() is None):
        pin.write(inp)
        pin.flush()
Run Code Online (Sandbox Code Playgroud)

这在https://try.jupyter.org/上运行良好,但显然我不想尝试在那里安装 conda 包,所以我不知道当 conda 提出问题时会发生什么。

幸运的是,输入字段位于单元格的底部(用 测试ls;sleep 10;ls)。不幸的是,输入字段最后需要一个额外的条目才能消失(这已经是“不错”的方式,当它是一个简单的while(...)- write(bytearray(input()))- flush()3-liner 时,它以异常退出。

如果有人想在 Windows 上尝试这个,它可以与 一起使用'cmd',但我建议使用硬编码'windows-1252'而不是sys.stdin/out.encoding:他们说 UTF-8,但是一个简单的dir命令已经产生既不是 UTF-8 也不是 ASCII 的输出(之间的不可破坏空格)大小的 3 位组是一个 0xA0 字符)。或者只是移除decode零件(并使用running=0xA in line


Iva*_*van 7

我遇到的大多数命令的好选择是使用非交互式参数。例如在上述情况下:

conda install package -y
Run Code Online (Sandbox Code Playgroud)

如果您绝对需要提供提示,则可以使用 printf hack,例如:

printf 'y\n' | conda install package
Run Code Online (Sandbox Code Playgroud)

这支持多个输入,你用 '\n' 分隔它们


Mat*_*att 6

!command语法的替代语法%system的魔力,它的文档可以找到这里

正如您所猜测的那样,它正在调用os.system,并且到目前为止,os.system还没有一种简单的方法来知道您将要运行的进程是否需要用户输入。因此,在使用笔记本电脑或任何多进程前端时,您将无法为正在运行的程序动态提供输入。(与input我们可以拦截的Python中的调用不同)。

当您明确表示有兴趣从笔记本电脑安装软件包时,建议您阅读杰克·范德普拉斯(Jake Van Der Plas)的以下文章,这是有关该主题的最新讨论的摘要,并解释了这样做的一些复杂性。您当然可以--yes选择conda选项,但不能保证使用conda进行安装将始终有效。

还要注意,这!commandIPython功能,而不是Jupyter功能。