>>> from env_helper import info; info()
页面更新时间: 2024-04-08 07:54:56
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-18-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

14.6. IPython 和 Shell命令

当使用标准的Python解释器时,有一个让人感到沮丧的地方就是你需要在不同的窗口之间进行切换,有时你需要使用Python,有时你又需要使用系统命令行工具。IPython将两者联系起来,它允许你直接在IPython终端中直接运行shell命令。这个魔术使用的是感叹号:任何出现在!之后的内容将被系统shell执行,而不是Python解释器。

本节内容假定你在使用一个类Unix的系统,如Linx或者Mac OS X。下面的一些例子会在Windows下面失效,因为它使用的是一种完全不同的shell(2016年Windows宣布将直接支持原生的Bash,很快这将不成为问题。译者注:目前在windows下使用bash还是会有很多问题,微软的原生实现并不理想)。如果你对于shell命令不熟悉,作者推荐你去Shell教程去学习一下基础的shell命令。

14.6.1. Shell快速介绍

如何使用shell/终端/命令行远远超出了本章的范围,但是对于初学者,作者还是准备了一个简单快速的介绍。从80年代中开始,微软和苹果想用户推出了它们的图形界面,时至今日,图形化操作系统已经是无处不在了。大部分的计算机用户都是使用他们熟悉的菜单点击和拖放操作来使用操作系统。但是实际上操作系统比这些图形用户界面出现早得多,当时都是由用户输入一系列的文本内容对操作系统进行控制:在提示符下,用户敲入一个命令,然后计算机会按照用户的指示进行工作。这种早期的提示符界面就是shell和终端的前身,也是直到今天很多数据科学家仍在使用的工具。

不熟悉shell的人可能会问,为什么你们要这么麻烦,为什么简单的通过点击图表和菜单就能实现的功能你们要敲命令。熟练使用shell的用户可能会这样回应:为什么通过简单的键盘命令就能完成的工作你们要点击鼠标呢。虽然看起来这是一个典型的技术偏好问题,但是当你需要完成的任务变得复杂的时候,shell确实能够提供更多的控制,哪怕shell的学习曲线会吓跑很多普通的计算机用户。

作为一个例子,这里有一个用户在Linux/OSX系统上浏览、创建和修改目录以及文件的shell会话(osx:~ $是提示符,所有出现在$后面的文本都是一条命令;以#开始的文本是注释作为命令的解释,而不是你需要真正输入的内容):

osx:~ $ echo "hello world"             # 使用echo打印输出,类似Python中的print
hello world

osx:~ $ pwd                            # pwd = 打印当前工作目录
/home/jake                             # 这是我们当前的工作目录

osx:~ $ ls                             # ls = 列示目录内容
notebooks  projects

osx:~ $ cd projects/                   # cd = 改变目录位置

osx:projects $ pwd
/home/jake/projects

osx:projects $ ls
datasci_book   mpld3   myproject.txt

osx:projects $ mkdir myproject          # mkdir = 创建新目录

osx:projects $ cd myproject/

osx:myproject $ mv ../myproject.txt ./  # mv = 移动文件,这里我们将父目录中的myproject.txt
                                        # 移动到当前工作目录下
osx:myproject $ ls
myproject.txt

请注意,上面的命令都是使用命令输入完成我们平常使用鼠标点击操作完成的任务(浏览目录结构、创建目录、移动文件等)。只需要少量的命令输入(pwdlscdmkdircp)我们就能完成很多通用的文件操作。当你更深入学习shell之后,你就会发现它们非常强大。

14.6.2. IPython 中的 shell 命令

任何在命令行中可以使用的命令,也都可以在IPython中使用,只需要在前面加上!号。例如,lspwdecho命令:

In [1]: !ls
myproject.txt

In [2]: !pwd
/home/jake/projects/myproject

In [3]: !echo "printing from the shell"
printing from the shell

14.6.3. 与 shell 之间传递值

shell命令不但能被IPython环境中调用,还能与IPython的命名空间产生交互。例如,你可以将shell命令的输出保存成一个Python的列表:

In [4]: contents = !ls

In [5]: print(contents)
['myproject.txt']

In [6]: directory = !pwd

In [7]: print(directory)
['/Users/jakevdp/notebooks/tmp/myproject']

值得注意的是,这些结果并不是返回成为普通的Python列表,而是一个IPython定义的特殊shell返回值类型:

In [8]: type(directory)
IPython.utils.text.SList

它看起来很像一个Python列表,但是还包含额外的功能,比方说grepfields方法,以及snp属性,让你能够使用简单方式搜索,过滤和显示结果。如果你想获得更多信息,请使用IPython內建的帮助特性来查看。

反过来,也可以传递Python的变量给shell,通过{变量名}语法就可以实现:

In [9]: message = "hello from Python"

In [10]: !echo {message}
hello from Python

花括号里面是变量的名称,在执行shell命令的时候将会被变量的值替代。

14.7. Shell 相关魔术命令

如果你已经在IPython中使用了shell命令一段时间了,你会发现你无法使用!cd来改变你的工作目录:

In [11]: !pwd
/home/jake/projects/myproject

In [12]: !cd ..

In [13]: !pwd
/home/jake/projects/myproject

这是因为在notebook里面shell是在一个子shell空间中执行的。如果你需要改变工作目录的话,你可以使用%cd魔术命令:

In [14]: %cd ..
/home/jake/projects

事实上,你甚至可以不用%号:

In [15]: cd myproject
/home/jake/projects/myproject

这被称为自动魔术,你可以使用%automagic来切换它的开关状态。

除了%cd之外,其他类似shell命令的魔术命令包括%cat%cp%env%ls%man%mkdir%more%mv%pwd%rm%rmdir,这些命令在automagic开启时都可以不带%使用。这功能令你可以几乎将IPython shell当成系统的shell来使用了:

In [16]: mkdir tmp

In [17]: ls
myproject.txt  tmp/

In [18]: cp myproject.txt tmp/

In [19]: ls tmp
myproject.txt

In [20]: rm -r tmp

能够在IPython环境中直接使用shell,意味着你可以不用来回在解释器和shell终端两个窗口之间进行切换,可以提高你写Python代码时候的效率。