【问题标题】:How do I provide inline input to an IPython (notebook) shell command?如何为 IPython (notebook) shell 命令提供内联输入?
【发布时间】:2016-09-12 05:41:15
【问题描述】:

我想将一个 IPython 笔记本与一些 shell 命令及其输入放在一起。在 bash 提示符中,我可以使用“here-document”语法:

bash-3.2$ mysql -u root <<END_IPUT
> use mydb;
> show tables;
> END_INPUT

如何在 IPython 中,特别是在 jupyter notebook 中获得相同的效果?我知道如何将 shell 命令作为 IPython 执行为“line magics”或“cell 魔法”,例如:

In [7]:  !! ls -tF
Out[7]:  ['Demo-notebook.ipynb',
          'createdb.sql',
          ...

我查看了IPython as a system shell,它展示了如何启用一些语法细节。在以下之后,我可以运行系统命令而无需预先添加!!!

# Turn everything in $PATH into an alias; 
# then enable calling aliases without ! or %
%rehashx      
%autocall 2 

但是这些都不能帮助为这些命令提供内联输入:here-document 语法在 IPython 中无效,并导致 python SyntaxError。那我该怎么做呢?

【问题讨论】:

  • 你尝试过 bash 细胞魔法吗?以%%bash 行开始一个单元格,然后将 bash 代码放入其中。
  • 好建议,谢谢!我已经找到了%%sx,我认为它的作用相同。但是%bash 的文档让我找到了%%script,这正是我想要的正是。与此同时,我还找到了一个专门针对sql 的扩展,它更好地解决了我眼前的问题。但如果你想写一个扩展你的建议的答案,我会接受。
  • @Thomas,在你第三次删除我的标签之前,看看有多少人关注每个标签。如果ipython-notebook是这样的问题,请着手进行标签合并。
  • 我正在尝试合并标签,但在新标签的使用量是旧标签的 80% 之前我不能这样做。我会定期将新问题扫到新标签上,以增加其数量。谢谢。
  • 我明白了。好吧,请停止删除我的标签。两者都应该对你来说已经足够了。 (只需添加 jupyter-notebook 到其他问题。)当然,让标签本身成为同义词。

标签: ipython ipython-notebook jupyter-notebook ipython-magic


【解决方案1】:

经过更多研究,并在@ThomasK 的提示(请参阅已接受的答案)的帮助下,我找到了几种方法。

  • 一个解决方案是细胞魔法%sx。它将单元格内容作为 bash 脚本执行,并捕获并以行列表的形式返回输出。有时方便,有时不方便。

    In[1]:  %%sx
            echo Hello, world
            cat -n <<DATA
            this
            and that
            DATA
    
    Out[1]: ['Hello, world', '     1\tthis', '     2\tand that']
    
  • 将其更改为%%bash,如@ThomasK 建议的那样,输出被打印出来,而不是返回。为了捕获它以进行进一步处理,ipython 提供了--out 参数。但是我需要自己打印它——默认情况下它不会显示出来。

    In[1]:  %%bash --out var
            echo Hello, world
            echo "   Again"
    
    In[2]:  var
    
    Out[2]: 'Hello, world\n   Again\n'
    
  • %%bash 实际上是%%script bash 的简写,被称为“就像脚本中的#! 行一样”(参见%%script? 的帮助)。它确实如此。因此,这里是如何放弃 here-document 语法并让任何程序读取单元格内容作为输入的方法。 %%script 也接受 --out 参数。

            %%script --out var mysql -u root -p XYZ
            USE somedb;
            SELECT * FROM users
                 WHERE passwd IS NULL\G
    

这已经足够好了,但我最终没有使用它,因为我的用例是 mysql,最终我发现有一个很棒的第三方 ipython-sql 扩展,我可以使用它来代替:

%load_ext sql
%sql mysql+pymysql://user:passwd@localhost/somedb

这以安装扩展为前提,pip install ipython-sql。对于mysql,我还需要pip install pymysql。完成上述设置后,我只是像这样与数据库交谈

In[1]:  %%sql 
        SELECT * FROM users
            WHERE passwd IS NULL

Out[1]: 1 rows affected.
        ...

返回的表格实际上是绘制为带有边框的笔记本表格,这还不错。它以 Pandas 数据框(智能列表)的形式提供,我可以从 _ 获取。

【讨论】:

  • 我可以:%%bash /usr/bin/env ipython 以便在命令行运行导出的notebook.py 吗?
【解决方案2】:

bash 单元魔术允许您输入多行 bash。只需使用%%bash 开始任何单元格:

%%bash
echo "This is bash"
ls

如果您使用 heredoc 将文本通过管道传输到另一个程序中,您还可以使用脚本单元魔法:

%%script bc
2+3

可能还有其他细胞魔法可以更具体地解决您的问题!

【讨论】:

  • 在运行命令时,!%%bash 之间几乎没有细微差别。 1. %%bash 不显示 ASCII 颜色,而使用! 时颜色看起来很好。 2.%%bash收集输出并在屏幕上刷新一次,而!在执行时将输出一一显示。