原文:https://datascienceatthecommandline.com/2e/chapter-2-getting-started.html 贡献者:Ting-xin
在这一章中,我需要确定你能够利用命令行做数据科学,为此你需要能满足一些条件。条件主要分为三个部分:(1)拥有与我在本书中使用的相同的数据集,(2)拥有一个适当的环境,拥有我在本书中使用的所有命令行工具,(3)了解使用命令行时的基本概念。
首先,我描述了如何下载数据集。其次,我解释了如何安装 Docker 镜像,它是一个基于 Ubuntu Linux 的虚拟环境,包含所有必要的命令行工具。随后,我通过例子介绍了基本的 Unix 概念。
在本章结束时,你将掌握进行数据科学的第一步,也就是获取数据。
2.1 获取数据
数据集下载步骤:
- 数据集压缩包下载地址:https://www.datascienceatthecommandline.com/2e/data.zip
- 创建一个新目录:你可以给这个目录起任何你想要的名字,但是我建议你使用小写字母、数字,可能还有连字符或下划线,以便更容易在命令行中使用。比如:
dsatcl2e-data
,然后记住这个目录在哪里 - 将 ZIP 文件移动到新的目录中,并将其解压
- 这个目录下每章都有一个对应的子目录
接下来我将介绍如何安装包含处理这些数据的环境,它包含的所有必要的命令行工具。
2.2 安装 Docker 镜像
在本书中,我们使用了许多不同的命令行工具。Unix 通常预装了许多命令行工具,并提供了许多包含相关工具的包。自己独立安装这些包通常不会太难。然而,我们也会使用那些不能以包的形式提供的工具,这也需要更多涉及安装的手动操作。为了获得必要的命令行工具而不必经历每个工具的安装过程,我建议安装专门为本书创建的 Docker 镜像,无论你的操作系统是 Windows、macOS 还是 Linux 。
Docker 镜像是一个或多个应用及其所有依赖项的包。Docker 容器是一个运行镜像的隔离环境,你可以使用docker
命令行工具(这也是你下面要做的)或 Docker GUI 来管理 Docker 镜像和容器。在某种程度上,Docker 容器就像一个虚拟机,只是 Docker 容器使用的资源要少得多。在本章的最后,我会推荐了一些资源来学习更多关于 Docker 的知识。
如果你仍然喜欢在本地而不是在 Docker 容器中运行命令行工具,那么你当然可以自己单独安装这些命令行工具。请注意,这是一个非常耗时的过程。附录中列出了本书中使用的所有命令行工具。安装说明仅适用于 Ubuntu。本书中使用的脚本和数据集可以通过克隆本书的 GitHub 仓库得。
为了安装 Docker 镜像,首先需要从 Docker 网站中下载并安装 Docker 本身。安装 Docker 后,你就可以在终端或命令提示符下调用以下命令来下载 Docker 镜像(不要输入入美元符号):
代码语言:javascript复制$ docker pull datasciencetoolbox/dsatcl2e
然后你可以运行 Docker 镜像,如下所示:
代码语言:javascript复制$ docker run --rm -it datasciencetoolbox/dsatcl2e
现在你处于一个称为 Docker 容器的隔离环境中,它安装了所有必要的命令行工具。如果下面的命令绘制了一头热情的牛,那么这就表示一切工作正常:
代码语言:javascript复制$ cowsay "Let's moove!"
______________
< Let's moove! >
--------------
^__^
(oo)_______
(__) )/
||----w |
|| ||
如果你想在容器和机器中交换数据,你可以为容器可以添加一个卷,这意味着机器中的本地目录将被映射到容器内的一个目录。所以我建议你首先创建一个新目录,然后进入这个新目录,然后在 macOS 或 Linux 上运行以下命令:
代码语言:javascript复制$ docker run --rm -it -v "$(pwd)":/data datasciencetoolbox/dsatcl2e
或者在 Windows 上使用命令提示符(也称为cmd
)上运行以下命令:
C:> docker run --rm -it -v "�%":/data datasciencetoolbox/dsatcl2e
或者当你使用 Windows PowerShell 上运行以下命令:
代码语言:javascript复制PS C:> docker run --rm -it -v ${PWD}:/data datasciencetoolbox/dsatcl2e
在上面的命令中,选项-v
指示docker
将当前目录映射到容器内的/data
目录,因此这也是 Docker 容器和机器交换数据的地方。
如果你想要知道更多关于 Docker 镜像的知识,请访问该 网址
当这些都完成后,你可以通过输入exit
命令来关闭 Docker 容器。
2.3 基本的 Unix 概念
在第一章中,我简单的给大家展示了命令行是什么。如果现在你正在运行 Docker 镜像,那么我们就可以真正开始了。在这一节中,我将讨论几个概念和工具,为了能在命令行中轻松地进行数据科学研究,你需要了解这些概念和工具。如果到目前为止,你主要用的都是图形用户界面,那么这次可能是一个相当大的改变。但是不要担心,我会从头开始,然后逐渐进入更高级的主题。
本节不是一个完整的 Unix 课程。我将只解释与做数据科学有关的概念和工具。Docker 镜像的优势之一是很多东西都已经设置好了。如果你想了解更多,请参考本章末尾的进一步阅读部分。
2.3.1 环境
现在我们刚刚进入了一个全新的环境,因此在做任何事情之前,我们都有必要对这个环境有一个大体的了解。该环境大致定义为四层,我将简单的的从上到下的介绍它们。
命令行工具
首先,也是最重要的是我们使用的命令行工具。我们通过输入相应的命令来使用它们。命令行工具有许多种类型(这个将在下一节讨论),常见例子有:ls
,cat
,jq
。
终端
终端是第二个概念,它是我们输入命令的应用。如果你看到书中提到的以下文字:
代码语言:javascript复制$ seq 3
1
2
3
然后你也可以跟着在你的终端上输入seq 3
,按下Enter
,结果就会生成一个数字序列。不要输入美元符号$
,它只是告诉你这是一个你可以在终端输入的命,这个美元符号被称为提示符。
Shell
第三层是 Shell。一旦我们输入命令并按下Enter
,终端就将命令发送给 Shell, Shell 是一个解释命令的程序。我使用的是 ZShell,还有许多其他可用的 Shell,比如 Bash 和 Fish。
操作系统
第四层是操作系统,在我们的例子中是 GNU/Linux。Linux 是内核的名字,它是操作系统的核心。内核直接与 CPU、磁盘和其他硬件接触,内核还执行我们的命令行工具。GNU,代表 GNU’s Not UNIX,指的是一套基本工具。Docker 镜像是基于一个特定的 GNU/Linux 发行版,该发行版称为 Ubuntu。
2.3.2 执行命令行工具
现在你已经对环境有了基本的了解,是时候尝试一些命令了。在你的终端中键入以下内容(不带美元符号),然后按Enter
:
$ pwd
/home/dst
你刚刚执行了一个包含单个命令行工具的命令。工具pwd
输出你当前所在目录的名称。默认情况下,你登录的是你的主目录。
ZShell 种内置的命令行工具cd
允许你导航到不同的目录:
$ cd /data/ch02 # ➊
$ pwd # ➋
/data/ch02
$ cd .. # ➌
$ pwd # ➍
/data
$ cd ch02 # ➎
➊ 导航到目录/data/ch02
。
➋ 打印当前目录。
➌ 导航到父目录。
➍ 再次打印当前目录。
➎ 导航到子目录ch02
。
cd
之后的部分指定你想要去的那个目录。命令后面的值被称为命令行参数或选项。两个点表示父目录。顺便说一下,一个点指的是当前目录。虽然cd .
不会有任何影响,但你仍然会看到一个点被用在其他地方。接下来让我们尝试一个不同的命令:
$ head -n 3 movies.txt
Matrix
Star Wars
Home Alone
这里我们将三个命令行参数传递给head
。第一个是选项。这里我使用了短选项-n
。有时一个短的选项有一个长的变量的意思,现在这种情况下就是--lines
,第二个是属于选项的值,第三个是文件名。这个特定的命令的意思是输出文件/data/ch02/movies.txt
的前三行内容。
2.3.3 命令行工具的 5 种类型
我们一直在说术语命令行工具,但是到目前为止也没有解释它的真正含义。我把它作为一个总称,指的是任何可以从命令行执行的东西(图 2.1)。实际上,每个命令行工具都是以下五种类型之一:
- 二进制的可执行文件
- Shell 内置程序
- 解释脚本
- Shell 函数
- 别名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uRi0900m-1680148019177)(null)]
图 2.1:命令行工具作为一个总称
我们需要知道命令行之间的区别。Docker 镜像预安装的命令行工具主要包括前两种类型(二进制可执行文件和 Shell 内置程序)。其他三种类型(解释脚本、Shell 函数和别名)允许我们进一步构建我们的数据科学工具箱,从而成为更高效、更高产的数据科学家。
二进制可执行文件
二进制可执行文件是传统意义上的程序,它是通过将源代码编译为机器代码而产生的。这意味着当你在文本编辑器中打开文件时是一个乱码。
Shell 内置工具
Shell 内置工具是 Shell 提供的命令行工具,在我们的例子中是 ZShell(或zsh
),它的内置工具包括cd
和pwd
。不同 Shell 的内置工具可能不同。Shell 内置工具像二进制可执行文件一样不容易检查或更改。
解释脚本
解释脚本是一个可以由二进制可执行文件执行的文本文件。常用的脚本包括:Python、R 和 Bash 脚本。解释脚本的一个很大的优点就是你可以阅读和修改它。下面的脚本可以用 Python 执行,之所以可以被执行,不是因为它的文件扩展名是.py
,而是因为脚本的第一行定义了应该执行它的二进制。
$ bat fac.py
───────┬──────────────────────────────────────────────────────────────
│ File: fac.py
───────┼──────────────────────────────────────────────────────────────
1 │ #!/usr/bin/env python
2 │
3 │ def factorial(x):
4 │ result = 1
5 │ for i in range(2, x 1):
6 │ result *= i
7 │ return result
8 │
9 │ if __name__ == "__main__":
10 │ import sys
11 │ x = int(sys.argv[1])
12 │ sys.stdout.write(f"{factorial(x)}n")
───────┴──────────────────────────────────────────────────────────────
这个脚本的作用是计算整数的阶乘,我们可以从命令行调用它,如下所示:
代码语言:javascript复制$ ./fac.py 5
120
在第四章中,我们将详细讨论如何使用解释脚本创建可重用的命令行工具。
Shell 函数
在我们的例子中,Shell 函数是由zsh
执行的函数。它们提供了与脚本相似的功能,但是它们通常(但不一定)比脚本小,也更倾向于个人化。下面的命令定义了一个名为fac
的函数,就像上面解释的 Python 脚本一样,它计算我们作为参数传递的整数的阶乘。它通过使用seq
生成一个数字列表,使用paste
将这些数字放在一行中作为分隔符,并将该等式传递给bc
,后者对其求值并输出结果。
$ fac() { (echo 1; seq $1_ | paste -s -d* - | bc; }
$ fac 5
120
文件~/.zshrc
是 ZShell 的配置文件,也是定义 Shell 函数的好地方,在这里定义之后就一直可用了。
别名
别名就像宏一样。如果你发现自己经常用相同的参数(或部分参数)执行某个命令,你就可以为它定义一个别名来节省时间。当你不断拼错某个命令时,别名也非常有用(Chris Wiggins 维护了一个有用的别名列表)。下面的命令就定义了这样一个别名:
代码语言:javascript复制$ alias l='ls --color -lhF --group-directories-first'
$ alias les=less
现在,如果你在命令行上输入以下内容,Shell 将用它的值替换它发现的每个别名:
代码语言:javascript复制$ cd /data
$ l
total 40K
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch02/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch03/
drwxr-xr-x 3 dst dst 4.0K Mar 3 10:38 ch04/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch05/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch06/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch07/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch08/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch09/
drwxr-xr-x 4 dst dst 4.0K Mar 3 10:38 ch10/
drwxr-xr-x 3 dst dst 4.0K Mar 3 10:38 csvconf/
$ cd ch02
别名比 Shell 函数简单,因为它们不允许参数。由于参数的原因,无法使用别名定义函数fac
。尽管如此,别名可以让你节省大量的击键次数。像 Shell 函数一样,别名通常在文件.zshrc
中定义。该文件位于你的主目录下,要查看当前定义的所有别名,可以不带参数地运行alias
。试试看,你看到了什么?
在本书中,我们将主要关注最后三种类型的命令行工具:解释脚本、Shell 函数和别名,因为这些类型很容易改变。命令行工具的目的是使你的生活更加轻松,并使你成为更有生产力和效率的数据科学家。你可以通过type
找到命令行工具的类型(它本身是一个 Shell 内置的工具):
$ type -a pwd
pwd is a shell builtin
pwd is /usr/bin/pwd
pwd is /bin/pwd
$ type -a cd
cd is a shell builtin
$ type -a fac
fac is a shell function
$ type -a l
l is an alias for ls --color -lhF --group-directories-first
type
为pwd
返回了三个命令行工具。在这种情况下,当你输入pwd
时,将使用第一个命令行工具。在下一节中,我们将学习如何组合命令行工具。
2.3.4 组合命令行工具
因为大多数命令行工具都遵循 Unix 哲学,它们被设计成只做一件事,但是做得非常好。例如,命令行工具grep
用来过滤行数据,wc
用来计数行数据,sort
可以排序行数据。命令行的强大之处在于它能够组合这些小而强大的命令行工具。
命令行的能力是通过管理这些工具的通信流实现的。每个工具都有三个标准通信流:标准输入、标准输出和标准错误。这些通常被简写为stdin``stdout``stderr
。
默认情况下,标准输出和标准错误都被重定向到终端,因此正常输出和任何错误信息都被打印在屏幕上。图 2.2 对pwd
和rev
都进行了说明,如果你运行rev
,你会看到什么都没有发生。这是因为rev
期望有输入,默认情况下,就是在键盘上按下任何键。试着输入一个句子并按下回车键,rev
就会立即对你的输入进行反向响应。你可以按Ctrl D
来停止发送输入,然后rev
就会停止。
图 2.2:工具的通信流:标准输入(stdin
)、标准输出(stdout
)、标准误差(stderr
)
但是实际上,我们不会使用键盘作为输入源,而是使用其他工具产生的输出和文件的内容。例如,通过curl
,我们可以下载 Lewis Carrol 写的《Alice’s Adventures in Wonderland》这本书,然后用管道把它送到下一个工具(curl 将再第三章讨论)。管道通过用管道操作符|
完成的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FTbZZlk1-1680148019354)(null)]
图 2.3:一个工具的输出通过管道传输到另一个工具
我们可以用管道将curl
的输出连接到grep
,以过滤每行的数据。想象一下,如果我们想看看目录中列出的章节,我们就可以将curl
和grep
结合起来使用,如下所示:
$ curl -s "https://www.gutenberg.org/files/11/11-0.txt" | grep " CHAPTER"
CHAPTER I. Down the Rabbit-Hole
CHAPTER II. The Pool of Tears
CHAPTER III. A Caucus-Race and a Long Tale
CHAPTER IV. The Rabbit Sends in a Little Bill
CHAPTER V. Advice from a Caterpillar
CHAPTER VI. Pig and Pepper
CHAPTER VII. A Mad Tea-Party
CHAPTER VIII. The Queen’s Croquet-Ground
CHAPTER IX. The Mock Turtle’s Story
CHAPTER X. The Lobster Quadrille
CHAPTER XI. Who Stole the Tarts?
CHAPTER XII. Alice’s Evidence
如果我们想知道这本书有多少章节,我们可以使用wc
,它非常擅长计数:
$ curl -s "https://www.gutenberg.org/files/11/11-0.txt" |
> grep " CHAPTER" |
> wc -l # ➊
12
➊ 选项-l
指定wc
应该只输出传递给它的行数。默认情况下,它还返回字符数和字数。
你可以把管道操作看成是一种自动的复制和粘贴。一旦你掌握了使用管道操作符组合工具的技巧,你会发现它几乎没有任何限制。
2.3.5 重定向输入和输出
除了将一个工具的输出输送到另一个工具外,你还可以将其保存到一个文件中。该文件将被保存在当前目录下,除非给出完整的路径。这被称为输出重定向,其工作原理如下:
代码语言:javascript复制$ curl "https://www.gutenberg.org/files/11/11-0.txt" | grep " CHAPTER" > chapter
s.txt
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 170k 100 170k 0 0 183k 0 --:--:-- --:--:-- --:--:-- 184k
$ cat chapters.txt
CHAPTER I. Down the Rabbit-Hole
CHAPTER II. The Pool of Tears
CHAPTER III. A Caucus-Race and a Long Tale
CHAPTER IV. The Rabbit Sends in a Little Bill
CHAPTER V. Advice from a Caterpillar
CHAPTER VI. Pig and Pepper
CHAPTER VII. A Mad Tea-Party
CHAPTER VIII. The Queen’s Croquet-Ground
CHAPTER IX. The Mock Turtle’s Story
CHAPTER X. The Lobster Quadrille
CHAPTER XI. Who Stole the Tarts?
CHAPTER XII. Alice’s Evidence
在这里,我们将grep
的输出保存在/data/ch02
目录下一个名为chapters.txt
的文件中。如果这个文件还不存在,它将被创建。如果这个文件已经存在,其内容将被覆盖。图 2.4 说明了输出重定向在概念上是如何工作的。注意,标准错误仍然被重定向到终端:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-35jdchrL-1680148019207)(null)]
图 2.4:工具的输出可以重定向到一个文件
你还可以使用>>
将输出附加到文件中,这意味着输出被添加到原始内容之后:
$ echo -n "Hello" > greeting.txt
$ echo " World" >> greeting.txt
工具echo
输出你指定的值。代表换行符的-n
选项指定echo
不输出尾随换行符n
。
如果你需要存储中间结果,将输出保存到文件中是非常有用的,例如在以后的阶段继续分析。要再次使用文件greeting.txt
的内容,我们可以使用cat
,它读取一个文件并打印它。
$ cat greeting.txt
Hello World
$ cat greeting.txt | wc -w # ➊
2
➊ -w
选项表示wc
只统计字数。
使用小于号(<
)可以获得相同的结果:
$ < greeting.txt wc -w
2
通过小于号(<
)这种方式,你直接将文件传递给wc
的标准输入,而不需要运行一个额外的进程。图 2.5 说明了这两种方式的工作原理。同样,最终的输出也是一样的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6X1nBfvn-1680148019382)(null)]
图 2.5:使用文件内容作为输入的两种方式
像许多命令行工具一样,wc
允许将一个或多个文件名指定为参数。例如:
$ wc -w greeting.txt movies.txt
2 greeting.txt
11 movies.txt
13 total
注意,在这种情况下,wc
也输出文件的名称。
你可以通过将任何工具的输出重定向到一个名为/dev/null
的特殊文件来保留它。我经常这样做来保留错误消息(见图 2.6 的说明)。下面的内容将导致cat
产生一个错误信息,因为它找不到404.txt
这个文件:
$ cat movies.txt 404.txt
Matrix
Star Wars
Home Alone
Indiana Jones
Back to the Future
/usr/bin/cat: 404.txt: No such file or directory
你可以将标准错误重定向到/dev/null
,如下所示:
$ cat movies.txt 404.txt 2> /dev/null # ➊
Matrix
Star Wars
Home Alone
Indiana Jones
Back to the Future
➊ 2
指标准错误
图 2.6:将stderr
重定向到/dev/null
注意不要从同一个文件中读出和写入。如果你这样做,你会得到一个空文件。这是因为输出被重定向的工具会立即打开该文件进行写入,从而将其清空。这有两个解决办法:(1)写到一个不同的文件,然后用mv
重命名;(2)使用sponge
,它在写到一个文件之前吸收了所有的输入。图 2.7 说明了这是如何工作的:
图 2.7:除非你使用sponge
,否则你不能在一个管道中读取和写入同一个文件
例如,假设你已经使用dseq
生成了一个文件dates.txt
,现在你想使用nl
添加行号。如果运行下面的代码,文件dates.txt
将会是空的。
$ dseq 5 > dates.txt
$ < dates.txt nl > dates.txt
$ bat dates.txt
───────┬────────────────────────────────────────────────────────────────────────
│ File: dates.txt <EMPTY>
───────┴────────────────────────────────────────────────────────────────────────
所以说你可以使用我刚刚描述的解决方法之一:
代码语言:javascript复制$ dseq 5 > dates.txt
$ < dates.txt nl > dates-nl.txt
$ bat dates-nl.txt
───────┬────────────────────────────────────────────────────────────────────────
│ File: dates-nl.txt
───────┼────────────────────────────────────────────────────────────────────────
1 │ 1 2022-03-04
2 │ 2 2022-03-05
3 │ 3 2022-03-06
4 │ 4 2022-03-07
5 │ 5 2022-03-08
───────┴────────────────────────────────────────────────────────────────────────
$ dseq 5 > dates.txt
$ < dates.txt nl | sponge dates.txt
$ bat dates.txt
───────┬────────────────────────────────────────────────────────────────────────
│ File: dates.txt
───────┼────────────────────────────────────────────────────────────────────────
1 │ 1 2022-03-04
2 │ 2 2022-03-05
3 │ 3 2022-03-06
4 │ 4 2022-03-07
5 │ 5 2022-03-08
───────┴────────────────────────────────────────────────────────────────────────
2.3.6 使用文件和目录
作为数据科学家,我们处理大量数据。这些数据通常存储在文件中。了解如何在命令行上处理文件(以及它们所在的目录)是很重要的。使用 GUI 可以做的每一个动作,都可以用命令行工具来完成(等等)。在这一节中,我将介绍列举、创建、移动、复制、重命名和删除文件和目录的最重要的方法。
用ls
可以列出一个目录的内容。如果不指定目录,它会列出当前目录的内容。我更喜欢ls
有一个长列表格式,并且目录和文件分组,目录在前。我使用别名l
,而不是每次都输入相应的选项。
$ ls /data/ch10
alice.txt count.py count.R __pycache__ Untitled1337.ipynb
$ alias l
l='ls --color -lhF --group-directories-first'
$ l /data/ch10
total 180K
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 __pycache__/
-rw-r--r-- 1 dst dst 164K Mar 3 10:38 alice.txt
-rwxr--r-- 1 dst dst 408 Mar 3 10:38 count.py*
-rw-r--r-- 1 dst dst 460 Mar 3 10:38 count.R
-rw-r--r-- 1 dst dst 1.7K Mar 3 10:38 Untitled1337.ipynb
你已经看到了我们如何通过使用>
或>>
重定向输出来创建新文件。如果你需要将文件移动到不同的目录,你可以使用mv
:
$ mv hello.txt /data/ch02
你也可以使用mv
重命名文件:
$ cd data
$ mv hello.txt bye.txt
你也可以重命名或移动整个目录。如果你不再需要一个文件,你用rm
删除它:
$ rm bye.txt
如果你想要删除整个目录及其所有内容,请指定-r
选项,它代表递归:
$ rm -r /data/ch02/old
如果要复制一个文件,使用cp
。这对于创建备份非常有用:
$ cp server.log server.log.bak
你可以使用mkdir
创建目录:
$ cd /data
$ mkdir logs
$ l
total 44K
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:39 ch02/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch03/
drwxr-xr-x 3 dst dst 4.0K Mar 3 10:38 ch04/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch05/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch06/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch07/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch08/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:38 ch09/
drwxr-xr-x 4 dst dst 4.0K Mar 3 10:38 ch10/
drwxr-xr-x 3 dst dst 4.0K Mar 3 10:38 csvconf/
drwxr-xr-x 2 dst dst 4.0K Mar 3 10:39 logs/
使用命令行工具来管理你的文件,一开始可能很可怕,因为你没有文件系统的图形概览来提供即时反馈。有一些可视化的文件管理器可以帮助解决这个问题,比如 GNU Midnight Commander、Ranger 和 Vifm。这些都没有安装在 Docker 镜像中,但你可以通过运行 sudo apt install,然后选择 mc、ranger 或 vifm,自己安装一个。
上面所有的命令行工具都接受代表 verbose 的-v
选项,这样它们就可以输出正在发生的事情。例如:
$ mkdir -v backup
/usr/bin/mkdir: created directory 'backup'
$ cp -v * backup
/usr/bin/cp: -r not specified; omitting directory 'backup'
/usr/bin/cp: -r not specified; omitting directory 'ch02'
/usr/bin/cp: -r not specified; omitting directory 'ch03'
/usr/bin/cp: -r not specified; omitting directory 'ch04'
/usr/bin/cp: -r not specified; omitting directory 'ch05'
/usr/bin/cp: -r not specified; omitting directory 'ch06'
/usr/bin/cp: -r not specified; omitting directory 'ch07'
/usr/bin/cp: -r not specified; omitting directory 'ch08'
/usr/bin/cp: -r not specified; omitting directory 'ch09'
/usr/bin/cp: -r not specified; omitting directory 'ch10'
/usr/bin/cp: -r not specified; omitting directory 'csvconf'
/usr/bin/cp: -r not specified; omitting directory 'logs'
除了mkdir
之外的所有工具也接受-i
选项,它代表“交互式”,这样工具就会要求你确认。例如:
$ rm -i *
zsh: sure you want to delete all 12 files in /data [yn]? n
2.3.7 管理输出
有时,一个工具或工具序列产生了太多的输出,无法包含在书中。与其手动改变这样的输出,我更喜欢通过一个辅助工具的管道将其透明化。你不一定要这样做,尤其是如果你对完整的输出感兴趣。
以下是我用来管理输出的工具:
我们可以使用trim
来限制输出给定的高度和宽度,默认情况下,输出被修剪为 10 行和终端的宽度,但也可以传递一个负数以禁止修剪高度和/或宽度。例如:
$ cat /data/ch07/tips.csv | trim 5 25
bill,tip,sex,smoker,day,…
16.99,1.01,Female,No,Sun…
10.34,1.66,Male,No,Sun,D…
21.01,3.5,Male,No,Sun,Di…
23.68,3.31,Male,No,Sun,D…
… with 240 more lines
我用来管理输出的其他工具有:head
、tail
、fold
、paste
和column
,附录中包含了每种方法的示例。
如果输出是逗号分隔的值,我通常通过csvlook
将它转换成一个好看的表格。如果你运行csvlook
,你将看到完整的表格。我通过trim
重新定义了csvlook
,这样表格就缩短了:
$ which csvlook
csvlook() {
/usr/bin/csvlook "$@" | trim | sed 's/- | -/──┼──/g;s/| -/├──/g;s/- |/──
┤/;s/|/│/g;2s/-/─/g'
}
$ csvlook /data/ch07/tips.csv
│ bill │ tip │ sex │ smoker │ day │ time │ size │
├───────┼───────┼────────┼────────┼──────┼────────┼──────┤
│ 16.99 │ 1.01 │ Female │ False │ Sun │ Dinner │ 2 │
│ 10.34 │ 1.66 │ Male │ False │ Sun │ Dinner │ 3 │
│ 21.01 │ 3.50 │ Male │ False │ Sun │ Dinner │ 3 │
│ 23.68 │ 3.31 │ Male │ False │ Sun │ Dinner │ 2 │
│ 24.59 │ 3.61 │ Female │ False │ Sun │ Dinner │ 4 │
│ 25.29 │ 4.71 │ Male │ False │ Sun │ Dinner │ 4 │
│ 8.77 │ 2.00 │ Male │ False │ Sun │ Dinner │ 2 │
│ 26.88 │ 3.12 │ Male │ False │ Sun │ Dinner │ 4 │
… with 236 more lines
我使用bat
来显示文件的内容,其中行号和语法会突出显示。例如源代码:
$ bat /data/ch04/stream.py
───────┬────────────────────────────────────────────────────────────────────────
│ File: /data/ch04/stream.py
───────┼────────────────────────────────────────────────────────────────────────
1 │ #!/usr/bin/env python
2 │ from sys import stdin, stdout
3 │ while True:
4 │ line = stdin.readline()
5 │ if not line:
6 │ break
7 │ stdout.write("%dn" % int(line)**2)
8 │ stdout.flush()
───────┴────────────────────────────────────────────────────────────────────────
有时,当我想明确指出文件中的空格、制表符和换行符时,我会添加-A
选项。
有时将中间输出写到文件中很有用。这允许你在管道中的任何步骤完成后对其进行检查。你可以在你的管道中插入工具tee
。我经常用它来检查最终输出的一部分,同时将完整的输出写入文件(见图 2.8)。在这个例子中,完整的输出被写入even.txt
,前 5 行被使用trim
打印:
$ seq 0 2 100 | tee even.txt | trim 5
0
2
4
6
8
… with 46 more lines
图 2.8:使用tee
将中间输出写入文件
最后,为了插入由命令行工具生成的图片(除了屏幕截图和图表之外的每张图片),我使用了display
。但是如果你运行display
,你会发现它不起作用。在第七章中,我介绍了四个选项,让你从命令行中显示生成的图像。
2.3.8 帮助
当你在命令行中摸索时,可能会需要帮助,即使是最有经验的用户在某些时候也需要帮助。我们不可能记住所有不同的命令行工具及其可能的参数。幸运的是,命令行提供了几种获得帮助的方法。
获得帮助最重要的命令或许是man
,是手动的简称。它包含大多数命令行工具的信息。如果我忘记了工具tar
的选项,这种情况经常发生,我只需使用以下命令访问它的手册页:
$ man tar | trim 20
TAR(1) GNU TAR Manual TAR(1)
NAME
tar - an archiving utility
SYNOPSIS
Traditional usage
tar {A|c|d|r|t|u|x}[GnSkUWOmpsMBiajJzZhPlRvwo] [ARG...]
UNIX-style usage
tar -A [OPTIONS] ARCHIVE ARCHIVE
tar -c [-f ARCHIVE] [OPTIONS] [FILE...]
tar -d [-f ARCHIVE] [OPTIONS] [FILE...]
tar -t [-f ARCHIVE] [OPTIONS] [MEMBER...]
tar -r [-f ARCHIVE] [OPTIONS] [FILE...]
… with 1147 more lines
并非每个命令行工具都有手册页。以cd
为例:
$ man cd
No manual entry for cd
对于像cd
这样的 Shell 内置,你可以参考zshbuildins
手册页:
$ man zshbuiltins | trim
ZSHBUILTINS(1) General Commands Manual ZSHBUILTINS(1)
NAME
zshbuiltins - zsh built-in commands
SHELL BUILTIN COMMANDS
Some shell builtin commands take options as described in individual en‐
tries; these are often referred to in the list below as `flags' to
avoid confusion with shell options, which may also have an effect on
the behaviour of builtin commands. In this introductory section, `op‐
… with 2735 more lines
按/
可以搜索,按q
可以退出。尝试为cd
找到合适的部分。
较新的命令行工具通常也没有手册页。在这种情况下,最好的办法是使用--help
(或-h
)选项调用工具。例如:
$ jq --help | trim
jq - commandline JSON processor [version 1.6]
Usage: /usr/bin/jq [options] <jq filter> [file...]
/usr/bin/jq [options] --args <jq filter> [strings...]
/usr/bin/jq [options] --jsonargs <jq filter> [JSON_TEXTS...]
jq is a tool for processing JSON inputs, applying the given filter to
its JSON text inputs and producing the filter's results as JSON on
standard output.
… with 37 more lines
指定--help
选项也适用于命令行工具,比如cat
。但是,相应的手册页通常会提供更多信息。如果在尝试了这三种方法后,你仍然有不明白的地方,那为啥不 Google 一下呢。在附录中,列出了本书中使用的所有命令行工具。除了如何安装每个命令行工具,它还显示了如何获得帮助。
手册页可能非常冗长,难以阅读。工具tldr
是一个由社区维护的命令行工具帮助页面的集合,旨在成为传统手册页面的一个更简单、更易用的补充。下面是一个显示tar
的tldr
页面的示例:
$ tldr tar | trim 20
tar
Archiving utility.
Often combined with a compression method, such as gzip or bzip2.
More information: https://www.gnu.org/software/tar.
- [c]reate an archive and write it to a [f]ile:
tar cf target.tar file1 file2 file3
- [c]reate a g[z]ipped archive and write it to a [f]ile:
tar czf target.tar.gz file1 file2 file3
- [c]reate a g[z]ipped archive from a directory using relative paths:
tar czf target.tar.gz --directory=path/to/directory .
- E[x]tract a (compressed) archive [f]ile into the current directory [v]erbos…
tar xvf source.tar[.gz|.bz2|.xz]
- E[x]tract a (compressed) archive [f]ile into the target directory:
… with 12 more lines
如你所见,tldr
没有像man
经常做的那样按字母顺序列出许多选项,而是通过给你一个实际例子。
2.4 总结
在本章中,你学习了如何通过安装 Docker 镜像来获得所有需要的命令行工具。我还介绍了一些基本的命令行概念以及如何获得帮助。现在你已经具备了所有必要的要素,也已经为 OSEMN 数据科学模型的第一步做好了准备:获取数据。
2.5 进一步探索
- 本书的副标题是向 Jerry Peek、Shelley Powers、Tim O’Reilly 和 Mike Loukides 的史诗般的书《Unix Power Tools》致敬。在该书 51 个章节和一千多页中,它几乎涵盖了关于 Unix 的所有知识,它的重量超过 4 磅,所以你可以考虑买本电子书。
- 网站 explainshell 解析了一条命令或一连串的命令,并对每个部分提供了简短的解释。这对快速理解一个新的命令或选项很有用,而不必粗略地阅读相关的手册页面。
- Docker 确实是一个出色的软件。在本章中,我简要介绍了如何下载 Docker 镜像和运行 Docker 容器,但学习如何创建自己的 Docker 镜像可能是值得的。Sean Kane 和 Karl Matthias 的《Docker: Up & Running》一书是一个很好的资源。