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

时间:2017-06-17 11:24:57

标签: cmd ipython jupyter

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

os

此外 - 此代码可以使用import os os.system('cmd command')

运行
!conda install package

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

[Y]/N

可能需要将来输入({{1}})或文件夹位置,但不会接受进一步输入。

5 个答案:

答案 0 :(得分:4)

!command语法是%system魔法的替代语法,可以找到哪些文档here

正如您所猜测的那样,它正在调用os.system并且就os.system而言,没有简单的方法可以知道您将要运行的进程是否需要来自用户的输入。因此,当使用笔记本或任何多进程前端时,您无法动态地为正在运行的程序提供输入。 (与Python中对input的调用不同,我们可以拦截)。<​​/ p>

当您明确表示有兴趣从笔记本中安装软件包时,我建议阅读the following from Jake Van Der Plas,这是最近关于该主题的讨论的摘要,并解释了这样做的一些复杂性。您当然可以使用conda的--yes选项,但不保证使用conda进行安装始终有效。

另请注意,!command IPython 功能,而不是Jupyter功能。

答案 1 :(得分:1)

假设您在询问交互性,可以尝试一些事情。

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

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

(故意简短的例子,因为这只是侧面信息。在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()

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

pin.write(b'ls -l\n')
pin.flush()

pin.write(b'exit\n')
pin.flush()

即使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()

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

幸运的是输入字段位于单元格的底部(使用ls;sleep 10;ls进行测试)。不幸的是,输入字段最后需要一个额外的条目才能消失(这已经是'很好'的方式,当它很简单时while(...) - write(bytearray(input())) - flush() 3线,它有一个例外。

如果有人想在Windows上试用,可以使用'cmd',但我建议使用硬编码'windows-1252'代替sys.stdin/out.encoding:他们说UTF-8,但是简单{ {1}}命令已生成既不是UTF-8也不是ASCII的输出(3位数组之间的不可分隔空间大小为0xA0字符)。或者只删除dir部分(并使用decode

答案 2 :(得分:0)

我发布这个作为答案。这不是一个好的答案,但我处理问题的方法是编写一个bash脚本在后台运行。我调查了'!'运营商,它似乎没有很多文档。我甚至无法在Jupyter源代码中找到它。这篇文章:

[关于Jupyter Predecessor和组件IPython的Safari书籍] [1] https://www.safaribooksonline.com/blog/2014/02/12/using-shell-commands-effectively-ipython/

表明这只是以前的事情,而且可能永远存在。除非你想入侵Jupyter笔记本的Magic Commands部分并自己解决它。

那就是说,考虑到通过一些小的bash编程(它简单而专注)你可以做你想做的事情,你可能会考虑这条路线。特别是如果你需要足够的结果来提升声誉。

如果您想查看针对预期响应运行bash脚本,您可以找到以下答案:Have bash script answer interactive prompts

答案 3 :(得分:0)

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

conda install package -y

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

printf 'y\n' | conda install package

这支持多个输入,您可以用'\ n'

分隔它们

答案 4 :(得分:0)

我知道这是一篇过时的文章,但是我没有看到此内容:

!是|康达安装包