批量下载、处理图片和 PDF,这些任务你可以在命令行中完成

📑 导语
日常工作和学习中有很多需要重复操作的任务。稍微了解一些命令行的解决方案,就能起到事半功倍的效果。本文从日常使用需求出发,介绍了从互联网上批量下载文件、处理图片和处理 PDF 三方面的命令行应用。

为什么使用命令行?

「命令行」(界面)是一个舶来品,翻译自英文 Command Line Interface(CLI),是指用户通过键盘输入指令,计算机接收到指令后,予以执行的操作界面。通常认为,命令行界面没有图形化界面(Graphical User Interface, GUI)那么方便用户操作。

如今,我们使用的大多数应用程序都是图形化或菜单导向型应用,需要用户结合鼠标和键盘或完全使用鼠标进行操作。对于非程序员用户来说,命令行往往充满着神秘色彩,一般不会轻易去触碰。互联网上关于使用某些命令行的 教程,往往也事无巨细,生怕出了一点差错,一步一步指导读者如何找到终端(Terminal)、打开、粘贴命令、按下回车、查看输出结果、最后关闭。

在命令行中,键盘是唯一的交互方式。因此,为了输入特定的指令,用户需要记住各式各样的命令,以及复杂琐碎的各种选项,再加上命令行单调乏味、毫不留情的提示语句,学习曲线非常陡峭,拉高了大多数用户的使用门槛。于是人们纷纷转向图形化应用,以致于有人会开发图形化应用,来封装需要复杂命令行操作的应用,降低用户使用门槛,比如最近很火的 Diffusion Bee

必须要承认,图形化应用在很多场景下具有明显的优势,但情况并不总是这样。例如,在数据分析领域,我们应该使用 Excel 还是 R?尽管 Microsoft Excel 是世界上使用最广泛的 编程语言,功能非常 强大,但遗憾的是,这个问题的答案往往是「使用 R 而不是 Excel」。对此,Hacker News 上一位用户评论道:如果某项操作你只需要做一次,使用 GUI(Excel),如果需要做十次,使用快捷键,如果需要做一百次,写一个脚本(R)。虽然这个说法有点简单粗暴,但是「话糙理不糙」,在处理一些繁琐重复的任务时,基于文本的命令行,能够避免重复的鼠标点击,的确更加高效便捷。

如果说图形化应用通过鼠标点击带来的收益是直观而便捷的操作方式,那么其背后的成本则是 工作流程难以复用A non-reproducible workflow)。举个例子,假设你需要将 100 个 DOCX 文件转换为 PDF,那么按照 GUI 的处理方式,你必须在 Microsoft Word 中重复「另存为 PDF」的动作 100 次,如果之后这些文件的内容都发生了变化,那么你还需要再重复 100 次此前的操作,用软件开发领域的话来说,这种做法违背了「一次且仅一次」原则(Don’t repeat yourself, DRY)。而与图形化应用正好相反,命令行工具则把需要重复的操作用文本的形式记录下来,如果之后还会用到,只需再次执行此前的命令,边际人力成本为零或非常小。针对这个「DOCX 转 PDF」的具体例子,使用命令行工具 docx2pdf,只需一行命令即可完成:docx2pdf myfolder/

Is It Worth the Time? 对于重复的任务,值得花时间来提高效率吗?图片来源:https://xkcd.com/1205/ Is It Worth the Time? 对于重复的任务,值得花时间来提高效率吗?图片来源:https://xkcd.com/1205/

在我的日常工作和学习中,有很多任务需要重复操作,比如批量下载文件、转换文件格式等,在不堪忍受图形化应用中繁琐重复的操作之后,我将目光转向了命令行。经过一段时间的摸索,总结了一些用命令行工具处理日常工作任务的方法,具体包括从互联网上批量下载文件、对图片和 PDF 进行处理三方面。

本文所有的操作都在 macOS 上完成,但所使用的命令行工具都有 Linux 和 Windows 版本。除特别说明外,文中所用到的命令行工具都使用 Homebrew 安装,安装命令为 brew install [package-name],如 brew install imagemagick,更详细的使用方法,推荐阅读我派上的 Homebrew 使用指北。Linux 系统可以使用包管理器如 APTYUM 进行安装。Windows 平台可使用 Chocolatey、WinGet 或 Scoop 等包管理器进行安装,在 PowerShell 或者 WSL 环境中运行。

尽管下文尽量将每条命令的含义都解释清楚,但考虑到 Unix-like 系统有着 非常庞杂 的命令行语法,常常让人摸不着头脑,如果你对下文中用到的命令有疑惑,或者想深入研究某些命令,可以在终端中输入 man [command-name] 来查看对应命令的官方文档,例如 man curl。不过由于某些命令没有 man page 或者不够详细,这里也推荐下面这几个网站,你可以在需要时在线查询更为丰富的文档内容:

在命令行中下载文件

从互联网上下载文件是上网冲浪的基本操作,即使用户没有主动下载,应用也可能会在后台自动下载所需资源。下载单个文件非常简单,直接在浏览器中打开对应链接即可,这似乎不是一个值得拿出来说的操作。然而,如果你有一系列链接,需要从互联网上把它们指向的文件一个个下载下来,如何简单快速地完成呢?这是我前段时间遇到的一个实际问题:用户提交的 PDF 文件存储在 Google Cloud Storage 中,网站后台无法直接下载,只有导出的 CSV 文件中有对应的文件存储链接。

使用 Curl

如何下载这些文件?我想到了 Curl(Client URL)—— 一个通过指定 URL 语法传输数据的命令行工具。作为一项互联网基础设施,Curl 在今天的互联网中几乎无处不在 1,甚至连 macOS 都预装了 Curl,因此如果你使用的是 macOS,就不需要额外安装,开箱即用 2

使用 Curl 下载单个文件很符合直觉,命令非常简单:

1
2
3
4
5
# 下载远程文件,并指定文件保存在本地的名称
curl https://cross-currents.berkeley.edu/sites/default/files/e-journal/articles/Kauffman.pdf --output output.pdf

# 下载远程文件,使用远程文件名称
curl -O https://cross-currents.berkeley.edu/sites/default/files/e-journal/articles/Kauffman.pdf

上面的两行命令中,--output 参数 表示输出为文件而不是标准输出(stdout),也可以用 -o (小写字母 o)代替。如果不需要重命名,可以使用 参数 -O(大写字母 O),这将把输出写入本地文件,文件名称与远程文件名保持一致。

为了使用 Curl 批量下载文件,我们需要先将所有链接保存在一个纯文本文件中,其中每行一个链接,例如 urls.txt 的内容如下:

1
2
3
https://neodb.social/media/movie/2022/09/09fb7e2d34-e22b-4f96-843b-709db076b7c5.jpg
https://i.stack.imgur.com/sk5Pr.png
https://www.tug.org/mactex/TeXLive2020+Changes.pdf

然后打开终端,进入 urls.txt 所在文件夹,输入:

1
xargs -n 1 curl -O < urls.txt

按下回车键之后,Curl 就会自动开始将 urls.txt 中所有链接对应的文件下载到当前文件夹中。其中,xargs -n 参数指定每次将多少项作为命令行参数,上面这行命令指定将每一项 -n 1 标准输入作为命令行参数,分别执行一次 curl 命令。以下是使用 Curl 批量下载 3 个文件的示例,如果你觉得 Curl 的输出太过冗长,可以加上 -# 参数,这样就只会在输出中显示下载进度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
$ echo -e "https://neodb.social/media/movie/2022/09/09fb7e2d34-e22b-4f96-843b-709db076b7c5.jpg\nhttps://i.stack.imgur.com/sk5Pr.png\nhttps://www.tug.org/mactex/TeXLive2020+Changes.pdf" > urls.txt

$ cat urls.txt
https://neodb.social/media/movie/2022/09/09fb7e2d34-e22b-4f96-843b-709db076b7c5.jpg
https://i.stack.imgur.com/sk5Pr.png
https://www.tug.org/mactex/TeXLive2020+Changes.pdf

$ xargs -n 1 curl -O < urls.txt
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  161k  100  161k    0     0   199k      0 --:--:-- --:--:-- --:--:--  201k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  258k  100  258k    0     0   158k      0  0:00:01  0:00:01 --:--:--  158k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 91781  100 91781    0     0  50648      0  0:00:01  0:00:01 --:--:-- 50876

$ ls
09fb7e2d34-e22b-4f96-843b-709db076b7c5.jpg sk5Pr.png TeXLive2020+Changes.pdf urls.txt

如果 Curl 提示 (3) URL using bad/illegal format or missing URL,这可能是因为 urls.txtDOS/Windows 的文件格式,你可以用文本编辑器将其 CRLF 换行方式改成 LF 换行方式,也可以使用 dos2unix 这个工具批量将其转换为 Unix 文件格式。

🔖 Note
本文为少数派会员文章,以上是其中部分内容,欢迎加入少数派会员 阅读全文

  1. 比如 Homebrew 就使用的是 Curl 来下载软件。 ↩︎

  2. 我非常喜欢这种「开箱即用」的工具,可以省掉繁琐的安装步骤,避免「从安装到放弃」,说的就是你 Python。 ↩︎