Linux-终端基础提示和技巧-全-

Linux 终端基础提示和技巧(全)

原文:Basic Linux Terminal Tips and Tricks

协议:CC BY-NC-SA 4.0

一、Linux 优先

今天成长起来的大多数人都是通过图形界面接触计算机的,无论是通过视频游戏控制台、笔记本电脑还是 iPad。因为大多数人与计算机的交互是通过某种图形界面来完成的。尽管图形界面很流行,但大多数严肃的编程和系统管理仍然是在命令行级别完成的。

图形越来越好。语音激活计算、可穿戴设备和物联网等创新正在引入更多与计算机交互的方式。桌面和移动设备上流行的操作系统的新版本在不断变化。然而,在从物联网到安卓的大多数新系统下,似乎都有一个命令行世界,它以稳定的状态存在,而构建在其上的一切都在变化。

Linux 操作系统和终端命令行作为输入方法的持久性证明了它的效率和有用性。虽然黑色背景上简单的绿色文本可能看起来过时了,但它实际上是通向神奇效率的大门。每个命令都像一个咒语。只需敲几下键盘,我们就可以完成使用鼠标和图形用户界面需要花费很长时间才能完成的任务和技巧。在某些情况下,我们甚至可以在命令行上做一些用 GUI 做不到的事情。

这本书是为那些想从命令行的角度探索 Linux 的人而写的——无论你是一个完全的新手,从零开始学习命令行,还是你已经熟悉了 Linux 机器,但想学习一些新的命令和实用程序,这些都会派上用场。

在这一章中,我们将看看什么是 Linux,回顾一些流行的发行版(或发行版),并看看一些处理文件和目录的基本命令。

什么是 Linux

在本书中,我们将探讨不同的命令行应用、内置命令和技术。在我们开始之前,有必要先了解一下“什么是 Linux”一些技术定义将只包括 Linux 内核(与计算机底层硬件一起工作的核心部分)。

通常这样的定义将发行版定义为 GNU/Linux。GNU 是一个递归的首字母缩写词,代表“GNU 不是 Linux”它指的是所有(或几个)开源应用,这些应用普遍与 Linux 内核捆绑在一起。这些工具包括bashcoreutilsgrepgroffgrubreadline,这里仅举几个例子。也就是说,并不是所有 Linux 内核附带的工具都是由 GNU 组织创建的。

在普通语言中,Linux 指的是围绕 Linux 内核构建的操作系统。这包括内核、预装的软件以及两者之间的一切。为了简单和与通用语言兼容,我们将 Linux 称为整个操作系统,而不仅仅是内核。

Unix 与 Linux

Linux 实际上是被称为“类 Unix”操作系统的更大的操作系统组的一部分。这些操作系统的灵感都来自于 1970 年发布的最初的 Unix 操作系统。除了 Linux 之外,它还包括几个操作系统家族:

  • MacOS(自 2015 年起)

  • Android(构建在修改后的 Linux 内核上)

  • Linux 操作系统

  • 操作系统

  • 加州大学伯克利分校软件(Berkeley Software Distribution)

  • NetBSD

看到 MacOS 和 Android 等流行的操作系统列在这里,你可能会感到惊讶。最初的 Unix 操作系统的影响是深远的。最初的 Unix 操作系统有一些至今仍然存在的关键特性,包括

  • 硬件和用户空间之间的内核

  • 所有数据存储为文件

  • 用户和权限系统

  • 至今仍在使用的目录布局(因操作系统而异)

在图 1-1 中,显示了利用 PDP-11/20 ( 设备,在实验显示系统标签的最右下方)的设置。这是 20 世纪 70 年代运行 Unix 的早期系统的一个例子。

img/494886_1_En_1_Fig1_HTML.jpg

图 1-1

PDP 11/35,PDP-11/20 的微程序后继者;设计团队由吉姆·奥洛夫林领导

基于 Unix 的标准的广泛采用产生了深远的影响。本书中涉及的许多核心命令和实用程序实际上可以在 Linux 之外的系统上运行。如果你在 Mac 甚至 Android 上打开一个终端会话,你会发现这里的许多命令都工作得很好。甚至 Windows 现在也包括一个可选的 Linux 子系统,以及它们自己的命令行系统上的各种别名,这些别名将 Linux 命令定向到它们的 Windows 等价物,例如'ls',它是 Windows 上'dir'的别名。

POSIX 标准

POSIX 代表便携式操作系统接口。它定义了脚本的标准语法和应该可用的实用程序列表。它用于保证类 Unix 系统之间的兼容性。如果一个程序或操作系统是 POSIX 兼容的,那么 bash 脚本可以在其上运行。

POSIX 还保证您可以访问一系列实用程序,其中包括catawkcutgrepkill,这里仅举几例。它还定义了指定实用程序的行为方式。以前,一些实用程序有相互竞争的实现,这给可移植性带来了问题。

选择发行版

大多数人在切换到 Linux 时面临的第一个重大决定是使用什么发行版(通常称为 distro) 。通常,人们最终会使用朋友或同事正在使用的产品,或者只是我们第一次听说的产品。有几十种流行的发行版,每一种都有它擅长的优点、缺点和特定的用例。

在这本书里,我将使用安装在 Ubuntu 和其他基于 Debian 的操作系统上的软件包管理器apt-get。也就是说,几乎所有这些都可以在任何 Linux 发行版上很好地工作;只需要找到您的发行版中有问题的包,并通过提供的包管理器安装它,手动安装它,甚至从源代码构建它。

对于许多流行的 Linux 发行版来说,这是有争议的。我个人选择使用 Ubuntu 主要归结于兼容性方面。Ubuntu 是桌面用户使用最广泛的 Linux 发行版。如果你在一家使用 Linux 的公司工作,你会发现使用那里使用的发行版很有用。尽管 bash 和 Linux 的其他方面具有可移植性,但发行版和 bug 之间还是存在差异,它们可能存在于一个发行版中,而不存在于另一个发行版中。因此,如果你在使用 Linux Mint,但其他人都在使用 Fedora,你可能会引入不必要的摩擦。

在我为 Linux 开发基于 GUI 的应用的经验中,我发现如果我在开发过程中使用一个不同于最终用户的发行版,通常会有视觉上的差异,这将极大地影响设计,或者在某些情况下只在一个发行版中出现错误。例如,最终用户系统和开发系统之间的系统字体系列或字体大小可能不同。尽管在大多数情况下,核心功能可以在大多数 Linux 系统上运行。Linux 发行版之间的高度可变性是许多游戏行业仍然没有提供对基于 Linux 的操作系统的完全支持的一个原因。

从一个流行的发行版开始的另一个好处是,当阅读在线教程和项目文档时,你经常会看到更流行的 Linux 发行版(如 Ubuntu)的说明,但对于不太流行的发行版却没有。此外,如果您确实有问题,并且您想提交一个 bug,该项目可能不会为较少使用的发行版提供支持。

也就是说,运行较少使用的发行版有很大的好处。作为一个年轻的业余爱好者,我发现运行像 Arch Linux 这样的最小发行版迫使我学习关于 Linux 发行版的组成部分以及如何使用命令行导航和修复我的系统的概念。通常,这种学习过程表现为实验、破坏系统、修复系统,在某些情况下,不得不重新安装所有东西并从头开始。

如果探索发行版和 Linux 的内部工作方式让你兴奋,我鼓励你去探索那些很少被使用并且可能更难安装的 Linux 发行版。Gentoo 甚至要求用户从代码中编译所有使用的程序。在像 Gentoo 或 Arch Linux 这样的发行版上启动和运行本身就是一项成就和一个学习过程。

除了便利性和学习过程的因素,考虑一个发行版优于另一个发行版的地方也很重要。例如,Arch Linux 对于为嵌入式或低端机器编译定制操作系统特别有用。Kali Linux 因其在渗透测试中的使用而臭名昭著。基于 Red Hat 的发行版通常用于企业服务器。如果您对渗透测试感兴趣,Kali 是显而易见的选择;如果你想成为一家企业公司的系统管理员,你可能想熟悉 Fedora。

开放源码软件的分支

在接下来的几节中,我们将看看一些更流行的 Linux 发行版。我包含了一个显示操作系统家族分支的树,让您了解不同流行操作系统之间的关系。请记住,父/子操作系统之间的关系可能会有很大不同(参见图 1-2 )。

img/494886_1_En_1_Fig2_HTML.jpg

图 1-2

Linux 发行系列

一种自由操作系统

Debian 于 1993 年首次发布,是几个流行的 Linux 发行版的主干,包括 Ubuntu、Kali 和 Linux Mint。它以拥有非常好的打包系统apt而闻名,是 Advanced Package Tool 的简称。我们将在整本书中使用apt,它可以在后面列出的所有基于 Debian 的操作系统上使用,尽管通过管理器可用的包在不同的操作系统之间会有所不同。

要用apt安装软件包,只需运行下面的命令,用<package>替换您要安装的软件包:

sudo apt-get install <package>

Note

sudo在前面的命令中是一个关键字,允许非根用户对文件或系统方面进行可能影响其他用户的更改。使用sudo时,系统会提示您输入密码,然后才能以 root 用户身份执行命令。如果您运行一个命令并得到“权限被拒绝”的消息,您可以简单地在命令前面加上sudo,它应该会工作。也就是说,在使用sudo之前,请确保您理解相关命令,因为 root 权限允许您修改对操作系统运行至关重要的系统文件。

人的本质

Ubuntu 是桌面上最流行的 Linux 发行版,尽管它通常也用于服务器。它建立在 Debian 的基础上,增加了对几个非自由软件二进制文件和编解码器的支持,改善了用户在线观看视频和玩游戏的体验。

它拥有 Debian 的许多优点,如强大的包管理器和稳定性,但也是为了提供良好的桌面体验。目前最新版本的 Ubuntu 使用的是 GNOME 界面(即操作系统的 GUI 桌面,位于底层软件之上)。

Ubuntu 有几个版本使用其他桌面用户界面,可能更适合低端硬件,比如使用xfce的 Xubuntu 和使用lxqt的 Lubuntu。这些发行版通常只是切换出了界面,而没有改变太多。如果你看一下图 1-3 ,它显示了 Linux 操作系统的堆栈,Xubuntu/Lubuntu 之间的区别在很大程度上仅仅是切换出接口层,以及交换一些预装的应用。

一个比较是,像脸书这样的网络应用通常有不同的接口来访问相同的核心功能。当使用我的手机时,我可以通过他们的网站、他们的应用,甚至是一个名为脸书 Lite 的轻量级版本访问脸书。所有这些界面看起来不同,可能有增强或限制,但最终所有的功能(发布、查看、喜欢等。)访问相同的核心功能。

img/494886_1_En_1_Fig3_HTML.jpg

图 1-3

Linux 操作系统堆栈

迦利

Kali 是一个基于 Debian 的发行版,主要关注攻击性安全工具。它包括几个用于数字取证、渗透测试和逆向工程的预装工具。它带有 600 多个预装工具,包括 Wireshark、Aircrack-ng 和 Burp Suite。这使得它对渗透测试器特别有用。也就是说,不建议日常使用。

同样值得注意的是,这些工具可以通过包管理器或者直接下载安装在其他系统上。对于包管理者来说,这个过程相当简单,但是当直接下载时,这个过程会因工具而异。例如,有些包可能是通过 Python 的包管理器 Pip 安装的,而其他包则需要您编译一个二进制文件或下载一个预编译的二进制文件,并将其放在系统可以找到可执行文件的文件夹中,例如/usr/bin。

使用 Kali 的另一个好处是,其他发行版上的软件包管理器上的工具版本可能是旧版本。由于这些包只是需要维护者打包、审查和更新的众多包中的一个,所以它们可能会落后,而在 Kali 上,与 Linux 安全相关的工具是焦点,因此需要付出更多的努力来保持它们的最新。

铸造

Mint 是另一个基于 Ubuntu 的发行版,它已经变得相对流行。Linux Mint 是基于 Ubuntu 的,但是它有一个利用 Cinnamon 桌面环境的替代界面。它和 Ubuntu 有相同的库,所以本书中的任何apt-get install命令都应该提供和 Ubuntu 相同的结果。

波波!波波

PopOS 是另一个基于 Ubuntu 的发行版,它获得了广泛的关注。它提供了一个替代 Ubuntu 的桌面体验,有相同的软件包,加上一些通过 PPAs(个人软件包档案)提供的额外的软件包。这些额外的软件包包括 Nvidia 图形驱动程序、Steam 和 Spotify 等其他流行程序。操作系统由 System76 维护,system 76 是一家总部位于科罗拉多州的计算机制造商,专注于生产高质量的硬件并重视开源软件。

一种男式软呢帽

Fedora 是由 Red Hat Linux 支持的社区驱动的操作系统。Fedora 是许多功能的试验场,这些功能最终被引入 RHEL (Red Hat Enterprise Linux),这是 Red Hat 的主要产品。对于 Fedora、RHEL 和 CentOS,使用命令安装软件包

dnf install <package>

在某些情况下,如果你使用的是 Fedora/RHEL 系统,你可以简单地用apt-get替换dnf。在其他情况下,包的名称可能会稍有不同,或者它可能不作为包提供。

RHEL(红帽企业 Linux)

虽然 Ubuntu 可能是桌面上最流行的发行版,但 RHEL 可能是企业服务器上使用最多的。它既是开源的,也是付费的产品,包含企业级的支持。如果你打算在企业环境中做系统管理员,你很可能会和 RHEL 一起工作。

重点是安全性、稳定性和速度。由于这个原因,与 Ubuntu 或 Red Hat 支持的更开放的版本 Fedora 相比,可用的包可能更少。

CentOS

虽然 Fedora 是 RHEL 的一个更具实验性和开放性的免费版本,但 CentOS 本质上与 RHEL 是相同的操作系统,但完全免费。购买 RHEL 许可证时,会附带 CentOS 不包含的支持。CentOS 为学习 RHEL 提供了一个很好的操作系统,或者不需要外部支持就可以简单地使用它。

斯拉克语

Slackware 是一个 Linux 发行版,可以追溯到 1993 年。它有一小群忠实的粉丝,但已经超过 3 年没有发行了,而以前它每年至少发行一次。

OpenSUSE

OpenSUSE 最初源自 Slackware,但它已经长出了自己的一套腿,如今几乎没有什么联系。虽然 Slackware 一直缺乏更新,但 OpenSUSE 仍然非常活跃,并拥有与 RHEL 类似的大公司支持。

拱门

Arch Linux 是 Linux 的一个分支,它是高度可定制的,专注于滚动发布包管理器。滚动发布包管理器意味着所提供的包可能是最新的。与大多数操作系统不同,没有主要版本。这是通过去掉在其他发行版的主要版本发布之前审查和确认任何变更的包维护人员来实现的。滚动发布意味着有可能获得最新版本的应用,但不利的一面是,在审核方面投入的精力较少,这可能会导致稳定性和安全性问题。

使用pacman软件包管理器安装软件包:

sudo pacman -S <package>

Arch Linux 的另一个值得注意的方面是,默认情况下,它不附带运行桌面体验所需的软件。取而代之的是由用户来选择特定的程序,比如声音、窗口管理器和图形界面。

曼哈罗

Manjaro 是 Arch Linux 的一个版本,它通过预配置的桌面体验解决了入门的困难。Ubuntu 有几种变体,比如 Xubuntu 和 Kubuntu。

巴布亚企鹅

Gentoo 是一个高度可定制的 Linux 版本,它允许定制到内核级别。Gentoo 不是下载预编译的应用,而是在本地计算机上编译源代码。当需要高度定制的体验时,它特别有用。

阿尔卑斯 Linux

Alpine Linux 是一个发行版,基本上没有人将其作为桌面或服务器的主要发行版,但它作为 Docker 容器的基础映像却非常受欢迎。如果您使用或修改 Docker 容器,您可能会遇到 Alpine Linux。它非常小,默认情况下几乎没有应用,尽管它有自己的包管理器apk

如果您有一个应用或进程想要用 Docker 进行容器化,那么可以考虑 Alpine Linux。这里的许多程序和脚本都是兼容的,尽管如果使用任何程序,你必须先用apk安装它们。

常见命令

在接下来的小节中,我们将会看到一些常见的命令,其中大部分都是默认安装在大多数 Linux 系统上的。

使用 man 命令阅读手册

我将在本书中提到许多程序。对于其中的大部分,我最多只会谈到它们的 5–10%的使用情况。如果您想更深入地研究这些程序,学习几乎所有 Linux 操作系统上都有的man命令是很重要的。

man是手动的简称。它的使用方法是运行命令并传入另一个 Linux 命令行程序的名称。例如,如果我们想获得关于命令ls的更多信息,我们可以运行以下命令:

man ls

这将返回程序的描述以及如何使用它,如图 1-4 所示。

img/494886_1_En_1_Fig4_HTML.jpg

图 1-4

手册页的示例

我鼓励你在探索 Linux 操作系统时经常使用man,因为它通常可以节省你进行冗长的互联网搜索的时间。您可以使用箭头键和 page up 或 page down 按钮来浏览手册页。

如果您需要搜索手册页来查找某个特定的关键字,有一个内置的搜索功能。要进行搜索,请按/键,然后键入您的术语并按 enter 键。如果存在,您将被带到第一个事件。若要前往下一个事件,请轻按n;每次点击n都会将你带到下一个实例。如果你想返回一个实例,按下大写N,和n一样,每按一次都返回一个实例。

编号手册页

在某些情况下,一个程序可能有多个手册页。例如,用程序stat,我们可以运行

man 1 stat

或者我们可以跑

man 2 stat

这些命令将把我们带到涉及程序不同方面的不同手册页。参见表 1-1 了解不同页码的列表及其包含的信息。并非所有程序都包含每种类型的页面。例如,printf有一个包含 C 库函数信息的第 3 页,但没有第 2 页。

表 1-1

编号手册页中的信息描述

|

页码

|

描述

|
| --- | --- |
| one | 用户命令 |
| Two | 系统调用 |
| three | c 库函数 |
| four | 设备和特殊文件 |
| five | 文件格式和约定 |
| six | 比赛 |
| seven | 多方面的 |
| eight | 系统管理工具和守护程序 |

在大多数情况下,我们会从用户命令的角度对程序感兴趣,所以我们可以只运行man而不使用默认为 1 的编号或找到的编号最小的页面。

man man
man -s 6 --regex -k '.*'

如果您想在自己的系统上看到表 1-1 中显示的列表,您可以运行“man man”。你可能想知道他们真的是游戏专用的页码吗?答案是肯定的。至少从 20 世纪 80 年代的 Unix System V 开始,游戏部分就已经包含在内了。它很少被使用,但是如果你运行下面的命令,你会得到一个在你的系统上使用它的包的列表。你可能会发现一些有趣的复活节彩蛋程序,比如“??”,这是一个安装在许多机器上的玩笑程序,声称可以读取用户的想法。

用于导航的有用命令

表 1-2 中列出了一些您想要熟悉的用于导航和创建新文件夹的命令。

表 1-2

用于导航和处理文件/目录的命令

|

命令

|

描述

|
| --- | --- |
| 限位开关(Limit Switch) | 列出目录内容 |
| 激光唱片 | 更改目录 |
| 显示当前工作目录 | 打印工作目录 |
| 创建目录 | 制作目录 |
| 是吗 | 删除目录(仅在空的情况下有效 |

用 ls 和 cd 导航文件系统

大多数用户在进入文件系统时学习的第一个命令是ls,它是“列出目录内容”的缩写,还有cd,它是“更改目录”的缩写。

只知道这两个命令就可以导航文件系统——首先通过运行ls来查看当前目录中的文件和文件夹,然后使用带有其中一个文件夹名称的cd来导航。

使用cd时要记住一点。任何时候你都可以不带任何文件夹名运行cd返回到你的主目录。如果你用cd进入一个目录,并想返回到包含你所在的目录,你可以使用..,例如:

cd ..

或者,如果您想向上返回两个文件夹:

cd ../..

你可能想用ls做的一些常见的事情是列出文件和文件夹名称之外的其他细节;这可以通过-l标志来实现:

ls -l

如果您想按最后修改时间排序,您可以使用-t标志,它最好与-l结合使用:

ls -lt

如果您想反转结果,使最旧的文件在顶部,添加-r标志进行反转:

ls -ltr

您应该得到类似于图 1-5 所示的输出。

img/494886_1_En_1_Fig5_HTML.jpg

图 1-5

运行 ls -ltr 的结果,l 表示附加信息,t 表示按修改时间排序,r 表示以相反的顺序显示结果

不可见文件(点文件)

重要的是要知道,在 Linux 中以.开头的文件在使用ls或图形文件浏览器时通常不会出现。这些文件是用于配置的,为了方便起见被隐藏起来了。我们经常想要编辑或查看这些文件,所以了解ls-a标志是很重要的。-a代表全部,将显示所有文件,包括隐藏的文件。

ls -a

用密码获取当前目录

有了所有这些导航,很容易忘记您在文件系统上的确切位置。如果发生这种情况,有一个简单的方法来确定你的确切位置。只需运行pwd即可返回您当前位置的完整路径。

pwd

制作目录

导航文件系统的一部分是创建新的目录来存放文件和子文件夹。使用mkdir命令相对容易,它接受文件夹名,并根据您的当前位置创建目录。例如,如果我们在主目录中运行以下命令:

mkdir music

我们将以一个名为“音乐”的文件夹结束。一次可以创建多少个是没有限制的。假设我们想要创建另外两个子文件夹,我们可以运行

mkdir music/rock music/classical

也可以使用完整路径而不是相对路径。例如,如果我在我的主目录中,我想在我的/tmp文件夹中创建一个新文件夹:

mkdir /tmp/test

这不是mkdir独有的;基本上所有可以使用相对路径的程序也允许你使用完整路径;它只要求路径以“/”开头。

递归创建目录

通常在创建一个文件夹时,你已经有了一个由多个目录组成的结构。例如,假设我们要创建一个名为 movies 的新文件夹,其中一个子文件夹是关于恐怖片的,另一个子文件夹是关于 2012 年的。如果我们逃跑

mkdir movies/horror/2012

我们将返回一个错误,说“没有这样的文件或目录”。标签提供了一种解决方法。-p代表创建父目录,意思是如果我们要创建的目录的父目录不存在,就会被创建。运行以下命令可以像预期的那样工作,给我们留下三个新文件夹:

mkdir -p movies/horror/2012

删除目录

创建目录后,您可能决定要删除它。一种方法是使用与mkdir类似的rmdir命令;只需将您想要删除的目录的名称传递给它:

rmdir music/classical

不幸的是,rmdir有一个主要的限制,它只能删除一个完全空的目录。试图在任何包含文件或子目录的目录上使用rmdir将返回“目录不为空”。因此,实际上许多人总是使用这个命令

rm -r music

该命令中的-r代表递归。这个命令很实用,因为不管目录是否包含任何内容,它都可以对文件和目录起作用。

使用文件

一旦你可以浏览目录,下一件你想做的事就是处理文件——创建、删除、复制文件,以及读取文件和比较它们的内容。

编辑文件

我们在上一节简单提到了nano;这是一个简单的文本编辑器,类似于大多数人熟悉的记事本。您只需通过将文件位置作为命令参数传递来打开文本文件:

nano /tmp/myFile.txt

文件将打开,如果不存在,将创建一个文件。您可以像在大多数文本编辑器上一样输入文本,按 backspace 删除文本,并使用箭头键导航。在屏幕的底部,显示了可以执行的操作列表,例如 ctrl+x 退出。

在后面的章节中,我们将会看到更强大的编辑器 Vim 和 Emacs,但是如果你发现它们很难,并且妨碍了你学习或者做你想做的事情,你总是可以求助于nano或者基于 GUI 的文本编辑器。

用于处理文件的命令

表 1-3 中列出了一些使用 Linux 的最有用和最基本的命令。这些命令在处理文件时非常方便。大多数是通过提供文件名作为参数来使用的。您可以在任何列出的命令上使用man <command>来获得额外的信息。我们将详细了解这些命令是如何工作的,其用法如下。

表 1-3

用于处理文件的命令

|

命令

|

描述

|
| --- | --- |
| 触控 | 创建文件或更新现有文件的时间戳 |
| 猫 | 输出文件的全部内容 |
| 头 | 从顶部开始返回文件的前 X 行 |
| 尾巴 | 从底部开始返回文件的前 X 行 |
| 丙酸纤维素 | 复制文件或目录 |
| 空间 | 删除文件或目录 |
| 平均变化 | 移动文件或文件夹 |
| 较少的 | 显示文件内容,同时允许轻松上下滚动 |
| 差速器 | 比较两个文件的差异 |
| 金属波纹管 | 逐字节检查两个文件是否相同 |
| 文件 | 获取有关文件类型的信息 |

使用触摸实用程序创建文件或更新时间戳

有时您希望创建一个空白文件,作为您计划以后编辑的占位符,或者可能作为一个指示器,例如,一个锁定文件。touch命令允许您快速创建一个或多个空白文件。只需运行命令并使用所需的文件名作为参数,例如:

touch notes.txt

或对于多个:

touch file1 file2 file3

touch 命令还可以用来更新文件的时间戳。运行脚本后,您可能希望用 touch 更新一个未使用的文件,以便您可以留下脚本完成时的一些痕迹。例如,您可能会更新日志文件的时间戳,尽管没有添加任何新的日志,因此其他人(人 或程序)可以推断脚本运行并且没有生成日志。这与创建文件的方式完全相同,只不过不是提供要创建的文件的路径,而是提供现有文件的路径:

touch log.txt

在对现有文件执行touch之后,您可以在该文件的目录中使用ls -l来确认时间戳已经更新。需要注意的是touch永远不会修改现有文件的内容,所以不要担心用空白文件覆盖任何现有内容。

使用 Cat 获取文件内容

使用命令行时,cat是需要知道的最有用的命令之一。cat简单地获取一个文件的内容并将它们输出到命令行。这允许您或者直观地看到该文件的内容(,而不需要打开和关闭程序),或者使用管道将该文件的内容作为其他程序的输入(,这是 bash shell 的一个方面,我们将在本书的后面部分中详细介绍)。

作为使用cat的一个例子,您可以运行以下命令,它将输出您系统上一个文件的内容:

cat /etc/passwd

这个文件列出了系统中的用户和一些相关信息,但是理解内容并不重要。这里重要的是,您可以使用cat获取系统上任何文件的内容,并将其显示为终端输出。

对头部或尾部不太满意

如果你理解了cat是做什么的,你就能很容易地理解headtail命令。当您使用cat时,会返回一个文件的全部内容。对于大文件,这意味着你可以一次得到几页内容,并把你以前的所有工作和命令推到屏幕上。

如果你想得到一个文件的预览,但不想要整个文件,你可以使用head,它将返回一个文件的前 X 行。默认情况下,X 是 10,所以如果你运行

head /etc/passwd

你应该得到文件的前十行(假设文件至少有十行)tail函数的工作方式与head完全相同,但它不是获取前 X 行,而是获取最后 X 行。因此,如果我们运行以下命令,我们将获得文件的最后十行:

tail /etc/passwd

如果您想要修改返回的行数,您可以使用-n 标志指定返回的行数,例如,如果我们想要前五行:

head -n 5 /etc/passwd

除了不要用大量文本填满屏幕之外,headtail命令在编写脚本时也很有用,如果你确切知道某个文件中需要多少行的话。例如,您可能有一个脚本想要查看日志文件中的最后 20 行,以分析文本中的某些特定错误;在这种情况下,我们可以利用tail -n 20 filename将输出通过管道传输到您的解析脚本中(稍后将详细介绍管道和脚本)。

使用 cp 复制文件

如果你正在做系统管理或软件开发,很可能你会经常使用cp命令。这是一个非常简单但非常有用的命令,代表复制。使用该命令时,第一个参数是要复制的文件,第二个参数是要复制到的位置,例如,将file1复制到位置file2将使用:

cp file1 file2

运行前面的命令会产生一个名为file2的新文件,它包含与file1相同的内容。

除了复制文件,cp还可以用来复制整个文件夹。要对文件夹使用cp,您需要指定-r 标志,它代表递归(类似于对文件夹使用 rm 命令)。因此,复制文件夹与复制文件非常相似,例如:

cp -r folder1 folder2

使用 rm 删除文件

由于目录一节中rmdir的限制,我们已经使用了rm。请注意,rm命令主要用于删除文件,这样做时,不需要包含-r标志,例如:

rm file1

用 mv 移动文件

另一个非常流行的内置命令,mv允许您将文件或目录移动到一个新的位置。它的用法与cp非常相似,除了你最终只能得到一个文件,例如,如果我们使用

mv file1 file2

我们名为file1的文件现在将被命名为file2——类似于在 Mac 或 Windows 等图形桌面操作系统上移动文件。也像我们看到的许多其他命令一样,您可以对目录使用mv,但是使用mv不需要使用特殊的标志,您可以简单地使用

mv folder1 folder2

请注意,如果文件已经存在,mv将会在没有警告的情况下覆盖该文件。例如,如果我将文件 1 移动到文件 2,但文件 2 已经存在,我的原始文件 2 将永远丢失。如果你担心发生这种情况,有一个特殊的标志-i会在覆盖任何内容之前提示你。

用更少的资源交互式查看文件内容

我们提到了使用cat是如何变得令人头疼的,因为大文件输出最终会挤满您的 shell。我们提到了headtail,它们允许你查看一小部分,但是在大多数情况下,我们希望选择查看整个文件,但是要慢慢滚动。这就是less的作用。

less不是输出文件的内容,而是打开一个独立于您终端的交互式浏览器,您可以在其中以自己的速度滚动浏览内容。与cattailhead一样,您只需将目标文件作为输入来运行命令:

less /etc/passwd

您将从文件的顶部开始,并能够使用箭头键和 page up/page down 按钮向下和向上滚动。这很像滚动手册页,你甚至可以访问相同的搜索方法 (vim 风格搜索)。也就是说,按下“/”,键入搜索词,然后按回车键。你将被带到这个术语的第一个实例,从那里你可以按n进入下一个实例,或者按N返回上一个实例(这种搜索方法也在 Vim 中使用,Vim 是一个文本编辑器,我们将在本书的后面讨论)。

Note

当你在 Linux 上探索不同的程序时,你可能会遇到more,并认为它与less相似,但又不同;毕竟命令headtail就是这种情况。more实际上是less所基于的一个更老的程序。more功能较少,不可用,例如,可以向下滚动,但不能向上滚动。很可能你会在你的系统上找到more,但是我们建议在所有可能考虑more的情况下使用less

比较文件

比较文件是一项你可能需要不时完成的任务,当然比mvcat要少得多,但尽管如此,对于软件开发来说,它是与文件相关且有用的命令。有几个程序可以用来比较文件。

默认情况下,cmpcomm安装在大多数系统上。然而,在实践中,diff更容易使用,colordiff甚至更好(与 diff 相同,但有颜色编码)。出于实用目的,建议使用diffcolordiff。在后面的章节中,我们将会看到如何别名diff来使用colordiff

为了演示比较文件,让我们转到/tmp目录并创建两个相同的文件。为此,请运行以下命令:

cd /tmp
cp /etc/passwd file1
cp file1 file2

接下来用nano或你喜欢的文本编辑器打开file2,改变一个字母;它可以是添加一个字母这样小的变化。进行更改后,保存并关闭文件。

与 Comm 命令比较

现在您有了两个几乎相同的文件,我们可以测试几个命令来比较差异。我们将尝试的第一个是comm,它可以通过传递两个文件名作为参数(最好是用于演示目的的类似文件)来运行:

comm file1 file2

这将返回文件的内容,这些内容相互重叠,具有三层深度。将用于文件中大部分行的最右侧深度是包含在两个文件中的行。然后,当您到达有差异的行时,您将有两个不同的缩进,一个用于仅file1行,另一个用于仅file2行。

它并不漂亮,但它完成了工作,可以在大多数系统上找到。尽管如前所述,我们建议安装 diff 或 colordiff。

请比较 Cmp 命令

虽然comm可以完全被diff代替,但命令cmp实际上略有不同。它不是比较文件的文本,而是逐字节比较文件。我们可以通过传递命令 2 文件名来测试程序:

cmp file1 file2

使用cmp,您将得到一行,它指定了文件之间第一个差异出现的行和字节。在您只想比较文件是否相同的脚本中,cmp可能是最快的选项,因为只要发现一个差异它就返回,而不是解析整个文件。

与 Diff 命令比较

diff命令类似于comm,但是可读性更强,并且有额外的特性和标志。默认情况下,大多数系统都不会安装它,所以您必须先安装它:

sudo apt-get install diff

安装了diff之后,我们就可以比较我们的文件了,这可以类似于commcmp来完成:

diff file1 file2

diff将只返回不同的行,而不是返回文件中的所有行。这意味着每一行都有两个不同的副本。第一个文件中的行将被加上一个<,第二个文件中的行将被加上一个>,允许您查看哪些行属于哪个文件。在这些行之前,您还会看到一个指示器,指示正在比较哪些行号。这使您能够发现不同之处,并在文本编辑器中快速找到它。

ColorDiff 甚至比 Diff 更好

comm相比,diff的主要优势是可用性,这是由于差异是如何显示的。如果你的终端支持彩色(大多数桌面终端都支持),你可能要安装colordiff来代替。colordiffdiff的一个包装器,它通过对不同之处进行颜色编码来进一步增强体验,因此您可以快速看到哪些行属于哪些文件。像diff一样,需要安装:

sudo apt-get install diff

安装colordiff后,比较两个文件,观察输出的不同:

colordiff file1 file2

获取文件类型

如果您来自 Windows,您可能习惯于这样的概念,即文件的扩展名决定了文件的类型及其运行的程序。在 Linux 上,经常使用文件扩展名,但这只是为了方便读者。文件扩展名不是强制性的,在某些情况下不使用。

你可以找到一个有名字但没有扩展名的文本文件或程序。在这种情况下,您可能会发现file命令很有用。给定一个文件作为输入,它将返回关于文件类型的信息。例如,如果我们在上一节中创建的file1上运行 file 命令,将文件位置作为参数传递,如下所示:

file file1

您应该恢复“ASCII 文本”类型如果你的电脑上有一个图像文件,试着在上面运行file。除了像 JPG 这样的图像类型之外,您还将获得像照片尺寸这样的额外元数据。

命令信息,包括类型、类型、位置或位置

与使用file获取文件信息类似,我们可以使用typewhichwhereislocate获取命令信息。第一个命令type内置于 bash 本身,它搜索您的路径并在找到时获取关于该命令的信息,例如:

type ls

在我的系统上,它返回一个别名(更多别名在后面的章节),如图 1-6 所示。

img/494886_1_En_1_Fig6_HTML.jpg

图 1-6

检查ls类型的输出

然后用which我们可以找到可执行文件的位置:

which ls

类似地,我们可以使用whereis并找到命令的可执行位置、源位置和手册页面文件。whereis命令应该返回多个文件位置,如图 1-7 所示。

img/494886_1_En_1_Fig7_HTML.jpg

图 1-7

使用whichwhereis显示程序的位置

 whereis ls

在某些情况下,您可能不记得确切的命令,所以在使用which时它不会出现;在这种情况下,您也可以尝试locate,它将搜索文件系统的数据库索引:

locate samba

定位有两个问题;首先,它可以返回大量结果,找到系统上每个文件的完整路径的文本输入的每个匹配项。例如,给定一个用户名,ubuntulocate ubuntu将返回主目录(因为每个文件都包含文件路径中的用户名)中的每个文件。第二个问题是支持locate的数据库(比用find手动搜索文件系统更快)每天只通过 cron 更新一次。如果您想手动更新它,您可以运行 sudo updatedb (运行时间可能需要几秒到几分钟,取决于系统和文件系统的大小)

更多关于须藤的信息

通常情况下,当你登录到你的操作系统时,你会得到一个用户名,它拥有特定文件夹的权限。文件夹位置通常是

/home/<username>/

通常,每个用户都有一个专用的主目录,他们对该目录拥有完全的管理权限。有时您需要使用个人文件夹之外的文件和文件夹。如果您试图做一些需要超出您的用户帐户权限的事情,您会得到一条消息说“权限被拒绝”或“您是 root 吗?”。

在这种情况下,您必须重试该命令,首先附加sudo,指定您希望作为 root 用户运行该命令。例如,该命令

cat /etc/sudoers

反而变成了

sudo cat /etc/sudoers

使用sudo时,会提示您输入密码。当然,sudo的成功依赖于你的主用户账户能够使用sudo。在/etc/sudoers中定义了用户可以使用sudo的策略。例如,在我默认安装的 Ubuntu 中,有这样一行代码

%sudo ALL=(ALL:ALL) ALL

这指定了组sudo中的所有用户都可以使用sudo。要查看用户所在的组,您可以运行

groups <username>

用你账户的用户名替换<username>,你将得到你所在的群组列表。

如果您需要连续运行多个命令,这些命令都使用了sudo,那么您可能需要切换到 root。通过这样做,您可以在没有它的情况下运行通常需要sudo的命令。要切换到 root,请运行以下命令,并在出现提示时输入您的密码:

sudo -i

现在你可以自由地运行任何你想要的命令。要返回到您的普通用户,请按ctrl+d

更少管道

当我们谈论文件类型检测时,值得一提的是 less pipe,它是许多系统上预装的命令less的文件类型预处理器。Less pipe 可让您在终端中查看通常无法在终端中访问的文件,例如 PDF 文件。

要查看是否安装了较少的管道,请运行以下命令:

echo $LESSOPEN

如果您得到一个后跟文件位置的管道,例如|/usr/local/bin/lesspipe.sh %s,那么它就安装在您的系统上。如果您发现运行该命令返回一个空字符串,那么您的系统没有lesspipe。如果是这种情况,不要担心,因为我们将在下一节介绍安装(或更新) less 管道。

更新/安装更少的管道

Ubuntu 和其他操作系统将会安装一个足够好的版本lesspipe。因此,如果您不想更改默认值,请随意跳过这一部分。

为了充分利用这里列出的所有特性,您可能需要更新 lesspipe。在我的系统 Ubuntu 18.04 上,我发现lesspipe的版本有点过时,没有给我关于最新版本中可用的照片元数据的深入细节。旧版本也可能不支持下一节中列出的所有文件格式,尽管它应该适用于 PDF 等常见格式。

首先,需要安装gitmake。Git 是一个用于编程的版本控制程序,make 用于编译源代码。在本书中,我们将使用git作为从 GitHub 下载公开可用代码的一种方式。您可以通过运行以下命令来安装它:

sudo apt-get install git

如上所述,我们还将使用make命令。make用于编译经常用 C 语言编写的程序(虽然不限于任何语言)。如果你下载了一个程序,它包含一个名为Makefile的文件,这是一个好迹象,表明这个程序可以用make编译。make utility通常与其他工具捆绑在一起,比如用于 C 和 C++的gcc编译器和公共库。要在 Ubuntu 上安装make,运行:

sudo apt-get install build-essential

安装了gitmake,我们就可以开始更新lesspipe;这个过程从下载项目代码、移入文件夹、编译代码和测试设置开始:

git clone https://github.com/wofr06/lesspipe
cd lesspipe
make
make test

运行make test后,观察结果和任何缺失的程序。例如,在我的例子中,如图 1-8 所示,我得到了各种建议安装的程序。如果不安装上述程序,您可能无法打开相关的文件类型。您可以根据自己使用的文件类型来决定要安装哪些文件,不要安装哪些文件。

img/494886_1_En_1_Fig8_HTML.jpg

图 1-8

编译lesspipe后运行make test的输出

基于来自测试脚本的反馈,安装丢失的包 ( 反馈 来自测试 s 脚本 可能因您的系统而异):

sudo apt-get install antiword unrtf rpm2cpio

如果你得到一个没有找到包的消息,你必须忽略它或者在你的操作系统包管理器上寻找正确的名字。比如我发现sxw2txt可以用名字odt2txt安装。

接下来,运行

sudo make install

这将取代你的旧版本lesspipe或安装它,如果你没有它。最后一步是打开您的~/.bashrc文件,并在底部添加以下几行:

LESSOPEN="|/usr/local/bin/lesspipe.sh %s"; export LESSOPEN

完成这些步骤后,您将充分利用 less pipe 来处理尽可能多的文件类型。

Note

.bashrc文件包含可以从命令行访问的帐户范围的配置和变量。例如,如果我们添加一行export FAVORITE_COLOR="Blue",然后打开一个新的终端,我们就可以访问该变量。例如,运行echo $FAVORITE_COLOR会将“蓝色”打印到屏幕上。一些程序允许你基于这样的变量来改变设置,例如,一个基于 GUI 的程序可能会寻找$FAVORITE_COLOR 来设置布局的颜色。这个特殊的变量并不常用,但是它演示了如何以这种方式配置程序。我们将在后面的章节中更多地讨论.bashrc,以及如何使用它来改善您的命令行体验。

定期使用较少

如前所述,less用于查看文件文本数据,允许您从顶部开始慢慢向下滚动。在打开其他文件类型之前,让我们回顾一下如何正常使用less。首先使用seq命令创建一个包含几行文本的长文件,这是序列的缩写。seq 命令将起始数字和结束数字作为参数,并返回它们之间的数字序列:

seq 1 999

这会输出 1 到 999 的数字(seq 对定制脚本或测试很有用)。现在再次运行相同的命令,但是使用特殊的>字符将输出定向到一个文件,该字符用于将文本输出定向到一个文件:

seq 1 999 > /tmp/numbers.txt

Note

当创建测试文件时,我通常会将位置设为/tmp;这个文件夹有一个特殊的属性,当你重新启动计算机时,里面的所有内容都会被删除。如果你知道你以后会删除一个文件,比如我们的numbers.txt文件,你应该在/tmp文件夹中创建它。这样,如果你忘记删除垃圾文件,你就不必担心垃圾文件到处都是。只是注意不要把任何重要的东西留在你的/tmp 文件夹中。有时候,一个开始时被扔掉的脚本可以发展成您想要保存起来以备后用的东西。

现在我们已经为测试目的创建了文件,使用less /tmp/numbers.txt打开它。这将从顶部开始打开less文件,如图 1-9 所示。您可以使用箭头键或 page down 和 page up 按钮上下滚动。按下q退出。

img/494886_1_En_1_Fig9_HTML.jpg

图 1-9

less中查看长文件

用更少的管道打开 pdf

更少的管道也使得less能够打开和读取 PDF 文件。类似于图像,运行less <filename.pdf>,你将在你的终端中得到 PDF 的文本版本。

用较少的管道打开压缩文件夹

当你安装了较少的管道时,压缩文件和文件夹可以用less打开。为了演示,创建一个包含一些文件的文件夹,并使用 tar (一个压缩和解压缩文件的常用工具)对它们进行压缩:

cd /tmp
mkdir folder
cd folder
touch file1 file2 file3
cd ..
tar -zcvf folder.tar.gz folder

运行这些命令后,您将有一个包含三个空文件的压缩文件夹。接下来我们试着用less打开它。你应该得到一个文件夹和文件的列表,包括每个文件的权限,如图 1-10 所示。

img/494886_1_En_1_Fig10_HTML.jpg

图 1-10

使用less打开压缩文件夹创建的输出

使用较少管道的图像元数据

对于下一个例子,您需要下载一个图像或者在您的系统上找到一个现有的图像。导航到包含图像的文件夹,并使用less打开它;如果你已经安装了最新版本,当你打开一个更少的图片时,你会得到详细的元数据,如图 1-11 所示。

img/494886_1_En_1_Fig11_HTML.jpg

图 1-11

使用 lesspipe 以更少的时间查看图像数据

Lesspipe 的其他文件

有各种各样的文件可以用 lesspipe 打开和查看。我们不会对所有这些进行深入探讨,但这里有一些其他的,所以你知道什么是可能的:

  • 各种压缩文件夹,包括 zip、g zip、7-zip 等等

  • Java JAR 文件

  • RAR 档案

  • RPM (Red Hat 软件包管理器文件)

  • Microsoft Word、PowerPoint 和 Excel

  • ePub 图书

  • 超文本标记语言

  • 便携文档格式

  • MP4

要获得完整和最新的列表,以及您可能需要为某个文件类型安装的任何其他配套程序,请查看位于 https://github.com/wofr06/lesspipe 的官方存储库。

Note

这里列出的一些文件类型取决于您安装了一些附加软件包的系统。如果你发现一个你想读的包不工作,回头参考运行make test的安装步骤。如果你打开的文件类型经过测试,返回“忽略”并列出要安装的软件包,你需要安装上述程序。如果文件类型显示“不正常”或显示“正常”,但仍然不起作用,您需要访问前面列出的 GitHub 页面,并检查问题选项卡,查看其他有类似问题的人(或打开您自己的问题,如果没有找到)。

使用 Cron 作业调度进程

另一个需要了解的重要工具是 cron jobs。cron 作业是在特定时间或间隔运行的脚本或进程。这对于清理日志文件夹或在设定的时间间隔备份文件是很有用的(我们将在第六章中讨论)。

首先,运行带有-e标志的 crontab,它是“edit的缩写

crontab -e

第一次运行时,会要求您选择一个编辑器。如果你不习惯命令行编辑器(我们将在后面的章节中讨论 Vim 和 Emacs),你应该选择nano,因为它最容易使用。如果您稍后决定要更改所使用的编辑器,您需要修改~/.selected_editor或删除它以恢复提示。

一旦crontab -e将你带到一个文件,转到最底部并创建如图 1-12 所示的示例作业。五个*符号中的每一个都可以用一个数字来代替,以表示它们应该何时运行。*符号表示通配符,意味着它匹配任何值。当所有 5 个值都是通配符时,意味着该命令将在每分钟、每小时、每天等等运行。图 1-12 所示的命令将每分钟使用 touch 创建或更新文件/tmp/hello的时间戳。

img/494886_1_En_1_Fig12_HTML.jpg

图 1-12

cron 作业的每个元素的标签

添加 cron 作业后,等待一两分钟,运行ls /tmp;您应该看到一个名为hello的新文件。在确认 cron 作业正常工作后,一定要删除该作业以保持系统干净。

表 1-4 包含使用各种列的 cron 计划示例,包括分钟、小时、工作日、日历日和月。

表 1-4

cron 中的时间间隔示例

|

克朗时间

|

描述

|
| --- | --- |
| * * * * * | 每一分钟 |
| 5 * * * * | 每小时的第五分钟 |
| */5 * * * * | 每 5 分钟一次 |
| 0 0 0 0 1 | 每周一午夜 |
| 0 2 1 1 * | 1 月 1 日,凌晨两点 |

摘要

在这一章中,我们学习了选择一个 Linux 发行版,使用 man 查找关于一个程序的信息,公共命令,创建脚本和文件权限。我们只是简单地触及了这些主题作为开始。随着我们的继续,我们将更深入地探讨列出的几个主题。

二、文件/文件夹导航

无论您在终端中做什么,您都希望知道自己在系统文件结构中的位置。您还想知道如何导航到其他文件夹,这些文件夹中有您可能需要处理的文件。在这一章中,我们将重申基础知识,并看看导航文件系统的其他工具和方法。

基础

终端上的任何人都应该知道的最基本的命令是列出结构的ls和改变目录的cd。输入ls将会返回你当前目录下的文件和文件夹列表,然后你可以移动到带有cd后跟目录名的目录。表 2-1 列出了一些可以和-ls一起使用的有用选项。

表 2-1

ls 的选项

|

命令

|

描述

|
| --- | --- |
| [构成动植物的古名或拉丁化的现代名] | 显示隐藏的文件和目录 |
| -颜色 | 彩色高亮输出 |
| -福 | 文件名末尾表示类型的符号 |
| [构成来自拉丁语、结尾为-us 的名词的复数] | 显示文件索引号(索引节点号 |
| -我 | 带细节的长格式 |
| 相当于-ED | 按日期时间排序 |
| 构成名词复数 | 按文件大小排序 |
| -r | 倒序 |
| -右 | 递归列出当前文件夹和子文件夹 |

虽然ls有几个常用的选项,但cd几乎从不与选项一起使用,尽管它有两个选项:-P不跟随符号链接,-L强制跟随符号链接。虽然你在使用cd时不需要选项,但有几个符号你应该知道。

导航时,有一些全局符号可用作表 2-2 所示路径的一部分。

表 2-2

目录符号

|

命令

|

描述

|
| --- | --- |
| 。 | 表示当前工作目录 |
| .. | 表示包含工作目录的文件夹 |
| ~ | 代表当前用户的主文件夹 |

当使用lscd时,这些简短的形式很方便;我们可以在文件系统的任何地方,如果我们想回到我们的主文件夹,我们可以简单地运行

cd ~

节点

我们提到过ls -i会返回一个文件索引号或者 inode 号,但是 inode 到底是什么?每次在 Linux 系统上创建文件时,都会在后台为它分配一个 inode。每个索引节点指向内存中文件所在的位置,以及与文件相关的元数据,包括文件大小、文件所有者和上次访问时间。

系统上的所有 inodes 都存储在一个表中,该表预先分配了一定数量的内存。这样做的一个有趣的副作用是,您可以在不耗尽磁盘空间的情况下耗尽文件空间。为此,您需要创建足够小的(或空的)文件来填充 inode 表,这几乎从来不会发生。要想知道可以存储多少个索引节点,可以运行

df -i

您将得到一个列表,其中包含系统中每个驱动器的一个名为IFree的列;这表示驱动器上的可用信息节点数量。在我的例子中,我有超过 650 万个空闲索引节点;因此,为了达到索引节点的最大数量,我必须创建超过 650 万个文件。

虽然可能性不大,但还是有可能的。如果您很好奇,想要模拟用完空闲的 inode,这里有一个将用完所有 inode 的 liner。在使用它之前,请确保您在/tmp文件夹中,这样如果您需要重新启动,所有文件将在下次启动时消失。

cd /tmp
mkdir test
cd test
for i in $(seq 1 7000000) ; do touch $i ; done

您需要用一个大于您的驱动器上的空闲 inodes 总数的数字来替换7000000。该命令纯粹是出于教育目的,可能需要几个小时才能完成。用完索引节点的情况非常罕见,但是在长时间运行且内存有限的系统上尤其会发生。

获取当前位置

每当你打开一个新的终端,你可能会在你的用户的主目录。因此对于用户ubuntu,您将在/home/ubuntu/中。情况并非总是如此,有时你会发现自己忘记了自己的位置。您可以通过运行以下命令找到您的当前位置

pwd

这将返回到您当前位置的完整路径。它代表“打印工作目录”

符号链接

在某些情况下,目录本身不是文件夹,而是另一个目录的快捷方式。这些被称为符号链接,或软链接。您可以通过运行以下命令为现有文件创建符号链接

ln -s original_file link_file

这将在指向original_file的工作目录中创建一个名为link_file的文件。这个新的符号链接文件本身不包含任何数据。符号链接只包含它作为别名的文件的文件系统地址。这意味着当移动或重命名别名文件时你必须小心,因为系统链接仍然指向原始位置。

当使用列表结构命令ls -l的详细版本时,你会看到一个从link_file指向实际文件位置的箭头(图 2-1 )。在这里,-l旗实际上代表“长”。

img/494886_1_En_2_Fig1_HTML.jpg

图 2-1

系统链接文件的详细信息

或者如果你使用ls -F,你会在文件末尾看到一个@符号,它是符号链接,如图 2-2 所示。

img/494886_1_En_2_Fig2_HTML.jpg

图 2-2

符号@指定系统链接

符号链接也可以应用于文件夹,使一个文件夹成为另一个文件夹的快捷方式。

硬链接

除了符号链接,还有硬链接。硬链接是指向文件的信息节点的文件克隆。删除只有一个硬链接的文件的硬链接(目录条目)也会删除该文件。多个硬链接可以指向同一个 inode,只要它们都在同一个文件系统中。删除一个或多个指向某个信息节点的硬链接不会删除该信息节点或它所指向的文件,直到所有硬链接都被删除。另一方面,符号链接只是指向原始文件的快捷方式。与符号链接不同,硬链接不能应用于文件夹,只能应用于文件。

创建硬链接类似于创建符号链接,但没有-s标志:

ln original_file link_file

使用ls -lls -F,您将无法将硬链接识别为特殊类型的文件。本质上,它是一个与原始文件平等的普通文件;改变一个就会改变另一个。这是因为两个文件都指向同一个 inode,而这个 inode 又指向文件的一个实例。这意味着不像软链接,你可以移动任何一个文件的位置而不影响链接。

如前所述,Linux 系统上的每个文件都有一个关联的 inode。通过使用ls -i,我们可以看到当前目录中每个文件的 inode。图 2-3 显示了在硬链接和原始文件上使用ls -i的示例;请注意,inode 是相同的。

img/494886_1_En_2_Fig3_HTML.jpg

图 2-3

'ls -i'的输出显示了具有相同信息节点号的两个文件

即使移动文件,inode 也保持不变。指向 inode 的目录条目从一个目录移动到另一个目录。索引节点保持不变,索引节点和属于该文件的数据的位置也保持不变。

带有 pushd 和 popd 的导航堆栈

cdls是众所周知的,但是一旦你熟悉了导航文件目录,还有一些命令可以派上用场。第一个是pushdpushd的行为类似于cd,但是它创建了一个目录堆栈,这样你以后可以很容易地返回到你当前的目录。例如,假设你在目录/tmp/中,你使用pushd ~,这将把你移动到主目录,就像cd一样,接下来做pushd /usr/local/bin。这又一次改变了你的位置,就像'cd',但是图 2-4 中返回了我们访问过的位置列表。

img/494886_1_En_2_Fig4_HTML.jpg

图 2-4

pushd 堆栈中显示的文件夹位置列表

当前目录显示在左边,堆栈目录的最下面显示在右边(在我们的例子中是/tmp)。现在,如果我们运行popd,我们将从堆栈中弹出当前目录,并向右移动一个目录,在本例中是~;然后再次运行它,我们将返回到/tmp。当你想跟踪一组要返回的目录时,这可以是一个有用的选择cd

*另一个相关的命令只是运行cd -。当您在cd后使用减号时,您实际上将导航到您之前所在的任何目录;你可以重复这几次回溯所有你访问过的目录。

看守人

我最常用的另一个 Linux 命令行程序是 Ranger。Ranger 是一个命令行程序,它使文件和目录浏览变得快速而简单,尤其是在没有基于 GUI 的目录浏览器的服务器或设备上。

通过运行以下命令安装 ranger

sudo apt-get install ranger

安装完成后,只需在要启动的目录中运行命令即可启动它:

ranger

您将得到如图 2-5 所示的三窗格视图。按向上和向下将改变您在中间窗格的选择。按右进入右侧显示的目录,按左浏览父目录。

img/494886_1_En_2_Fig5_HTML.jpg

图 2-5

使用 Ranger 导航

以这种方式航行将很快成为第二天性。受 Vim 中绑定的启发,Ranger 还提供了几个键盘快捷键。我最喜欢的包括

  • s——输入大写字母S将打开在最左侧窗格中选择的目录,该目录将在 bash 会话中打开。从那时起,如果您按 ctrl+d 或手动运行exit,您将返回到 Ranger。

  • s——输入小写字母s将在屏幕左下方打开一个小文本框,可以在其中输入 shell 命令。例如,导航到/tmp,按下s后,输入命令mkdir hello,然后按回车键。您将看到一个名为hello的新目录出现在/tmp中。

  • q-输入大写Q将退出 Ranger 并返回到命令行。

  • @–键入@符号将允许您在不离开 Ranger 的情况下输入 bash 命令,例如,您输入touch hi并按 enter,您会看到您所在的当前目录添加了一个同名的空文件。

  • ~–键入~符号将在三级目录视图和一个只关注当前视图的视图之间切换;再按一次返回。当您处理长文件夹名称或不想分心时,较大的视图非常有用。

  • o–输入小写字母o将显示当前目录中文件排序的可能方式列表,例如,按时间变化或字母顺序。

用树可视化文件结构

除了lsranger是我最常用的查看文件结构的程序。然而,另一个值得一提的是tree,它需要安装在大多数发行版上。tree也是非常轻量级的,不用像ranger那样打开一个完整的程序来探索文件结构,tree可以用来立即创建文件结构的可视化——例如,如果我导航到一个项目并运行以下命令

tree -L 2

Note

这里的两个表示深度显示了多少层(或目录);要深入了解,只需增加数量。

该命令将产生如图 2-6 所示的两个文件夹深度的文件结构的可视化。

img/494886_1_En_2_Fig6_HTML.jpg

图 2-6

使用树显示文件系统树

用 Vim 导航文件系统

我们将有一个专门的章节来用 Vim 进行编辑,但是它也有一个内置的文件/文件夹浏览器。在正常模式下打开 Vim,运行以下命令:

:Ex

这是同样有效的:Explore的简称。运行该命令将在 Vim 中打开一个文件浏览器,如图 2-7 所示,类似于 Ranger,但没有预览。

img/494886_1_En_2_Fig7_HTML.jpg

图 2-7

Vim 探索

您可以选择传递一个想要在 Vim 中使用 explore 打开的文件夹的参数,例如:

:Ex /home

这将导致浏览模式在主文件夹而不是当前工作目录中打开。您将能够使用正常的 Vim 键绑定j进行向下导航,使用k进行向上导航,或者使用箭头键进行导航。您可以在文件夹或文件上按 enter 键来打开它。

摘要

在本章中,我们探讨了与导航文件目录相关的命令。我们还查看了文件属性,如系统链接、隐藏文件和元数据,如上次修改时间。我们看到了 inodes 如何通过将文件名与元数据和磁盘空间中的底层数据相关联,在底层文件系统的工作方式中发挥关键作用。

除了查看文件系统的属性之外,我们还介绍了一些工具,使得探索文件系统变得更加容易。Ranger 和 Vim Explore 都允许我们快速浏览文件。而ls上的附加标志选项允许我们看到通常隐藏的文件属性。*

三、历史和快捷方式

在这一章中,我们将研究如何使用 shell 历史、bash 终端的内置键盘快捷键和文件 globbing。这些技巧将帮助您在输入新命令、重复以前的命令或修改部分编写的命令时动作更快。

历史

指尖上有许多有用的命令是很好的,但是有了这么多,很容易迷失方向。这就是history命令派上用场的地方。大多数 Linux 系统都应该预装了history命令。运行该命令将返回上次运行命令的列表。

默认情况下,大多数系统在删除旧的历史记录之前只会保留大约 2000 条命令。我建议增加这个数字。你可以通过修改你的~/.bashrc;搜索包含HISTSIZEHISTFILESIZE的行:

# see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=10000
HISTFILESIZE=10000

也可以将您的历史记录设置为无限制;只需声明一个空值:

HISTSIZE=
HISTFILESIZE=

为了在保存大量命令时节省空间,我喜欢打开ignorebotherasedupsignoreboth是一个由ignoredupsignorespace组合而成的简写。ignoredups选项使连续运行多次的命令只被记录一次。ignorespace选项导致以空格开头的命令不被保存到历史记录中。因此,如果出于某种原因你不想保存一个命令,只需在它前面加上一个空格。erasedups选项实际上会在你每次运行一个命令时检查你的整个历史,并删除它的任何其他实例。erasedups的一个潜在缺点是,如果您获得历史记录,然后运行多个命令,删除一个命令会改变数字,在这种情况下,您必须再次运行history来更新正确的数字,或者意外运行错误的命令。

HISTFILESIZE=10000
# don't save duplicate lines or lines starting with space
# See bash(1) for more options
HISTCONTROL=ignoreboth:erasedups

另一个值得打开的历史选项是histappend,当你使用多个终端会话时,它有助于跟踪历史。默认情况下,当终端实例关闭时,历史文件将被覆盖,而不是被追加。这将导致仅保存上次关闭会话的历史记录。您可以通过以下方式打开histappend

# append to the history file, don't overwrite it
shopt -s histappend

滚动 10000 行会花很长时间;这就是grep派上用场的地方。假设您记得使用ffmpeg来剪切视频,但是您不记得确切的标志和输入。简单地跑

history | grep ffmpeg

一旦你看到你正在寻找的命令,你可以使用左边的数字快速再次运行它。历史输出的另一个例子如图 3-1 所示。

img/494886_1_En_3_Fig1_HTML.jpg

图 3-1

命令历史

给定图 3-1 中所示的历史输出,我们可以通过输入

!2007

此工作流程将大大加快您输入命令的速度。在某些情况下,您可以通过使用!?而不是仅仅!。例如,如果我们想运行图 3-1 中的命令 2012,我们可以运行

!?vi

这样做的目的是搜索历史中包含vi的最近命令。只要字符串在命令中,它也不必引用命令的开头。因此,以下内容也会导致命令 2012 运行:

!?bash

使用前面的使用history的方法可以大大提高你输入命令的速度。但是,您必须小心,因为如果文本出现在您想要的命令之外的命令中,它将自动运行。

Bash 快捷方式

键盘快捷键在大多数程序中都很方便,bash 也是如此。您应该知道 bash shell 有大量的键盘快捷键。就我个人而言,我只使用其中的一些命令,但是我使用的那些命令非常有用。

当你第一次开始时,你可能会发现你只用一两个。你可能会慢慢地、逐渐地学习命令,一旦适应了,你可能会决定在你的常规工作流程中添加更多的命令。从这里列出的几个有用的命令开始,当你习惯了它们之后,再回来尝试合并更多的命令。

使用 bash 时最基本的快捷键是 tab 键。双击 tab 键激活自动完成功能,如图 3-2 所示。为了进行演示,请尝试编写ls命令,后跟一个空格,并在按 enter 键之前,轻按 tab 键两次。

img/494886_1_En_3_Fig2_HTML.jpg

图 3-2

双击可用于自动完成的文件夹

您应该会看到工作目录中的所有文件,如图 3-2 所示。Tab 可以以这种方式用于几乎任何以文件作为输入的命令。

Note

使用ctrl加一个字母的快捷键是基于大多数发行版的默认组合键。如果您发现这些快捷键在您的机器上不起作用,您会希望看到下一节“Emacs 与 Vim 键盘绑定”。因为默认模式可能在你的系统上不同或者已经被改变。如果你的发行版给绑定分配了一些全局行为,这些快捷方式也可能不起作用。例如,在使用 Xubuntu 时,我发现一些我最常用的 bash 键盘快捷键不起作用。我最后做了一些研究,发现了一个特定于发行版的设置面板,在那里我可以删除一些全局快捷键,这些快捷键会导致应用特定的快捷键再次激活。

除了 tab,我用的最多的键盘快捷键是ctrl+bctrl+a

ctrl+a =将文本光标移动到命令的开头

ctrl+b =将文本光标移动到命令的末尾

因此,如果你写了一个很长的命令,并在按 enter 键之前发现了一个打字错误,你可以使用ctrl+a快速返回并修复它,然后返回到使用ctrl+b时的位置。

我经常发现自己把这个和&&结合使用。这告诉 bash 只有在第一个命令成功运行之后,才在&&之后运行该命令。或者,如果您希望不管第一个命令是否成功都运行第二个命令,您可以使用单个&(例如,如果tmp.txt不存在,使用&&git add *不会运行,而使用&时会运行)。

比方说,你已经输入了命令git add *,但是你意识到你有一个你想首先删除的文件。只需按下ctrl+a将光标移动到终端输入的第一个字符,并将命令改为

rm tmp.txt && git add *

不要删除已经写好的内容,以后再重新输入,只需在开头写下先决条件命令,并用&&将其链接起来。将几个命令链接在一起并让它们都成功运行是一件令人满意的事情。我可能会这样想,因为在输入一连串命令后的那一瞬间,可能是在等待命令处理的时候倒一杯咖啡的最佳时机。

我使用的另外两个命令是ctrl+cctrl+d

ctrl+c =取消当前命令

ctrl+d =关闭当前端子

按下ctrl+d只是关闭当前的终端实例,产生与运行命令exit相同的结果。显而易见的用途是在结束时快速关闭终端窗口,但是您也可以使用它来关闭其他程序,如 tmux 或结束 ssh 会话。

你是否曾经写了一个很长的命令,然后意识到你想做一些完全不同的事情?当这种情况发生时,我们的本能是按住退格键,因为这似乎是永远的。下次试试ctrl+c,清除输入的简称。它会给你一个新的输入,而不需要执行命令。

如果您经常发现自己在运行命令clear,您会想要记下ctrl+l

ctrl+l =清除屏幕上的所有文本,在终端会话顶部留下一个新的命令行

表 3-1 列出了所有 Emacs 键盘快捷键(大多数系统的默认模式)。

表 3-1

默认(Emacs 风格)bash 键盘快捷键列表

|

顺序

|

描述

|
| --- | --- |
| ctrl+a | 转到行首 |
| ctrl+e 组合键 | 走到这条线的尽头 |
| alt+b | 将光标向后移动一个单词 |
| Ctrl+b | 将光标向后移动一个字符 |
| alt+f | 将光标向前移动一个单词 |
| ctrl+f | 将光标向前移动一个字符 |
| alt+t | 交换最后两个单词 |
| Ctrl+t | 交换最后两个字符 |
| alt+r | 如果您从历史记录中修改了命令,重置更改 |
| ctrl+k | 删除光标后的所有内容 |
| ctrl+u | 删除光标前的所有内容 |
| ctrl+w 组合键 | 删除最后一个单词 |
| ctrl+y | 粘贴删除的单词(相当于 ctrl+w 的撤消) |
| Ctrl+l | 清除过去的终端输出(与clear命令相同) |
| ctrl+z 组合键 | 后台运行进程 |

Emacs 与 Vim 键盘绑定

一个有趣的事实是,bash 键盘快捷键实际上是基于 Emacs(一个流行的开源文本编辑器)中的键绑定。许多在 bash 中工作的键绑定也可以在 Emacs 中工作。然而,可以在 bash 中启用类似 Vim 的键绑定。为此,请运行以下命令:

set -o vi

运行set -o vi将只为您当前的会话设置 Vim 键绑定;要永久启用它,您应该将它添加到您的.bashrc文件中。通过在您的.inputrc文件中添加下面一行,您可以设置 bash 甚至更多的程序同时使用 Vim 绑定:

set editing-mode vi

或者,如果您想显式地指定 Emacs 样式的绑定,您可以添加

set editing-mode emacs

.inputrc文件影响所有使用 GNU readline 库的程序的输入,这是一个流行的库,被一些实用程序使用,包括 bash 和其他操作系统,如 OpenBSD。一些使用 GNU readline 库的程序包括但不限于

  • Abiword,Amanda,Atari800,Bacula,Bareos,GNU bc,BlueZ,Cdecl,ConnMan,Freeciv,FreeRADIUS,GNU ftp,NetKit ftp,FVWM,GDB,GPG,guile,Hatari,hunspell,LFP,NetworkManager,nfss,parted,rc shell,Samba,SQLite,GNU Units,VICE,wesnoth,WPA Supplicant,Lua REPL,Python REPL,Ruby REPL …】

因此,在.inputrc中改变的任何设置都会影响它们。默认情况下,.inputrc文件并不存在,但是如果添加的话,将会影响 bash 接收输入的方式。除了在缺省 emacs 模式和 vi 模式之间改变之外,终端的其他行为也可以被修改。我们将在下一章深入探讨.inputrc

vi风格的键绑定没有一组等价的快捷键,而是模仿了分别输入和运行命令的模式。如果您正在使用vi模式并按下esc,您将切换到命令模式,在那里您可以使用一些(但不是全部)vi命令,如0前进到行首、$前进到行尾、w前进一个单词、b后退一个单词。

如果您不熟悉 Vim 或vi以及各种命令,我们建议坚持使用默认的 Emacs 键绑定,尽管 Vim 绝对值得学习,在本书中将有一章专门介绍 Vim。在阅读完它并熟悉使用 Vim 之后,您可能希望返回到 bash 设置并尝试使用vi风格的快捷方式。我使用 Vim 作为编辑器,但仍然更喜欢 bash 上的 Emacs 风格的键绑定,因为它们很简单,也是常见的默认设置。

反向搜索

上一节我们没有讨论的另一个快捷方式是ctrl+r用于反向搜索。我更喜欢使用history命令,但是许多人更喜欢使用交互式反向搜索。

按下ctrl+r后,你将进入一个交互模式,如果你开始键入一个先前写好的命令,它将显示在自动完成中,如图 3-3 所示。

img/494886_1_En_3_Fig3_HTML.jpg

图 3-3

终端中的反向搜索

一旦看到想要运行的命令,就可以按 enter 键运行它。或者,您可以按 tab 键返回到正常的 shell 模式,命令已准备好运行或修改。例如,给定前面的命令,我可以按 tab,然后按ctrl+e转到行尾,删除cups,然后编写一个不同的服务来获取状态。

如果你已经开始在反向搜索中编写一个命令,而自动完成不是你想要的,你可以按ctrl+r再返回。所以在所示的例子中,按下ctrl+r将显示历史上以sys开始的下一场比赛。

文件成组或通配符

文件 globbing 是 Linux 中的一个特性,它允许通过使用通配符来表示多个文件。最广为人知的通配符是*,它代表一个或多个任意字符。例如,运行

echo *

这将对当前目录中的所有文件运行命令echo。通配符也可以与其他字符结合使用,例如:

ls /dev/sd*

它不会返回/dev/中的所有文件,而只会返回文件夹中以“sd”开头的文件。

*不是唯一可以使用的字符,尽管它是最常用的。globbing 的另一个通配符是??字符与*相似,它可以表示任何字符,但它只是单个字符,而不是任何数量。如果我们将前面的命令修改为

ls /dev/sd?

我们现在只取回以“sd”开头并有一个额外字符的文件,而不是取回所有以“sd”开头的文件。注意图 3-4 中两者的输出差异。

img/494886_1_En_3_Fig4_HTML.jpg

图 3-4

比较*和?通配符

最后一个可以使用的字符,或者更确切地说是字符组合,是方括号[],这是一个内部经常使用字符的集合。例如,如果我们想重复前面的命令,该命令使用了?,但也包括其他驱动器,如sdbsdc(如果存在,我们可以这样做

ls /dev/sd[abc]

这将匹配单个字符,只要它是括号内指定的字符,在本例中是 a、b 或 c。

摘要

在这一章中,我们研究了 bash 历史、快捷方式和文件打包的使用。通过使用这些技术,您可以大大加快工作流程,因为您输入命令时需要写得更少。

四、脚本和管道

创建脚本

一旦您熟悉了处理文件和使用各种命令,您很快就会发现您想要组合几个命令,有时会创建较长的序列,这可能会有些耗时。我们稍后会更详细地讨论,但现在最好知道这是可能的。创建一个命令列表来一个接一个地运行,就像写一个你需要购买的东西的购物清单一样简单(一旦你知道了基本的步骤)。

你只需使用任何编辑器打开一个文本文件(前面提到过 nano,但是如果更简单的话,你甚至可以使用桌面文本编辑器)。在文本文件的第一行,你写或粘贴一个特殊的行,称为“shebang ”,表示这个文件是一个脚本(更多细节在下一节)。然后,您开始逐行列出要运行的命令。

为经常运行的命令序列创建脚本会很方便。您可以将命令保存为文本文件,然后以单步方式运行该序列。从鸟瞰图创建脚本所需的步骤如下:

  1. 创建包含命令的文本文件。

  2. 使文件的第一行成为一个 shebang(稍后解释)。

  3. 保存文件。

  4. 使用权限使文件可执行(稍后解释)。

  5. 运行命令./myScript.sh

下面是一个名为name.sh的简单脚本的例子:

#!/usr/bin/env bash

echo First name: $1
echo Last name: $2

这个脚本有两个参数,一个用于名,一个用于姓。这些参数在代码中用$1$2表示。它将通过运行以下命令来执行

./name.sh Philip Kirkbride

运行时将输出两行,第一行是“名字:Philip”,第二行是“姓氏:Kirkbride”。当然,除非您将输入换成您自己的名字,在这种情况下,这些名字将被换出。

在接下来的小节中,我们将更多地关注前面列表中的步骤 2 和 4,它们是实际运行脚本之前所需要的。

事情

shebang 指的是脚本中的第一行,当该行以#!开始时。这个词来自于音乐符号术语“升”和“??”,有时被称为“砰”;将这两者结合起来就成了“sharp-bang”或简称 shebang。

shebang 用作文件的第一行时,指定将用于解释脚本的程序。与编写 Linux 脚本相关的最流行的方法是

#!/bin/bash

同样的事情可以用/usr/bin/env来表达,它通过使用在用户路径中找到的任何 bash 版本来增加可移植性。

#!/usr/bin/env bash

shebang 并不局限于 bash 脚本。在用其他脚本语言如pythonrubyperl编写脚本时,它也应该是第一行。

#!/usr/bin/env python

文件权限

如前所述,制作可执行脚本的第四步是更改文件的权限以允许执行。最简单快捷的方法就是跑步

chmod +x name.sh

这只是为当前用户添加了文件的执行权限。运行该命令后,您只需运行以下命令就可以使用它(假设您与该文件在同一个目录中):

./name.sh

理解 Linux 上权限的概念是值得的,因为它是操作系统的一个重要方面。每个文件都有三种不同类型的权限:

  • 阅读

  • 执行

这三种权限中的每一种都可以为三个组单独设置:

  • 用户

  • 其他人

使用ls -l时,可以看到左侧表示的每个文件的设置权限,如图 4-1 所示。

img/494886_1_En_4_Fig1_HTML.jpg

图 4-1

运行 ls -l 时第一列中显示的文件的权限

Note

这个十个字母序列中的第一个字母用于表示特殊的文件类型。可能的值是 D =目录,c =字符设备,s =符号链接,p =命名管道,s =套接字,b =块设备,D =门。我们不必处理这些特殊类型,但知道第一个字母是什么是值得的。

在表示特殊文件类型的第一个字母之后,还有九个字母。我们可以将这九个字母分成三组,如图 4-2 所示——第一组是文件所有者的文件权限,第二组是用户组的文件权限,第三组是所有其他用户的文件权限。

img/494886_1_En_4_Fig2_HTML.jpg

图 4-2

文件权限的组件

对于这三个部分,我们有三个不同的字母,如果存在,则表示组具有上述权限:

  • r =读取

  • w =写

  • x =执行

在给出的例子中,我们有一个文件,它的所有者拥有所有权限,用户组拥有读和写权限,而其他可以访问该文件的用户只有读权限。

权限数据也可以显示为一组三个数字符号,其中一个数字代表权限的组合。每种权限类型都有一个数值:

  • 4 =读取

  • 2 =写入

  • 1 =执行

对于任何组,我们将权限相加,得到一个代表允许权限的数字。例如,读取和写入将为 6 (2 + 4),写入和执行将为 3 (1 + 2),无权限将为 0。

使用这种符号,我们将把rxw rw- r--表示为764。更改文件权限时,可以使用这两种表示法中的任何一种。例如,我们可以跑步

chmod 777 numbers.sh

这将所有权限授予所有用户。或者,如果我们想使用带字母的符号,我们可以运行下面的命令来取消所有组的执行权限(注意-;如果要加的话,应该是 +):

chmod -x numbers.sh

如果我们希望对特定的列(用户、组或其他)使用数字表示法,我们可以首先指定组,例如,添加回执行权限,但仅限于所有者:

chmod u+x numbers.sh

文件类型

虽然我们已经使用文件类型.sh定义了我们的脚本,但这在 Linux 中实际上并不是必需的。我们可以很容易地将它命名为name而不是name.sh,它的工作方式也是一样的。

Note

一些团队更喜欢没有“.sh”扩展名的脚本,例如,Google Shell 风格指南实际上指定了不应该使用扩展名.sh。尽管如此,谷歌管理的几个公共存储库包含了包含.sh的 shell 脚本。这只是表明,即使在一个声明偏好的公司,你也不能确定脚本是否会包含.sh扩展。

检测文件类型的一个有用命令是file。为了进行试验,首先将文件名name.sh改为name。接下来运行以下命令:

file name

您应该得到一条消息,说明文件类型是 Bourne-Again shell 脚本。接下来,尝试打开文件,将 shebang 编辑成 python 的 shebang,如 she bang 部分所列。

#!/usr/bin/env python

保存后,再次尝试运行file。重复这个过程,尝试不同的 shebangs,包括 python、ruby 和 perl。您应该会得到类似于图 4-3 所示的结果。

img/494886_1_En_4_Fig3_HTML.jpg

图 4-3

通过编辑菜单更改文件类型的结果

管道

管道是基本语法最常见的特性之一。如果你对它们很熟悉,可以跳过这一部分。管道只是将一个命令的输出作为输入连接到另一个命令。我们将用一个有趣的例子来演示这个概念。

开始安装fortunecowsay:

sudo apt-get install fortune-mod cowsay

Fortune 是一个完整的小命令行程序,其历史可以追溯到 20 世纪 90 年代早期的 Linux 版本 7。它只是生成一个随机的引用,例如,在我的电脑上运行该命令现在返回

“你永远不知道你有多少朋友,直到你在海滩上租了一所房子。”

自己跑几次fortune试试吧。每次运行时,都会从一个长列表中随机输出一个报价。现在为了好玩,让我们将输出通过管道传输到cowsay:

fortune | cowsay

现在我们在图 4-4 所示的一小段文字艺术中找回一份随机的财富。

img/494886_1_En_4_Fig4_HTML.jpg

图 4-4

给考赛输送财富

由于产生的财富来自随机列表,您看到的应该与图 4-4 中的不同。这里发生的事情是,fortune 代码的输出被用作cowsay命令的输入。接收命令完全不知道生成所述文本的过程。

例如,我们可以用一个简单的echo替换我们的fortune命令:

echo hello world | cowsay

在这种情况下,如你所料,奶牛会说“你好,世界”。可以使用的管道数量没有限制。在将文本发送给 cow say 之前,我们可以在两个命令之间使用另一个管道来进一步处理我们的文本:

echo hello world | rev | cowsay

在这种情况下,我们的“hello world”文本在到达cowsay命令之前被反转为“dlrow olleh”。在下一节中,我们将更多地研究如何使用多个管道。

多管道

在本书中,除了简单地探索命令行程序之外,我们还将编写 bash 脚本。随着您开始编写更多的 bash 脚本,您会经常发现您需要使用 pipe,不是一次而是多次。

对于用管道将命令行程序串在一起的复杂脚本,您会发现您的脚本开始看起来有点乱。最有用的格式化技术之一是多行管道。这只是当你使用\将一系列管道分成多条线时。

如果您的命令管道可以很好地放在一行中,如下所示,您就不需要担心将它分散在多行中:

# All fits on one line
command1 | command2

但是,如果您在一个链中使用多个命令,并且它超出了一行或看起来难以阅读,请将它分散到多行,如下所示:

# Long commands
command1 \
  | command2 \
  | command3 \
  | command4 \

前面的例子来自 Google Shell Style Guide,这是一个很好的资源,提供了让 Shell 脚本更具可读性的技巧。一些指导原则与公司的内部偏好有关(例如,使用两个空格而不是制表符),而其他提示通常适用于所有 shell 脚本。

一旦您对编写 shell 脚本变得更加熟悉,并且发现您经常这样做,那么您应该看看 Google Style 脚本风格指南。它将帮助您考虑使您的脚本对可能遇到您的脚本的其他开发人员或系统管理员更具可读性的因素。

https://google.github.io/styleguide/shell.xml

用&&和||链接命令

在这一节中,我们将讨论 bash 中内置的一些可以派上用场的逻辑语法——具体来说,可以用作 AND 的&&和可以用作 OR 的||

&& the operator for "and"
|| the operator for "or"

当您需要使用一个长时间运行的命令后跟另一个命令时,这非常有用。例如,假设你连接到一个互联网连接缓慢的物联网设备,你需要更新系统,一旦完成,安装一个新程序。你可以简单地跑

sudo apt-get update \
  && sudo apt-get install -y program-x

注意使用的-y标志;这告诉 apt-get 在被要求确认时回答 yes。

这在与tmux(一个用于在终端实例之间快速切换的程序,我们将在后面的章节中深入探讨)结合使用时非常有用。在之前的一份工作中,我经常发现自己在现场不得不 SSH 到五到十个不同的物联网设备。将多个命令串在一起,我可以给一个设备足够的工作,让它忙碌 15 分钟,然后立即切换到已经通过 SSH 连接到另一个设备的另一个 tmux 会话,并立即开始工作。

当您知道需要运行第二个命令时,or 运算符||同样有用,但只有在第一个命令失败的情况下。例如,假设我们的物联网设备有一个常见问题,如果一个命令失败,我们可能会用完磁盘空间;在上述情况下,我们希望删除所有日志:

sudo apt-get install -y program-x \
  || sudo rm -rf /var/log/*

&和||的退出代码

应注意的是,是否触发||&&取决于其之前命令的退出代码。仅仅输出标准误差是不够的。例如,让我们在/tmp/err.sh写一个如下的文件:

#!/usr/bin/env bash
>&2 echo Error

chmod +x /tmp/err.sh使文件可执行,然后用如下的||语句运行命令:

/tmp/err.sh || echo error

注意,您得到了标准的错误文本,但是echo error命令从未运行过。这是因为我们的程序仍然返回一个退出代码 0。我们可以通过在脚本底部添加以下内容来查看退出代码:

echo $?

现在,当运行脚本时,您应该会看到一个额外的“0”输出。如果你想改变退出命令,你可以使用exit命令。在我们脚本的底部,添加

exit 1

现在,如果我们用我们的||语句再次运行脚本,我们将看到echo error命令触发。这里我们不局限于退出代码 1,数字 0-255 都是有效的退出代码。退出代码 0 表示执行成功,而代码 1–255 表示错误。其中一些退出代码通常用于特定的错误;其他的留给程序特定的错误。标准错误代码编号及其含义见表 4-1 。

表 4-1

退出代码的标准含义

|

密码

|   |
| --- | --- |
| Zero | 默认情况下,命令运行没有问题 |
| one | 所有非特定错误的总称 |
| One hundred and twenty-six | 调用的命令不可执行 |
| One hundred and twenty-seven | 找不到命令 |
| One hundred and twenty-eight | 退出的参数无效 |
| 128+n | 致命错误信号“n” |
| One hundred and thirty | 按 ctrl+c 结束脚本 |
| 255* | 退出状态超出范围 |

如您所见,即使有这些保留的误差范围,也有足够的空间让您定义自己的定制误差。如果您的脚本有多种可能失败的方式,并且您想要一种以编程方式检测这些特殊情况的方法,那么这将非常有用。

将&&与||一起使用

对于更复杂的用例,您还可以将操作符混合在一起。比方说,我们想使用grep检查一个字符串是否在文本文件中,然后将单词“true”或“false”传递给cowsay程序。在这种情况下,我们需要引入括号的用法:

( grep -q dog /tmp/test && echo true || echo false ) \
  | cowsay

类似于在 math 中使用括号,括号内的语句将被求值并通过管道传递给 cowsay,如图 4-5 所示。如果文件/tmp/test存在,并且包含单词 dog,我们应该看到如下内容:

img/494886_1_En_4_Fig5_HTML.jpg

图 4-5

根据一个条件说对或错

当然会返回 false,因为文件/tmp/test不存在。尝试创建包含“狗”的文本文件。您可以使用命令快速完成这项工作

echo dog > /tmp/test

一旦运行了这个命令,运行前一个命令应该会返回true。这里使用的>符号是一个重定向,我们将在下一节中更仔细地研究它。

重新寄送

正如我们在上一节中看到的,我们可以使用>字符将文本发送到一个文件中,而不是通过管道发送到另一个程序中。这可以通过任何程序的输出来完成。使用标准重定向时,您应该知道该文件中的任何现有内容都将被覆盖。运转

echo dog > /tmp/test
echo cat > /tmp/test

将导致/tmp/test只包含文本“cat”。如果您想在文件中添加文本而不是替换内容,您应该使用>>:

echo dog >> /tmp/test
echo cat >> /tmp/test

这将产生一个包含两行的文件,一行是“狗”,一行是“猫”。

默认情况下,重定向中的输出包含输出和任何错误。相反,我们可以通过添加

echo cat > /tmp/test 2> /tmp/error

但是,在前面的示例中,没有创建任何错误。要在单个命令中生成标准输出和标准错误,请在现有文件和不存在的文件上使用ls:

ls /tmp/test /tmp/nope777 > /tmp/test 2> /tmp/error

运行前面的命令后,您应该在/tmp/test文件和/tmp/error中都有内容。和普通的重定向一样,我们可以使用>>来追加而不是替换文本:

ls /tmp/test /tmp/nope777 >> /tmp/test 2>> /tmp/error

如果多次运行前面的命令,每次运行时,每个文件中都会有几行。

用三通立即重新定向和输送

将输出重定向到文件和管道都是强大的工具,但是如果您想同时做这两项工作呢?一个名为tee的流行实用程序就是为此而存在的。它复制输入并将其发送到文件和输出,如图 4-6 所示。

img/494886_1_En_4_Fig6_HTML.jpg

图 4-6

tee 命令的输出图

tee命令从标准输出中获取输出,将其保存到您选择的文件中,然后将该输出传递给它自己的标准输出。例如,假设我们有以下命令,使用重定向将输出“hello”写入一个名为greeting的文件:

echo hello > greeting

运行前面的命令,我们将在我们的greeting文件中以“hello”结束,但是在我们的标准输出中将看不到任何内容。为使用tee而修改的相同程序应该是

echo hello | tee greeting

对于tee,我们将在greeting文件中以“hello”结束,但是我们在标准输出中也会看到“hello”。如果您想让tee>>一样追加到文件中,而不是像>那样替换文本,您可以使用-a标志。

另一个使用 tee 的例子,假设我们想将一个数学方程传递给数学实用程序bc进行处理。我们将把结果输出到一个名为math的文件中,但是我们也想显示得出结果的等式。我们可以使用下面的命令来利用tee:

echo "7 * 7" | tee math.txt | bc >> math.txt

这导致文件math.txt被写入两次。一次使用三通和输入,第二次通过''。文件math.txt应该包含:

7 * 7
49

xargs

虽然在多个文件上运行命令时通配符有利于文件扩展,但有时您可能希望在另一个命令的每一行输出上运行一个命令。为此我们可以用xargs来演示;我们将使用一个可以通过通配符轻松完成的命令:

ls | xargs cat

前面的命令与cat *的输出相同;它输出当前目录中每个文件的内容。区别在于如何做。我们没有扩展通配符并将每个文件传递到一个单独的cat命令中,而是从ls命令中取出每一行输出,并将其用作每一行单独的cat命令的输入。

使用xargs允许你做用通配符不可能做的事情。例如,假设我想删除某一类型的所有文件。我将使用的一个例子是.swp文件;这些是文本编辑器 Vim 的恢复文件。在我的例子中,它们不包含任何有用的数据,而是由于突然退出程序而留下的(例如,在没有关闭编辑器的情况下关闭终端窗口)。我可以通过运行以下命令在我的主目录上运行查找和删除

find ~/ -name "*.swp" | xargs rm

这将获取由find返回的每个结果,并对其运行rm。我在命令前后跑了find,演示所有的.swp文件都被删除了,如图 4-7 所示。

img/494886_1_En_4_Fig7_HTML.jpg

图 4-7

使用find搜索 swp 文件的结果

Bash 中的条件表达式

当您开始通过命令行使用&&||组合程序的几个组件时,您可能会发现编写专用脚本比从命令行手动输入一长串命令更容易。当您从命令行转向编写脚本时,使用一些更复杂的语法工具会更容易。

其中一个工具是 if 语句,它更像是一系列可能的测试,每个测试都有自己特定的选项。例如,如果我们想检查一个文件是否存在,我们可以使用-e选项。创建一个脚本并添加以下内容:

if [ -e /etc/passwd ]; then
  echo passwd exists
fi

当您运行脚本时,您应该得到输出“passwd exists”。尝试将/etc/passwd更改为不存在的文件。或者如果您想测试该文件是否不存在,您可以添加一个!,如下所示:

if [ ! -e /etc/passwd ]; then

与其他语言一样,我们可以在 if 语句中添加一个else:

if [ -e /etc/passwd ]; then
  echo passwd exists
else
  touch /etc/passwd
fi

前面的语法适用于几种不同的可能的测试,这些测试可以通过替换-e来运行。列表很长,可以通过运行man bash并向下滚动到条件表达式部分找到。表 4-2 中显示了一些更常用的标志。

表 4-2

条件表达式选项

|

密码

|   |
| --- | --- |
| -d | 如果存在并且是目录,则为 True |
| -f | 如果存在并且是常规文件,则为 True |
| -e | 如果存在,则为真 |
| 构成名词复数 | 如果文件存在并且大小大于 0,则为 True |
| [加在以-u 结尾的法语词源的名词之后构成复数] | 如果存在并且是可执行文件,则为 True |

是一个带有-d 的目录

-d标志可用于确认文件存在并且是一个目录。如果您想使用一个目录,但不确定它是否存在,或者如果它存在,它是一个目录而不是一个文件,这将非常有用。这里显示了一个使用-d的例子:

mkdir /tmp/test
if [ -d /tmp/test ]; then
  rmdir /tmp/test
fi

是一个带有-f 的普通文件

标志-f类似于-d,但是告诉我们一个文件是否是一个常规文件,而不是一个目录。同样,这可以在使用文件之前使用,以确保它存在并且是正确的类型。这里显示了一个-e的例子:

touch /tmp/test
if [ -f /tmp/test ]; then
  rm /tmp/test
fi

用-e 检查文件是否存在

-e-f-d的一种组合,因为它只测试文件是否存在,而不考虑文件的类型。这里显示了一个使用-e的例子:

touch /tmp/test
if [ -e /tmp/test ]; then
  rm -rf /tmp/test
fi

使用-s 检查是否存在以及大小是否大于 0

如果您正在处理一个文件的内容,您可能还想知道这个文件中是否有内容。在这种情况下,您可以使用-s,只有当文件存在并且大小大于 0 时,它才会返回 true。这里显示了一个使用-s的例子:

touch /tmp/test
if [ -s /tmp/test ]; then
  echo “doesn’t run”
fi
echo data > /tmp/test
if [ -s /tmp/test ]; then
  echo “does run”
fi

使用-x 检查是否存在以及是否是可执行文件

如果您对文件的使用实际上是将其作为程序执行,您可能希望在执行之前确认该文件是否存在。这就是-x派上用场的地方,它检查文件的文件权限以确认它是可执行的。尽管请记住,这只是检查文件权限以确认文件是可执行的,但它实际上并不检查文件是否包含脚本。在下面的例子中,我们的可执行文件实际上只是一个空白文件,然而在运行了chmod +x /tmp/executable之后,-x标志将它识别为可执行文件:

touch /tmp/executable
if [ -x /tmp/executable ]; then
  echo “doesn’t run”
fi
chmod +x /tmp/executable
if [ -x /tmp/executable ]; then
  echo “does run”
  bash /tmp/executable
fi

也可以使用类似的语法来比较字符串。用于比较字符串的标志列表如表 4-3 所示。

表 4-3

字符串比较条件

|

密码

|   |
| --- | --- |
| -z S1 | 如果 S1 是长度为 0 的字符串,则为 True |
| S1 北部 | 如果 S1 是长度大于 0 的字符串,则为 True |
| S1 == S2 | 如果 S1 和 S2 是同一字符串,则为 True |
| S1!= S2 | 如果 S1 和 S2 不是一个字符串,则为真 |
| S1 < S2 | 如果 S1 排在 S2 之前,则为真 |
| S1 > S2 | 如果 S2 排在 S1 之前,则为真 |

检查值是长度为 0 的字符串,带有-z

在编程或编写脚本时,一个未设置的或空的变量通常会带来麻烦。Bash 提供了一种使用-z标志检查变量是否为空的方法。这里显示了一个示例:

S1=""
if [ -z $S1 ]; then
  echo "is empty string"
  S1=”something”
else
  echo "not empty"
fi

检查值是带有-n 的非空字符串

如果不是检查空值,而是想检查值是否不为空,可以使用-n。它本质上与-z相反,对于任何非空字符串都将返回 true。下面是一个例子,其中我们只在变量$S1不为空时才使用它:

S1="something"
if [ -n $S1 ]; then
  echo $S1
else
  echo "variable is empty"
fi

检查字符串是否相等

像许多编程语言一样,bash 也提供了检查字符串是否相等的方法。这可以用双等号==来完成。一个简单的例子如下:

S1="something"
S2="something"
if [ $S1 == $S2 ]; then
  echo "same"
else
  echo "not the same"
fi

检查字符串是否不相等

正如您所料,我们可以通过使用!=以类似的方式测试字符串是否相等。下面是一个示例,它将返回文本“same”:

S1="something"
S2="something"
if [ $S1 != $S2 ]; then
  echo "not the same"
else
  echo "same"
fi

检查字符串排序顺序

在处理字符串时,我们也可以使用><符号进行比较。第一次看到这些,你可能会认为它们比较的是数值或者哪个字符串更长。实际上,字符串使用的大于号和小于号检查排序顺序。

默认情况下,这是按字母顺序。为了演示排序,我们可以运行以下命令;请随意用数字或符号替换字母:

letters='a y b v b c'
echo "$letters" | tr ' ' '\n' | sort | tr '\n' ' '

运行前面的命令应该会返回“a b b c v y”。您可以忽略tr命令,它只是将空格转换成换行符,并在排序后用空格替换换行符。您可以尝试使用前面的命令来了解事情是如何排序的。

该排序顺序用于><符号。在下面,我们有一个使用<的例子:

S1="a"
S2="b"
if [ $S1 < $S2 ]; then
  echo $S1 sorts before $S2
else
  echo $S2 sorts before $S1
fi

除了测试文件和字符串,还支持测试整数。表 4-4 概述了比较整数的几种方法。注意在表 4-4 中,N1 和 N2 是可以包含任何整数的变量。

表 4-4

算术运算符

|

密码

|   |
| --- | --- |
| N1-情商 N2 | 如果 N1 等于 N2,则为真 |
| n1-N2 | 如果 N1 不等于 N2,则为真 |
| N1-N2 中尉 | 如果 N1 小于 N2,则为真 |
| N1 勒 N2 | 如果 N1 小于或等于 N2,则为 True |
| N1 -gt N2 | 如果 N1 比 N2 更伟大 |
| N1-葛 N2 | 如果 N1 大于或等于 N2,则为真 |

检查数字是否相等

在比较数字时,有一套完全不同的标志可以使用。其中之一是-eq标志,它检查两个数字是否相等。-eq的使用示例如下:它应该返回“1 和 1 相等”:

N1=1
N2=1
if [ $S1 -eq $S2 ]; then
  echo $N1 and $N2 are equal
else
  echo $N1 and $N2 are not equal
fi

检查数字是否不相等

为了检查数字是否不相等,使用-ne标志。这和-eq本质上是一样的但是相反。使用-ne的例子如下:它应该返回“1 和 2 不相等”:

N1=1
N2=2
if [ $S1 -ne $S2 ]; then
  echo $N1 and $N2 are not equal
else
  echo $N1 and $N2 are equal
fi

检查数字是否小于

我们还可以使用一个标志来检查一个数字是否小于另一个数字。使用-lt的例子如下:它应该返回“1 小于 2”:

N1=1
N2=2
if [ $S1 -lt $S2 ]; then
  echo $N1 is less than $N2
else
  echo $N1 is not less than $N2
fi

检查数字是否小于或等于

标志-le-lt几乎相同,唯一的例外是,如果数字彼此相等,它也返回 true。下面显示了一个例子,其中相等的数字触发 true,尽管如果$N1小于$S2,它也会触发 true。运行代码应返回“2 小于或等于 2”:

N1=2
N2=2
if [ $S1 -le $S2 ]; then
  echo $N1 is less than or equal to $N2
else
  echo $N1 is not less than or equal to $N2
fi

检查数字是否大于

每当您有能力检查一个数是否小于时,您很可能也有能力检查它是否大于。bash 就是这种情况,您可以使用-gt标志来检查一个数字是否大于。下面是一个使用-gt标志的例子。以下应返回“3 大于 2”:

N1=3
N2=2
if [ $S1 -gt $S2 ]; then
  echo $N1 is greater than $N2
else
  echo $N1 is not greater than $N2
fi

检查数字是否大于或等于

如果你想匹配大于或等于,你可以使用-ge。其用法示例如下。运行以下代码应返回“3 大于或等于 3”:

N1=3
N2=3
if [ $S1 -ge $S2 ]; then
  echo $N1 is greater than or equal to $N2
else
  echo $N1 is not greater than or equal to $N2
fi

虽然前面的代码很方便,但是还有一些使用双括号的算术表达式的语法,我们将在下一节中讨论。

带双括号的算术

虽然在 bash 中使用方括号括起来的测试比较整数是可能的,但是最好使用双括号,它允许使用任何使用另一种语言编程的人都熟悉的语法,例如:

if ((2 < 3)); then
  echo 3 is greater than 2
fi

在前面的代码中,恰好((2 < 3))的计算结果为 true。我们在这里使用硬数字,但在大多数情况下,你会比较变量,可以用在他们的地方。

((N1 < N2))

如果你想用数学来设置一个变量,你还需要使用双括号,前面加一个美元符号,例如:

N1=$((1+1))
if ((N1<3)); then
  echo 3 is greater than $N1
fi

无论您是否将结果设置为变量,无论何时您想要使用结果,都需要使用$,即使我们只是想要echo结果:

echo $((1+3))

请注意,如果您尝试使用不带双括号的算术,它会将数字附加为字符串,例如:

N1=2
N1+=1
echo $N1

前面的代码返回“21”,而

N1=2
((N1+=1))
echo $N1

将返回 3。

带括号的子 Shell

我们已经看到了双括号的作用,但是单括号呢?当代码放在括号内时,它作为一个子 shell 运行。复制当前的 shell 运行时并创建一个新的。这样做的效果是,子 Shell 中发生的任何事情都不会影响 Shell,例如:

S=Hi
(
  echo $S
  S=Hello
  echo $S
)
echo $S

在前面的脚本中,我们创建了一个变量S。然后我们打开一个 subshell 并echo这个值;注意,subshell 可以看到创建时就存在的S变量的值。然后我们在 subshell 中改变S的值。

在 subshell 的外面,我们再次echo这个值。该值仍然是“Hi”而不是“Hello ”,因为更改是在 subshell 内部进行的。

子 shell 本身又可以产生自己的子 shell,作为子进程。

用花括号展开

bash 内置的另一个符号是花括号{}。花括号可以用于列表的 Shell 扩展。例如

echo {1..100}

将扩展为 1 到 100 之间的所有数字。

img/494886_1_En_4_Fig8_HTML.jpg

图 4-8

使用扩展回显 1 到 100

我们还可以指定增量。例如,如果我们想每次增加 2,我们可以这样做

echo {1..100..2}

现在我们将只得到奇数( 1,3,5 等)。)。同样的技术可以应用于字母和数字。

echo {a..z..2}

前面的代码将返回所有奇数字母( a,c,e 等)。)。

我们甚至可以把这两个结合起来,比如说我们想要每个字母的两个版本:

echo {a..c}{1..2}

这将返回一个包含( a1 a2 b1 b2 c1 c2 )的小集合,尽管我们可以根据自己的喜好将它变得复杂和长。例如,假设我们想要打印总共五位数的二进制数的所有组合:

echo {0..1}{0..1}{0..1}{0..1}{0..1}

另一个用例,假设我们想在/tmp中创建一个文件列表:

touch /tmp/{file1,file2,file3}

或者更好:

touch /tmp/file{1..3}

这两个命令都将在/tmp目录中生成三个文件。

Bash 中的循环

像其他语言一样,bash 也提供了一种对一组项目进行循环的方法。例如,给定一组姓名,我们可以为每个姓名打印“hello ”:

for name in jesse james jen
do
  echo "Hello $name"
done

这对于我们在上一节中看到的扩展非常有用,例如:

for i in {1..100}
do
  echo "Hello $i"
done

我们也可以用一个i++语句做一个传统风格的循环,你可能在其他语言中见过:

for ((i=1;i<=100;i++));
do
  echo "Hello $i"
done

也有可能形成无限循环:

for (( ; ; ))
do
  echo "Hello [CTRL+C to stop]"
done

在某些情况下,您可能希望尽早脱离循环。

for i in {1..100}
do
  if((i==10))
  then
    break
  fi
  echo "Hello $i"
done

在前面的例子中,第 1–9 次运行,但是在第 10 次运行之前,我们点击了break关键字来提前停止循环。或者,我们可以使用continue关键字来结束当前的迭代,而不退出循环。作为一个例子,我们将使continue在所有偶数上触发。注意 if 行的空格,因为缺少空格会导致脚本无法正常运行。

for i in {1..100}
do
  if [ $((i%2)) -eq 0 ];
  then
    continue
  fi
  echo "Hello $i"
done

前面的脚本将对数字 1 到 100 运行循环,但是任何被发现是偶数的数字将提前退出循环,为下一个数字让路。这是因为在i为偶数的迭代中,会读取continue关键字,导致迭代提前结束。

也可以使用数组作为循环的数据提供者。数组是使用 bash 定义的,如下所示:

array=( 1 39 47 )

然后,要使用该数组,需要使用花括号对其进行扩展:

for i in ${array[@]}
do
  echo "Hello $i"
done

虽然我们在这里使用了整数,但是您也可以在数组中使用字符串或其他数据类型。

While 循环

在某些情况下,使用while循环可能比使用for循环更好。您可能希望根据与迭代次数无关的值来结束循环,而不是设定迭代次数。例如,假设我们想知道在 7 秒钟内我们可以循环多少次代码。

Note

对于下面的例子,您需要将代码放入一个脚本文件,并运行chmod +x来添加执行权限。这是因为我们使用了特殊变量$SECONDS$SECONDS变量包含终端,或者在我们的例子中,脚本,已经运行的秒数。

#!/usr/bin/env bash

i=0
while [ $SECONDS -lt 7 ]; do
  i=$((i+1))
done

echo $i

执行该脚本将返回循环在 7 秒内能够运行的次数。你可能会惊讶于这个数字有多高。在我的例子中,循环运行了 927375 次。

while 循环允许我们像 for 循环一样,在没有特定数字的情况下限制代码段的运行。虽然我们使用了时间的例子,但是你也可以使用一些外部值。例如,如果一个网站关闭了,你可能需要每隔几分钟检查一次,直到它恢复。

working=false
while [ $working == false ]; do
  curl google.com && working=true
  echo $working
  sleep 60
done

前面的脚本可能只运行一次,因为我们正在检查 www.google.com 。如果你想知道当一个网站关闭时它是如何工作的,试着把这个网站切换到一个不存在的网站(因此总是会失败)。

while 循环也使得无限循环变得特别容易。要使一个循环永远运行,只需使检查值true如下所示。下面是一个脚本示例,它会每分钟说一次“hello ”,直到关闭:

while [ true ]; do
  echo "hello"
  sleep 60
done

直到循环

until 循环与 while 循环几乎相同,只是我们不是检查值是否为真,而是检查值是否为假。请注意,下面的脚本与我们的 while 循环几乎相同,但我们不是在 while false 时运行,而是一直运行到 true:

working=false
until [ $working == true ]; do
  curl google.com && working=true
  echo $working
  sleep 60
done

Bash 中的引用

bash 中的引号可以用来防止特殊字符被解释,而是被解释为它们的文字值。例如,我们echo以下符号,如果没有引号,这些符号会导致错误:

echo '$ & * ; |.'

通过用引号将这些特殊字符括起来,我们使它们具有了字面意义。

双引号类似于单引号,但是仍然允许处理美元符号、反引号和反斜线。在下面的示例中,双引号中的变量将被扩展,而单引号中的变量不会被扩展:

greeting=hello

echo '$greeting world'
echo "$greeting world"

另一个例子是如何解释空格;考虑以下两个命令:

touch hello world
touch “hello world”

由于空格是 bash 中的默认分隔符,第一个命令会将输入作为两个独立的参数处理,而使用引号的命令会将输入视为一个文件名。

使用反斜杠的命令替换

反引号与单引号和双引号完全不同。反勾号不会阻止对特殊字符的解释,而是会导致在求值之前对包含的文本进行解释。

为了演示,我们将使用下面的命令,该命令将一个加法语句传送到bc中,以生成一个数字:

echo 5 + 5 | bc

前面的代码将输出数字 10。现在,假设我们想在一个更大的命令中使用这个命令。例如,我们将使用该命令的结果作为要创建的文件的名称。

touch /tmp/`echo 5 + 5 | bc`

在前面的示例中,反勾号中的命令将首先被解释。一旦反斜线被解释,该命令将作为

touch /tmp/10

当您有一个生成文件名或脚本其他方面的动态过程时,这可能会很有用。

定义函数

如果您正在编写一个脚本,您可能希望将一个代码块定义为一个可重用的函数。当您在整个脚本中的多个地方使用同一段代码时,这是非常有用的。通过将一些功能包装成一个命名函数,您可以避免重写相同的代码,如果您决定更改所使用的代码,也可以避免在多个位置进行更新。

在 bash 中创建函数相当容易。我们将创建一个非常简单的例子。首先,我们将创建一个名为greet的函数,它将一个名字作为输入,输出“hello”和这个名字。

greet() {
  echo hello $1
}

定义了前面的代码后,我们现在可以运行

greet David

这将把输入“David”传递给我们的greet函数中的echo hello $1。请注意,传递给函数的变量没有命名,而是按照它们的输入顺序指定的。如果我们想处理第二个参数,我们将把它添加为$2,第三个参数将是$3,以此类推。

缺少命名参数并不是 bash 中唯一缺少的特性。在编写函数时,有其他语言经验的人期望发现的另一件事是从函数返回值的能力。不幸的是,没有像您期望的那样可以在函数内部使用 return 关键字。作为一种解决方法,您可以在函数内部定义一个变量,并在函数外部使用它。为了演示这一点,我们将创建一个随机时间生成器,它可以用作测试脚本的一部分。

Note

我们将使用shuf命令来生成随机数。您不需要担心安装它,因为它是 GNU Coreutils,并且几乎存在于所有的 Linux 系统上。

random_time() {
  hour=$(shuf -i 0-12 -n 1)
  min=$(shuf -i 0-60 -n 1)

  hour=$(printf %02d $hour)
  min=$(printf %02d $min)
  r_time=$min:$hour
}

定义了我们的随机时间生成函数后,让我们运行它并echo结果。我们将这样做两次,以确保每次都获得不同的值。

random_time
echo $r_time

random_time
echo $r_time

来自文件的源代码

如果您来自另一种编程语言,您可能习惯于从外部文件导入源代码。导入相对简单。假设我们已经将上一节中的random_time函数保存为random.sh。首先从上一节中获取random_time函数,我们在这里定义并保存它为一个名为random_time.sh的脚本文件。确保在第一行包含一个 shebang(本节后面的例子作为参考),保存后在上面运行chmod +x

现在我们已经将random_time函数保存为random_time.sh,我们将在同一目录下的另一个文件中使用它。为此,创建一个名为sourcing.sh的新脚本文件;包括此处显示的代码:

#!/usr/bin/env bash

source random_time.sh
random_time
echo r_time

如果您不在与random_time.sh文件相同的目录中,请确保使用完整路径。文件导入后,您可以使用文件中定义的任何变量或函数。

摘要

在这一章中,我们从管道和重定向开始,它们可以用来将不同的 Unix 实用程序和命令粘合在一起,或者直接处理输出,或者保存到文件中。

然后我们看了 bash 脚本语法的各个方面,包括条件表达式、函数、引号和导入文件。

五、使用 SSH

在本章中,我们将了解 SSH(安全 Shell)。SSH 是系统管理中最常用的工具之一。它允许您通过加密连接连接到远程服务器或设备。它也是构建在 SSH 之上的其他程序的基础,例如 X2Go,它是一个 Linux,相当于 RDP(远程桌面协议)客户端,如 VNC。

通过使用 SFTP(安全文件传输协议)命令,SSH 也可以以类似于 FTP(文件传输协议)的方式用于文件传输(下一章将详细介绍)。

在某些情况下,SSH 只是用作代理流量的一种手段,以隐藏用户或脚本的位置或 IP 地址。这可以通过 SSH 隧道和 SOCKS 代理来实现。

SSH 的历史

虽然 SSH 只能追溯到 1995 年,但它实际上是建立在早在 1969 年的早期程序上的,比如telnet。SSH 默认监听端口 22,离telnet使用的端口 23 只有一个端口。历史上,几乎所有的 Linux 系统都是通过分时系统使用的,在分时系统中,一台中央计算机可以通过几个不同的基于文本的终端连接。这些基于文本的终端除了远程连接到中央计算机所需的软件之外,不包括任何东西。

这段历史对 Linux 操作系统有很大的影响。很明显,SSH 等基于文本的工具仍在广泛使用,允许多个用户连接到一个服务器来运行作业、访问数据和管理系统。

telnet(电传网络的缩写)这样的早期程序的主要缺陷是它们缺乏安全性。使用telnet,客户端和服务器之间的通信是完全未加密的明文(包括任何密码)。双向加密和更高级的安全特性使得 SSH 在流行程度上迅速超越了早期的工具,如telnet

虽然telnet几乎已经被 SSH 完全取代,但今天仍然有一些有趣的在线服务,包括 ASCII 格式的星球大战,telnet 上基于文本的在线象棋,以及 telnet 上的天气查询服务。

telnet towel.blinkenlights.nl

telnet freechess.org 5000

telnet rainmaker.wunderground.com

图 5-1 显示了来自towel.blinkenlights.nl的基于文本的开场动画。

img/494886_1_En_5_Fig1_HTML.jpg

图 5-1

基于文本的远程登录星球大战再现

基本的 SSH 使用

您想要熟悉的用于连接服务器的最重要的命令是 SSH。SSH 是用于远程连接到服务器、计算机和嵌入式设备的程序。它提供到服务器或设备的安全加密连接,并被广泛使用。当谈到远程管理服务器时,除了非常有限的特定于供应商的管理仪表板之外,确实没有 SSH 的替代方案。

要检查您的系统是否预装了 SSH,请尝试运行

which ssh

如果您获得了一个ssh文件的文件位置,就可以开始了。否则,继续安装它:

sudo apt-get install ssh

如果您已经运行了一个打开连接的服务器或设备,那么它就像运行

ssh <username>@<address>

之后会提示您输入密码。

使用 ssh-keygen 的密钥对

如果您已经使用 SSH 和密码成功登录到服务器或设备,您首先要做的事情之一就是切换到使用公钥鉴定。有两个主要好处:

  • 密钥对被认为比密码更安全。

  • 密钥对更方便,因为它们不需要密码。

一对密钥由两部分组成,第一部分是私钥,它将保留在您的计算机上,永远不应该共享;第二部分是公钥,它可以公开共享,用于签署请求,任何拥有公钥的人都可以验证请求来自您。

要开始创建密钥对,首先运行

ssh-keygen

系统会提示您选择密码;这是可选的。密码短语只是用来在本地加密您的私钥。这样,如果有人获得了你的笔记本电脑和私人密钥,他们将无法读取它,假设你选择了一个强密码。

如果您正确地遵循了这些说明,您应该会得到如图 5-2 所示的输出。

img/494886_1_En_5_Fig2_HTML.jpg

图 5-2

ssh-keygen 的输出

接下来,我们将把新的公钥复制到我们的远程 SSH 服务器/设备上;SSH 有一个内置命令来简化这一过程:

ssh-copy-id <username>@<address>

您将再次被提示输入登录服务器的密码。一旦该命令成功运行,您将能够自动登录到服务器,而无需使用服务器密码。但是,如果您选择一个密码来加密您的私钥,您将需要在使用该密钥之前输入该密码。

PEM 和其他关键文件

在某些情况下,服务器可能会使用 PEM 文件,这是隐私增强邮件的缩写。一个流行的例子是 Amazon EC2 服务器。这些键使用-i标志指定,例如:

ssh -i <pem-file-location> <username>@<address>

使用-i标志的另一种方法是使用ssh-add将您的密钥添加到会话中,例如:

ssh-add <pem-file-location>

这将向身份验证代理添加密钥文件。它将保持活动状态,直到 SSH 重新启动,这主要发生在计算机重新启动时。

上述方法并不特定于 PEM 文件,而是可以用于 SSH 服务器所需的任何密钥文件。其他的还有 PPY,Putty 私钥的简称,或者.pub files,公钥的简称。

禁用服务器上的密码登录

我们提到过使用 ssh 密钥对的主要好处之一是它比密码认证更安全。为了获得这种附加安全性的好处,您必须在服务器上禁用密码登录。当您第一次添加密钥对时,服务器将允许使用这两种方法中的任何一种登录。由于 keypair 更安全,建议您关闭使用密码的功能,以避免任何类型的暴力攻击。

首先,使用 SSH 连接到服务器。然后你需要找到文件/etc/ssh/sshd_config。打开sshd_config,修改提及ChallengeResponseAuthentication的行;您需要确保它被设置为no,如下所示:

ChallengeResponseAuthentication no

其次,在同一个文件中,找到提到PasswordAuthentication的那一行,将其设置为 no:

PasswordAuthentication no

这两个设置将确保密码不能用于登录服务器。因此,在更改这些值之前,确保公钥身份验证正常工作非常重要。否则,您可能会发现自己完全被锁定在服务器之外。

最后,还有最后一个步骤,让 SSH 服务器重新加载已经更改的设置,这样它们才能生效。为此,请运行以下命令:

service sshd restart

重启 SSH 服务器的最后一步值得注意,因为它并不特定于这个设置。每当您对 SSH 配置进行任何更改时,您都需要在服务器上重新启动服务,以使这些更改生效。

带有 SSH 配置文件的服务器昵称

使 SSH 变得简单一点的另一个便利技巧是创建一个客户端 SSH 配置文件。您可以使用它为您经常登录的每台服务器创建默认用户名、服务器 IP 和身份验证密钥文件。当您经常需要在多个服务器或设备之间切换时,这变得特别有用。

您需要做的第一件事是创建 SSH 配置文件,该文件应该位于~/.ssh/config:

touch ~/.ssh/config

接下来,您需要确保它拥有正确的权限:

chmod 600 ~/.ssh/config

完成后,您可以打开配置文件并为您的每台服务器创建一个条目。例如,我将使用我目前正在使用的 AWS 服务器:

Host aws
 Hostname ec2-35-174-116-189.compute-1.amazonaws.com
 User ubuntu

现在,我可以不指定完整的主机名和用户,而是

ssh -i ~/.ssh/file.pem aws

您可能不需要-i ~/.ssh/file.pem,这取决于您的服务器是否需要身份文件。关键文件类型.pub.ppk也可以与-i一起使用。

我们可以通过将身份文件添加到我们的配置中来进一步简化这一过程:

Host aws
 Hostname ec2-35-174-116-189.compute-1.amazonaws.com
 User ubuntu
 IdentityFile ~/.ssh/file.pem

现在我们可以简单地做

ssh aws

要为多个服务器添加条目,只需在配置文件中添加下面的附加块。这使得连接到不同的服务器更加容易,因为你不需要记住每个服务器的地址。

Note

IdentityFile也可用于指定公钥/私钥登录的 RSA 密钥。尽管默认情况下该值是~/.ssh/id_rsa。因此,如果您使用默认的密钥位置,就不需要添加它。

在连接上运行命令

有时您只想连接到服务器来运行一个命令。这通常与必须连续在几个相似的设备或服务器上执行一些修复有关。在一个例子中,我工作的一家公司有几个设备有一个错误,破坏了我们的配置管理设置。修复方法是简单地删除这些设备上的一个锁定文件。我们能够通过创建一个 for 循环来快速修复所有这些问题,该循环获取每个设备的 IP,连接,然后运行所需的命令。

Note

如果您经常发现自己必须连接到多个系统来运行相同的命令、修改配置或更新程序,那么您会想要查看 Ansible 程序,这是一个轻量级的开源程序,用于在几台机器上同时进行相同的更改。Ansible 构建在 SSH 之上,因此当您编写一个配置发送到多个设备时,它实际上是通过 SSH 连接并在幕后运行命令。Ansible 的其他受欢迎的替代品包括木偶、厨师和盐。

为此,您只需在 ssh 命令的末尾提供一个带引号的命令,例如:

ssh user@server.com "touch /tmp/testing123"

连接后,您几乎会立即断开连接并返回到您的本地机器命令行,如图 5-3 所示。

img/494886_1_En_5_Fig3_HTML.jpg

图 5-3

指定在 SSH 连接上运行的命令

如果您想在连接上运行一个命令,但不想立即断开连接,您可以修改命令 run on connection 来启动一个 bash 会话:

ssh user@server.com "touch /tmp/testing123; bash"

这将运行命令,然后将您置于 bash 会话中,不会断开连接。

中断挂起的 SSH 会话

使用 SSH 时可能出现的一个常见问题是,您让一个会话在后台或另一个窗口中运行,当您返回时,它完全冻结了。连接问题也可能是 SSH 会话挂起的常见原因。当客户端失去与服务器的连接时,它将挂起,直到服务器重新连接。您可能会想尝试按 ctrl+c 或 ctrl+d,但即使这样也不会结束冻结的 SSH 会话。

当这种情况发生时,退出会话的最简单方法是按 enter 键,然后按~,再按.。这样做应该会退出会话并返回如下消息

Connection to yourServer.com closed.

这种组合键是最广为人知的转义序列,但不是唯一的。如果你改为按回车键,~,然后?,你将得到所有支持的转义序列列表,包括表 5-1 中的那些。

表 5-1

转义序列列表

|

顺序

|

描述

|
| --- | --- |
| ~. | 终止连接(以及任何多路复用会话) |
| ~B | 向远程系统发送中断 |
| ~C | 打开命令行 |
| ~R | 请求重置密钥 |
| ~V/v | 减少/增加详细程度(日志级别) |
| ~^Z | 暂停 ssh |
| ~# | 列出转发的连接 |
| ~& | 后台 ssh(等待连接终止时) |
| ~? | 列出所有序列 |
| ~~ | 通过键入两次来发送转义字符 |

在大多数情况下,您主要希望使用常规的~.,当然,除非您刚刚输入了一个换行符,并且您确实希望键入~字符;在这种情况下,只需第二次点击它。还要注意的是,如果~是一行的第一个字符,它只会被作为转义序列读取;如果你已经进入了一行,你需要先按回车键或者清除输入。

保持健康

有时当你不得不中断连接时,或者如果你曾经不得不使用类似minicom的程序或者有时甚至是 SSH 来使用串行端口连接到一个设备,你将会有如图 5-4 所示的终端窗口故障。当这种故障发生时,您键入的字符可能不会像您预期的那样出现。这可能会导致意外的行为,使终端屏幕的大部分内容不可读,或者只是看起来不正确。

img/494886_1_En_5_Fig4_HTML.jpg

图 5-4

终端中的 ASCII 乱码故障(又名 mojibake)

或者您可能没有得到图中所示的 ASCII 类型的字符,但是您的空格是关闭的,终端通常不按预期运行;参见图 5-5 了解可能出现的奇怪间距类型。

img/494886_1_En_5_Fig5_HTML.jpg

图 5-5

视觉间距毛刺

如果这些小故障或任何视觉上的事情发生,你可以使用stty sane来修复你的终端,而不必关闭并重新打开。简单地跑

stty sane

在这种情况下可以使用的另一个命令是reset,它不带任何参数独立运行(不要与 reboot 混淆,reboot 将重新启动系统)。

reset

停止 SSH 挂起

能够从一个挂起的 SSH 会话中断开连接是很好的,但是如果能够完全避免这种情况发生就更好了。根据您的系统,默认情况下这可能不是问题,但是可以在您的客户端的/etc/ssh/ssh_config文件中更改ServerAliveInterval设置。

此设置告诉客户端多久向服务器发送一次信号,以确认您仍然连接并使用该连接。如果您在文件中没有看到ServerAliveInterval的实例,请添加以下几行:

Host *
ServerAliveInterval 100

您必须在出现问题的服务器上编辑同一个文件/etc/ssh/sshd_config:

ClientAliveInterval 60
TCPKeepAlive yes
ClientAliveCountMax 10000

这告诉服务器,如果没有收到任何保持会话活动的消息,则每 60 秒向客户端发送一条保持活动消息。TCPKeepAlive确保防火墙不会丢弃空闲连接,而ClientAliveCountMax指定服务器将在多长时间内保持发送保活消息,即使没有从客户端听到任何消息。

SSH 隧道

SSH 隧道是通过 SSH 将一台计算机上的端口转发到远程计算机的过程。SSH 隧道有多种用途,我们将在接下来的章节中介绍。

本地 SSH 隧道

最简单的 SSH 隧道之一是本地隧道,它将本地端口绑定到远程机器上的地址。例如,我们可以使用-L标志将本地端口 8080 绑定到一个通过远程机器访问的网站:

ssh -L 8080:textfiles.com:80 user@server.com

在写这篇文章的时候,这在 textfiles.com 网站上运行得很好(这是一段有趣的互联网历史。查看 Jason Scott 的 Defcon 17 演讲,了解背后的故事)。不幸的是,这取决于你想隧道网站,它可能会或可能不会工作。像nginx这样的现代服务器软件实际上会检查你的浏览器中正在使用的主机名,但由于不匹配而无法工作。

在某些情况下,网站无法通过隧道工作,因为它们会检查浏览器使用的 URL,并且在使用“localhost”时会出现故障。Youtube 等大多数流行的网络应用都是如此。如果你想通过隧道访问一个不工作的网站,你可以通过更新/etc/hosts将该 URL 映射到你自己的服务器的 IP 地址,或者你可以发送一个虚假的标题,声称你的主机名实际上是预定的网站。根据您的操作系统,您可能需要安装curl

sudo apt-get install curl

下面是一个使用curl手动设置带有-H标志的主机头的例子:

curl -H "Host: youtube.com" -L localhost:8080

这应该会返回 YouTube 的源代码。如果您想要一种更实用的方法来使用 SSH 隧道进行 web 浏览,我们在下一节关于 SOCKS 代理的内容中提供了一个更好的解决方案。

虽然这个例子向我们展示了本地 SSH 隧道是如何工作的,但它并没有确切地展示为什么会使用它。对于任何与浏览相关的内容,下一节中显示的 SOCKS 代理方法将是首选。

当您想要通过 SSH 访问服务器上运行的服务时,SSH 隧道就很方便了。这是一种特别安全的方式来为一个小团体提供 web 服务,而不必担心很多安全问题。由于该网站只对那些通过端口 22 上的 SSH 访问它的人可用,因此不存在可能以公开登录页面为目标的攻击威胁。

用 SSH 创建 SOCKS 代理

SSH 非常适合连接到远程服务器和设备,但它实际上可以用于各种用途。其中之一是创建一个 SOCKS 代理连接,当使用像 web 浏览器这样的应用时,它可以用来在本地计算机上引导流量。

SOCKS 代理具有与使用 VPN(虚拟专用网络)相关的大部分好处,包括

  • 匿名网页浏览

  • 绕过地理定位封锁

  • 绕过本地网络或 ISP 的网站阻止

  • 比 VPN 还快

请记住,第一个好处“匿名网页浏览”只是部分真实,这取决于你打算匿名的人和你用来代理流量的服务器。如果你试图向政府隐藏你的身份,并且你使用的服务器是以你的名字注册的,这可能不会有效。

然而,从你正在访问的网站的角度来看,他们只会看到你的终端服务器的 IP 地址。例如,他们可能看到流量来自位于美国东部的 AWS 服务器。

当使用您自己的服务器作为 SOCKS 代理时,需要记住的另一个警告是,一些服务器提供商的 IP 可能会被标记为 SOCKS 代理,并受到一些服务和网站的限制。这是因为许多自动化脚本和恶意服务都来自这些类型的服务器。如果您使用的是较小的主机提供商的服务器,您可能会绕过这类问题。

要开始,只需运行以下命令,用用户名和主机替换您自己的用户名和主机:

ssh -D 8123 -f -C -q -N user@server.com

这里包含的标志如表 5-2 所示。

表 5-2

使用的标志

|

|

描述

|
| --- | --- |
| -D 8123 | 绑定到端口 8123 的连接 |
| -f | 将进程转移到后台 |
| -丙 | 发送前压缩数据 |
| q | 安静模式 |
| 同-EN | 不要执行远程命令 |

如果运行没有错误,您应该让 SOCKS 代理监听端口 8123 ( 随意用另一个替换端口号)。我们可以使用psgrep进行双重检查:

ps aux | grep ssh

如果正在运行,您应该看到您运行的命令被列为正在运行的进程。使用代理取决于您使用的具体应用。作为一个例子,我们来看看 Firefox。在 Firefox 中打开偏好设置,然后向下滚动到“网络设置”在网络设置中,如图 5-6 所示,您可以使用“localhost”配置“手动代理配置”,并将您选择的端口作为 SOCKS 主机。

img/494886_1_En_5_Fig6_HTML.jpg

图 5-6

设置 web 浏览器使用 SOCKS 代理

在 Firefox 上更新您的代理并保存后,您需要验证它是否按预期工作。要做到这一点,你需要找到一个网站来检查你的 IP 地址。我的首选方法是去 www.duckduckgo.com (面向隐私的搜索引擎),搜索“我的 ip 是什么”这样做应该会显示你的 IP 地址和位置,如图 5-7 所示,而不必点击进入任何第三方网站。

img/494886_1_En_5_Fig7_HTML.jpg

图 5-7

DuckDuckGo 显示我们的远程 SSH 服务器的 IP

反向 SSH 隧道

SSH 是连接远程服务器和设备的一个很好的工具,但是有时防火墙和路由器会碍事。例如,如果你家里有一个运行 Linux 服务器的 Raspberry Pi,并且想从你的本地网络之外通过 SSH 连接到它,你可能会因为路由器和互联网提供商的限制而遇到麻烦。

一个很好的解决方法是创建一个反向 SSH 隧道。反向 SSH 隧道依赖于相关设备来维持活动的传出连接。例如,我们的 Raspberry Pi 将持续保持与远程服务器的连接。因为是 Pi 对传入连接有限制,而不是相反,所以 Pi 进行传出连接没有问题。

当我们准备好 SSH 到 Pi 时,我们实际上在隧道内创建了我们的连接,这是 Pi 的输出连接。因此,Pi 在其自己的输出连接中接收输入连接。

要建立一个反向 SSH 隧道,首先在相关的服务器上打开一个终端会话;在这种情况下,我们的树莓派在防火墙后面。运行以下命令:

ssh -R 9876:localhost:22 user@server.com

-R标志在作为主要 SSH 连接的隧道内创建一个较小的隧道;-R代表远程,作为隧道入口点在远程机器上;这类似于-L旗,除了-L旗在本地侧有入口点。

另请注意,我们已经选择端口 9876 作为进入远程端的内部隧道在本地端结束的位置。请随意将端口 9876 与设备上任何未使用的端口交换。

一旦准备好连接到运行反向代理的设备,只需像平常一样使用 SSH,但要指定上一步中使用的端口。因此,在我们的示例中,我们将使用以下命令:

ssh -p 9876 user@server.com

通过反向代理服务网站

这种类型的 SSH 隧道是流行的开发工具 ngrok 的基础。Ngrok 允许开发人员立即将运行在本地机器上的 web 应用发布到 web URL 上,供任何人查看。您可以使用自己的 web 服务器做同样的事情。

为了演示,首先我们将创建一个运行在端口 8080 上的最小站点。如果你运行的是最新版本的 Ubuntu,默认情况下你应该已经安装了python3;否则你需要安装它。

cd /tmp
echo Hello World > index.html
python3 -m http.server 8080

运行这三行代码后,您将能够在 web 浏览器中转到 localhost:8080,并看到文本“Hello World”。我们的小站点运行在端口 8080 上,现在我们可以运行以下命令:

ssh -R 8080:localhost:8080 user@myServer.com

这将把我们本地机器上的端口 8080 镜像到远程服务器上的端口 8080,从而允许我们在一个活动的 IP 上演示我们的本地主机网站。

SSH 代理跳转

有时您不想直接连接到 SSH 服务器。使用跳转框有两个主要原因:

  • 通过仅允许从特定 IP 或非公共网络连接到最终目标服务器来降低安全风险。

  • 您不希望最终的目的服务器记录您的实际 IP 地址。

在第一种情况下,您的目标服务器可能在公共互联网上不可用。在这种情况下,跳转框充当一个 DMZ ( 非军事区),您可以从这里进行连接。这意味着受保护的盒子是完全隐藏的,不会被端口扫描器或任何扫描开放互联网的恶意脚本发现。

您可以使用-J标志来使用跳转服务器,如下所示:

ssh -J user@server1.com user@server2.com

当使用跳转服务器时,使用 SSH 配置文件会很方便,因为您不能使用-i标志直接指定跳转服务器的身份文件,但是如果您使用本章中描述的 SSH 配置文件,您可以在那里定义身份文件。

如果你的情况更符合试图隐藏你的起源,你甚至可以使用一系列的跳转服务器。有了多个跳转服务器,即使是连接到目的服务器的跳转服务器也不会知道你的 IP 地址。通过提供多个以逗号分隔的跳转服务器,您可以使用多个跳转服务器:

ssh -J user@jump1.com,user@jump2.com user@server.com

更改 SSH 服务器上的默认端口

有几个原因可能导致您想要更改 SSH 服务器的默认端口——如果您知道您将从一个网络连接到服务器,该网络限制了除端口 80 或 443 之外的任何出站连接。

或者,如果您将使用密码验证,并且希望降低服务器被可能尝试暴力攻击的爬虫发现的机会,在这种情况下,请使用不常见的端口,如 79279。如果您不确定您选择的随机端口是否不常见,您可以使用nmap进行检查。nmap默认情况下不会安装,因此您必须通过您的软件包管理器安装它:

sudo apt-get install nmap

一旦安装了'nmap',使用以下命令:

nmap --top-ports 1000 localhost -v -oG -

这将返回 1000 个最受欢迎的端口列表,您可以reference查看您的端口是否匹配。

打开防火墙

在更改端口之前,务必确保您没有防火墙或其他会阻止传入流量的配置。要检查是否启用了防火墙,请运行

sudo ufw status

如果ufw正在运行,您可能需要将其配置为接受来自您想要的端口的流量。如果它没有运行,您可能仍然需要处理您的云提供商安全设置。例如,Amazon AWS 安全实例的安全规则是在服务器本身之外的安全组规则中设置的。许多其他云提供商遵循相同的模式,只开放端口 22(可能还有端口 80 和 443),以使服务器在默认情况下是安全的。请咨询您的服务器提供商,了解是否需要额外的步骤来允许端口访问。

如果ufw正在运行,你可以通过运行告诉它允许你的端口

sudo ufw allow <port-number>

修改 sshd_config

可以通过编辑文件/etc/ssh/sshd_config来修改 SSH 服务器的设置。在更改活动服务器上的端口之前,请确保该端口是可访问的。如果您将端口更改为阻止传入请求的端口,可能会将您自己锁定在服务器之外。要更改默认端口,只需找到如下注释行

#Port 22

取消对线路和交换机 22 的注释,使用您选择的端口:

Port 7929

Note

SSH 服务器的默认端口也可以在您的客户端 SSH 配置文件中指定,这样您就不需要在连接到服务器时使用-p 标志来指定它。

更新文件后,您需要重新启动 SSH 服务:

sudo service ssh restart

摘要

在本章中,我们了解了如何使用 SSH 和一些常见的配置远程连接到服务器或设备。这些配置包括关闭密码登录以使用密钥对,切换默认端口,以及通过修改保持活动设置来停止挂起。我们研究了 SSH 隧道和常见用法,比如创建 SOCKS 代理。

虽然这个列表很难涵盖 SSH 使用的所有地方和方式,但是它为使用一些常用设置连接到远程服务器打下了良好的基础。

六、文件传输

在这一章中,我们将看看在机器之间传输文件的各种程序。

文件传送协议

传输文件最常见的协议之一是 FTP ( 文件传输协议)。要开始使用 FTP,你应该安装lftp,一个复杂的文件传输程序。该程序主要用于 FTP,但也可用于其他协议:

sudo apt-get install lftp

安装lftp后,您可以使用以下命令进入交互模式

lftp

这将打开一个交互式 shell,您可以在其中运行特定于lftp的命令。它看起来应该类似于图 6-1 。

img/494886_1_En_6_Fig1_HTML.jpg

图 6-1

lftp 交互模式

lftp shell 的行为很像普通的 bash shell,让您可以访问几个命令,比如lscd。您还可以获得额外的命令。要查看可用的命令,只需输入?并按回车键。

需要知道的最重要的命令是connect,它被简单地用作

connect -u <username> <server-address>

之后,系统会提示您输入密码。连接后,您可以使用下载文件

get <file-name>

或使用上传

put <file-name>

Note

如果你正在寻找 FTP 服务器来练习,并且不想建立自己的 FTP 服务器,使用谷歌呆子寻找不安全的 FTP 服务器可能是有用的。Google dork 是一个搜索词,用于使用搜索词查找特定的应用或不安全的网站。寻找 FTP 服务器的一个好方法是intitle:"index of" inurl:ftp

science for the people 为人类服务的科学

Note

对于 SFTP 和 SCP(下一节),您可以在本地主机上测试这些命令,而不是指定一个远程服务器。只需使用本地主机和您的用户名。当然,从一个本地主机到另一个本地主机并没有比类似于mv的命令提供更多的好处,但是它确实允许您在没有远程服务器设置的情况下测试这些命令。

您可能熟悉 FTP,它是文件传输协议的缩写。它通常与 FileZilla 等 GUI 程序一起使用,用于向服务器上传和下载文件。在 PHP 最流行的时候,使用 FileZilla 更新服务器的www目录是标准做法。

虽然像 FileZilla 这样的程序仍然被广泛使用,但这些程序现在使用了一种叫做 FTPS 的新的安全版本的 FTP。FTP 有一个主要弱点,使得攻击者能够在用户连接到服务器时,嗅探到 FTP 服务器的流量并获取用户凭据。

FTP 的另一个流行且易于使用的替代方法是 SFTP。SFTP 支持文件传输,看起来和感觉上像 FTP,但通过端口 22,SSH 会话使用的同一端口。如果您已经在服务器上使用了 SSH,那么使用 SFTP 连接它应该没有问题。它不需要在服务器或连接客户端上安装任何额外的软件。大多数 SSH 安装都应该包含 SFTP,除了极少数轻量级版本。

首先,只需使用您已经在使用的命令通过ssh连接到您的服务器,并使用sftp代替,例如:

sftp ubuntu@myserver.com

或者,如果您使用 PEM 文件进行身份验证(这在 AWS 服务器中很常见),请使用

sftp -i ~/.ssh/key.pem ubuntu@myserver.com

连接前需要注意的一点是,您连接的目录将是您打算下载或上传的目录。

一旦登录到服务器,您将能够使用一些通常在ssh会话中可用的命令,但不是全部。最重要的是,您将能够使用lscd ( 就像使用 FTP )来浏览您的文件系统。

如果您想下载一个文件,导航到相关文件夹并使用get命令:

get readme.txt

如果一切正常,您应该会看到一些确认下载的输出,如图 6-2 所示。

img/494886_1_En_6_Fig2_HTML.jpg

图 6-2

使用 lftp 从远程服务器获取文件

从那时起,通过按 ctrl+c 断开sftp连接。一旦回到本地机器,运行ls,您应该会看到下载的文件。

你可能想利用的另一个上传文件的功能是put。与get一样,在通过sftp连接之前,导航到包含您想要上传的文件的文件夹。然后与sftp连接;在服务器上,导航到您想要上传文件的位置。键入put,确保包含put后的空格,然后按 tab 键。在put之后按 tab 应该会显示目录中的文件列表。在图 6-3 中,你可以看到鸟、猫和狗的图像文件。

img/494886_1_En_6_Fig3_HTML.jpg

图 6-3

使用自动完成功能查看可以放入哪些文件

从这一点来说,我可以简单地完成三个选项中的一个,或者如果您意识到您在错误的文件夹中,您可以开始键入替代路径,例如,..//,然后再次按 tab 以帮助找到您想要上传的文件。

Note

在章节 5 中,我们看了如何创建一个~/.ssh/config文件来创建包含服务器、用户名和其他选项的快捷方式。这个相同的配置文件也适用于 SFTP 和 SCP。

单细胞蛋白质

SCP 是 secure copy protocol 的缩写,是 SSH 附带的另一种文件协议。功能类似于 SFTP,但它没有交互方面。使用 SCP 的上传或下载必须在一个命令中声明,而不是首先连接到一台机器,然后才能浏览目录。

总的来说,SCP 似乎比 SFTP 更糟糕,因为它没有提供额外的功能,交互性也更差。但是,SCP 的优势是文件传输速度比 SFTP 快。对于中小型文件,这可能会被忽视,但如果你是移动一个大文件,你可能会决定用 SCP 而不是 SFTP。如果您将文件作为脚本的一部分进行传输,您也可以考虑使用 SCP,交互模式实际上是一种阻碍而不是一种好处。

要从服务器下载文件,只需运行scp,然后运行username@serverName,然后运行:/file/location ( ,不带空格,然后作为第二个参数运行您希望在本地机器上保存文件的路径,例如:

scp ubuntu@myserver.com:/tmp/myFile.txt ./

许多在sshsftp上起作用的标志也将在scp上起作用——例如,如果您需要使用 PEM 文件登录到您的服务器:

scp -i ~/.ssh/mykey.pem ubuntu@myserver.com:/tmp/myFile.txt ./

如果您需要将文件上传到服务器,只需切换路径的顺序:

scp ./ ubuntu@myserver.com:/tmp/myFile.txt

备份

Note

如果您使用密码登录您的服务器,您需要设置公钥认证,如第五章“ssh-keygen 的密钥对”一节所述除了设置 SSH 之外,您的远程服务器唯一需要安装的是rsync

Rsync 是另一个在 Linux 系统上上传和下载文件的工具,但它的功能更像是一个自动备份系统,类似于 Dropbox 提供的服务。设置完成后,它将监控一个系统上的目标文件夹,如果有任何文件被添加或更改,它们将被同步到远程服务器。这很方便,因为与一些定制备份脚本不同,它将只保存新的或更改的文件,而不是定期运行备份文件夹的scp命令。

要开始使用,请安装rsync:

sudo apt-get install rsync

要使用该程序,您需要运行以下命令:

rsync -r --progress \
  ~/backup ubuntu@<myserver.com>:/home/ubuntu/backup

在前面的命令中,我们首先指定我们的本地文件夹~/backup,这是我们想要备份的文件夹。在文件夹之后,我们指定用户名和服务器ubuntu@<myserver.com>,您将用您的服务器信息替换它。如果没有空格,我们就有了:/home/ubuntu/back,这是我们将要备份文件的文件夹位置。

虽然我们首先指定本地文件夹,但这不是必需的。如果我们想将远程服务器备份到本地文件夹,我们只需交换参数的顺序,然后运行以下命令:

rsync -r --progress \
  ubuntu@<myserver.com>:/home/ubuntu/backup ~/backup

我们使用的可选标志是-r--progress,前者导致文件夹被递归备份,后者提供一些关于备份过程进行到什么程度的视觉反馈。

如果您正在使用一个身份文件,您将需要使用-e标志并指定用于启动会话的特定 SSH 命令。我们使用添加身份文件的例子,但是如果您想以任何方式修改 SSH,您可以使用-e标志。然而,在某些情况下,比如更改远程服务器用于 SSH 的端口,rsync提供了自己的标志--port(和往常一样,您可以查看手册页以获得选项的完整列表)。

rsync -r --progress \
  -e "ssh -i /home/philip/.ssh/key.pem" \
  ~/backup ubuntu@myserver.com:/home/ubuntu/backup

如前所述,我们使用了-r标志。如果没有-r选项,文件夹中的文件将不会被备份。有几个选项可以和rsync一起使用;表 6-1 中列出了一些最常见的。

表 6-1

常见 rsync 选项

|

短旗

|

满旗

|

描述

|
| --- | --- | --- |
| -v | -冗长 | 更详细的输出 |
| q | 安静 | 无文本输出 |
| [构成动植物的古名或拉丁化的现代名] | -存档 | 同步时归档文件 |
| -r | -递归 | 递归同步目录 |
| -b | -备份 | 制作备份 |
| -你 | -更新 | 如果目的地较新,不要复制文件 |
| -我 | -链接 | 复制符号链接 |
| 同-EN | -预演 | 试验 |
| -e | -rsh="command " | 指定远程 Shell 命令 |
| z | -压缩 | 同步时压缩数据 |
| -h | -人类可读 | 人类可读格式的尺寸 |
|   | -进步 | 同步过程中显示进度 |

为 Rsync 设置 Cron 作业

我们已经看到使用rsync备份整个文件夹或一组文件夹是多么容易,但是它还不是完全自动的。为了让生活变得简单一点,我们可以创建一个 cron 作业来自动执行定期调用命令的过程。

为此,我们将创建一个 cron 作业,但首先让我们在脚本文件中移动备份命令。您可以在您喜欢的任何位置创建该文件;定制脚本的一个常见位置是/usr/local/bin/。打开您的脚本文件,在我们的例子中,我们将使用/usr/local/bin/backup.sh,添加一个 shebang,并粘贴特定于您的服务器和备份文件夹位置的rsync命令:

#!/usr/bin/env bash

rsync -r --progress \
  ~/backup ubuntu@myserver.com:/home/ubuntu/backup

确保将用户、服务器和文件夹替换到您的特定设置中。如果您想要备份多个文件夹,您可以在第一个文件夹下添加额外的rsync命令。保存后,请确保为新文件添加执行权限:

chmod +x /usr/local/bin/backup.sh

最后,我们将通过运行crontab -e创建 cron 作业,并在文件底部添加

0 0 * * * /usr/local/bin/backup.sh

有了这个设置,你的系统应该在每天午夜进行备份。

同音双向同步

我们已经看到了rsync如何使从一台机器到另一台机器的备份变得容易,但这与像 Dropbox 这样提供双向同步的流行服务不太一样。如果你需要以两种方式同步文件,你可以使用建立在rsync之上的unison程序,它提供双向同步。

确保在您想要同步的两台机器上都安装了unison:

sudo apt-get install unison

由于没有用unison指定一个.pem键的选项,你只能将它添加到ssh中,并让ssh在需要时提供它。你可以通过运行(你必须在每次系统重启时运行这个步骤)

ssh-add <path/to/file.pem>

完成后,您就可以运行unison:

unison -auto -batch \
  ~/backup  \
  ssh://ubuntu@server.com//home/ubuntu/backup/

建议使用-auto-batch标志来使过程自动化;如果没有它们,您将被手动要求验证每个同步的文件。

当文件同步更改时自动同步

不幸的是,包括 Ubuntu 在内的一些包管理器上可用的版本unison不包括监控文件系统的配套二进制文件unison-fsmonitor。这给你留下了两个选择:

  1. 使用 cron 作业定期检查,就像我们使用 rsync 一样。

  2. 从源代码手动编译 unison。

如果您想使用 cron 的简单方法,只需参考上一节关于 rsync 的内容,用一个unison命令替换backup.sh中的rsync命令;您可能还想增加 cron 作业的频率。如果您想从源代码编译以获得在文件改变时立即自动同步的能力,请继续阅读,我们将介绍从源代码编译所需的步骤。为避免任何错误,请确保两台机器上的rsync版本相同。

首先,我们需要卸载包管理器版本的unison并安装ocaml,这是编写 unison 的语言:

sudo apt-get remove unison
sudo apt-get install ocaml

接下来转到 https://github.com/bcpierce00/unison/releases 并记下最新的可用版本。在写的时候,是 2.51.2。无论版本号是多少,都要设置一个环境变量,因为我们会多次使用它:

UNISON_VERSION=2.51.2

设置好版本号后,运行以下一系列命令;注意,我们使用了为版本号设置的环境变量:

wget \
  github.com/bcpierce00/unison/archive/v$UNISON_VERSION.tar.gz
tar -xzvf v$UNISON_VERSION.tar.gz
rm v$UNISON_VERSION.tar.gz
pushd unison-$UNISON_VERSION
make
sudo cp -t /usr/local/bin ./src/unison ./src/unison-fsmonitor
popd
rm -rf unison-$UNISON_VERSION

您需要在想要同步的两台服务器上运行前面卸载、构建和安装unison的步骤。完成后,您可以在两台服务器中的一台上运行以下命令:

unison -batch -auto ~/backup \
  ssh://ubuntu@server.com//home/ubuntu/backup/ \
  -repeat watch

运行该程序后,您可以尝试在任一服务器上的备份目录中创建一个文件,并查看文件是否同步。

Note

设置unison时,注意不要互相备份两个主目录。在测试过程中,我们发现每次使用主文件夹备份后,都会更新一个日志文件,它本身会触发另一个备份,从而导致无限循环。

同音设置文件

正如我们在注释中提到的,由于日志文件的原因,我们在尝试创建两个主目录之间的备份时遇到了一个错误。但是,如果需要,可以修改 unison 日志文件的位置以及程序运行的许多其他方面。unison 的设置在文件.unison/default.prf中指定。如果我们想改变日志的位置,我们可以添加下面一行。

logfile = /tmp/unison.log

其他可以设置的选项包括忽略某些文件类型;在此查看忽略 mp4 文件的示例:

ignore = Name *.mp4

有关 unison 上可配置内容的更多信息,请参见 www.cis.upenn.edu/~bcpierce/unison/docs.html 的官方文档。

创建一个服务来保持 Unison 运行

虽然我们已经在两台服务器上实现了双向自动同步,但仍然存在一些问题。首先,你不得不保持终端窗口运行一致,其次,如果你重启电脑,它会关闭。

作为这两个问题的解决方案,我们将创建一个systemd服务,它将在启动时打开unison,并确保它保持运行,这样您的文件夹总是同步的,而无需您运行命令或考虑它。

我们要做的第一件事是移动调用 unison 时使用的所有命令行参数,并将它们转换成位于~/.unison/bidirsync.prf的 unison 配置文件。创建~/.unison/bidirsync.prf并添加以下内容:

# Unison preferences
label = bi-directonal sync with server
root = /home/<user>/backup
root = ssh://<user>@<server-name>//home/<user>/backup
batch = true
auto = true
repeat = watch
logfile = /home/<user>/.unison/unison.log
#debug=all

如果您的服务器需要一个像 PEM 这样的身份文件,您还需要添加一行来指定该文件,格式如下:

sshargs = -oIdentityFile=/home/<user>/.ssh/<privkey-name>

通过运行unison bidirsync测试配置。注意,bidirsync既是我们创建的文件名,也是我们配置文件中的标签。您可以使用~/.unison/文件夹创建任意多的 unison 配置,并以这种方式快速运行它们。

现在我们有了一个工作配置,我们将创建一个systemd服务(参见第十一章了解更多信息)。首先创建一个新文件夹~/.config/systemd/user:

mkdir -p ~/.config/systemd/user

然后在那个文件夹中,创建一个名为unison.service的文件。它应该包含以下内容(确保将用户和组更新为您自己的值):

[Unit]
Description=Unison

[Service]
Environment="PATH=/usr/local/bin:/usr/bin"
ExecStart=/usr/local/bin/unison bidirsync
User=<yourUser>
Group=<yourUser>
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

一旦创建了服务文件,就可以运行以下命令来启动它:

sudo systemctl start unison

您可以通过运行以下命令来检查一切是否正常,并查看日志

systemctl status unison

摘要

在这一章中,我们看了几个可以用于跨机器下载、上传和同步文件的服务。我们从经典的ftp和更安全的替代品开始,如sftpscp。然后我们看了看rsync如何轻松同步文件夹,甚至看了看unison,它能够在不同机器上的文件夹发生变化后立即自动保持同步。

七、网络扫描

通常,您会想要查看本地网络上有哪些设备,包括设备的 IP 地址。这在几种情况下很方便,包括但不限于

  • 你想得到你的路由器的 IP 地址。

  • 您到达一家酒店,想要检查网络是否有漏洞或隐藏设备,例如可能被遗忘的流氓 Raspberry Pi。

  • 你想看看网络上其他电脑的 IP 地址,看看有没有不安全的地方。

  • 对网络上有哪些设备的普遍好奇。

在这一章中,我们将介绍如何检测网络上有哪些设备以及它们打开了哪些端口。在某些情况下,甚至可以确定设备运行的操作系统、某个端口上运行的应用的版本或者服务器的物理位置。

用 Ping 检查连接

在我们开始扫描网络之前,有必要提及一个最简单但有用的命令。ping允许您检查您是否已连接到互联网,以及您的目标网站是否已打开。为了检查你的互联网连接是否良好,许多人会向8.8.8.8发送一个ping;这是谷歌的主要 DNS 服务器,众所周知非常可靠。你可以用

ping 8.8.8.8

Note

由于其长寿和高正常运行时间,8.8.8.8 经常被用作发送 pings 的虚拟服务器。然而,由于这是一个企业(Google)使用的活动服务器,您可能希望考虑周到,不要给他们的负载增加额外的流量。互联网数字地址分配机构专门保留网站example.com作为示例网站,用于上述目的。出于这个原因,我们将使用example.com来代替 8.8.8.8。然而,知道 8.8.8.8 经常被用于这个目的是很好的,这样如果你在一个脚本中看到它,你可以识别正在发生的事情。

大约每秒钟你都会得到一个响应,告诉你连接是好的。可以用ctrl+c退出程序;如果您只想 ping 一次或固定次数,您可以使用-c标志后跟一个数字。如果您想在连接到互联网或目标网站启动的情况下执行某些操作,这可能会很有用,例如:

ping -c 1 example.com && echo connected

如果我们用一个不活跃的 IP 或网站来改变example.com,那么echo connected将永远不会运行。

arp 扫描方法

最简单的方法是安装一个名为 arp-scan 的程序。arp-scan是一个向网络上的所有设备发送 arp 数据包并显示收到的响应的程序。

在基于 Ubuntu/Debian 的系统上,您应该能够安装它

sudo apt-get install arp-scan

安装后,使用--localnet选项查看本地网络上的所有设备;该命令需要 root 权限:

sudo arp-scan --localnet

该程序将返回一个设备列表,包括 IP 地址,唯一的 MAC 地址,如果可能的话,还有设备的制造商。

当我在酒店房间写这篇文章时,我可以看到本地的 Cisco 路由器,毫不奇怪,它可以使用设备的默认用户名和密码登录。

此外,我有时可以看到我的 Android 手机也连接到网络。对于 android 设备来说,看到它取决于发送 arp 数据包时是否收到响应,这在睡眠模式下通常不会发生。

记下设备的唯一 MAC 地址会很有用,例如,如果您想稍后查看某人是否在另一个位置。说我在朋友家;我可能会记录下他笔记本电脑和手机的 MAC 地址。然后,当在单个网络上的大型建筑物(例如,图书馆)时,我可以扫描网络以查看他的设备是否连接,从而知道他是否在所述位置。

nmap 方法

虽然我发现 arp-scan 为找到的设备提供了最完整的信息,因为它返回 IP、MAC 地址和制造商,但也有设备不包括在扫描范围内的情况——例如,如果某个设备存在于网络上,但尚未分配 IP 地址。

要获得更完整的列表,请使用第二种方法。它需要安装 nmap,即“网络映射器”的缩写。同样在 Ubuntu/Debian 上,你应该能够安装它

sudo apt-get install nmap

一旦安装完毕,你会想要使用选项-sn,它代表无端口扫描。在 nmap 的旧版本中,可以使用选项-sP来代替-sn。此选项通常被称为“ping 扫描”。

完整的命令如下,确保使用 root 权限和sudo(否则结果会不同):

sudo nmap -sn 192.168.1.0/24

前面的命令假设您的网络正在使用 IP 范围192.168.1.*;在某些情况下,第三个数字可能不同。如果您没有从nmap ping 扫描中得到任何结果,您应该手动检查您的网络正在使用的 IP 范围。在这种情况下,您可以通过运行(“a”是地址的简称)来查找

ip a

在结果中,查找带有无线或以太网接口的部分(取决于您使用的接口),并在本地网络中查找您自己的 IP。以我为例,我的无线接口叫wlp3s0,我的本地 IP 地址范围是 192.168.30。*如图 7-1 所示。

img/494886_1_En_7_Fig1_HTML.jpg

图 7-1

使用ip a查找本地使用的 IP 地址

所以在我的情况下,我实际上需要运行

sudo nmap -sn 192.168.30.0/24

该命令中的0/24指定了 CIDR 符号的范围。用nmap指定范围有三个选项:

  • cid 符号( 0/24

  • 范围( 1-5 )

  • 通配符( *** )

因此,相同的命令可以表示为

nmap 192.168.1.0/24
nmap 192.168.1.0-255
nmap 192.168.1.*

Note

想观看网络直播吗?在运行nmap之前,打开第二个终端并运行ip monitor。这将使你能够实时观看网络上发生的一切。或者,如果您只想查看活动表单nmap,您可以在命令中添加-d标志。

查看开放端口

一旦你有了一个设备的 IP 地址,你经常想看看哪些端口是开放的。这也适用于服务器,毕竟服务器只是位于互联网上某个 IP 地址的设备,与本地计算机、智能手机或物联网设备没有什么不同。这可能会派上用场的情况包括

  • 根据开放端口判断网络上的设备类型

  • 寻找可能被黑客利用的开放端口

  • 找到一个可以在浏览器中访问的开放端口,或者通过其他方式进行设备交互

因为我们之前安装了nmap,我假设你已经安装了它。

扫描设备开放端口的最常见方法是简单地使用 nmap,后跟要扫描的设备的 IP 地址。例如,使用前面的提示,我能够发现我的酒店的路由器的 ip 地址是 192 . 168 . 1 . 1;然后,我将使用以下命令来查找开放端口:

nmap 192.168.1.1

在我的例子中,输出如下:

Host is up (0.82s latency).
Not shown: 999 closed ports
PORT   STATE SERVICE
80/tcp open  http

Note

nmap获得这种输出依赖于设备实际上位于您输入的 IP 上。可能192.168.1.1不是您网络上的任何设备。

它显示端口 80 是打开的;这是基本的 http 端口,基于 web 的界面在此为路由器的设置面板提供服务。

您可能希望检查您自己的计算机上打开了哪些端口;你可能会惊讶于你的发现:

nmap localhost

需要指出的是,默认情况下,nmap 仅扫描指定设备上 1000 个最常用的端口。当服务器或设备想要谨慎时,可以使用不太流行的端口。如果你真的想扫描所有可能的端口,你应该使用-p-标志,例如:

nmap -p- localhost

这将扫描所有 65535 个端口,也就是说,是默认端口的 65 倍以上,因此需要很长时间才能完成。

同样的方法也可以用在网址上,例如:

nmap -p- example.com

这将为 example.com 返回服务器上开放的端口。在撰写本文时,只有端口 80 和 443 是开放的——端口 80 用于 http 流量,端口 443 用于 https。稍后,我将列出一些最常见的端口及其最可能的用途。牢记“最有可能”这句话;没有什么可以阻止服务器使用一个通常用于一件事的端口来做另一件事。一些最常用的端口如表 7-1 所示。

有时,有人可能会在意外的端口上运行服务,例如,在端口 80 而不是端口 22 上运行 ssh,以破坏不允许 SSH 的限制性网络策略。防火墙阻止端口 22,试图阻止在网络上使用 ssh,但是如果服务器侦听端口 80(通常用于 web 流量),这种阻止方法就会失效。

表 7-1

通常易受攻击的端口

|

通道数

|

多畜共牧

|
| --- | --- |
| Eighty | 超文本传送协议(Hyper Text Transport Protocol 的缩写) |
| Four hundred and forty-three | 安全超文本传输协议 |
| Twenty-one | 文件传送协议 |
| Twenty-two | 嘘 |
| Twenty-five | 简单邮件传输协议 |
| One hundred and thirty-five | Windows RCP |
| One hundred and thirty-seven | 网络基本输入输出系统(Network Basic Input / Output System) |
| Three thousand three hundred and six | 关系型数据库 |
| Three thousand three hundred and eighty-nine | 远端桌面协定 |

在非默认端口上运行服务的另一个常见用途是避免利用 bot,这些 bot 可能会使用这里使用的扫描技术。例如,假设有人正在大规模扫描 IP 地址,以查找运行在默认端口 3306 上的 MySQL 实例;在端口 7777 上运行服务的服务器将不会被检测到。尽管像 MySQL 这样的东西,最好的策略是对公众完全关闭端口,只对需要它的内部应用开放。对于 SSH 之类的东西,您可能没有完全关闭端口的选项。正是因为这个原因,SSH 密钥认证比密码认证更受推荐,因为它使得暴力攻击几乎不可能。

如果您想查看一个更完整的列表,您可以解析列出了nmap已知的所有服务的/usr/share/nmap/文件。列表太长,没有用,所以您可能会发现删除所有标记为未知的条目是有用的:

cat /usr/share/nmap/nmap-services | grep -v unknown

即使在删除所有未知条目后,我们仍然得到超过 12,000 个结果。我建议颠倒线路,从编号较低的端口开始。你可以通过将前面的命令输入tac ( cat命令,行颠倒)来实现:

cat /usr/share/nmap/nmap-services \
  | grep -v unknown \
  | tac

这样,您可以从端口 1 开始向上滚动。或者,你可以通过管道将结果输入到'less',该功能在第一章中探讨,通过简单的滚动来查看结果。

设备和端口

如果您想扫描本地网络上的所有设备,并扫描这些设备上的开放端口,您可以将前面的两个提示合并到一个命令中。

这既可以用简单但缓慢的方法,也可以用快速的方法。

简单但缓慢

简单但缓慢的方法是,通过在 IP 范围而不是 IP 上运行nmap,在一个步骤中简单地对整个过程使用 nmap。这意味着将对指定范围内的所有 IP 尝试 nmap 如果您想扫描所有端口而不是 1000 个最常用的端口,只需添加-p-:

sudo nmap 192.168.1.0/24

Note

根据您的网络,这种方法可能会非常慢。

快速方法

更快的方法是使用 arp-scan 获取 IP,grep 提取 IP,最后使用xargsnmap对每个 IP 执行扫描。看起来是这样的:

sudo arp-scan --localnet \
  | grep -o \
    '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' \
  | xargs nmap

操作系统检测

如果您从结果中发现一些有趣的机器 IP 地址,您可以让nmap尝试猜测机器上运行的操作系统:

sudo nmap -O <ip-address>

如果您想检测使用上一节中的脚本扫描的每个设备的操作系统,您可能需要使用--osscan-limit来将操作系统检测扫描限制在有希望的目标上。或者如果你想让nmap更积极地猜测操作系统并显示最接近的匹配,使用--osscan-guess

用 masscan 扫描互联网

Masscan 是一款互联网规模的端口扫描器,适用于互联网或内部网络的大规模调查。虽然默认传输速率仅为 100 包/秒,但它可以选择高达 2500 万包/秒,这一速率足以在 3 分钟内扫描一个端口的互联网。

—masscan 手册页

Note

nmap一样,如果您想获得最新的特性(例如- top-ports flag ),您将希望从源代码构建masscan,尽管在大多数包管理器中都有一个旧版本。你可以在 www.github.com/robertdavidgraham/masscan 找到出处。

Masscan 是一个与nmap非常相似的工具,但它是后来发布的,能够以更快的速度扫描端口。在这两者之间切换很容易,因为masscan使用了与nmap兼容的语法。您甚至可以通过运行以下命令获得masscannmap之间相似特性的列表

masscan --nmap

虽然masscannmap快得多,但它的功能较少,也不太准确。通常masscan将用于初始侦察以寻找目标,一旦目标被选定,nmap将用于更大的准确性和细节。

当使用masscan时,您可能会注意到它的运行速度比手册页中描述的最大速度慢得多。这是因为还有其他几个限制masscan运行速度的因素,包括你的路由器上传和下载流量的速率。

也就是说,我们可以运行一个相当于nmap的脚本来进行比较:

time sudo masscan --top-ports 192.168.1.0/24

完成后,尝试nmap中的相同操作:

time sudo nmap 192.168.1.0/24

您会发现masscan运行速度明显更快,因为它在发送下一个请求之前不等待响应,尽管一旦发现设备,它仍然必须扫描每个端口以找到哪些端口是打开的。

正如描述中提到的,默认速度是每秒 100 个包,尽管可以一直提高到每秒 2500 万个包。该速率将受到网络和设备处理能力的限制。如果你想改变速率,使用--rate标志,例如:

sudo masscan -p 22 --rate 1000 192.168.1.0/24

当扫描公共范围时,要小心,因为向非常大范围的 IP 发送大量的无限制信息可能会触发您的互联网服务提供商的危险信号。可能更好的方法是 SSH 到一个便宜的服务器上,然后从那里高速测试大型扫描。

使用 nmap 运行脚本

除了扫描端口和检测操作系统,nmap还通过脚本模块提供高级功能。默认情况下,程序附带了很多这样的脚本,还可以从头开始安装或编写其他脚本。要获得nmap附带的脚本的完整列表,请查看usr/share/nmap/scripts文件夹:

ls /usr/share/nmap/scripts

在撰写本文时,默认情况下,nmap附带了超过 600 个预先编写好的脚本。

Note

apt-get或其他包管理系统获得的版本可能不是最新的,因为nmap仍然是一个非常活跃的项目。您可以在 www.github.com/nmap/nmap 找到最新版本。

要使用脚本,只需像下面这样传递带有--script标志的脚本:

nmap --script http-headers example.com

在这个例子中,我们使用了一个脚本来获取 example.com 的 http-headers;您的结果应该包括端口 80 和 443 的报头,如图 7-2 所示。

img/494886_1_En_7_Fig2_HTML.jpg

图 7-2

http-headers nmap 脚本中的标头信息

traceroute 脚本

一些像前面提到的脚本可以直接运行。其他选项可能需要与其他选项结合使用。例如,traceroute-geolocation处理来自--traceroute标志的数据。所以使用这个脚本需要:

sudo nmap --traceroute \
  --script traceroute-geolocation example.com

--traceroute标志用于跟踪所有跳或中间路由器;结合traceroute-geolocation,我们可以得到沿途每个路由器的地理位置。图 7-3 显示了使用--traceroute标志的结果示例。

img/494886_1_En_7_Fig3_HTML.jpg

图 7-3

使用 nmap - traceroute 查看服务器的位置

http-enum 脚本

编写http-enum脚本是为了测试网站的几个路径,以检测可能提示服务器上正在运行什么应用或内容管理系统的信息。

sudo nmap --script http-enum example.com

http-enum也是一个可以传递参数的脚本示例。如果您希望脚本使用一个基本路径运行,例如,example.com/blog而不是website.com,您可以这样做

sudo nmap --script http-enum --script-args \
  http-enum.basepath='blog/' example.com

为 nmap 编写自己的脚本

nmap附带了许多有用的脚本,这些脚本对于使用它进行端口扫描功能的大多数人来说是相对陌生的。更鲜为人知的是,您实际上可以通过编写 NSE 文件并将其放在 scripts 文件夹中来创建自己的脚本。

NSE 代表 Nmap 脚本引擎,是一种特定于领域的语言,构建在 Lua 编程语言之上。如前一节所述,脚本可以用于各种用途,包括

  • 网络发现

  • 版本/操作系统检测

  • 漏洞检测

  • 后门检测

  • 漏洞利用

每个 NSE 在一个文件中包含三个部分:

  • 页眉

  • 规则

  • 行动

头部分通常包含一个描述并导入任何需要的库。一个非常简单的例子是

-- Header --
local shortport = require "shortport"

前面的脚本导入了 shortport 库,该库可用于确定端口是否属于服务类型。标题之后是规则部分。我们的示例应用将使用 shortport 库来检查端口是否是 http:

-- Rule --
portrule = shortport.http

接下来是剧本的动作部分。我们将告诉脚本在端口是 http 常用端口的情况下应该做什么:

-- Action --
action = function(host, port)
      return "Hello World!"
end

写完这三节,保存你的脚本,另存为/usr/share/nmap/scripts/testing.nse。然后在网站上运行以下内容:

sudo nmap --script testing <website.com>

如果您已经正确地复制并运行了脚本,您应该会在任何找到的 http 端口下看到一个子部分,如图 7-4 所示。

img/494886_1_En_7_Fig4_HTML.jpg

图 7-4

示例脚本的输出

我们的“hello world”NSE 脚本不是特别有用,但它为您提供了 NSE 脚本的三个主要部分的概要(标题、规则、动作)。如果你想尝试制作一个高级的 NSE 脚本,看看/usr/share/nmap/scripts中的其他预构建脚本;这些为构建您自己的脚本提供了很好的示例或起点。

wireshark/tshar

另一个值得了解的工具是 Wireshark,我们不会在这里深入讨论。这是一个用于数据包分析的全功能 GUI 应用。它允许您捕获和分析网络上的流量。Wireshark 有一个面向终端的版本叫做tshark。大多数包管理器上都有这两个版本。如果您想要 Wireshark 的体验,但没有在机器上访问 GUI 的权限,您也可以查看社区项目termshark,它在终端中模拟 Wireshark 的 UI。

Wireshark 通常用于信息安全、网络质量测试和网络使用软件的质量保证。

虽然arp-scannmap是查找网络设备最简单的工具,但 Wireshark 在查找可能隐藏的设备方面实际上更强大。例如,如果一个设备不响应任何请求,nmapmasscanarp-scanping将永远无法找到它,即使有 IP。但是,如果这些设备在某个时候想要使用网络,并且 Wireshark 正在进行记录,它们将会被发现,并且它们的存在会为人所知。

要查看使用tshark的所有流量,只需在没有任何选项的情况下运行它(需要 root 权限):

sudo tshark

根据您的网络,这将返回显示网络流量的快速滚动屏幕,类似于图 7-5 所示。

img/494886_1_En_7_Fig5_HTML.jpg

图 7-5

运行 tshark 时的输出示例

随着流量的快速移动,将输出保存到文件中通常更有用:

sudo tshark > /tmp/output.txt

该命令将一直运行,直到您按下“ctrl+c”取消。运行的时间越长,样本量就越大。稍后可以解析该文件以提取更具体的细节,并按照您自己的速度进行分析。

如果您想更具体地了解所记录的数据包,tshark有各种各样的过滤器,例如,如果我们想查看特定的设备:

sudo tshark host <ip-address>

如果您要解析结果来查找单个设备,这将节省您大量的时间和精力。您还可以按流量类型进行过滤,例如,仅显示 http 流量:

sudo tshark -Y http

您可以使用以下命令显示 http 请求的完整路径

sudo tshark -Y http.request.full_uri

对于tshark和 GUI 等价物Wireshark,有各种各样的过滤器。我们不会深入研究所有这些工具,但如果您想分析本地网络流量,这是一个值得研究的强大工具。另外,在 GUI 版本中,Wireshark 是主版本。这是一个非常有用的工具,有很多关于如何使用它的书。

更多网络工具

到目前为止概述的工具经常会派上用场,但是它们只是 Linux 上可用的网络工具的一小部分。表 7-2 是一个更长的 Linux 网络工具列表,你可以更深入地研究。

Note

我们在列表中包括了几个不推荐使用的实用程序。虽然不再对它们进行维护,但它们仍然在旧系统上广泛使用,或者由继续使用它们的系统管理员使用。出于这个原因,它们是值得注意的,尽管我们会确保列出最新的替代方案。

表 7-2

网络实用程序

|

通道数

|

多畜共牧

|
| --- | --- |
| 挖苦 | 获取域信息 |
| 显示网络连接 | 网络统计数据(已弃用) |
| 命令 | 列出系统网络接口(已弃用) |
| 阿尔普 | 使用 ARP 缓存(不推荐) |
| 途径 | 显示/操作 IP 路由表(已弃用) |
| 互联网协议(Internet Protocol 的缩写) | 显示/操作路由、网络设备、接口和隧道 |
| 悬浮物 | 套接字统计 |
| ngrep | 就像grep但是对于网络流量 |
| 显示路由信息 | 查找数据包到达服务器的路由 |
| 平均拆卸时间(Mean Time of Remove) | 网络诊断工具 |
| (美国)北卡罗来纳州 | “ncat”的缩写,类似于cat,但用于网络数据。也可用作其他程序的网络接口模块 |
| 神经原纤维紊乱 | 用于包过滤和分类的网络工具 |
| 防火墙 | 管理防火墙设置(已弃用) |
| sysctl | 在运行时配置内核参数(一些与网络相关,如套接字缓冲区大小 |
| ethtool | 分析以太网连接 |
| 谁是 | 获取域名的 whois 信息 |
| lsof | 查找哪些程序正在使用哪些端口 |
| 平 | 与 ping 类似,但有更多的方法和选项 |
| 惊呆 | “窝猫”的简称,像nc ( 网猫)但是有更多的特性 |

挖苦

Dig 是一个 DNS 查找工具。如果您的系统上没有安装它,您可以在基于 Debian 的软件包管理器上的dnsutils和 Fedora、CentOS 和 Arch 上的bind-utils中找到它。

Dig 的使用方法是将一个 web 域作为参数传递给它,它将返回网站上的 DNS 信息。如果没有选项,来自dig的信息会有些混乱并且缺少条目。我们建议使用选项+noall+answer:

dig +noall +answer

Dig 应该返回该域的所有 DNS 条目。我们在图 7-6 中的例子包括一个对 example.com 的查询和另一个对 yahoo.com 的查询。我们包含了第二个查询来展示一个域有多个 A 记录时的输出示例。

img/494886_1_En_7_Fig6_HTML.jpg

图 7-6

对 example.com 和 yahoo.com 的质疑

Netstat(已弃用)

Netstat 是一个多用途实用程序,用于检查网络连接、路由表、网络接口统计和其他网络诊断。虽然您可能仍然会看到对netstat的引用,而且它确实有效,但是它已经被弃用了。

由于netstat已被弃用,建议您使用替代它的实用程序,包括digipss

ifconfig(已弃用)

netstat一样,实用程序ifconfig已经被弃用。尽管如此,您可能会发现它存在于许多机器上,并可能在脚本中使用。这是一个使用网络接口的工具。建议您使用iproute2包附带的ip命令。

如果您还记得本章前面的内容,我们使用了命令ip a来找出网络 IP 范围。在ip成为这方面的首选工具之前,运行ifconfig也是用来做同样的事情。ifconfig还能够与接口交互,例如,启用或禁用接口(假设您的以太网接口名为 eth0):

ifconfig eth0 up

现在同样的事情可以通过使用ip来完成

ip link set eth0 up

arp(已弃用)

arp代表地址解析协议,用于将设备的 MAC 地址(全球唯一标识号)映射到 IP。计算机包含一个 ARP 表,映射映射和 IP 地址。要查看表中的所有条目,请运行以下命令:

arp -a

由于arp现在已被弃用,建议您使用ip来实现相同的功能。与前面的ip函数等价的是

ip n

其中n是邻居的简称。有关更多高级功能,请参见arpip的手册页。

路线(已弃用)

route命令用于显示/操作 IP 路由表。带有''的最简单命令是不带任何选项或参数运行它,这将返回 IP 路由表。与ip等效的命令如下:

ip r

其中r代表路线。

互联网协议(Internet Protocol 的缩写)

如前所述,ip实用程序是包括ifconfigroute在内的几个实用程序的替代品,它包含在iproute2包中。运行ip route或简称ip r可以看到路线。还有另外的路由命令用于添加或删除,如ip route del unreachable 10.1.0.0/24,其中“不可到达”是路由名称,“10.1.0.0/24”是路由。

悬浮物

ss是一个监控套接字使用的实用程序。名字中的首字母代表套接字统计。如果没有安装ss,你可以在iproute2包含的大多数包管理器中找到它。当独立运行ss时,您将得到一个所有已连接插座的长列表,如图 7-7 所示。为了使读取输出更易于管理,您可以通过运行ss | less将结果传输到less

img/494886_1_En_7_Fig7_HTML.jpg

图 7-7

运行ss返回的套接字统计示例

理解默认情况下所有这些套接字是什么有点困难。为了使事情变得简单,您可以添加标志-p,它将告诉您每个套接字连接的进程名称和 ID。这允许您将套接字连接与机器上运行的进程相关联。

ngrep

ngrep是一个网络实用程序,它提供了类似于grep的解析网络数据的能力。给定一些要监听的特定文本,ngrep将监控网络流量并报告任何匹配的连接数据。例如,我们将查看访问 example.com 产生的流量;首先,我们将告诉ngrep监听字符串“example ”,如下所示:

sudo ngrep example

ngrep现在正在解析网络流量中的字符串“example”。如果您在 web 浏览器中查看 example.com,应该会看到匹配结果。为了演示 https 的重要性,让我们使用curl向示例发送一些未加密的数据。在ngrep仍然运行的情况下打开第二个终端,并运行以下命令:

curl --data "user=name&password=secret" example.com

您应该在运行ngrep的窗口中看到该请求。如果您仔细阅读文本,您应该能够看到用户和密码字段,如图 7-8 所示。

img/494886_1_En_7_Fig8_HTML.jpg

图 7-8

使用 ngrep 记录的未加密数据

如果运行相同的命令,但指定 https,如下所示

curl --data "user=name&password=secret" https://example.com

您仍然可以看到请求,但是看不到发送的数据,甚至看不到访问的具体网站。

显示路由信息

traceroute实用程序允许您向主机发送数据包,并获得到达主机的路由的详细信息。这听起来可能很熟悉,因为在第七章中,我们使用了一个“traceroute”NES 脚本来查看流量从我们的本地机器到一个网站的跳数。如果我们运行“traceroute”实用程序,它将作为一个独立的实用程序提供此功能

traceroute example.com

我们将看到我们的数据包在到达最终目的地之前所经过的所有机器的 IP 地址。这从本地路由器开始,到实际网站的 IP 地址结束,如图 7-9 所示。

img/494886_1_En_7_Fig9_HTML.jpg

图 7-9

使用 traceroute 显示通往 example.com 的路线

平均拆卸时间(Mean Time of Remove)

mtr实用程序是一个结合了pingtraceroute的网络诊断工具。名称mtr实际上是“我的跟踪路线”的缩写mtr不是像traceroute那样发送一组数据包,而是在接收到前一个数据包后继续发送额外的数据包(类似于ping)。如图 7-10 所示,一个更新显示屏显示关于定时的详细信息。如果你的连接有问题,mtr可以帮助你了解问题出在哪里。

img/494886_1_En_7_Fig10_HTML.jpg

图 7-10

不断更新港铁显示的 example.com 路线数据

(美国)北卡罗来纳州

nc是 network cat 的简称,名字灵感来自cat实用程序。nc是一个强大的工具,它提供了通过 TCP 或 UDP 连接和监听连接的能力。这意味着它甚至可以用于在两台机器之间打开一个聊天或文件传输的通道(尽管 SSH 等其他工具是首选)。

nc通常被称为“网络的瑞士军刀”,可用于多种网络任务,包括端口扫描、服务网站或欺骗报头。虽然许多用例有更好的选项,如用于端口扫描的nmap,但它对于一些简单的事情仍然有用,如抓取报头或伪造自己的报头。

要伪造您自己的标题,请运行

nc example.com 80

然后,您将能够添加额外的文本。您可以基于以下示例创建欺骗标头:

GET / HTTP/1.1
Host: example
Referrer: duckduckgo.com
User-Agent: fake-browser

输入标题后,按两次回车键,你将使用伪造的标题获取网站。您将得到一个包含站点标题信息的响应。

NFL–不可战胜

nftables是用于包过滤和分类的 nftables 框架的管理工具。虽然你可以在包管理器上找到这个名字下的nftables,但是运行它的命令实际上是nftnftables中的“nf”代表“网络过滤器”,它们用于过滤网络流量。可以是传出的也可以是传入的。例如,您可能不允许特定 IP 的传出流量,或者不允许特定端口的传入流量。nftables通过跟踪一系列系统范围的规则来工作,这些规则可以添加或删除,并在流量过滤过程中使用。

iptables(已弃用)

iptables工具已经被弃用,取而代之的是nftablesiptables是基于规则的,但缺乏nftables所包含的功能,比如用一个规则同时针对 ipv4 和 ipv6 数据包。

sysctl

sysctl用于在运行时配置内核参数。这不一定仅仅是网络问题,尽管有些问题是如套接字大小。对于经常发送和接收大文件的服务器,可以这样做,因为调整套接字缓冲区大小可以提高特定用例的网络性能。

ethtool

ethtool实用程序是以太网工具的缩写,可用于获取有关以太网连接的详细信息。这包括数据传输本身和物理硬件。要查看以太网接口的信息,您首先需要获得它的名称。这可以通过运行

ip a

记录您的以太网接口的名称(可能包含一个“e”),并将其作为参数传递给ethtool:

ethtool enp0s25

在我的例子中,以太网接口名称是“enp0s25 ”,但您的接口可能会不同。以太网接口最常见的名称之一是“eth0”。当你使用接口作为ethtool的参数时,你应该得到关于硬件的信息(即使你没有主动使用以太网),如图 7-11 所示。

img/494886_1_En_7_Fig11_HTML.jpg

图 7-11

ethtool输出的以太网接口信息

谁是

whois是一个用于检索注册服务商提供的网站所有权信息的实用程序。只需提供一个域作为参数就可以使用它。例如,运行以下命令应该会返回如图 7-12 所示的所有权和联系信息:

img/494886_1_En_7_Fig12_HTML.jpg

图 7-12

yahoo.com 的 whois 信息

whois yahoo.com

lsof

lsof代表“打开文件列表”;默认情况下,它会返回一个很长的列表,其中包括系统中所有打开的文件。在网络方面,你想知道的关于lsof的主要选项是-i旗帜。-i标志告诉lsof寻找 IP 套接字。添加-P来连接端口也是有用的。要演示,请尝试跑步

lsof -i -P

这将返回一个本地端口列表,这些端口连接到远程服务器上的端口以及与所述连接相关的程序。预期输出的示例如图 7-13 所示。

img/494886_1_En_7_Fig13_HTML.jpg

图 7-13

来自lsof -i -P的示例输出

hping是一个攻击性的安全网络工具,它的名字来源于ping。像ping一样,它通过网络向目的地发送数据包,但它有高级选项,允许定制数据包,为 TCP 和 UDP 指定目的地端口和假冒的源 IP。此外,它有一些内置的方法,如--flood选项,可用于类似 DDOS 的攻击,如 SYN flood 攻击。

当前版本是 3,集成在大多数包管理器的命令和名称中:

sudo apt-get install hping3

在 Kali Linux 这样的攻击性安全操作系统上,你会发现默认安装了hping。后面显示了 SYN flood 攻击的一个示例。SYN flood 攻击包括在没有完成握手的情况下打开几个连接。它可以用来测试您的网络是否免受这些攻击;以下是一个执行 SYN flood 攻击的示例,用于测试网络中目标设备使用的 IP 交换机:

hping3 --rand-source -S -d 500 -p 21 --flood 127.168.1.110

前面的命令结合了几个选项。第一个--rand-source告诉hping伪造一个随机的 IP 地址作为其来源。然后-S标志指定 SYN 包网络,-d 500是包的大小,-p 21是目的端口,最后--flood开启发送许多请求的洪泛模式。

惊呆

socat类似于nc (netcat),但具有更高级的功能。也像 netcat 一样,它的名字取自cat,代表“socket cat”它可以在大多数包管理器上找到,名为socat。用 netcat 可以做的任何事情用socat都是可能的,但是它也有一些额外的特性,比如单个端口上的多个客户端和使用 UDP 的选项。

摘要

在本章中,我们学习了一些网络技术,尤其是与端口扫描相关的技术。我们还简要介绍了一些流行的网络工具,这些工具可用于通过分析、配置和打开通信通道来处理网络。

八、系统监控

在维护 Linux 系统时,您会发现自己想做的另一个常见任务是监视系统进程、内存和网络使用等情况。这有助于您衡量您正在利用多少容量。了解哪些资源可能不足,可以让您深入了解如何降低系统负载,或者应该增加哪些资源。在这一章中,我们将看看进行不同类型监控的工具。

顶端

每当系统或设备遇到性能问题时,首先要做的事情之一就是检查哪些程序正在运行以及它们使用了多少系统资源。简单的方法是安装在大多数 Linux 系统上的top。运行它将列出所有当前正在运行的进程。通过按下z并输入目标进程的进程 ID (PID ),您可以在不离开top的情况下快速终止一个进程。

如果你发现自己经常使用top,你可以考虑安装htop。htop 是top的增强版,具有改进的可视化界面,并显示了流程的完整路径。

如果你更喜欢使用像top这样的内置工具,或者你在一台不能安装htop的机器上,你实际上可以使用键盘命令的组合来获得看起来几乎和htop一样的东西,在某些方面甚至更好。

在顶部打开的情况下,按下zxcVm1t0(作为一个序列,而不是同时),你将得到看起来如图 8-1 所示的东西。

img/494886_1_En_8_Fig1_HTML.jpg

图 8-1

运行后顶部zxcVm1t0

我们可以通过按A进入交替显示模式来更进一步;这将屏幕分成四个独立的字段组。一旦进入交替显示模式,您可以通过按下g在字段组之间切换,这将提示您输入字段编号。如果你在每个字段组之间切换并输入zxcVm1t0,你将得到一个整洁的多字段显示,如图 8-2 所示。

img/494886_1_En_8_Fig2_HTML.jpg

图 8-2

风格多样的多标签顶部

当然,你可能认为这看起来很棒,但是每次打开top都要运行很多步骤。要保存这些设置,您只需按下W即可。这将保存您在top中的当前配置,当您重新打开它时,它看起来会是一样的。

如果您想回到默认值,只需删除创建的配置文件;默认应该是~/.toprc

类似 Top 的程序

有几个受top启发的程序,或者监控top中没有的系统的某些特定方面,或者以不同的布局提供相同的信息。在这一部分,我们将回顾一些名字和格式都来自top的流行节目。

快上来

这是一个非常类似于top的程序,与top相比,它默认提供了一个改进的图形界面,如图 8-3 所示。它不是默认安装在大多数发行版上的,但是可以通过许多包管理系统获得,比如 Debian/Ubuntu 上的apt

img/494886_1_En_8_Fig3_HTML.jpg

图 8-3

htop 以默认设置运行

在顶上

这是一个类似于top的高级系统和过程监视器,但适用于长期运行的分析。它提供了将系统监控结果作为日志文件输出以供分析的能力。如图 8-4 所示,它有一个简单的循环,但提供了tophtop中没有的导出为日志的功能。

默认情况下,它没有预装在大多数发行版中,但是它在包括 Debian 和 RHEL 在内的软件包管理系统中广泛存在。

img/494886_1_En_8_Fig4_HTML.jpg

图 8-4

使用默认设置运行

默认情况下,atop中的日志文件将被保存到文件夹/var/log/atop/中。这些日志文件可以通过用如下所示的-r标志传递给atop来读取,除了用您想要打开的日志的文件名替换atop_20200310:

atop -r /var/log/atop/atop_20200310

iftop

这是受top的启发,但专门监控网络使用,而不是 CPU 或内存使用。当给定一个网络接口时,它将侦听所有传入和传出的流量,并提供诸如起始端口和哪些外部服务器使用网络最多之类的信息。由于访问网络接口,使用iftop需要sudo权限。

默认情况下,它不会安装在大多数发行版上,但是可以广泛使用。我们将在本章后面的监控网络流量部分进一步研究这个程序。

恩通普

一个比iftop更高级的选择是ntop,它也监控网络流量。然而,与这里的其他程序不同,它是一个基于 GUI 的系统,可以通过浏览器访问。虽然这使得它不那么轻量级,但它确实提供了一些更高级的可视化,如图 8-5 所示。

不像到目前为止提到的其他程序,你不会在包管理器上找到带有标准名称的ntop。相反,你会发现它的名字是ntopng:

img/494886_1_En_8_Fig5_HTML.jpg

图 8-5

ntop 中的应用页面

sudo apt-get install ntopng

一旦安装并启动,它将在端口 3000 上运行,并提供几个基于网络使用的统计和可视化管理页面。

iotop

这是另一个受top启发的程序,它专注于文件系统的读写使用。线程按磁盘读取和磁盘写入使用的顺序列出。这个包在基于 Debian 和基于 RHEL 的系统上都广泛可用。像iftop使用iotop将需要sudo权限才能运行。iotop包含每个进程的基本信息,如用户和命令,以及磁盘写入和IO>(这是一个进程花费在 IO 上的时间百分比的度量)。iotop动作示例见图 8-6 。

img/494886_1_En_8_Fig6_HTML.jpg

图 8-6

io 以默认设置运行

slabtop

这是一个用于监控内核 slab 缓存信息的顶级程序,如图 8-7 所示。它主要对那些需要担心内核级问题的人有好处。

iftopiotop一样,使用slabtop将需要sudo权限。

img/494886_1_En_8_Fig7_HTML.jpg

图 8-7

slabtop 以默认设置运行

查看流程的更多信息

topatop这样列出的程序对于查看过程来说是很棒的。也可以使用ps手动查询所有正在运行的任务,然后通过管道将它们传递给其他程序。当单独运行ps时,您将获得当前终端会话中运行的进程列表。该列表可能很小,仅包括bashps工艺本身,如图 8-8 所示。

img/494886_1_En_8_Fig8_HTML.jpg

图 8-8

在新的终端中运行 ps

但是,如果您的终端已经打开了一段时间,并且您已经对一些进程进行了后台处理,您可能会看到更多。我们可以手动创建一个后台流程,通过以下步骤进行演示:

  1. 运行睡眠 500 秒,并在后台运行进程sleep 500 &

  2. 运行ps并观察新流程。

  3. 从 sleep 命令中取出 PID,并使用 kill kill 123结束该过程。

  4. 再次运行ps并观察差异。

这些步骤应该导致一个额外的过程,由ps返回sleep,如图 8-9 所示。

img/494886_1_En_8_Fig9_HTML.jpg

图 8-9

有后台进程的 ps

当然,大多数情况下,您会希望看到机器上运行的所有进程,而不仅仅是当前终端会话中的进程。要获得所有正在运行的进程,您可以运行ps -eps -ef,不同之处在于添加的f显示了更多细节。详细的ps视图如图 8-10 所示。

img/494886_1_En_8_Fig10_HTML.jpg

图 8-10

运行 ps -ef 查看系统范围的进程

虽然我们可以使用grep来按用户解析进程,但是ps提供了一些内置的标志来简化这一过程,例如,ps -u philip或者带有ps --pid 123的特定 PID。这两者都可以和-e一起使用来获得更多的细节。

终止一个进程

经常与ps结合使用的命令有killkillall。运行ps时,我们看到有一列显示 PID,是进程 ID 的简称。如果一个进程运行不正常、挂起,或者我们只想结束它,一种方法是使用kill命令。只需将 PID 传递给它,例如,假设 PID 为 123:

kill 123

如果你想通过名字而不是 PID 来匹配进程,你可以使用killall,例如,如果 Firefox 被冻结,我们想强制退出:

killall firefox

另一个与killall非常相似的选项是pkillpkill也可以通过名称匹配服务,但是会包含更多的匹配,不像killall如果使用-i进行模式匹配,它不需要精确匹配。例如,如果我们只是传入“Firef ”,我们仍然会杀死进程:

pkill -i Firef

同样风格的命令可以和pgrep一起使用,在不杀死进程的情况下找到进程。例如,如果我们在 Firefox 打开的情况下运行以下命令,我们将获得与该程序相关联的 PID 列表:

pgrep -i Firef

为了让前面的命令更有用一点,可以添加-l标志来获取每个进程的确切程序名,或者添加-a来获取更多信息。

用 pstree 可视化流程树

要记住的另一个概念是,流程存在于一个层次结构中,有些流程有父流程和子流程;这可以在图 8-11 中看到。例如,当您在终端中运行ps时,它是终端进程的子进程。如果我们运行sleep 500然后关闭终端,子进程sleep 500将随着父进程的终止而自动终止。然而,情况并非总是如此;在某些情况下,子进程将在父进程关闭后继续运行,并继承父进程的父进程。

我们的终端进程本身是另一个进程的子进程,可能systemd取决于您的 Linux 发行版。因此,如果一个进程在关闭终端后继续运行,在我们的例子中,新的父进程将是systemd

可视化这种关系的一个很好的工具是pstree,它可以用来显示我们系统上运行的所有进程,就像ps一样,但是以可视化的方式显示进程之间的父/子关系。尝试用-p标志运行它,这将确保进程 ID 也被返回。它应该返回一个很长的进程列表,所有这些进程都源自左边 PID 为 1 的单个进程。

img/494886_1_En_8_Fig11_HTML.jpg

图 8-11

使用-p 标志运行 pstree 以显示进程 id

正如我们在终端中运行命令时提到的,它实际上是终端进程的一个子进程。要演示这一点,请运行以下命令:

sleep 500 &
pstree -p | grep -A 5 -B 5 pstree

这将在后台创建一个休眠进程,获取pstree,然后为pstree进程执行 greps,这样我们就可以找到当前的终端进程。-A旗代表比对手高出五行,-B代表比对手低五行。结果应该类似于图 8-12 所示。

img/494886_1_En_8_Fig12_HTML.jpg

图 8-12

点击 pstree 查看特定进程

注意以绿色突出显示的pstree流程及其下方的sleep流程。它们都源于 bash 过程,而 bash 过程本身又源于gnome-terminal

处理好价值

当使用top时,你可能已经注意到标有“NI”的列。这指的是“好的”价值观,这是 Linux 中的一个关键概念。每个进程都有一个很好的值-20 到 19。数字越小,进程在调度中的优先级越高。一种思考方式是,好的进程(例如, 10 个好值)在队列中等待,而不好的进程插在前面( -20 个好值),真正好的进程( 19 个好值)让其他进程插在队列的前面。当然,这是一种简化,因为 nice 值是相对于队列中其他值而言的。

如上所述,您可以在列NI下的top中查看流程的 nice 值。另一种方法是使用带有-o标志的ps,后跟您想要查看的列(包括 ni,例如:

ps ax -o pid,ni,cmd

这将返回所有运行进程的进程 ID、nice 值和命令,如图 8-13 所示。

img/494886_1_En_8_Fig13_HTML.jpg

图 8-13

用 ps 获取命令、PID 和 nice 值

请注意,在启动过程中启动的几个命令(我们可以知道,因为 PID 接近 1 )有一个很好的值-20,因为它们被认为是运行操作系统的关键。

您可能还会注意到一些标有-的进程(取决于您的操作系统);这些是系统级的进程,由一组不同的优先级控制(它们总是先运行)。在大多数情况下,您不需要担心这些底层流程。

其他优先系统

如前所述,一些流程由不同的优先级集控制。我们在用户空间中主要关心的正常进程由SCHED_OTHER控制。

其他主调度器SCHED_FIFOSCHED_RR用于需要在所有正常进程之前运行的实时进程。这两个调度器具有相同的优先级,但调度方式不同。FIFO 代表先进先出(如先来先服务,RR 代表循环法(轮流,直到流程完成)。

如果您不在内核级工作,您可能不需要处理这些调度程序。如果您想了解进程的实时和绝对优先级值,可以运行

ps -e -o class,rtprio,pri,nice,cmd

从输出中,您会发现几个进程比那些被列为-20 nice 值的进程具有更高的绝对优先级;这些都是实时过程。

更改好的值

现在你知道了 nice,你是如何使用它的?您可以使用renice命令更改任何正在运行的进程的 nice 值。通常,更改好的值不是一项常见的任务。然而,没有什么理由让你想这么做。比方说,您已经创建了一个自定义脚本,它通过压缩旧的日志文件并将其发送到长期存储服务来清理旧的日志文件。您可能希望为这个过程赋予一个很高的 nice 值,这样使用服务器的用户总是比备份过程具有更高的优先级,备份过程没有截止日期或紧迫性。

让我们创建一个流程来使用:

sleep 500&

获取返回的进程 ID(在我们的示例中是的 1234)并与renice一起使用:

renice -n 19 1234

现在,如果我们使用ps检查 nice 值,我们应该看到该值已经更新。

ps -o ni 1234

僵尸进程

在下一节中,我们将编译一个 C 程序来探索僵尸进程的概念。这有点技术性,关于僵尸进程的知识并不重要。如果您觉得这一部分太专业,请随意跳过。

本节将要求您安装 C 编译器和这里使用的库。它们都可以在基于 Debian 的系统上的build-essential包中获得。

sudo apt-get install build-essential

在查看进程时,另一个值得理解的概念是僵尸。僵尸进程是一个已经退出的子进程,但是还没有被它的父进程清除。大多数程序在退出后会很快移除其子进程,所以僵尸进程相当罕见。尽管名字邪恶,僵尸进程是相当无害的,不会对你的机器性能产生负面影响。

为了演示,我们将创建一个 C 程序来制作我们自己的僵尸进程。

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main () {

  // Create variable with type of process identification
  pid_t child_pid;

  // Fork main process creating a child
  child_pid = fork ();

  // Both main script and forked child run the code below the fork point

  // Child process will have a PID of 0 within script
  if (child_pid > 0) {
    // Only parent process runs this section
    sleep (500);
  }
  else {
    // Only forked child runs this section, exiting immediately
    exit (0);
  }

  return 0;
}

写完前面的 C 程序,另存为zombie.c。接下来,您需要通过运行以下命令来编译它

cc zombie.c -o zombie

一旦你成功编译了zombie,我们就可以演示僵尸进程是什么样子的了。运行可执行文件并在后台运行:

./zombie &

接下来,我们将使用前面的一些命令来查看该过程。不带选项的第一次运行ps。您应该会看到父进程zombie和子进程的条目,后面跟有<defunct>,如图 8-14 所示;这表明该进程处于僵死状态。

img/494886_1_En_8_Fig14_HTML.jpg

图 8-14

创建僵尸进程

如果你要运行top,你也会在右上角看到一个僵尸进程正在运行的提示,如图 8-15 所示。

img/494886_1_En_8_Fig15_HTML.jpg

图 8-15

在顶部查看僵尸数量

如前所述,僵尸进程是相当无害的,并且从技术上讲已经不运行了。因此,运行kill 7450(基于图 8-14 中的进程 ID)将无效。杀死僵尸进程的唯一方法是杀死它的父进程。

kill 7449

当然,如果你想让这个程序继续运行,这是一个问题。我们的建议是让僵尸进程自己处理,因为它们通常不会引起问题。

检查可用磁盘空间

服务器或嵌入式设备的另一个常见问题是磁盘空间不足。我遇到过一些这样的情况,由于一个程序在几个月的时间里无法压缩或删除旧的日志文件,导致一个停止工作的设备没有足够的空间来写入数据。

检查可用磁盘空间最简单的方法是使用实用程序df,它是“空闲空间”的缩写。要找到您的可用磁盘空间,请运行命令

df -h

前面的命令将返回包含每个分区信息的分区列表。其中一个分区将是您的系统使用的主分区。您可以通过查看“挂载于”列并找到值为“/”的那个来找到它。

接下来,您需要查看该分区的“大小”和“使用%”。这将告诉你有多少磁盘空间,以及目前使用的百分比。

关于df返回的列的完整列表,参见表 8-1 。这个表还包括可以用-i标志启用的 inodes used 列和用-T标志启用的 type 列。

注意我们在前面的例子中使用了-h标志;这代表“人类可读”如果没有-h标志,df仍然可以工作,但是以 KB 为单位显示可用空间,而不是将大量空间转换为 MB 或 GB。建议使用-h,除非您有特定的原因需要 KB 中的所有值。

表 8-1

df 命令返回的信息

|

圆柱

|

描述

|
| --- | --- |
| 文件系统 | 文件系统的名称 |
| 大小 | 分区的大小(默认情况下隐藏,用-h 显示) |
| 1K 块 | 以 1K 块为单位的系统大小(使用-h 时替换为大小) |
| 二手的 | 使用的空间量 |
| 有空的 | 可用空间量 |
| 使用% | 以百分比显示的已用空间量 |
| 安装在 | 分区的目录位置 |
| IUsed | 分区上使用的索引节点(默认情况下隐藏,使用-i 显示) |
| 类型 | 分区文件系统类型(默认情况下隐藏,用-T 显示) |

查找系统中最大的文件

如果您发现系统空间不足,您可能希望在系统中搜索大文件。这里有一个超过 100 米的例子:

sudo find / -xdev -type f -size +100M -exec ls -la {} \; \
  | sort -nk 5 \
  | tac

前面的命令假设您想要查看系统上的每个文件。如果您想只包含特定文件夹中的文件,您可以修改find命令的第一个参数,例如,假设我想只搜索用户 philip 的文件夹中的文件,那么我将使用

sudo find /home/username -xdev -type f \
  -size +100M -exec ls -la {} \; \
    | sort -nk 5 \
    | tac

如果您只想查找总容量超过 1gb 的文件和目录,您可以这样做

sudo du -ahx / | grep -E '\d*\.?\d*+G\s+'

Note

通过组合-size-printf标志,也可以用find获取和打印尺寸;但是,find 只显示以 KB 为单位的大小,与 GB 相比很难阅读。详见man find

监控设备网络使用

您可能想要检查的另一个统计数据是系统整体的网络使用情况,以及按进程或网络接口的细分情况。这在互联网接入受限或带宽昂贵的设备上非常有用,例如,通过 GSM SIM 卡连接的物联网设备甚至笔记本电脑。在这种情况下,使用过多数据的程序会非常昂贵。

即使您不在数据有限的系统上,查看哪些程序正在使用您的互联网连接也会很有用。如果你看到一些让你吃惊的事情,你可能想进一步调查。我用了几个不错的程序来进行网络监控,每个程序都略有不同。

bmon–监控每个网络接口

使用 bmon,您可以监控每个接口(例如,Wi-Fi、以太网)。这在前面描述的 GSM SIM 卡情况下非常好。想象一下,你有一台同时支持 Wi-Fi 和 5G 的设备。你可能不介意 Wi-Fi 接口上的高网络使用率,但会希望确保 5G 使用保持在一定水平以下。

在这种情况下,您可以编写软件来检测正在使用的互联网接口,并根据连接类型减少或增加数据使用。bmon通过分解每个接口上传输的数据量,为您提供了一种确保这些措施切实有效的方法。

默认情况下不会安装,但大多数软件包管理器上都有。当在终端运行bmon打开时,你会看到如图 8-16 所示的界面。如果您的终端窗口没有最大化,底部的绿色/红色图形可能会被隐藏。

img/494886_1_En_8_Fig16_HTML.jpg

图 8-16

运行 bmon

nethogs 按带宽使用列出程序

大多数时候,你不会对正在使用的接口感兴趣,而是想知道哪些程序使用了最多的带宽。为此安装并运行nethogs;你会看到如图 8-17 所示的界面。请记住,如果您关闭该程序,当您稍后打开它时,它将再次从头开始。为了清楚地了解一段时间内的使用情况,您需要打开nethogs并让它运行一段时间。几个小时甚至几天后再回来,您会更清楚哪些程序使用了最多的带宽。

img/494886_1_En_8_Fig17_HTML.jpg

图 8-17

运行网络猪

iftop

另一个选择是iftop,这是顶级家族的另一个项目。iftop让我们可以根据流量大小来监控哪些外部 IP 地址的通信量最大,而不是通过接口或应用进行监控。

启动iftop时,需要指定网络接口。如果您不知道您的网络接口,您可以通过运行

ip a

您将得到一个包含大量细节的接口列表;接口是左边的键值。在我这里,Wi-Fi 接口叫做wlp3s0,如图 8-18 。你通常可以分辨出哪个接口是 Wi-Fi,因为它会包含一个“w”。

img/494886_1_En_8_Fig18_HTML.jpg

图 8-18

ip a返回的 Wi-Fi 接口

一旦有了想要监控的接口,就用-i标志将其传递给iftop:

sudo iftop -i wlp3s0

这将产生一个外部 IP 地址列表以及正在上传和下载的数据量,如图 8-19 所示。

img/494886_1_En_8_Fig19_HTML.jpg

图 8-19

使用 iftop 监控 Wi-Fi

为了让事情变得更清楚,你可以按下s来隐藏左边的信号源(因为它们大部分是本地信号源)。然后按p显示始发端口。Port 比 source 有用得多,因为它让我们对原始程序有了更好的了解,并且如果我们想进一步研究某个连接,它还提供了一种更深入的方法。图 8-20 所示为用端口替换源的iftop界面。

img/494886_1_En_8_Fig20_HTML.jpg

图 8-20

在 iftop 中按传出端口查看流量

用于监控的其他程序

-嘘-嘘

另一个可以用来长时间监控系统使用情况的程序是sysstat,类似于atop,但更全面。与其检查系统的当前状态,不如让sysstat在后台运行,然后阅读每日报告。它的工作原理是每 10 分钟运行一次 cron 作业并记录系统数据。

默认情况下它可能是可用的,但是如果不是,您可以使用

sudo apt-get install sysstat

首先打开/etc/default/sysstat,确保下面一行设置为真;默认情况下,在 Ubuntu 上,它将被设置为 false:

ENABLED="true"

然后用systemctl启用它:

sudo systemctl enable --now sysstat

完成这些简单的步骤后,您的系统将开始在/var/log/sysstat文件夹中保存系统数据。将为该月的每一天创建一个新文件,例如,如果您从 26 日开始,该文件将是/var/log/sysstat/sa26。您可以通过运行以下命令来查看当天的数据

sar

一旦它运行了一段时间,sar将返回如图 8-21 所示的内容。

img/494886_1_En_8_Fig21_HTML.jpg

图 8-21

运行 sar

如上所述,这些统计数据保存在/var/log/sysstat文件夹中。如果您想查看之前监控的一天,用sar指定要打开的文件:

sar -f /var/log/sysstat/sa27

请注意,一旦您使用sysstat超过一个月,这些文件将开始被覆盖。如果您想将日志保存更长时间,您必须手动备份它们。

平均负载

平均负载是指正在运行或等待运行的线程的平均数量。有许多方法可以获得这些信息,最简单的方法是运行

uptime

这将返回系统运行的时间、登录的用户以及三个不同的平均负载值。这三个不同的值是 1 分钟、5 分钟和 15 分钟的平均值。使用这三个值,您可以了解负载是增加还是减少。

如果你现在已经经常使用top,你可以在顶行找到相同的三个负载平均值。

重要的是要记住,无论计算机有多少个 CPU,平均负载都是由队列中的线程来衡量的。在单 CPU 机器上平均负载为 2 比在有两个 CPU 的机器上平均负载为 3 要高。想象一下,每个线程都是一个在杂货店等待付款的人,每个 CPU 都是一个收银员。在不知道店内收银员人数的情况下,知道有多少人在排队并不一定有用。

要考虑的一个更有用的统计数据是平均负载除以 CPU。如果平均负载除以 CPU 数量大于 1,这可能表明您的系统过载。考虑一下前面探讨的友善的概念。如果一个 nice 值为 19 的进程正在运行,但是平均负载总是高于可用的 CPU,它可能永远不会结束执行,因为它一直允许进入该行的新进程首先运行。

根据一个传闻,当麻省理工学院的 IBM 7094 在 1973 年被关闭时,他们发现了一个低优先级的进程,该进程在 1967 年就已经提交,并且还没有运行。这正是所描述的队列一直存在的情况,因为进程的优先级低,所以它一直排队等待,总是让新的高优先级任务先运行。这个问题通常被称为资源匮乏。

Note

如果您忘记了一台机器上有多少个 CPU,您可以使用lscpu来查找标题为“CPU(s)”的行

用户

在上一节中,我们看到uptime返回的第三个值实际上是登录的用户。如果你最终看到了一个你没有预料到的数字,你可以使用whow获得更多关于当前登录用户的信息。如果你的系统有,w是首选,因为它是对who的重写,包含了更多的用户信息。简单地跑

w

您将获得用户列表以及他们正在使用的 TTY。如果用户使用多个 tty,它们会被多次列出。用户使用单个 TTY 的示例如图 8-22 所示。

img/494886_1_En_8_Fig22_HTML.jpg

图 8-22

使用 w 查看已登录的用户

图 8-23 显示了一个用户使用多 TTY ( 通过 tmux ,一个保持终端会话打开但后台的程序)的例子。

img/494886_1_En_8_Fig23_HTML.jpg

图 8-23

在几个 tmux 会话打开的情况下运行 w

日志文件夹

在监控或调试系统时,您需要注意系统日志文件夹。最好的地方之一是/var/log,这是存放各种日志的系统文件夹。导航到文件夹并查看文件:

cd /var/log
ls

根据正在运行的服务和系统运行的时间,您应该会在这里看到几个不同的文件和文件夹。我的日志文件夹的内容如图 8-24 所示。

img/494886_1_En_8_Fig24_HTML.jpg

图 8-24

/var/log 中的内容示例

如果你在 Ubuntu 这样的 Debian 系统上,主日志文件将会是/var/log/syslog。如果你在 CentOS 这样的非 Debian 系统上,你应该寻找/var/log/messages。我们会打开它

less /var/log/syslog

你会看到来自不同程序的各种信息。

在大多数系统上负责写这些日志的程序是rsyslogd。可以通过编辑/etc/rsyslog.conf文件进行定制。

Note

除了 syslog,另一个检查日志的好方法是 systemd 的journalctl;参见第十一章中的Journalctl部分。

其他 sysstat 实用程序

当您安装并启用sysstat时,您实际上获得了一整盒实用程序和二进制文件,它们以各种方式处理和显示系统数据。这些公用设施在表 8-2 中列出。

表 8-2

sysstat 实用程序列表

|

命令

|

描述

|
| --- | --- |
| 特别行政区 | 收集数据并显示所有系统活动 |
| 南共体 | “系统活动数据收集器”在后台运行 |
| sa1 | 从 cron 运行并处理收集的数据 |
| sa2 | 创建每日摘要,从 cron 运行 |
| 萨夫 | 将 sar 报告导出为 CSV、JSON、XML 等格式。 |
| 监视磁盘状态 | 用于查看 I/O 用途 |
| 系统的工具 | 用于查看与流程相关的统计数据 |
| 你会的 | 按进程 ID 查看数据 |
| cifsiostat | 查看 CIFS ( 通用互联网文件系统)统计信息;这是一个微软的文件系统,可以在 Linux 中通过 Samba 启用 |

显示虚拟内存状态

vmstat是一个较旧的系统监控工具,它返回与系统内存、进程、中断、分页和块 I/O 相关的系统信息。它没有安装在大多数系统上,但可以在大多数软件包管理器中找到。

它接受两个输入值;第一个是以秒为单位的采样周期,第二个是要采集多少样本。因此,如果我们使用输入 1 和 10 运行,如下所示:

vmstat 1 10

我们退回十排。第一行永远是开机以来的总结。然后我们得到 9 行,每一行在最后一行之后 1 秒打印,显示 1 秒样本的平均值。图 8-25 显示了运行vmstat10 个 1 秒周期的示例。

img/494886_1_En_8_Fig25_HTML.jpg

图 8-25

使用 vmstat 获取 9 秒长的样本

由于用来显示表的空间被压缩了,所以很难解释列值。表 8-3 列出了缩写形式及其含义。

表 8-3

vmstat 列列表

|

顺序

|

描述

|
| --- | --- |
| r | 队列中等待 CPU 的线程 |
| b | I/O 上阻塞的线程 |
| swpd 的 | 使用的总交换空间(KB) |
| 自由的 | 总空闲内存 |
| 爱好者 | 用作缓冲区的内存 |
| 躲藏 | 用作缓存的内存 |
| 大音阶第七音 | 从磁盘换入的内存 |
| 因此 | 内存交换到磁盘 |
| 双性恋的 | 从块设备接收的块 |
| 呸 | 发送到块设备的块 |
| 在 | 每秒中断数 |
| 铯 | 每秒的上下文切换 |
| 我们 | 运行非内核代码花费的时间 |
| 叙利亚 | 运行内核代码花费的时间 |
| 编号 | 空闲时间 |
| 华盛顿 | 等待 I/O 花费的时间 |
| 标准时间 | 从虚拟机窃取的时间 |

r–等待运行时的线程

正如我们在讨论平均负载时提到的,队列中的线程是等待在 CPU 上运行的进程。因此,该列基本上与平均负载相同。然而,返回的第一行将是启动机器后的平均值(如果已经安装了vmstat)。这给了你一个完整运行时间的平均值,这是用topuptime无法得到的。

对于顶线以下的值,您将获得取样瞬间的值,而不是平均值。

b–被 I/O 阻塞的线程

I/O 阻塞的线程是在等待进程读取或写入存储时被内核置于等待状态的线程。如果有大量线程被 I/O 阻塞,这可能表明存在与存储设备相关的问题,或者仅仅是大量使用 I/O 的进程正在运行。

swpd–使用的总交换

交换指的是当实际 RAM 内存已满时,分配给充当 RAM 的磁盘空间。交换内存比普通 RAM 慢得多,会导致依赖该内存的程序运行缓慢。如果您经常使用交换内存,您的系统可能需要 ram,或者某个程序可能不必要地使用了过多的 RAM。

空闲–总空闲内存

这以 KB 为单位显示了系统中未使用的内存总量。这类似于运行free命令时显示的自由栏。这让你知道你有多接近使用你所有的内存。

buff–缓冲区中使用的内存

这类似于缓存,但特定于文件元数据;有关更多详细信息,请参见下一节。

缓存–用作缓存的内存

有时内存会被用来缓存程序经常访问的数据。这加快了程序的速度,但是看起来你的可用内存比实际情况要少;如果您的系统已经运行了很长时间,这种情况经常发生。

如果free的值很低,而cache的值很高,那么您仍然不需要担心交换空间被使用,因为缓冲区中的内存可以被重新分配。然而,如果cache + buff + free加在一起接近 0,这是你的机器资源紧张的迹象。

si–从磁盘换入的内存

如前所述,数据或元数据(与缓冲区一样)通常存储在内存中,以提高程序运行的速度。我们讨论了如果更多的内存最终被其他东西需要,如何释放这些内存。在其他情况下,缓存在内存中的数据可能会被其他数据换出。

通过交换,该数据实际上包含执行程序本身的方面,例如,由程序产生的仅在程序运行时存在的数据结构。这种交换就是si列所测量的。si是每秒从磁盘交换的内存。

交换的使用表明系统没有足够的内存可用于缓存,只能求助于使用磁盘空间。如果您有一致的或高交换率,这意味着您的系统没有足够的内存。

所以–内存从磁盘换出

顾名思义,这与内存交换密切相关。换入是将数据从磁盘加载回内存的过程,而换出是数据首次保存到磁盘的过程。

bi-从块设备接收的块

这实际上是从磁盘存储设备中读取的数据量。默认情况下,块的大小为 512 字节。

bo–发送到块设备的块

这是通过块设备保存到磁盘的块数。

输入-每秒中断次数

中断是需要立即处理的信号。例如,当按下键盘上的一个键时,就会产生一个需要处理的中断。同样,当连接到互联网的网卡产生输入信号时,就会产生一个中断。可以通过查看文件/proc/interrupts直接查看中断。

中断发生是系统操作的正常部分,但是如果中断高于正常,可能有硬件问题。下一步可能是查看/proc/interrupts,并找出是什么设备导致了高计数。

cs–上下文切换

当 CPU 在一个进程和另一个进程之间切换而没有完成第一个进程时,就会发生上下文切换。上下文切换需要保存第一个进程的状态,以便稍后完成。存在与上下文切换相关联的成本,因为需要资源来保存第一个进程的状态并在稍后加载该状态。

如果您看到异常大量的上下文切换,这可能与某个严重使用多线程的特定程序有关。

us——运行非内核代码花费的时间

如题,us是运行非内核代码的时间。我们前面提到的内核是类 Unix 系统的核心,它将物理硬件连接到用户级软件。所有“花费的时间”值都是以时间的百分比来度量的,因此值 2 表示在所度量的时间段内有 2%的时间花费在非内核代码上。

sy——运行内核代码花费的时间

这是运行内核代码所用时间的百分比;一个简单的方法是,花费在用户级别之外的系统进程上的时间。花费在系统进程上的时间值异常高可能表示硬件问题、内存瓶颈或内核级锁定问题。

id–空闲时间

这是空闲时间的百分比。这用于与ussy进行比较。请注意,添加ussyidwa ( ,我们将在下一个中查看)后的总和应该在 100%左右(由于四舍五入,可能会略有出入)。如果你在测试vmstat时没有在后台运行很多程序,很可能大部分时间都是空闲的。较低的空闲时间表示您的系统正在进行大量处理。

wa—等待 I/O 花费的时间

第四类“花费在vmstat上的时间”是花费在等待 I/O 上的时间百分比。在关于b的章节中,我们提到了线程在等待写入磁盘或从磁盘读取时如何被阻塞。wa为我们提供了一个衡量等待 I/O 时损失了多少 CPU 时间的指标。等待 I/O 的时间百分比高可能表明我们的磁盘存储很慢,或者我们只是在对磁盘进行大量的读写操作。如果您发现等待 I/O 似乎占用了您系统的大量时间,您可以通过用具有更高读/写速度的磁盘存储升级底层硬件来降低这一百分比。

如果您想模拟一个导致大量磁盘读写的进程来观察vmstat中的效果,您可以运行以下代码片段:

 (cd /tmp &&
  (sync ; vmstat 1 & PID1=$! ; \
  cat </dev/zero >test & PID2=$! ; \
  sleep 3 ; kill $PID2 ; sync ; kill $PID1))

这个代码片段移动到/tmp目录,启动vmstat,然后开始从/dev/zero读取零,并将它们写入/tmp/test。PID1 和 PID2 包含两个正在运行的进程的进程 ID,并在休眠 3 秒后杀死它们。当运行这个命令时,您应该看到wa值上升到一些高值。

ST-从虚拟机窃取的时间

顾名思义,st值表示运行在您系统上的虚拟机等待访问分配给它的资源所花费的时间。这仅在您的系统运行虚拟机时才相关。值持续大于 0 可能表明您为虚拟机分配了过多的内存,这意味着您的主系统不得不从它们那里窃取时间,或者您根本没有足够的内存来运行您托管的虚拟机和主系统。

工具

nmon”系统监控工具可以显示 CPU、内存、网络、磁盘(迷你图或数字)、文件系统、NFS、顶级进程、资源(Linux 版本和处理器)和电源微分区信息。nmon的独特之处在于,它允许您在这些不同的统计数据之间混合和匹配,以创建您自己的定制显示屏。nmon不是默认安装的,但是在大多数软件包管理器上都可以找到nmon

当你第一次通过运行不带选项的命令打开nmon时,你会看到一个类似于图 8-26 的开始屏幕。

img/494886_1_En_8_Fig26_HTML.jpg

图 8-26

运行 nmon

在这里,您可以按底部列出的任何按钮来打开特定的统计数据。比如我们按n,屏幕会显示网络信息;如果我们按下c,我们将会看到网络和 CPU 信息,如图 8-27 所示。

img/494886_1_En_8_Fig27_HTML.jpg

图 8-27

在 nmon 中查看 CPU 和网络信息

你一次可以查看多少不同的统计数据的唯一限制是你的屏幕大小。任何时候,您都可以通过按下用于激活某个部分的按钮来删除该部分。

使用 Snort 进行高级网络监控

另一个值得一提的监控系统是 Snort,这是一个开源的网络入侵预防和检测系统。Snort 的工作原理是实时分析网络流量,并根据一组定义的规则进行检查。常见的规则集包括

  • 对照黑名单检查 IP 地址

  • 检查来自 IP 的异常请求量

  • 检查请求的内容

  • 特定于 FTP、SSH 或 https 等特定服务的规则

  • 任何自定义规则

Snort 还允许系统管理员连接规则来触发操作,例如向系统管理员发送通知或阻止来自违规 IP 的请求。Snort 是完全开源的,有几个社区维护的规则集,也有定期更新的高级规则集,并作为付费服务提供。

我们不会详细讨论如何安装或设置snort,尽管它可以从大多数软件包管理器中获得。设置过程相当长,超出了本书的范围,但是如果用例适用于您的设置,这是值得研究的。

纳吉奥斯

另一个开源的全套网络监控系统是 Nagios,它配有基于 web 的 GUI。它可用于监控多台机器和基础设施上的资源,其特性包括

  • 基于潜在问题的警报

  • 监控你的网站,记录任何停机时间

  • 捕获端口使用( http,SMTP,SNMP,FTP,SSH,POP 等。)

  • 网络请求的大量日志

与 Snort 一样,Nagios 服务器对于那些运行大中型基础设施来提供基于 web 的服务的人来说更有用。

摘要

在这一章中,我们看了可以用来监控 Linux 系统的各种程序和命令,从使用topatop的基本进程监控到更具体的监控程序,如nethogsiftop

九、硬件详细信息和/dev/

在这一章中,我们将会看到一些有用的命令来检查你正在使用或连接的机器的硬件细节。当通过 SSH 连接到一台机器时,您可能不知道您正在处理哪种硬件的所有细节。即使你使用的是你熟悉的机器或一些嵌入式设备,你也可能不知道所有的细节。此外,如果您完全熟悉设备的硬件,您可能能够通过检查细节来发现硬件问题,以查看它们是否与您预期的相匹配。

运行lshw时,/dev/目录中的文件夹丢失或设备丢失可能会提醒您某些硬件未能安装或已损坏。

用于硬件细节的命令

在这一节中,我们将看看命令和程序,它们可以让您更好地了解您正在使用的系统上的硬件类型。

每个人都知道ls,但是有一个完整的硬件查询命令列表,它们的名字来自这个命令。表 9-1 中列出了一些有助于找出机器底层硬件信息的工具。

表 9-1

获取硬件详细信息的有用命令

|

命令/应用

|

描述

|
| --- | --- |
| lspci | 列出所有 PCI 设备 |
| lsblk(消歧义) | 列出所有块设备 |
| sudo fdisk-l | 与lsblk相似,但具有更详细的信息,包括扇区 |
| lscpu(中央处理器) | 列出了有关 CPU 架构的信息 |
| 断续器 | 硬件详细信息的深入列表。也可以使用-short标志来显示压缩版本 |
| ls /dev | Linux 系统上的/dev文件夹 |
| ls -l /sys/block | 列出连接的硬盘和总线 ID。您可能还会看到几个名为loop的虚拟设备 |
| lsusb(USB) | 显示系统中 USB 总线以及连接到总线的设备的信息 |
| cat /proc/cpuinfo | 提供关于处理器的数据 |
| 自由 h | 显示空闲内存,-h为人类可读 |
| 东风-m | 列出挂载的文件系统 |
| ip a | 列出网络接口 |
| netstat -i | 用于列出接口的ifconfig的更简洁的替代方法 |
| hdparm | 获取/设置 SATA/IDE 设备参数 |
| 联名制-r | 显示内核版本 |

/dev/文件夹

另一个可用于深入了解连接硬件的文件夹是/dev文件夹。/dev文件夹包含许多与已安装设备相关的文件和文件夹,以及一些其他具有特殊用例的非硬件文件。表 9-2 显示了可以在/dev文件夹中找到的文件的详细列表。您的系统可能不会拥有所有这些。

Note

所有以类似于js0的数字结尾的文件可以有多个实例;每个后续实例都用递增的数字命名,在本例中为js1js2等等。

表 9-2

/dev/文件夹中的设备示例

|

文件夹/文件

|

描述

|
| --- | --- |
| /dev/dsp | 数字信号处理器 |
| /dev/fd0 | 软盘阅读器 |
| /dev/fb0 | 帧缓冲设备 |
| /dev/js0 | 模拟操纵杆 |
| /dev/lp0 | 并行打印机 |
| /dev/usb/lp0 | USB 打印机 |
| /dev/cdrom | cd-r om |
| /dev/dvd | 数字影碟 |
| /dev/rtc | 实时时钟 |
| /dev/sda | 硬盘驱动器 |
| /dev/ttyS0 | 串行端口 |

这个列表并不完整。本质上,任何可以连接到您的计算机的 I/O 设备都会出现在/dev文件夹中。

/dev/文件夹中的特殊文件

除了物理设备,您还可以在/dev/文件夹中找到一些特殊的文件。这些表示具有一些特殊行为的伪设备。表 9-3 显示了一个流行的列表。

表 9-3

/dev/文件夹中的特殊文件

|

文件夹/文件

|

描述

|
| --- | --- |
| /dev/null | 一种特殊的文件,可以丢弃任何扔进去的东西 |
| /dev/random | 产生随机输出的特殊文件 |
| /dev/天王星 | 与random相同,但当系统耗尽熵时不会阻塞 |
| /dev/stdin | 流程的标准输入 |
| /dev/stdout | 流程的标准输出 |
| /dev/stderr | 流程错误的标准输出 |
| /dev/zero | 一个返回全零的特殊文件 |
| /dev/tty0 | 电传打字机(见下面的注释) |
| /dev/loop0 | 使文件可用作块设备的伪设备 |

接下来,我们将更深入地看看这些特殊的文件。

电传打字机

TTY ( 电传打字机)是一种可以通过各种媒介发送和接收文本的设备。这个名字来源于历史上的电传打字机,它出现在基于屏幕的计算机之前。自 20 世纪初以来,贝尔公司普遍使用电传打字机;示例见图 9-1 。贝尔后来在 1971 年创建了 Unix,其中包括一个虚拟电传打字机作为核心概念。

img/494886_1_En_9_Fig1_HTML.jpg

图 9-1

贝尔电话杂志 1921 年电传打字机的历史范例

当在 Unix 终端中输入时,您实际上是将文本输入到一个虚拟或伪 TTY 中,它接受输入并可以返回输出。当然,在屏幕终端的情况下,它是模拟的硬件。在任何时候,您的系统都可能有几个 tty。要查看所有内容,只需运行

ls /dev/ | grep tty

可能太多了,无法手工计算;如果您想知道有多少行,您可以将结果输入到wc -l中并获得行数:

ls /dev/ | grep tty | wc -l

就我而言,我有 98 个。为什么这么多?其中一些 tty 代表正常的终端会话,而另一些则有特殊的用例。例如,tty0是一个特殊的别名 TTY,它总是指向当前终端。tty 也可以用于在后台包含进程或应用。试试跑步

ps ax

这将返回进程列表;注意TTY列,它显示了一些流程的父 TTY。一些进程可能被列为?,这意味着它们没有绑定到终端,在后台运行。

也可以通过按下ctrl+alt+F1将您的屏幕直接连接到这些 tty 中的一些,用相关的端子号( F1、F2、F3 等)替换 F1。)。在很多 OS 上,tty1会用于 X 服务器;因此,移动到另一个终端会导致你的电脑看起来完全离开了操作系统(音乐关闭,看不到应用或系统菜单)。

stdin、stdout 和 stderr

特殊文件stdinstdoutstderr是“标准输入”、“标准输出”和“标准误差”的简称它们更类似于 I/O 流,而不是文件本身,但是因为在 Linux 中(几乎)一切都被表示为文件,所以操作系统的这些方面都有相关的文件。

如果你打开它们,你会发现它们完全是空的,尽管你可以在操作系统的后台直接输入文本,例如:

echo hello > /dev/stderr

有必要知道什么是stdinstdoutstderr。你可能会遇到它们,即使它们的文件名没有直接提到它们。通过流程将“标准输入”转换为“标准输出”和“标准误差”的系统如图 9-2 所示。

img/494886_1_En_9_Fig2_HTML.jpg

图 9-2

将标准输入转换为标准输出和标准误差的流程图

/dev/null

一个常用的特殊设备文件是/dev/null。这个文件就像一个黑洞,你把信息输入进去,但是什么也没有出来。起初这听起来可能没什么用,但实际上它可以用来停止一个进程,否则这个进程会将输出打印到终端或日志文件中。

为了展示一个例子,我们将使用ping命令并将我们的输出重定向到/dev/null。我们可以重定向两种类型的输出,标准输出(由 1 ) 和标准误差(由 2 表示)。

为了测试将标准输出和标准错误重定向到/dev/null,我们将创建一个文件,简单地将一条消息写入标准输出,将另一条消息写入标准错误。我在/tmp/out.sh创建我的:

#!/usr/bin/env bash
echo Working
>&2 echo Error

保存文件后,一定要添加执行权限:

chmod +x /tmp/out.sh

接下来让我们试着运行它:

/tmp/out.sh

接下来,尝试使用以下重定向来运行它:

/tmp/out.sh 1>/dev/null

你现在应该只得到错误,因为标准输出被导向黑盒。让我们做同样的事情,但是把 1 换成 2:

/tmp/out.sh 2>/dev/null

正如您可能预料的那样,现在我们只能看到输出,而看不到错误。也可以一次重定向两者。两者的语法略有不同:

/tmp/out.sh > /dev/null 2>&1

图 9-3 显示了每个命令的预期输出。

img/494886_1_En_9_Fig3_HTML.jpg

图 9-3

重定向到/dev/null

/dev/random 和/dev/urandom

另一个有用的特殊设备是 random 和 urandom。这两者本质上是一回事,因为它们都充当输入完全随机数据的设备。因此,它充当伪随机数发生器。像大多数伪随机数发生器一样,它依靠一些输入来产生熵。

用于输入的熵是系统状态的随机方面的结果,例如鼠标移动、按键和其他设备输入(例如,驱动器的速度)。使用这个熵,在/dev/random/dev/urandom中产生随机字符。

randomurandom的主要区别在于,如果random耗尽了熵,它会阻塞一个依赖它的程序,而urandom不会。一般来说,urandom应该是首选。

为了了解/dev/urandom中的数据类型,让我们使用head获取前 500 个字符:

head -c 500 /dev/urandom

这将返回一长串不可读的字符,如图 9-4 所示。

img/494886_1_En_9_Fig4_HTML.jpg

图 9-4

/dev/urandom 中的示例内容

当然这并不完全有用。但是,它可以用来为程序生成有用的随机数据。例如,假设我们想生成一个随机数用于一个程序。我们可以使用od(八进制转储的缩写)来生成一个人类可读的数字:

od -vAn -N1 -tu1 < /dev/urandom

前面的示例生成一个 1 字节大小的无符号数(0–255)。如果我们想做 2 个字节,我们可以运行

od -vAn -N2 -tu2 < /dev/urandom

/dev/zero

您将在/dev文件夹中找到的另一个特殊文件是zero。读取该文件将返回一串零,这种情况将永远持续下去。为了演示/dev/zero,让我们用 512 字节的空 0 创建一个文件:

dd if=/dev/zero of=/tmp/zero count=1

如果你在这之后打开/tmp/zero,你应该看到类似图 9-5 ( 取决于你的文本编辑器如何解释空字符)。

img/494886_1_En_9_Fig5_HTML.jpg

图 9-5

/dev/zero 的输出示例

这主要用于创建虚拟文件。它也可以用来清空计算机上的内存。当文件在计算机上被删除时,底层内存仍然存在,但它已被标记为可用的空闲空间。

通过创建全为零的大型文件,可以删除这些底层数据,尽管这种方法受到了批评,但人们倾向于使用随机数据而不是零,因为先进的方法仍然可以恢复这些数据。

更彻底的方法是使用shred命令,例如:

shred /dev/sda

这不仅会删除驱动器中的内容,还会使它们难以恢复。

内核是什么?

您可能已经听说过 Linux 内核,但是它到底是什么呢?Linux 内核是所有 Linux 操作系统的核心组件,也是构建其他一切的基础。果仁一词最初指的是坚果或水果的中心。同样,Linux 内核是所有 Linux 系统的核心。

Linux 内核控制系统的物理硬件和内部软件之间的所有通信。许多开发人员和 Linux 用户永远也不会直接与内核交互,但是了解一下这意味着什么是值得的。

Linux 内核负责的事情包括

  • 内存管理

  • 进程管理

  • 设备驱动程序

  • 系统调用

  • 安全

很多这样的事情发生时,用户甚至都没有意识到。硬件、内核和进程的层次结构如图 9-6 所示。

img/494886_1_En_9_Fig6_HTML.jpg

图 9-6

用户空间、内核和硬件堆栈

获取内核版本

您可以通过运行以下命令来找出您正在使用的 Linux 内核的版本

uname -r

有关该版本的更多完整信息,可以运行

cat /proc/version

这将返回更多关于你的内核的完整信息,如图 9-7 所示。除了版本之外,还列出了编译内核的人的身份、使用的编译器、编译的类型以及编译的日期/时间。

img/494886_1_En_9_Fig7_HTML.jpg

图 9-7

显示内核版本

配置和安装驱动器

通常在设置服务器时,无论是在个人还是在云中,默认的存储空间都不足以存储数据。在这一节中,我们将看看如何将一个驱动器附加到文件系统。

/dev/一节所述,所有连接的驱动器将显示在/dev/文件夹中。但是,这些将显示为单个文件,而不是可以浏览的文件夹。为了将驱动器视为文件系统,需要挂载它。

安装驱动器的第一步是找出哪个文件在/dev文件夹中。您可以通过运行mount并抓取“/dev/sd”的实例来实现这一点:

mount | grep /dev/sd

这将列出所有连接的驱动器及其挂载点,如图 9-8 所示。

img/494886_1_En_9_Fig8_HTML.jpg

图 9-8

显示可装载的驱动器

注意突出显示的部分/dev/sda4 on / type ext4。这告诉我们一些关于 sda4 驱动器的事情。首先,它被挂载为我们的系统/的根,其次,它的格式是 ext4。

mount命令不会列出所有设备;为了更好地了解情况,尝试运行lsblk,它应该会返回如图 9-9 所示的列表。

img/494886_1_En_9_Fig9_HTML.jpg

图 9-9

使用 lsblk 查看驱动器和分区

注意,在这种情况下,我们可以看到sda ( 物理驱动器)和那个磁盘上的分区( sda 1 到 4 )之间的关系。

在我的例子中,sda3是一个以前用于 Windows 安装的分区。由于不再需要它,我将格式化它并挂载它。无论何时格式化,都要仔细检查驱动器是否有你需要的数据,以及是否是正确的分区名。格式化分区后,所有数据都将丢失。

我们将采取的步骤:

  1. 删除 windows 分区

  2. 创建新分区

  3. 格式化分区

  4. 安装分区

  5. 确保在启动时总是挂载分区

删除分区

要删除分区,首先您将进入相关驱动器的fdisk交互模式:

sudo fdisk /dev/sda

您将被要求输入一个命令;输入d进行删除。然后输入分区号,在我的例子中是 3。为了最终完成更改,输入w命令进行写入。删除过程将开始,如图 9-10 所示。

img/494886_1_En_9_Fig10_HTML.jpg

图 9-10

使用 fdisk 删除分区

现在,如果您再次运行lsblk | grep sd,我们将会看到少了一个分区。

创建分区

接下来,我们将使用释放的空间创建一个新的分区。再次打开fdisk:

sudo fdisk /dev/sda

这次输入命令n进行新建。首先你会被要求选择一个数字;我们将用 3 来替换被删除的那个。接下来,您将被要求选择硬盘上的扇区来启动新分区。在大多数情况下,默认将是最低的可用位置,是一个很好的选择。

选择起始扇区后,你会被问及结束扇区;您可以指定内存中的特定位置或指定分区的大小。我们将简单地选择默认选项,该选项将使用所有剩余空间来创建我们的分区。在我的情况下,我也被问及是否要删除 ntfs 签名,这是 Windows 特有的事情;可以安全移除。该过程的示例如图 9-11 所示。

img/494886_1_En_9_Fig11_HTML.jpg

图 9-11

用 fdisk 创建分区

创建分区后,您需要运行以下命令来重新读取分区表:

partprobe

格式化分区

我们现在有了一个新的/dev/sda3文件,但是我们仍然需要格式化它。我们将使用mkfs命令来完成这项工作,它是“make filesystem”的缩写。

sudo mkfs.ext4 /dev/sda3

Or:

sudo mkfs -t ext4 /dev/sda3

安装分区

格式化分区后,我们现在可以将它挂载到我们的文件系统中。首先,您需要创建一个文件夹,它将被挂载到。推荐的安装位置是/mnt/media,尽管这些文件夹有不同的推荐用途。/mnt文件夹用于手动安装的驱动器,而/media是自动安装的可移动驱动器(如 USB 便携驱动器)将出现的地方。

然而,从技术上来说,没有什么可以阻止你在任何你想安装的地方安装一个设备。在我的例子中,我将创建一个名为/mnt/drive1的文件夹:

sudo mkdir /mnt/drive1

创建完成后,让我们将驱动器安装到它上面:

sudo mount /dev/sda3 /mnt/drive1

从分区到~/的系统链接

把你的存储放在你的主目录之外可能会很尴尬,因为它不在你的主目录之内,而且默认情况下你没有权限。你能做的就是在你的主目录中创建到其他文件夹的系统链接。

例如,假设我们需要更多空间来存放位于~/Movies的电影收藏。首先进入/mnt/drive1并创建文件夹:

sudo mkdir Movies

接下来,让自己成为目录的所有者:

sudo chown $USER:$USER /mnt/drive1/Movies

现在我们有了使用~/Movies的权限,我们将在我们的主目录中创建一个符号链接作为快捷方式,这意味着我们永远不必到主目录之外去使用它(确保第一个参数使用完整路径):

ln -s /mnt/drive1/Movies/ ~/

现在,如果你去你的主目录,你应该看到一个电影文件夹。保存到~/Movies文件夹中的任何内容都将被保存到我们新安装的驱动器中。

使挂载的分区持久化

我们的分区运行良好;你可能认为我们结束了。不幸的是,如果我们现在重启我们的机器,它会在没有sda3挂载的情况下重新启动。为了让新分区在每次启动时挂载到/mnt/drive1,我们还需要做一件事。

启动时,系统查看文件/etc/fstab以确定需要安装哪些驱动器。在我们开始之前,让我们看看需要哪些值:

  1. 块设备的 UUID(用 lsblk -d -fs <文件> 查找)

  2. 要装载的文件夹

  3. 文件系统类型

  4. 安装选项(使用默认选项或参见手册

  5. 是否应该转储文件系统(通常为 0 )

  6. Fsck 顺序(主分区使用 1,其他分区使用 2

要获得分区的 UUID,请使用您自己的分区位置运行以下命令:

lsblk -d -fs /dev/sda3

一旦有了所需的六个值,打开/etc/fstab 进行编辑。我们将使用的值显示在图 9-12 的第二个未注释行中。

img/494886_1_En_9_Fig12_HTML.jpg

图 9-12

编辑/etc/fstab

编辑/etc/fstab时要小心,因为不正确的输入会导致系统重启时进入紧急模式。如果发生这种情况,不要惊慌,只需在紧急模式下使用命令行打开/etc/fstab并注释掉您添加的行。

您可以通过运行以下命令来减少出错的可能性

sudo findmnt --verify

这将发现诸如磁盘上的文件类型和声明的文件类型不匹配之类的问题,但在捕捉错误时并不是 100%安全的。

lm 传感器

安装lm-sensor后,首先需要让应用检测你的系统上有哪些传感器。用...做这件事

sudo sensors-detect

它会问几个问题,您可以回答“是”来启用。在大多数情况下,默认的响应是好的,所以你只需按下回车键。完成设置过程后,您可以运行

sensors

这将返回传感器、风扇和其他可用数据,如图 9-13 所示。

img/494886_1_En_9_Fig13_HTML.jpg

图 9-13

使用 lm 传感器查看传感器

inxi

在获取硬件信息时,可以安装一个类似于lshw的程序来改善体验,这就是 i-nex。它可以与一起安装

sudo apt-get install inxi

默认情况下,它将在单行输出中返回非常基本的数据。要获得完整的详细信息,请使用-F标志运行:

inxi -Fxz

这将返回硬件信息的详细列表,如图 9-14 所示。

img/494886_1_En_9_Fig14_HTML.jpg

图 9-14

使用 inxi 查看硬件

迪米特里

虽然lshwinxi对于大多数人来说应该足以看到一台机器的基本硬件细节,但是dmidecode可以用于更深入的了解。

例如,使用dmidecode,您可以使用以下命令查看 BIOS 信息

sudo dmidecode -t bios

sudo dmidecode的身份独立运行该命令将返回所有详细的系统信息,包括序列号和制造商等信息,这些信息在不太详细的实用程序中是找不到的。当单独使用它时,您可能希望通过管道连接到less以便于阅读:

sudo dmidecode | less

对于主板,可以运行

sudo dmidecode -t baseboard

有各种选项可以通过-t指定,以指定具体的硬件信息;有关更完整的信息,请参见手册页。

摘要

在这一章中,我们看了几种你可以使用像lshwinxidmidecode这样的工具探索系统底层硬件的方法。我们还查看了连接的硬件如何出现在/dev/文件夹中,该文件夹包含硬件设备和许多特殊文件,如对各种任务有用的/dev/null/dev/urandom。我们通过使用mount命令将硬盘安装到/mnt目录中,与/dev文件夹中的硬盘进行交互。

十、解析文本

无论您在 Linux 上做什么,您可能会发现自己在某个时候需要解析文本。由于 Linux 在很大程度上是基于文件的,因此非常需要能够解析大量文本以找到特定值、格式化并处理它的实用程序。

有几个实用程序可用于解析文本。在这一章中,我们将看看这些工具中的几个,以及如何用它们来解析文本。

可做文件内的字符串查找

grep是最常用的命令行工具之一。它允许您在一组文本中查找特定的字符串。例如,给定一个有几行的文件,我们可以找到包含我们要找的文本的那一行。例如,让我们在/etc/passwd文件中找到根用户。

cat /etc/passwd | grep root

您应该得到如图 10-1 所示的单个条目。

img/494886_1_En_10_Fig1_HTML.jpg

图 10-1

从/etc/passwd 中抓取根目录

或者更好的是,我们可以直接在文件本身上执行grep,而不需要管道:

grep root /etc/passwd

你也可以做相反的工作,在没有的情况下查找行,为此添加代表反匹配的-v标志:

cat /etc/passwd | grep -v root

这应该会为系统中的其他用户返回类似的条目。-v标志只是可以和grep一起使用的众多选项之一;详见表 10-1 。

表 10-1

grep 的选项

|

|

描述

|
| --- | --- |
| -e | 正则表达式模式 |
| [构成来自拉丁语、结尾为-us 的名词的复数] | 忽略大写/小写 |
| -v | 反转匹配 |
| -c | 竞赛比赛 |
| 同-EN | 匹配前获取 X 行并显示行号(需要数字输入) |
| -h | 匹配行前不显示文件名(当抓取单个文件时默认为 |
| [加在以-u 结尾的法语词源的名词之后构成复数] | 精确线匹配 |
| -f | 从文件中加载正则表达式 |
| 表示“具有…性质的” | 仅输出一行中匹配的部分 |
| [构成动植物的古名或拉丁化的现代名] | 匹配后显示 N 行(需要数字输入 |
| -乙 | 匹配前显示 N 行(需要数字输入 |
| -丙 | 在匹配前后显示 N 行(需要数字输入 |

切口

虽然grep可以解析文件以返回文件中的相关行,但有时需要解析行本身的文本。对于解析单行,cut工作得很好。cut可用于按字符、字节或自定义分隔符拆分一行的内容,例如,用 byte:

echo hello world | cut -b 1,2

前面的命令将返回“he ”,因为这是“hello world”的第一个和第二个字节的内容。也可以从字节 X 到行尾,例如:

echo hello world | cut -b 7-

这应该只返回“你好”。cut不需要从管道接收其输入;您也可以直接从文件中读取。当从文件中读取时,相同的转换将应用于每一行。例如,让我们从/etc/passwd文件中的每一行获取第 1 到第 9 个字节:

cut -b 1-9 /etc/passwd

您应该为每个用户返回一行,如图 10-2 所示。

img/494886_1_En_10_Fig2_HTML.jpg

图 10-2

从/etc/passwd 中抓取根目录

Note

对于普通的文本文件,-b-c标志的作用是一样的,因为单个字符是一个字节长。

当然,在前面的例子中,结果不是特别有用;我们已经获得了几个用户名,但是由于不是所有用户的长度都一样,一些线路获得了额外的数据,而另一些线路被切断了。最常用的模式是-d作为分隔符。例如,让我们只获取用户名。我们提供了想要用作分隔符的字符,在我们的示例中,每个用户名前面都有一个“:”。然后,我们用-f标志指定要返回的剪切文本的部分:

cut -d : -f 1 /etc/passwd

这将返回所有用户的列表,如图 10-3 所示。

img/494886_1_En_10_Fig3_HTML.jpg

图 10-3

用 cut 获取每行的第一列

金圣柱

解析文本时另一个有用的命令是uniq,用于解析出重复的行。为了测试这个命令,让我们首先创建一个包含一些重复行的文件:

printf 'Hello %d\n' 1 1 1 2 2 3 > /tmp/hello.txt

文件/tmp/hello.txt现在应该包含六行,其中三行是唯一的。为了确认,首先cat文件的内容,然后做第二个cat传入uniq:

cat /tmp/hello.txt
uniq /tmp/hello.txt

您的内容应该类似于图 10-4 中所示的内容。

img/494886_1_En_10_Fig4_HTML.jpg

图 10-4

使用 uniq

值得注意的是,独特的功能只适用于彼此相邻的副本。例如,如果我们在文件的末尾添加另一个“Hello 1 ”,它仍然会被打印为唯一的一行。确保使用 >> 而不是 > 作为一个单独的重定向符号将覆盖文件而不是添加文件:

echo Hello 1 >> /tmp/hello.txt
uniq /tmp/hello.txt

注意第一行和最后一行是多么的相似,如图 10-5 所示。

img/494886_1_En_10_Fig5_HTML.jpg

图 10-5

当重复行不相邻时使用 uniq

如果我们只想打印完全唯一的行,我们必须首先用sort解析文件,我们将在下一节看到。

表 10-2 中显示了一些需要注意的可与sort一起使用的选项。

表 10-2

uniq 的选项

|

|

描述

|
| --- | --- |
| -c | 统计每行的出现次数 |
| -d | 仅显示重复的行 |
| [构成来自拉丁语、结尾为-us 的名词的复数] | 不分大小写 |
| 构成名词复数 | 跳过每行的前 N 个字符(需要数字输入 |
| -你 | 仅显示独特的线条 |
| -w | 仅比较前 N 行(需要数字输入 |

分类

sort实用程序用于对文件中的行进行排序。为了进行演示,让我们创建一个编号为 1–5 的文件,后面再跟一遍相同的编号:

seq 1 5 > /tmp/numbers.txt && seq 1 5 >> /tmp/numbers.txt

接下来让我们查看输出,然后通过sort再次查看输出:

cat /tmp/numbers.txt
sort /tmp/numbers.txt

第一个命令的输出应该按照 1,2,3,4,5,1,2,3,4,5 的顺序,而第二个命令将数字排序为 1,1,2,2,…

这在与uniq结合使用时特别有用,因为您可以确保相似的行彼此相邻。假设您仍然有在uniq部分创建的/tmp/hello.txt文件,让我们对它进行排序,然后得到唯一的行:

sort /tmp/hello.txt | uniq

通过sortuniq的组合,你将只能得到每行的一个实例,如图 10-6 所示。

img/494886_1_En_10_Fig6_HTML.jpg

图 10-6

使用 sort with uniq 只显示每行的一个实例

使用-u选项,单独使用sort可以达到同样的效果:

sort -u /tmp/hello.txt

正如我们已经讨论过的其他实用程序一样,sort有一些有用的选项,如表 10-3 所示。

表 10-3

排序选项

|

|

描述

|
| --- | --- |
| -r | 反向排序(可与其他选项结合使用) |
| 同-EN | 数字排序 |
| -d | 字典排序,仅考虑空白和字母数字字符 |
| k | 按列排序(需要数字输入 |
| -你 | 仅显示独特的线条 |
| -男 | 按月份排序(在行中采用月份名称) |
| -五 | 版本号排序 |

正则表达式

Regex 本身不是一个实用程序,而是文本解析的标准形式,被许多实用程序和编程语言使用。Regex 是正则表达式的缩写。正则表达式提供了再次测试字符串的模式。举个简单的例子,假设我们想匹配“Hello”或“Hi”。对此的常规表达应该是

(Hello|Hi)

对于扩展的正则表达式,grep有一个特殊的-E选项。所以我们可以用grep来表达。在此之前,让我们在上一节创建的/tmp/hello.txt文件中添加一行“Hi 1 ”:

echo "Hi 1" >> /tmp/hello.txt

完成后,运行以下命令:

grep -E '(Hello|Hi)' /tmp/hello.txt

你应该在每一行都得到一个匹配,匹配的部分高亮显示,如图 10-7 所示。

img/494886_1_En_10_Fig7_HTML.jpg

图 10-7

带有 grep 的正则表达式

相同的 regex 格式可以用于多种实用程序和编程语言:Perl、JavaScript、Python 和 Ruby 等等。例如,如果您安装了perl,您可以使用完全相同的正则表达式:

perl -pe '(Hello|Hi)' /tmp/hello.txt

除了一个或另一个单词,我们实际上可以使用通配符或特定的类来再次匹配。假设您正在编写验证产品序列号的软件,它们以“数字数字字母数字字母数字”的模式出现这种模式可以表示为

[0-9][0-9][0-9][a-zA-Z][a-zA-Z][0-9]

注意,对于字母,我们使用[a-zA-Z];这表明我们接受大写和小写。如果我们只想要大写字母,我们可以做[A-Z]

现在,假设我们想让我们的序列号更难猜测,所以我们希望第一个数字是 3、5 或 8。我们将使用第一个字符的[358]来更新表达式:

[358][0-9][0-9][a-zA-Z][a-zA-Z][0-9]

同样的模式也适用于字母和数字,例如,[123ABC]将匹配列出的任何字符。另一个常见的类似用法可能是电话号码:

[0-9]{3}[-][0-9]{3}[-][0-9]{4}

前面的例子引入了一个我们还没有使用过的新元素。不用定义数字中的每个字符,我们可以用简写形式[0-9]{3},意思是三个[0-9]的实例。所以我们有一个三位数,后面跟着一个破折号,一个三位数后面跟着一个破折号,然后是一个四位数。

上述正则表达式的一个缺点是,它明确要求破折号。您可以在任何字符后加上?使其成为可选字符。因此,如果我们想使用相同的正则表达式,并使破折号可选,我们最终会得到

[0-9]{3}[-]?[0-9]{3}[-]?[0-9]{4}

注意添加了两个?。所以现在我们的正则表达式将匹配带或不带破折号的电话号码。如果您来自美国/加拿大以外的国家,您可能需要进一步调整 regex 以匹配您所在地区使用的模式。此外,这个正则表达式没有考虑在数字周围使用“()”的可能性。但是,使用这些简单的元素,您可以修改正则表达式来处理任何类型的电话号码格式。

为了测试电话号码示例,让我们打开在sort一节中创建的numbers.txt文件。然后添加一行包含“519-555-0100”格式的电话号码。完成后,运行以下命令:

grep -E '[0-9]{3}[-]?[0-9]{3}[-]?[0-9]{4}' /tmp/numbers.txt

这应该只返回添加了电话号码的换行符。

另一个常见的正则表达式用于查找电子邮件。这不是一个全面的例子,但它适用于大多数电话号码:

\S+@\S+\.\S+

在这个例子中,我们使用的是后面跟有+的任意非空格字符\S,这意味着前面的一个或多个字符。因此,合在一起\S+表示任意数量的非空格字符。然后我们有一个“@”符号,后面跟着另一个\S+;之后,我们有\.;通常.是一个通配符,但是有了反斜杠,它就有了“.”的字面意思。然后我们以另一个\S+结束。

就像电话号码一样,如果我们将电子邮件添加到我们创建的/tmp/numbers.txt文件中,我们可以将正则表达式作为命令的一部分进行测试:

grep -E '\S+@\S+\.\S+' /tmp/numbers.txt

表 10-4 包含了 regex 中常用符号的列表。

表 10-4

正则表达式符号

|

特殊字符

|

描述

|
| --- | --- |
| \s | 匹配任何空格或制表符 |
| \S | 匹配任何非空格字符 |
| \d | 匹配任何数字 |
| \D | 匹配任何非数字字符 |
| \w | 匹配任何单词字符 |
| \W | 匹配任何非单词字符 |
| 。 | 匹配任何字符 |
| ^ | 行首 |
| $ | 行结束 |
| * | 匹配前面的字符零任意次 |
| + | 匹配前面的字符一次或多次 |
| ? | 零次或一次匹配前面的字符 |
| | | 用于 Or 表达式的 or 符号 |

使用

awk是一种模式扫描和处理语言和命令行实用工具。它擅长处理格式化的文本数据。例如,使用以下文本创建文件/tmp/users.txt:

Jesse 4557389203 jesse@gmail.com xl 1991 1
Matt 8839293940 matt@hotmail.com s 1983 1
Jeff 8493739304 jeff@outlook.com l 1980 3
Sarah 4939304952 sarah@email.com m 1974 2

我们将使用这个文件作为样本数据进行处理。鉴于前面的数据,我们想看看所有的电子邮件。我们可以跑

awk '{ print $3 }' /tmp/users.txt

这将打印出$3指定的第三列的所有信息,如图 10-8 所示。

img/494886_1_En_10_Fig8_HTML.jpg

图 10-8

用 awk 打印文件中的第三列

我们可以混合和匹配这些值,并按照我们喜欢的方式设置它们的格式,例如,获取电子邮件和大小,并用空格将它们分开:

awk '{ print $3" "$4 }' /tmp/users.txt

或者说我们想使用每行数据的信息生成一个句子(图 10-9 中的输出示例):

img/494886_1_En_10_Fig9_HTML.jpg

图 10-9

在 awk 中使用列作为变量

awk '{ print "Hello "$1", thanks for buying a "$4" shirt" }'\
  /tmp/users.txt

我们还可以使用基本的搜索功能来查找特定的行,例如:

awk "/Jeff/" /tmp/users.txt

这将返回用户 Jeff 所在的行,如图 10-10 所示。

img/494886_1_En_10_Fig10_HTML.jpg

图 10-10

使用 awk 搜索字符串

我们之前看到的正则表达式也与awk兼容。比方说,我们希望获得所有大号为“l”的用户。我们将创建一些正则表达式来查找两边都有空格的“l”的情况:

awk "/\sl\s/" /tmp/users.txt

或者如果我们既想得到大的又想得到小的,我们可以使用(...|...)模式,就像我们对(Hello|Hi)做的那样。记住每个\s实际上是一个空格,并不是指字母本身。所以\ss\s实际上是“s”的意思:

awk "/(\sl\s|\ss\s)/" /tmp/users.txt

这将返回小和大的条目,如图 10-11 所示。

img/494886_1_En_10_Fig11_HTML.jpg

图 10-11

使用 awk 获得大小不同的用户

任何正则表达式都可以和awk一起使用;简单地把它放在我们已经看到的/ /之间。

这些是awk有用的几个例子。它并不全面,因为awk实际上是它自己的编程语言,并且已经有整本书都在讨论如何使用它。如果您感兴趣,其他功能包括

  • 创建由awk直接调用的.awk文件

  • 定义和使用变量的能力

  • 支持在 awk 脚本中编写独立的函数

  • 像随机数生成器这样的内置函数

  • 支持 if、else 和循环

一项 Linux 指令

代表流编辑器,它将出现在大多数 Linux 安装中。awksed能做的事情有很大的重叠。它们都可以用来搜索匹配的文本或对数据执行操作。例如,如果我们想像在awk中一样在/tmp/users.txt中搜索该行,我们可以这样做

sed -n "/Jeff/p" /tmp/users.txt

-n标志禁止sed自动打印文件,取而代之的是,我们将只打印我们指定的行。然后我们比赛图案末端的p代表印刷。

总的来说,我推荐学习awk而不是sed,因为它使用起来更简单,而且对于更多的情况来说是一个更完整的工具。然而,sed有一些事情比awk简单。其中之一就是查找和替换文本。

让我们以示例数据为例,将“Jeff”替换为“Jeffery”:

sed -i 's/Jeff/Jeffery/g' /tmp/users.txt

这里的-i支持就地编辑,所以我们正在读取的文件被改变了。然后s/告诉sed使用替代命令。然后我们匹配Jeff,在/的另一边,我们指定替换。最后,末尾的/g指定这是一个全局更改,而不是简单地替换第一个匹配。

但是,前面的命令有一个小问题。如果运行第二次,它会尝试将“Jeff”替换为“Jeffery”与awk一样,我们可以指定空格与\s的匹配,然后在替换部分使用一个文字空格:

sed -i 's/Jeff\s/Jeffery /g' /tmp/users.txt

您可能从 regex 表中认出了\s。与awk一样,regex 语法与sed兼容。

使用 JQ 与 JSON 一起工作

Linux 上使用的许多老程序都是在 JSON 成为 web 应用间信息共享的标准之前编写的。虽然像sedgrep这样的程序在解析和文本操作方面很强大,但它们并不太适合处理 JSON。处理 JSON 最流行的命令行程序是 JQ,以至于它已经开始成为许多发行版的标准,比如 Ubuntu。

JQ 是一个用 c 语言编写的速度非常快的 JSON 处理器。我问作者 JQ 是否代表 JSON Query,他说这很有意义,但他不打算让它代表任何东西。尽管如此,您可以将其视为一种查询和使用 JSON 的方式。

Note

在本节中,我们将使用 Open Trivia DB 作为获取 JSON 的示例 API。请随意用它来替换任何其他 API。当然,您必须针对您正在处理的数据修改命令。一些有趣的不需要获取 API 键的 API 包括

打开琐事 DB-www.opentb.com

TheSportsDB-www.thesportsdb.com

JQ可以做的最简单的事情是将有效的 JSON 通过管道输入其中,并接收一个有色结果,例如,用 Open Trivia DB:

curl -s https://opentdb.com/api.php?amount=3 | jq

这将返回相同的 JSON,但颜色编码便于阅读,如图 10-12 所示。

img/494886_1_En_10_Fig12_HTML.jpg

图 10-12

正在用 JQ 解析 Curl 请求

你会发现使用JQ更加容易,特别是如果你请求的服务器最初以压缩格式提供 JSON。还要注意,对于curl,我们使用了-s标志;如果没有这个,你会看到一个小小的进度条,不必要的浪费空间。

当然这只是开始;JQ 不仅仅是一幅简单漂亮的版画。让我们用同样的数据做一点工作。比方说,我们只想显示查询中的第一个问题(记住,每个请求的问题都是随机的)。

curl -s https://opentdb.com/api.php?amount=3 \
  | jq '[ .results][0][0]'

我们简单地添加[0]来获得数组中的第一个元素,类似于您可能熟悉的类似 C 的语言,如 JavaScript。在这种情况下,我们实际想要的结果被包装在一个只包含我们的目标数组的外部数组中,所以它最终被命名为[0][0]

如果您熟悉使用 JavaScript 或其他语言中的数组和对象,那么做更复杂的事情对您来说会非常容易。假设现在我们要回答第一个问题,并且只选择问题文本。

curl -s https://opentdb.com/api.php?amount=3 \
  | jq '[ .results][0][0]'.question

如果在您阅读本文时数据库格式保持不变,并且您已经正确地复制了命令,那么您应该会在屏幕上看到一个问题文本。让我们回想一下关于管道的部分,将结果发送到cowsay(默认情况下没有安装)只是为了好玩。

curl -s https://opentdb.com/api.php?amount=3 \
  | jq '[ .results][0][0]'.question \
  | cowsay

输出应该如图 10-13 所示。

img/494886_1_En_10_Fig13_HTML.jpg

图 10-13

利用 JQ 得到一个问题,然后把它传给考赛

我们可以扩展前面的示例,通过将 curl 请求的结果保存在脚本中并提取问题和答案以分别显示,来创建一个完整的基于命令行的问答游戏。有关命令行问答机器人的完整示例,该机器人打印潜在答案列表并检查用户是否给出了正确答案,请参见以下链接:

https://github.com/Apress/basic-linux-terminal-tips-and-tricks

摘要

在本章中,我们看了从命令行和脚本解析文本的工具。对于纯文本文件或管道输入,这些包括grepcutuniqsortawksed。我们看到,正则表达式对于匹配文本模式非常有用,并且受到几个实用程序和大多数流行编程语言的支持。最后,我们看到了如何使用 JSON,JSON 通常是通过使用程序 JQ 从 web APIs 返回的。

十一、systemd

我们已经探索了使用像ps这样的工具直接查看流程;查看系统上运行的进程的另一种方式是从守护进程的角度。守护程序是在系统后台运行的长期运行的进程;通常它们会在系统启动时由类似systemd的 init 程序自动启动。systemd中的“d”来自守护进程的概念,因为它充当系统上运行的所有守护进程的控制器。

是一个调度系统,已经在 Linux 发行版中广泛使用。它经常是赞扬和批评的主题。它在包括日志记录、调度、服务监控和系统初始化在内的许多领域中控制系统功能的核心作用导致一些人说它太集中了,违背了每个程序做好一件事的 Unix 哲学。systemd的捍卫者会指出,它实际上是几个二进制文件的集合,如systemctljournald,它们各自做一件事,共同创造一个更大的系统。

无论你对systemd有什么看法,它已经变得如此普遍,如果你使用任何流行的 Linux 发行版,这几乎是不可能避免的。它最初是在 2010 年由 Red Hat 开发的,作为替换旧的 init 系统,特别是 SysV 风格的 init 的一种方式。到 2015 年,systemd已经取代了 SysV init 和大多数流行发行版上的其他 init 系统,包括 CentOS、RHEL、Debian、Ubuntu 和 SUSE。

systemctl

如果你的系统运行的是systemd,你应该有一个命令行程序叫做systemctl,是系统控制的缩写。systemctl可用于监控、查询和修改systemd控制的服务和流程。参见图 11-1 查看由systemd监控的子任务的可视化。

img/494886_1_En_11_Fig1_HTML.jpg

图 11-1

系统的许多用途

systemctl是系统控制,连接系统的各个方面,跟踪每个服务状态,根据设置打开/关闭服务,解析服务输出并将其移动到日志文件。

不带任何标志运行systemctl将返回活动systemd单元列表,如图 11-2 所示。

img/494886_1_En_11_Fig2_HTML.jpg

图 11-2

运行 systemctl 的输出示例

停止、启动、禁用和启用服务

我们已经使用了一些我们将在这里介绍的命令,但是值得重申一下,因为它们是一些您想要使用 systemd 管理服务的最常见的命令。

停止服务

如果一个服务正在运行,你想通过systemd停止它,只需用sudo运行以下命令;我们将使用打印服务cups作为例子(成功时没有输出显示):

sudo systemctl stop cups

获取服务的状态

接下来,为了确保服务关闭,我们将使用status命令。当您不确定服务的状态时,这在许多情况下会很有用。

sudo systemctl status cups

你不仅可以得到服务的状态,还可以得到最新的日志;示例见图 11-3 。添加最近日志是旧的 System V service 命令中没有的功能。

img/494886_1_En_11_Fig3_HTML.jpg

图 11-3

使用 systemctl 获取特定程序的状态

请注意底部的日志,其中显示了启动和停止的时间和消息。

启动服务

接下来让我们重新打开服务;正如您可能已经猜到的那样,这可以通过以下命令来完成:

sudo systemctl start cups

运行start后,重新运行status命令,确认cups再次运行。

禁用服务

停止和开始处理当前会话中服务的状态。禁用和启用在机器启动后的新会话启动期间处理服务的状态。简单地在一个服务上使用stop将导致它在每次计算机停止时重新启动。要彻底关闭服务,应该使用 disable 命令:

sudo systemctl disable cups

运行后,再次检查status并观察差异。

启用服务

正如您可能猜到的,disable 的反义词是 enable:

sudo systemctl enable cups

测试禁用命令后,如果希望该服务在引导时继续启动,请确保将其重新启用。

单位文件

程序通过单元文件将它们的配置传递给systemd,单元文件是位于/etc/systemd/system/文件夹中的 ini 文件。最简单的单元文件只是告诉systemd保持程序运行。让我们创建一个示例程序和单元文件来演示;称之为logTime.sh。我在/tmp文件夹中创建了我的文件夹,因为我不打算保留它。

#!/usr/bin/env bash

while true
  do
    echo time is $(date)
    sleep 5
  done

编写完脚本后,使用以下命令授予它可执行权限:

chmod +x logTime.sh

进入文件夹/etc/systemd/system;这是你可以放置配置程序使用systemd的单元文件的地方。我们将为简单记录时间的脚本创建尽可能简单的单元文件;将文件命名为logTime.service。您需要拥有 root 权限才能在/etc/systemd/system中编辑和创建文件。

[Service]
ExecStart=/tmp/logTime.sh

保存单元文件后,您现在可以打开服务了。

sudo systemctl start logTime

接下来,我们将获得守护进程的状态。

sudo systemctl status logTime

这应该会返回一些信息,告诉我们服务是活动的,并显示最近的日志,如图 11-4 所示。

img/494886_1_En_11_Fig4_HTML.jpg

图 11-4

启动自定义单位文件并检查状态

您可以使用journalctl主动查看生成的日志。

sudo journalctl -u logTime -f

当您想要调查正在您的机器上运行的一些特定服务时,这可能是有用的。如果它看起来不正常或者占用了太多的资源,查看日志可能会给你一些提示。

在单元文件中还可以设置其他几个选项。下面是一个更完整的单元文件,带有描述每行内容的注释:

[Unit]
# Description of what the program does
Description=Log time every 5 seconds
# List services needed for this service to work
After=time-sync.target

[Service]
# Path to executable
ExecStart=/tmp/logTime.sh
# Policy for restarting when stops
Restart=always
# Working directory for executable
WorkingDirectory=/tmp
# The user the process will run under
User=philip
# User group for the process
Group=philip
# Set environment variables
Environment=MYVAR=var

[Install]
# Which programs require the unit
# multi-user.target is when linux start
# Adding this line makes the program start when system is booting
WantedBy=multi-user.target

如果您手动修改服务文件,您需要使用以下命令对systemd进行软复位:

sudo systemctl daemon-reload

即使最后一行告诉程序在引导期间打开,也需要启用它来实际考虑单元文件。

sudo systemctl enable logTime

这将激活服务。如果您想禁用该服务,只需运行

sudo systemctl disable logTime

disable 命令非常有用。比方说,您检查正在运行的服务,看到一个您没有使用也不需要的程序。你终止了进程或者关闭了它,却发现下一次重启计算机时,它又回来了。如果你遇到那种情况,systemctl disable或许可以解决。

在您完成这一部分后,确保删除我们在/etc/systemd/system中创建的服务文件。如果您像我们在这里一样在/tmp目录中创建了可执行文件,那么如果您没有通过删除服务文件来删除它,那么在您第一次重启之后,服务将会失败。

查找正在运行的服务

当您登录到一台机器时,您可能想要弄清楚哪些服务已经在运行。我们之前看到的命令systemctl,用于启用和禁用我们的logTime服务,也可以用来获得机器上运行的服务的完整列表。

systemctl是 system control 的缩写,是 systemd 的命令,用于控制系统上的服务。鉴于此,几乎所有的服务都将通过 systemd 启动(至少是重启后自动启动的)。

你可以用systemctl做的最简单的命令是独立运行它:

systemctl

这将返回系统中当前活动的进程列表,如图 11-5 所示。

img/494886_1_En_11_Fig5_HTML.jpg

图 11-5

systemctl 的输出

这列出了所有的东西,很难通读。如果您想查看正在运行的特定单元文件服务,您可以使用

systemctl list-units --type service

关于这个的另一个有用的事情是,你可以看到设置为正在运行但由于某种原因失败的服务,如图 11-6 中的postfix@-.service的情况。

img/494886_1_En_11_Fig6_HTML.jpg

图 11-6

仅使用 systemctl 列出服务

如果我们只想查看失败的服务,我们可以在前面的命令中添加--state failed标志。

此外,请注意活动但已退出的服务,这意味着从技术上讲,它们正在工作,但没有运行。要仅查看当前正在运行的程序,您可以使用以下命令:

systemctl list-units --type service --state failed

另一个有用的命令将允许您查看所有单元文件及其当前状态:

systemctl list-unit-files --type service

这将输出所有的单元文件及其当前状态,示例如图 11-7 所示。

img/494886_1_En_11_Fig7_HTML.jpg

图 11-7

用 systemctl 列出单元文件

有几种可能的状态,在表 11-1 中列出。最常用的是启用、禁用和静态。

表 11-1

systemd 的可能服务状态

|

状态

|

描述

|
| --- | --- |
| 使能够 | 服务已打开 |
| 有缺陷的 | 服务已关闭 |
| 静电 | 无法打开/关闭服务、依赖关系或单一运行脚本 |
| 戴面具的 | 已锁定,因此即使手动也无法打开 |
| 连接的 | 通过系统链接变得可用 |
| 间接的 | 间接启用 |
| 生成的 | 通过生成器工具动态生成 |
| 短暂的 | 通过运行时 API 动态生成 |
| 严重的 | 无效的单位文件 |

有关这些状态的更多详细信息,您可以运行

man systemctl list-unit-files

期刊

systemd 不仅仅处理调度任务。它还在指导运行服务生成的日志方面发挥作用。这就是journalctl的用武之地,是日志控制的简称。与systemctl一样,您可以运行的最简单的命令是journalctl本身。

journalctl

这将返回通过 systemd 创建的所有日志的列表。我们可以通过使用-f标志来观看这个文件更新时的实时版本:

journalctl -f

这将显示发生的任何日志;要退出,可以按ctrl+c

有许多选项,让你不必自己想出复杂的解析器;表 11-2 包含了几个有用选项的列表。

表 11-2

日志选项列表

|

[计]选项

|

描述

|
| --- | --- |
| -f | 获取实时日志流 |
| k | 显示内核日志 |
| -u | 显示特定服务的服务 |
| -b | 显示启动消息 |
| -r | 按相反顺序排序 |
| -p | 按进程优先级排序 |
| _PID= | 从特定进程 ID 获取日志 |
| _UID= | 从特定用户 ID 获取日志 |
| _GID= | 从特定组 ID 获取日志 |

journal CTL–按时间解析

除了前面的标志,还可以使用--since--until标志解析特定时间之间的日志,例如:

journalctl --since yesterday

直到使用基本小时表示法的时间

journalctl --until 13:00

或者使用两者的组合

journalctl --since "2 days ago" --until yesterday

还支持传统时间戳:

journalctl --since "2019-12-24 23:15:00" --until "2019-12-25"

其他初始化系统

虽然systemd已经被广泛使用,但仍有几个地方可以找到其他的 init 系统——仅举几个例子:

  • 最小的 Linux 版本,如 Alpine Linux

  • 旧版本的 Linux

  • 较少使用的操作系统

  • 高度定制的操作系统

系统 V 初始化

systemd成为标准之前,经典的 Linux 系统使用 SysV init。单词“init”指的是引导期间启动的第一个进程。跑步还是能看到的

ps -up 1

然而,脚本本身很可能是initsystemd版本。systemd被有意设计成与 SysV init 兼容。使用 SysV init,内核启动 init 进程,该进程处理系统状态的更改,以便引导、重启和关机。对于 SysV,在表 11-3 中定义了八种不同的运行级别。

表 11-3

SysV 上的运行级别

|

运行级别

|

目录

|

使用

|
| --- | --- | --- |
| 普通 | - | 系统引导 |
| Zero | /etc/rc0.d/ | 暂停系统 |
| one | /etc/rc1.d/ | 单用户模式 |
| Two | /etc/rc2.d/ | 多用户模式 |
| three | /etc/rc3.d/ | 联网的多用户 |
| four | /etc/rc4.d/ | 为自定义运行级别保留 |
| five | /etc/rc5.d/ | 图形用户界面启动( X11 ) |
| six | /etc/rc6.d/ | 重新启动 |

当系统启动时,它在运行级别之间移动,并不总是按顺序移动,例如,进入单用户模式(运行级别 1)是一种特殊的状态。当您的操作系统在启动过程中被破坏时,例如,/etc中的一个脚本(如/etc/fstab)被破坏,您将只能以 root 用户身份登录到单用户模式。其他级别更有顺序性,例如,在到达级别 5 之前,通常要通过运行级别 2 和 3。

与每个级别相关联的文件夹包含与需要在该级别启动的程序相关联的 bash 脚本。

Note

虽然运行级别对于 SysV 风格的 init 至关重要,但是它们仍然以相同的级别 N、0 和 1 - 6 存在于 systemd init 中。在大多数系统上,您可以通过运行who -r来查看您当前的运行级别。

暴发户

另一个以前流行的 init 系统是 Upstart ( 上一次发布是在 2014 年)。Upstart 是在 Ubuntu 上使用的,直到他们从 Debian 8 开始改用systemd。尽管如此,你仍然会发现 Upstart 今天仍在使用。

Upstart 看起来像其他 init 系统,不包含名为“upstart”的命令。如果您不确定您的操作系统正在运行 Upstart,您可以使用

ps -eaf | grep '[u]pstart'

如果您看到一些进程而不是 grep 调用本身,那么您的系统已经安装了 Upstart。您可以使用它来检查哪些服务正在运行

service --status-all

这将返回服务及其状态的列表。您可以通过直接与服务的 init 脚本进行交互来与服务进行交互,例如:

sudo /etc/init.d/ssh status

或者要重新启动服务,请运行

sudo /etc/init.d/ssh restart

这种互动方式并不是 Upstart 特有的。甚至在systemd系统上,你会发现许多程序都有一个/etc/init.d文件,可以像前面显示的那样直接交互。

摘要

在这一章中,我们看了一下systemd系统,以及如何使用它来控制系统上运行的程序。我们看了如何通过停止、启动、启用和禁用来使用systemctl处理这些服务。为了查看正在运行的服务及其日志,我们探索了journald的使用。我们甚至创建了自己的单元文件来从头开始制作一个systemd服务。

十二、VIM

迟早,您会想要开始使用基于终端的文本编辑器,如果不是全职的,那么至少当您远程登录到服务器或设备时。

许多系统管理员最终依赖于nano,一个预装在许多系统上的简单文本编辑器。nano的主要优点是它容易被新用户理解和使用。从长远来看,使用nano会大大降低你的速度。有了 nano,当你试图浏览一个文本文档时,你不得不长时间按住箭头键或删除。

Vim 通过创建一种基于键盘的语法来解决这个问题,这种语法可以在文档中导航,并且不需要鼠标就可以快速修改。在一次击键中,你可以从一个文档的顶部到底部G,然后用两个gg再返回。Vim 有各种类似的基于击键的命令,可以帮助你快速移动和编辑。

模式

如前一章所述,许多键被绑定到特殊的动作或命令,例如,G转到文档的底部。那么,当你真的想在文档中输入“G”的时候呢?这就是模式出现的地方。Vim 中有两种主要模式,第三种使用较少但仍然重要的模式:

  • 正常模式–用于运行G等命令

  • 插入模式–像在其他编辑器中一样书写文本

  • 视觉模式–用于选择文本,类似于用鼠标突出显示文本

常见命令

当您在 Vim 中打开一个文档时,默认情况下您将处于正常模式。正常模式是运行 Vim 特定命令的模式。表 12-1 中列出了一些你可能想熟悉的最常见的。

表 12-1

Vim 命令

|

命令

|

描述

|
| --- | --- |
| :问 | 退出 Vim |
| :w | 保存文档 |
| :x | 保存并退出 |
| 我 | 进入插入模式 |
| :u | 取消 |
| Ctrl+r | 重做 |
| | 从插入模式返回正常模式 |
| :e | 在 Vim 已经打开的情况下打开文件 |
| :h | 帮助屏幕 |

注意如何退出 Vim 这是一个常见的问题,也是一个笑话,新加入这个项目的人很难退出这个项目。

Note

人们经常在退出 Vim 时遇到困难。在正常模式下,可以按:q。如果您更改了文件,您将在未保存的文件上方得到提示。你可以用:w保存一个文件,并将这两个动作合并为:wq。保存和退出也可以用一个稍微短一点的命令:x来完成。

使用帮助命令

如果您发现自己忘记了 Vim 基础知识,您可以通过运行:h打开帮助页面。这将把您带到一个常规帮助页面。如果您需要关于特定命令的信息,您可以在命令的:h后面跟随,例如:

:h G

这将调出G命令的具体帮助文本,如图 12-1 所示。

img/494886_1_En_12_Fig1_HTML.jpg

图 12-1

G 命令的帮助屏幕

复合命令

Vim 的一个伟大之处在于,它可以用一种非常简单的语言来组合命令。某些电源命令可以串在一起创建新的命令。做“删除内引号”这样的事情,三次击键就能完成;简单地按下

di" // delete in quotes

前面的命令表示三个较小的组件串在一起:

d = delete
i = in
" = quotes

现在你知道如何删除引号,你认为你如何删除括号内?

di) // delete in brackets

删除当前单词?删除段落中的?

diw // delete in word
dip // delete in paragraph

有几个类似的选择器可以用在同一个“在 X 中删除”序列中。你要做的就是把三个键序列中的最后一个键换出来。表 12-2 中显示了其中一些键和符号。

表 12-2

可与“删除于”复合命令一起使用的选择器

|

钥匙

|

描述

|
| --- | --- |
| " | 引用 |
| (, {, , < | 各种支架类型 |
| t | HTML 标签 |
| p | 段落 |
| w | 单词 |

Note

对于前面列出的任何方括号,如(、{、和[,您也可以使用该方括号的结束版本来获得相同的效果。

我们也可以把所有这些语句的第一个字母换出来,改变意思。一些复合命令示例如表 [12-3 所示。在极少数情况下,这个形容词可能根本不需要。例如'diw'可以进一步简化为'dw'。

表 12-3

复合命令的示例

|

动词

|

(数字)

|

形容词

|

名词

|

描述

|
| --- | --- | --- | --- | --- |
| c | - | 我 | t | 在 HTML 中创建标签 |
| d | four | - | l | 删除四个字母 |
| c | - | a | < | 删除-左右- |
| d | Two | - | w | 删除两个词 |

使用视觉模式选择

Vim 还有第三种模式,它提供的功能类似于在其他程序中用鼠标高亮显示一段文本。例如,用 Vim 打开/etc/passwd(确保不要使用 sudo 或 root,因为我们不想保存对此文件的任何更改,最好将/etc/passwd复制到您的/tmp文件夹中,并练习编辑副本)。

文件打开后,按v;这将使您进入视觉模式。现在你处于可视模式,按键盘上的向下箭头或j;当你向下移动文本时,你的高亮显示会改变。参见图 12-2 中您应该看到的示例。

img/494886_1_En_12_Fig2_HTML.jpg

图 12-2

在可视模式下选择文本

现在文本高亮显示,我们可以对它执行操作。如果我们按下d,所有高亮显示的文本都将被删除。

请注意,我们在前面的图像中为单词“games”选择了悬挂的字符。避免这种情况的一个好方法是进入视觉行选择模式,这与视觉选择模式相同,但只突出显示整行。要使用视觉行选择,使用shift+v而不仅仅是v

虽然这可能看起来与您习惯在普通文本编辑器中使用鼠标的方式相似,但 Vim 视觉模式实际上要强大得多。我们可以选择垂直的代码块,而不是选择文本行。为此,首先确保您处于正常模式,按下esc。现在按下ctrl+v并使用j或向下箭头向下滚动。

向下滚动四行后,按几次l或右箭头键。请注意,我们正在做与上面视觉模式相同的事情,但是选择了一个垂直的代码块,它将被高亮显示,如图 12-3 所示。

img/494886_1_En_12_Fig3_HTML.jpg

图 12-3

在视觉模式下垂直选择

此时,我们可以对选中的代码执行一个操作,如d删除或按esc切换取消选择并返回正常模式。视觉模式的另一个常见用法是在所有的行前添加一些常见的文本。例如,假设我们想要注释掉前四行代码。回到左上角,按下ctrl+v。接下来向下滚动四行,按ctrl+I(必须是大写的 I);这将进入插入模式,但我们实际上将同时输入所有四行。

现在如果我们输入#,变化将在每一行重复,如图 12-4 。当您对插入的文本感到满意时,按esc完成操作。如果我们想取消对这些行的注释,我们可以使用选择一个垂直的代码块并按下d来删除我们刚刚添加的内容的技术。

img/494886_1_En_12_Fig4_HTML.jpg

图 12-4

一次在几行的开头添加一个散列符号

确保不要保存任何这些更改。要退出 Vim 而不保存,您可以在正常模式下按:q!

我是来当家教的

当你安装 Vim 时,它还附带了另一个名为vimtutor的可执行文件。当您运行它时,将会打开一个教程,引导您使用 Vim。Vim 导师的第一课如图 12-5 所示。

img/494886_1_En_12_Fig5_HTML.jpg

图 12-5

我是来当家教的

它包含了做简单事情的详细课程,比如移动光标、编辑、删除和创建文本。建议您通过 Vim tutor 学习,掌握在 Vim 中做普通事情的窍门。

查找文本

在导航文本时,另一件常见的事情是查找特定的文本字符串。这可以在正常模式下使用/键完成。首先按下/,然后键入您要搜索的字符串。您将在屏幕的左下角看到您的输入。输入搜索短语后,按 enter 键,光标将根据光标的起始位置转到下一个字符串实例。

将光标放在第一个实例上,可以按n转到下一个实例,或按N转到上一个实例。

搜索可能是导航文档的一种强大方式,通常后跟一个组合命令,如用于“创建单词”的cw

查找和替换

有时当你搜索时,你真正想做的是找到一个变量或单词的所有实例,并用另一个名称或单词替换它。一旦记住了命令,这在 Vim 中也相当容易。

:%s/old/new/g

这里的%s代表替身;然后是旧词,后面是我们要替换的词。在这种情况下,g代表 global,意味着我们希望用“new”替换所有“old”的实例。运行不带g的相同命令将只替换找到的第一个实例。

另一个可以与 substitute 一起使用的有用选项是i不区分大小写(与 regex 相同),例如:

:%s/old/new/gi

这将替换该单词的任何匹配项,而不管该单词的任何字母是大写还是小写。

运行命令

也可以从 Vim 中运行 Unix 命令。例如,让我们在/tmp文件夹中创建一个名为“vim”的文件:

:!touch /tmp/vim

按 enter 键后,您将进入一个 shell 实例,其中显示了命令的结果。然后再次按回车键,您将返回到 Vim。这对于在不离开 Vim 或不改变窗口的情况下快速命令是很方便的。

除了运行一次性命令,还可以在 Vim 中运行全窗口终端。您可以通过运行:terminal或简称:term在 Vim 中打开一个迷你终端。它将在窗口的上半部分打开一个新的终端会话,如图 12-6 所示。

img/494886_1_En_12_Fig6_HTML.jpg

图 12-6

在 Vim 中打开终端会话

终端窗口显示在顶部,您可以在应用内终端和您正在编辑的文本之间快速来回移动。要在两个窗口之间切换,按下ctrl+w,然后按下w

要关闭终端窗口,首先按下ctrl+w,然后按下:q!,再按下enter,与强制关闭正常窗口的方式相同。

Vim 排序命令

另一个方便的内置命令是 Vim 的 sort,它类似于我们在前一章中看到的命令行实用程序sort。为了演示排序,进入/tmp文件夹,用 1 到 99 之间的 10 个随机数创建一个文件:

for i in `seq 10`;
  do echo ${RANDOM:0:2};
done > /tmp/numbers.txt

现在,如果我们打开/tmp/numbers.txt,你应该有十个未排序的数字,每个都在不同的行上。接下来在 Vim 中运行以下内容:

:1,5!sort

按回车键后,前五行应该被排序。第一个数字是排序的起点,第二个数字是终点。因此,如果您用 10 而不是 5 再次运行相同的命令,文件中的所有数字都应该是有序的。

显示和隐藏行号

在上一节中,我们在 sort 命令中使用了行号,这很容易,因为我们从第 1 行开始,但是如果您在一个长文件的中间呢?如果您需要查看行号,您可以运行

:set number

然后要再次删除数字,运行

:set nonumber

交换文件

在使用 Vim 时,您可能会注意到扩展名为.swp的文件的创建。当您正确关闭 Vim 时,会自动创建和删除这些备份文件。如果由于某种原因,您的 SSH 连接中断或 Vim 意外关闭,您将有机会恢复您的更改。只要重新打开关联有.swp文件的文件,你就会看到如图 12-7 所示的屏幕。

img/494886_1_En_12_Fig7_HTML.jpg

图 12-7

当打开一个有交换文件的文件时

请注意页面底部显示的选项。要恢复更改,请按R。如果不想恢复更改,就要按D;否则,每次打开该文件时都会看到这条消息,直到.swp文件被删除。

摘要

在本章中,我们看了如何使用 Vim 文本编辑器来提高生产率。它允许您快速操作文本,而无需使用鼠标,因为鼠标会导致您丢失上下文。我们研究了 Vim 的三种主要模式——正常模式、插入模式和可视模式。我们还看到了 Vim 如何拥有自己的语言来创建复合命令,比如代表“在 word 中创建”的ciw虽然这一章只展示了 Vim 的一小部分功能,但是希望它可以作为一个起点,让您能够使用编辑器并提高编辑文件的速度。

十三、编辑器

在这一章中,我们将谈论一个在 Linux 世界中非常受欢迎的编辑器。Emacs 是历史最悠久、最受欢迎的编辑器之一。虽然 Vim 非常紧凑,只专注于编辑文件的任务,但 Emacs 更像是一个可以为其创建“模式”的平台。Emacs 中的不同模式以不同的方式解释命令和文本。

模式可以与正在编辑的文本文件的类型相关,例如,特定于编程 Python、JavaScript、C++等的模式。然而,模式也可以像程序一样,例如,org-agenda 提供了一个全功能的议程、待办事项列表,以及 calendar 或 EWW 提供了一个功能性的 web 浏览器,而无需离开 Emacs。甚至还有一些社区制作的模式与外部 API 绑定,例如,telega模式提供了一个嵌入 Emacs 的全功能电报聊天应用。

我们不会查看 Emacs 中的每个模式,甚至所有标准特性,因为这本身就需要一整本书。相反,我们将调查一些从终端有用的有趣内容,如果您希望更深入地研究 Emacs 世界,这些内容可以提供一个起点。

Note

当讨论 Emacs 时,我将使用它们的标准语法来描述命令。当你看到类似

M-x run-command

“M-x”代表按住修饰键的同时按“x ”,在大多数机器上是 ALT 键。

你会看到的第二个东西是 RET 这仅仅代表按下回车键。

安装 Emacs

在大多数包管理器上都可以找到 Emacs 的相对最新的版本。要在基于 Debian 的系统上安装 Emacs,运行

sudo apt-get install emacs

在撰写本文时,我们发现 ELPA (Emacs Lisp Package Archive)上验证包的程序附带的 GPG 密钥已经过期。您可以使用以下命令手动更新密钥:

gpg --homedir ~/.emacs.d/elpa/gnupg \
  --receive-keys 066DAFCB81E42C40

根据读取时间的不同,可能需要更改066DAFCB81E42C40上方的键。查看 GNU 网站链接, https://elpa.gnu.org/packages/gnu-elpa-keyring-update.html ,在那里你可以找到最新的密钥,以便与“完整描述”正文中的命令一起使用

为了告诉 Emacs 使用 MELPA 包存档,您必须在您的主文件夹中创建一个名为.emacs的文件。它应该包含以下代码:

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(package-initialize)

Vim 绑定又名 Emacs 邪恶模式

我喜欢 Vim,因为你几乎可以在任何地方找到它,如果不是完整的,那么至少是限量版的vi。让 Vim 对我来说很棒的是,按键绑定允许我非常快速地修改和输入数据。然而,当谈到有趣的模式、模块和扩展时,我更喜欢 Emacs。

我们要看的有趣模块的例子包括艺术家模式、组织模式、演示和 tramp。在我们查看这些模块之前,我们将启用 Vim 键绑定,这样我们就可以在运行 Emacs 时使用我们所看到的 Vim 的最佳特性。值得注意的是,其他几个程序和 ide 提供了可选的 Vim 键绑定(在实现中有不同的质量水平),例如 VS Code 和 Qt Creator。一些终端程序如 Ranger 甚至默认使用它们,而另一些如bash允许你用一个选项来设置它们。

要在 Emacs 上启用 Vim 键绑定,我们首先需要安装模块“evil-mode”;这个名字一半是关于 Emacs 与 Vim 竞争的笑话,一半是基于 e (Emacs) + vi (Vim)的文字游戏。

在安装任何软件包之前,您应该更新本地软件包列表。这类似于在 Debian apt-get update上更新你的操作系统包管理器。要更新 Emacs 包管理器,请运行以下命令:

M-x package-refresh-contents

要安装 evil-mode,可以使用内置的包管理器 MELPA。运行以下命令:

M-x package-list-packages

这将显示 MELPA 上所有可用软件包的列表。接下来,我们将安装邪恶模式使用

M-x package-install RET evil

这将安装软件包,在屏幕的左下方,您应该看到“完成”安装了软件包后,您应该能够运行以下命令来为当前会话启用按键绑定:

M-x evil-mode

但是,在关闭 Emacs 并重新打开后,绑定将不再启用。为了确保在打开 Emacs 时默认启用绑定,我们将修改我们的~/.emacs文件。将以下两行添加到文件的底部:

(require 'evil)
(evil-mode 1)

Note

Emacs 中的一个主要概念是模式。改变模式可以改变输入键的反应方式。让 Emacs 使用 Vim 绑定的模式本身就是一种叫做evil-mode的模式。Emacs 中有两个子类别的调式:小调调式和大调调式。主要模式是排他的,而多个次要模式可以同时启用,并且每个模式都增加了一些功能。

在其他模式下使用 Vim 绑定的社区扩展已经存在,并且正在积极地维护/开发中。您可以在以下网址了解更多信息

www.github.com/emacs-evil/evil-collection

内置教程

像 Vim 一样,Emacs 有一个内置的教程,可以通过按

C-h t

这将打开一页文本,如图 13-1 所示。

img/494886_1_En_13_Fig1_HTML.jpg

图 13-1

GUI 模式下的 Emacs 内置教程

在切换到终端模式之前(我们将在下一节中进行操作),有必要研究一下默认的起始页,了解一下“打开主目录”等选项和链接的文档。从许多方面来说,Emacs 是为从 GUI 而不是在终端中使用而构建的。如果您喜欢 GUI 版本,并且它适合您的设置,请随意使用它。

在很大程度上,从终端而不是 GUI 使用 Emacs 并没有什么好处。它确实使从终端进入文件变得更容易,对于那些来自 Vim 的用户来说可能会感觉很舒服,但是许多 Emacs power 用户相信 GUI 版本,并且在单个实例中打开多个文件并在后台运行它。

在终端中运行 Emacs

默认情况下,Emacs 是一个桌面 GUI 程序。当然,如果你正在读这本书,你是为了终端特定的程序和工作流程而来的。您会很高兴听到 Emacs 也可以像 Vim 一样在终端中运行。为此,您需要使用--no-window-system选项打开程序,如下所示:

emacs --no-window-system

同样的事情也可以用捷径-nw来完成:

emacs -nw

当然,您可能不希望每次从终端启动 Emacs 时都这样写。你可以做的是给你的.bashrc文件添加一个别名,这样emacs就可以调用emacs --nw。在我的例子中,我决定使用e,因为敲五个键看起来工作量很大。.bashrc别名如下:

alias e='emacs -nw'

使用哪个按键模式的提示

如果你是 Emacs 新手,甚至是老用户,一个很好的安装模式是which-key-mode。此模式会弹出一个小缓冲区,显示您当前状态下可以使用的键盘快捷键。图 13-2 显示了哪个键对话的示例。

img/494886_1_En_13_Fig2_HTML.jpg

图 13-2

哪个键模式建议

从 MELPA 安装which-key-mode与安装evil-mode的过程相似。

M-x package-list-packages
M-x package-install RET which-key

一旦安装了which-key-mode,你需要修改你的~/.emacs文件,告诉which-mode在你输入命令时在迷你缓冲区显示建议。我们将使用use-package命令,所以我们首先需要导入它。在我们上一节写的以(package-initialize)结尾的代码块下,添加

  (package-install 'use-package))
(require 'use-package)

(unless (package-installed-p 'use-package)  (package-refresh-contents)

这将允许我们在命令中使用use-package。现在,在文件的底部,添加

(use-package which-key
  :ensure t
  :config
  (which-key-mode))

这确保了 Emacs 打开时which-key-mode开启。

完成后,关闭并重新打开 Emacs。现在如果你打字

C-x

你应该会看到一个小缓冲区,显示所有可以用来在C-x之后完成的键以及它们的作用,如图 13-3 所示的例子。

img/494886_1_En_13_Fig3_HTML.jpg

图 13-3

C-x 的哪个键模式建议

如果有太多的可能性需要列出,迷你缓冲区将被分成几个部分。要在它们之间切换,请按

C-h

这将允许使用n前进或p后退一节。

which-key有一些其他可以运行的内置命令。例如,如果您需要当前主要模式下可用命令的概述,请运行

M-x which-key-show-top-level

例如,如果你在evil-mode中,你会看到evil-mode的可用选项。

当您不熟悉 Emacs 时,能够看到所有可能的命令特别有用,因此强烈推荐这种模式。

Emacs 艺术家模式

虽然我更喜欢使用 Vim 进行文本编辑,但我欣赏 Vim 的竞争对手文本编辑器 Emacs 的独特性和有趣的模式。其中一些模式是内置的,而另一些必须使用内置的软件包管理器 MELPA 来安装。

这些有趣的模式之一是 Emacs 艺术家模式。艺术家模式提供了一套用于创建基于文本的艺术或图表的工具。图 13-4 显示了我在演示文稿和自述文件中包含的服务器架构图。

img/494886_1_En_13_Fig4_HTML.jpg

图 13-4

以艺术家模式制作的图表示例

这类图表的真正优势在于能够在终端上制作和查看它们。当通过 SSH 登录服务器并看到自述文件时,无法显示正常图像。然而,用 Emacs artist-mode 创建的图可以很容易地更改。

这类图像在非图形读物或手册中特别有用。例如,我在一个关于向物联网设备提供更新的系统的演示中使用了这种艺术,结合了 Emacs 演示模式,这是我们接下来要看的另一个模块。

Note

我们将在这里向您展示如何通过 Emacs 的终端版本使用艺术家模式,但这是一种在 GUI 版本中更容易使用的模式。这是因为在 GUI 中,你可以使用鼠标和拖放形状来绘制文本,而在终端中,你需要使用键盘来完成所有的事情。如果您的设置允许,您可能希望在 GUI 模式下启动 Emacs,并尝试用鼠标在艺术家模式下绘制文本。

用 Emacs 创建一个空白文件,然后切换到艺术家模式。在切换到艺术家模式之前,您需要创建一个空白空间(文字空格字符)的“画布”,在这里您将绘制您的图像。使用 Vim 绑定实现这一点的一个简单方法是按下i进入插入模式,并按住空格键,直到光标向右移动到您想要的画布宽度。然后按esc退出插入模式。按两次y复制空行;接下来按住p直到你的光标到达你想要的画布深度。你的光标应该停留在右下角,如图 13-5 所示。

img/494886_1_En_13_Fig5_HTML.jpg

图 13-5

在 Emacs 中创建一个空白画布,用于艺术家模式

从光标到左上方的空间现在都是空白,我们将在使用艺术家模式时操作。

接下来使用以下命令切换到艺术家模式:

M-x artist-mode

如果您启用了 Vim 绑定,您还会想要关闭它们,因为它们与artist-mode不兼容。您可以通过运行相同的命令来打开它们:

M-x evil-mode

一旦进入艺术家模式,我们有大量的形状工具可供选择。在终端模式下使用 Emacs 时,首先按下ctrl+c,然后按下ctrl+a,可以在所有形状之间进行切换,之后你可以在对应于特定形状的字母(不区分大小写,我复制了 Emacs GUI 中出现的快捷键)。

C-c C-a L         ## Line
C-c C-a r         ## Rectangle
C-c C-a s         ## Square
C-c C-a P         ## Poly-line
C-c C-a C         ## Ellipse
C-c C-a T         ## Text
C-c C-a z         ## Spray-can
C-c C-a E         ## Erase
C-c C-a V         ## Vaporize

在我们的例子中,我们将选择矩形;一旦你用C-c C-a r选择了矩形,移动你的光标到你想要开始绘图的地方。然后按下enter并四处移动光标;你会看到当你移动它的时候,矩形会改变形状。当对大小和形状满意时,按 enter 键完成。

尝试制作如图 13-6 所示的两个矩形。

img/494886_1_En_13_Fig6_HTML.jpg

图 13-6

在艺术家模式下创建的两个矩形

接下来使用切换到线条工具

C-c C-a l

将光标移动到顶部矩形的底部中间,然后按 enter 键开始您的行。将其向下移动到第二个矩形的顶部,使它们如图 13-7 所示连接起来。

img/494886_1_En_13_Fig7_HTML.jpg

图 13-7

用线条连接两个矩形的艺术家模式

为了让它看起来更像一个从顶部矩形到底部矩形的箭头,我们将把+替换为v。要做到这一点,只需在光标位于上图所示位置时按下v。你应该得到类似图 13-8 的东西。

img/494886_1_En_13_Fig8_HTML.jpg

图 13-8

在艺术家模式下,用 v 替换+使线条变成箭头

当不在艺术家模式下使用特定形状时,按下一个键就可以用您所按下的内容替换光标当前所在位置的文本。我们可以用同样的效果给矩形添加一些标签。将光标移动到您想要添加标签的位置,然后简单地输入。您可以添加标签文本,如图 13-9 所示。

img/494886_1_En_13_Fig9_HTML.jpg

图 13-9

在艺术家模式下向图表添加标签

如果您不小心写错了,您可以简单地将光标放在单词的开头,然后按空格键用空格覆盖文本。同样的道理也适用于当你书写时不小心弄乱了你的形状;只需用这种方法手动添加形状的缺失文本。

有了这两个简单的形状和技术,你可以创建相对复杂的建筑图形,就像本节顶部显示的木偶流行机一样。然而,如果你探索其他工具并且有时间,你可以创造无限的文字艺术。我会给你一些灵感,一个我在同一个演示中发现并使用的 pop 机器文本艺术图形,如图 13-10 所示。你可以在像www.asciiworld.comwww.asciiart.eu这样的网站上找到这样的文字艺术。

img/494886_1_En_13_Fig10_HTML.jpg

图 13-10

Pop 机器文字艺术

组织模式

另一种在原始文本中有效记录笔记甚至进行演示的有用模式是 Emacs org-mode。Emacs org-mode 是 organization mode 的缩写,提供了在分层标题下编写文本的能力,能够方便地扩展和压缩章节,例如,给定如图 13-11 所示的格式(标题由*指定)。

img/494886_1_En_13_Fig11_HTML.jpg

图 13-11

具有扩展部分的组织模式

要折叠一个部分,只需将光标放在要折叠的标题上,然后按下tab。级别由标题前面的星的数量来定义,如图 13-12 所示。

img/494886_1_En_13_Fig12_HTML.jpg

图 13-12

具有精简子部分的组织模式

折叠更高的标题将隐藏其所有子标题,如图 13-13 所示。

img/494886_1_En_13_Fig13_HTML.jpg

图 13-13

组织模式折叠部分

artist-mode一样,它不能很好地处理 Vim 绑定。如果你想同时使用 Vim 绑定和org-mode,有一些软件包试图给org-mode添加补丁,使其与 Vim 绑定一起工作,但我发现这不值得努力。套餐包括evil-orgorg-evilsyndicate。我的建议是不要同时使用这两种模式。如果您在启动时启用了evil-mode,您必须在运行org-mode之前通过运行evil-mode手动关闭它。

使用org-mode不需要安装任何额外的包,因为它是 Emacs 的标准配置。

组织模式下的表格

Org-mode 还有一个用于制作和使用表格的内置模式。组织模式下的表格由|字符指定。要生成表格,首先按

C-c |

这将在页脚打开一个对话框,询问您想要多大的表格,如图 13-14 所示。

img/494886_1_En_13_Fig14_HTML.jpg

图 13-14

屏幕底部的对话框询问新表格的尺寸

对于我们的例子,我们将使用 2x3。输入尺寸后,将生成如图 13-15 所示的空表。

img/494886_1_En_13_Fig15_HTML.jpg

图 13-15

在组织模式下创建的空 2x3 表格

接下来用一些示例数据填写表单。这样做后,工作台很可能会像图 13-16 所示那样错位。

img/494886_1_En_13_Fig16_HTML.jpg

图 13-16

组织模式下的无格式表

要重新格式化表格,请确保将光标放在表格的某个位置,然后按 ctrl+c 两次。

C-c
C-c

第二次按下后,org-mode 将重新排列表格,产生如图 13-17 所示的布局良好的表格。

img/494886_1_En_13_Fig17_HTML.jpg

图 13-17

组织模式中的格式化表格

您现在应该有了一个格式良好的基于文本的表格。

您可以找到处理表格的其他功能,例如将 CSV 格式转换为表格,以及在表格的组织手册页中重新排列行: https://orgmode.org/worg/org-tutorials/tables.html

从组织模式导出

使用org-mode可以做的一件方便的事情是使用一个简单的命令导出到其他几种文件格式。可能的格式包括

  • 便携文档格式

  • 超文本标记语言

  • 乳液

  • OpenDocument Text (ODT)文件

  • 纯文本

  • 伊卡伦达尔

要开始,请按

C-c C-e

这将打开一个显示可能导出选项的导出菜单,如图 13-18 所示。

img/494886_1_En_13_Fig18_HTML.jpg

图 13-18

组织模式下的导出类型选择

例如,如果我们想导出为 PDF,按下l按钮,该部分将会高亮显示。参见图 13-19 的 PDF 小节示例。

img/494886_1_En_13_Fig19_HTML.jpg

图 13-19

LaTeX 子部分在组织模式导出菜单中突出显示

我们现在可以按p导出为 PDF。完成后,将在与您的 org 文件相同的目录中创建一个 PDF。

组织-议程

处理 org 文件时,可以使用特殊的TODO指示器将文本标记为议程项目。你也可以告诉 org-agenda 跟踪某些文件,作为全球可访问的议程的一部分,包括像每日计划和日历这样的东西。

为了演示,创建一个名为/cal.org的文件。然后,为不同优先级的任务创建分区(高优先级、低优先级,如图 13-20 )。创建文件后,按

C-c [

这将把文件添加到 Emacs 的文件列表中,以供 org-agenda 查询。您可以通过运行以下命令来删除文件

C-c ]

添加文件后,任何 TODO 实例都将包含在 org-agenda 中。TODO 前面必须有一个*,如图 13-20 所示。

img/494886_1_En_13_Fig20_HTML.jpg

图 13-20

组织模式下的待办事项列表

现在,如果我们按 alt+x,输入 org-agenda,然后按 enter:

M-x org-agenda RET

我们将得到 org-agenda 的选项列表,如图 13-21 所示。

img/494886_1_En_13_Fig21_HTML.jpg

图 13-21

组织-议程菜单

t可以看到所有待办事项列表,如图 13-22 所示。

img/494886_1_En_13_Fig22_HTML.jpg

图 13-22

组织议程中列出的所有待办事项

在该议程选项卡中,我们现在可以按n进入下一行,按p进入上一行。下到您的列表项目之一,然后按下t。这将在您的议程和最初编写的文件中标记该任务为已完成。请记住,议程可以跟踪任意多的不同文件。因此,如果你想用不同的文件列出不同类型的任务,你可以这样做,然后把它们都拉进你的日程表(编译后的待办事项列表示例如图 13-23 所示)。

img/494886_1_En_13_Fig23_HTML.jpg

图 13-23

在组织议程中将待办事项标记为已完成

要退出议程,请按q

Org-agenda 也支持任务期限。要为待办事项添加截止时间,请将光标放在待办事项上,然后按

C-c C-s

这将打开一个可以输入日期的提示,如图 13-24 所示。

img/494886_1_En_13_Fig24_HTML.jpg

图 13-24

在组织模式下向待办事项添加日期

在输入日期/时间并按下回车键后,您将在任务下放置一个关联的日期,如图 13-25 所示。

img/494886_1_En_13_Fig25_HTML.jpg

图 13-25

组织模式下计划日期的待办事项示例

现在,如果您通过输入以下内容返回到组织议程选项

M-x org-agenda RET

然后按a进入日程周视图,你会看到你一周的任务按天显示,如图 13-26 所示的例子。

img/494886_1_En_13_Fig26_HTML.jpg

图 13-26

组织日程模式下的每周日程视图

一个预定的项目将保留在你的议程上,直到完成。Org-agenda 还提供了创建一个显示在日历上的条目的能力,但不管它是否被标记为完成,都将通过;要使用此替代时间戳,请在项目上按下C-c .而不是C-c s。还有一个高优先级的时间戳截止时间,可以在待办事项上按下C-c d来使用。

将组织日程与 Google 日历同步

Org-agenda 是一个很好的工具,但是它没有提供像手机甚至其他电脑这样的设备之间的无缝集成。MELPA 上有一个名为org-calendar的社区包,使 org-agenda 和 Google Calendar 之间的拉、推和双向同步变得容易。

从 MELPA 安装后,您必须在 Google 开发者控制台上设置一个项目,以使用他们的日历 API。你可以在他们的 GitHub 页面上找到关于设置org-calendar的最新说明。请记住,上次提交是在 2017 年 4 月,因此更新和支持可能有限。

www.github.com/myuhe/org-gcal.el

大纲演示模式

另一个可以与 Emacs 艺术家模式结合使用的好模式是 Emacs 演示模式。大纲演示模式允许您采用组织模式大纲,并将其转换为演示文稿,其中每个部分都充当幻灯片。不幸的是,这种模式没有在 MELPA 包管理器中发布。为了安装大纲演示模式,您需要手动下载脚本,然后将其添加到您的~/.emacs中。我发现很难在网上找到原始代码,所以我把脚本上传到了 GitHub。您应该使用 GitHub 下载它:

cd /tmp
git clone https://github.com/kirkins/outline-presentation-mode

然后进入下载的文件夹,将脚本移动到你的~/.emacs.d/extra/文件夹中(如果文件夹不存在就创建文件夹)。

cd /outline-presentation-mode
mv outline-presentation-mode.el ~/.emacs.d/extra/

现在,Emacs 脚本保存在您的~/.emacs.d/extra/文件夹中,您必须修改您的~/.emacs文件,以便在 Emacs 启动时加载脚本。在文件底部,添加以下内容:

(load-file (expand-file-name "~/.emacs.d/extra/outline-presentation-mode.el"))

现在,当您打开 Emacs 时,您将能够以大纲演示模式打开文件。您可能没有组织大纲文件演示文稿来测试;我在一个仓库里做了一个,你可以下载

git clone https://github.com/kirkins/puppet-pop-machine
cd puppet-pop-machine

接下来,在 Emacs 中打开名为presentation.org的文件。文件打开后,切换到presentation-outline-mode:

M-x presentation-outline-mode

这将打开演示文件并显示演示的轮廓,如图 13-27 所示。

img/494886_1_En_13_Fig27_HTML.jpg

图 13-27

Emacs 中的演示大纲模式

现在,您可以按住alt键并点击n进入下一张幻灯片;要返回,点击p。可使用的命令列表如表 13-1 所示( M 表示修改键,默认为 alt)。

表 13-1

Emacs 大纲模式命令

|

命令

|

描述

|
| --- | --- |
| 男男 | 下一张幻灯片 |
| M-p | 上一张幻灯片 |
| 男-女 | 下一部分的第一张幻灯片 |
| 前一个单词 | 返回上一节幻灯片 |
| 并购 | 第一张幻灯片 |
| 环粘贴 | 扩展目录 |
| M-s | 在目录中显示幻灯片光标 |
| M-r | 返回到您进入目录的幻灯片 |
| M-q | 退出演示模式并返回到组织模式 |

图 13-28 显示了一个纯文本幻灯片的示例。

img/494886_1_En_13_Fig28_HTML.jpg

图 13-28

嵌入在大纲演示幻灯片中的艺术家模式制作的图表

Emacs 蹦床

Emacs TRAMP 代表 Emacs 透明远程访问,多协议。它允许您通过在后台使用 rlogin、telnet 或 ssh 来访问远程文件系统,就像它们是本地系统的一部分一样。

Emacs TRAMP 默认包含在 Emacs 22.1 版本中,因此您不必做任何额外的工作来安装它。

要使用 ssh TRAMP,您首先要按

C-x C-f

这将在屏幕底部打开一个提示,让您导航您的系统以找到一个文件。它应该如图 13-29 所示。

img/494886_1_En_13_Fig29_HTML.jpg

图 13-29

按下 C-x C-f 后,在屏幕底部找到一个文件对话框

按 backspace 键删除文件路径,代之以/ssh:<your server>,如图 13-30 所示。为了使事情变得简单,我将使用一个在我的 SSH 配置文件中定义的简称“aws ”,这个文件已经有了我的用户名和密钥文件设置。

img/494886_1_En_13_Fig30_HTML.jpg

图 13-30

在查找文件对话框中输入/ssh:remotehostname 来激活 Emacs TRAMP

此时,按 tab 键,系统将开始在后台连接远程机器,出现如图 13-31 所示的信息。

img/494886_1_En_13_Fig31_HTML.jpg

图 13-31

显示 Emacs TRAMP 连接到远程服务器的对话框

一旦连接上,你就可以按 tab 键并获得所有远程文件的列表,就好像它是你本地机器上的一个文件夹一样。图 13-32 显示了一个例子。

img/494886_1_En_13_Fig32_HTML.jpg

图 13-32

通过 Emacs TRAMP 自动完成显示远程服务器上的文件

方便的是,您可以编辑远程机器上的文件,然后切换到本地机器上的文件,然后返回到远程机器上的文件,连接将保持打开。

您甚至可以同时与几台远程机器连接,并在文件之间无缝切换,同时保持本地 Emacs 编辑器设置——而不是通过 SSH 连接到那些机器,并使用每台本地机器上的编辑器的配置文件。由于这个原因,Emacs TRAMP 对于那些必须定期在几台机器上切换编辑文件的人来说特别有用。

其他模式

这里我们只看了几种 Emacs 模式,但还有很多。如果你感兴趣,这里有一个小清单可以让你开始。请记住,我这里关注的是类似应用的模式,但是几乎每种编程语言和配置文件类型都有模式。其他流行模式列表见表 13-2 。

表 13-2

Emacs 模式

|

名字

|

描述

|
| --- | --- |
| 壳 | Emacs 中的命令行 shell |
| 干燥的 | 导航目录的模式 |
| 呀 | Emacs 中的网络浏览器 |
| 魔法吗 | 高级 git 接口,用于合并等操作 |
| 常春藤 | 用于自动完成的交互式界面 |
| 牛羚 | 阅读电子邮件、RSS、新闻组群组等等 |
| 彩虹模式 | 为十六进制颜色代码设置背景 |
| 公司 | 文本完成 |
| 埃迪夫 | 用于比较文件和补丁的工具 |
| 飞溅模式 | 拼写检查用红色突出显示错误的单词 |

如果你已经安装了模式,你可以简单地按 alt+x 并输入名称。如果您想获得已安装模式的完整列表,请按

C-h a

然后进入“模式”;这将列出所有安装的模式,并附有非常简短的描述。

摘要

在这一章中,我们介绍了 Emacs 文本编辑器及其通过模式和嵌入式应用提供的许多功能,从创建艺术风格的图表和文本表格到管理任务列表和个人日历。正如我们所看到的,Emacs 不仅仅是一个文本编辑器,更像是一个可以构建基于文本的应用的平台。

十四、配置 Bash

在这一章中,我们将会看到 bash 的各种配置。这通常是通过使用 bash 启动时运行的配置脚本以及其他配置文件来完成的,这些配置文件控制已安装的实用程序或底层库,如.inputrc

配置脚本

我们将从用于直接定制bash的三个配置文件开始。这些包括.bashrc_profile.bashrc.profile

。bashrc_profile 或者。轮廓

.bashrc_profile配置脚本类似于.bashrc,但是它只在用户第一次登录时运行一次。在某些系统上,这个文件可能被指定为.profile,尽管如果.profile.bash_profile都存在,那么将使用.bash_profile

.bashrc_profile是定义.bashrc位置的入口点。这里有一个例子:

if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
        . "$HOME/.bashrc"
    fi
fi

前面的代码检查执行脚本的语言。如果语言是 bash,那么它会检查主文件夹中是否存在一个.bashrc文件。如果存在一个.bashrc文件,则执行该文件。

一个更简单的实现可能只包括以下内容,即如果.bashrc存在,则加载它:

test -r ~/.bashrc && . ~/.bashrc

虽然通常情况下.bashrc_profile只是加载.bashrc,但是也有可能将在.bashrc中完成的任何事情直接包含在.bashrc_profile中。

Note

的“.”在前面的. ~/.bashrc中是内置 bash 命令source的简写,它允许您将外部脚本加载到正在运行的脚本中。

.bashrc

~/.bashrc文件包含 bash 配置。它可用于定义在所有会话中都可用的变量或函数。每当您打开一个新的 bash 终端时,就会运行该脚本。

作为一个实验,试着打开你的.bashrc,它应该在~/.bashrc是可访问的。在文件的底部添加一行如下内容(尽管在文件的任何地方添加都可以):

export HELLO=world

接下来通过运行(或关闭终端并重新打开来重新加载~/.bashrc文件

source ~/.bashrc

现在,您应该能够在 bash 中使用变量$HELLO,并让它返回值“world”,例如,使用echo:

echo $HELLO

。bash_logout

虽然.profile脚本在登录时运行一次,但是.bash_logout正好相反。它只在您注销时运行一次。如果您想删除临时文件,这可能很有用。举个例子,我的 Ubuntu 系统上默认的.bash_logout包括以下内容:

# when leaving console clear the screen to increase privacy

if [ "$SHLVL" = 1 ]; then
    [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q
fi

前面的代码说明,如果退出的 shell 是基础层,并且文件/usr/bin/clear_console存在,那么运行带有-q标志的文件。

这里的$SHLVL 是一个自动存在的环境变量。要了解它是如何工作的,试试echo $SHLVL;这应该会返回值 1。那就试试

bash
echo $SHLVL

在 bash 中运行一个 bash 会话后,这个数字将是 2。如果您在那个会话中运行另一个 bash 会话,这个数字将变为 3。

Note

取决于您的发行版和用户,该文件可能存在,也可能不存在。比如我们发现使用 root 用户时,默认没有.bash_logout。当使用 Fedora 而不是 Ubuntu 时,我们发现该文件确实存在,但包含的代码不同。

全球版本

除了主目录中的.bashrc,如果你在基于 Debian 的系统上,你会在/etc/bash.bashrc有一个全局版本,在基于 Red Hat 的系统上,你会有/etc/bashrc。此外,你应该有一个充当全球版.profile/etc/profile。这些文件用于为所有用户设置 bash 的初始状态,在本地概要文件之前运行,.bashrc文件为每个用户运行。

在启动过程中,当/etc/profile运行时,还有一个文件夹执行几个名为/etc/profile.d/的脚本。如果你把一个可执行脚本放在这个目录中,只要它的扩展名是.sh,它就会在启动时运行。与普通的可执行文件不同,执行这些文件需要扩展名。

有用的配置。没有则创建

你可以用一个.bashrc文件做几件有用的事情。一些最常见的包括为常用任务创建别名,或者添加简单的函数以便在系统范围内访问。

定义别名

别名是一个短命令,它可以转换成一个更长的命令。这使得编写命令更加方便。例如,许多 Ubuntu 系统默认使用别名ll作为ls -alF的简称,它显示了当前目录的更详细视图。当我打开我的.bashrc时,我看到ll和一些默认的别名一起被定义:

alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'

我在自己的机器上添加的一个是将vi别名化为vim。这允许我运行相同的命令,不管我是运行在一个有完整 Vim 的机器上还是只有vi。如果你在 Fedora 上,你会发现这个别名是默认存在的。

alias vi="vim"

本着同样的精神,你可能想升级diff来代替使用colordiff(注意colordiff可能不是默认安装的):

alias diff="colordiff"

自定义功能

在某些情况下,如果你想创建一个快捷方式,你会发现你需要创建一个短函数,而不是使用一个例子。人们喜欢做的一件事是创建一个函数,用mkdir创建一个文件夹,然后用cd立即移动到那个目录。让我们通过向.bashrc添加以下函数来创建一个命令:

mkcd() { mkdir -p "$1" && cd "$1"; }

保存后,关闭终端并重新打开,因为新终端打开时会运行.bashrc文件。或者,您可以运行source .bashrc来重新加载配置,而无需重启您的终端。现在,如果你运行mkcd hello,你将创建一个名为 hello 的文件夹,并立即移入其中。

在某些情况下,您可能只是想包装一个有些难以记忆的现有命令。例如,许多系统将amixer用于声音。可以用amixer改变音量;我们可以包装现有的命令,使它变得简单一些:

volume() { amixer sset 'Master' $1%; }

这允许您从终端传入 0 到 100 之间的任何值来设置音量。

添加到路径

.bashrc中的另一个常见变化是增加了$PATH变量。此变量跟踪系统中存储可执行文件的文件夹列表。当您在没有指定完整路径的情况下运行一个可执行文件时,例如nmap,系统会检查您路径中指定的所有文件夹。当找到匹配时,就使用它。

如果你在系统上安装了编程语言,它们通常会自动修改你的.bashrc文件,并将保存可执行文件的文件夹添加到你的路径中。通过这样做,他们使他们的所有模块对你可用,作为你的路径的一部分。下面是安装 Rust 编程语言时创建的一行代码的示例。

export PATH="$HOME/.cargo/bin:$PATH"

注意结尾的:$PATH。这指定我们使用旧的\(PATH,并在前面加上出现在`:`之前的所有内容。在追加或前置现有的\)PATH 变量时,请始终使用该变量。否则,您可能会删除添加到其他文件或位置的文件夹。

更改 PS1 提示

.bashrc中另一个常见的定制是改变提示文本的颜色或内容。光标左侧显示的提示由环境变量 PS1 控制。如果您运行echo $PS1,您将在您的系统上看到一个编码版本。

可以通过更新 PS1 变量来改变,比如让我们把文本变成红色(为了实验,直接在终端运行而不是修改。bashrc):

export PS1="\e[0;31m[\u@\h \W]\$ \em "

运行前面的命令应该会导致提示符变成红色。接下来,尝试再次运行相同的命令,但增加 31,并观察每个数字如何产生不同的颜色。预期结果的示例如图 [14-1 所示。

img/494886_1_En_14_Fig1_HTML.jpg

图 14-1

更改 bash 提示文本的颜色

这段代码内容有点难以理解,因为它首先以一个根本看不到的转义字符\eo;开始。转义字符的存在导致窗口的标题栏包含工作目录,如图 [14-2 所示。

img/494886_1_En_14_Fig2_HTML.jpg

图 14-2

标题栏中的文件路径由于\eo;在 PS1

之后我们需要31m[来设置颜色。这是一个 ANSI 转义序列,可追溯到 20 世纪 70 年代;它们被用作嵌入文本的一种方式,而文本应该被解释为命令而不是文本。在这条线的最末端,我们有\e[m来重置颜色;如果不包含,您在终端中键入的文本将与别名的颜色相同。不同 ANSI 颜色代码的列表如表 [14-1 所示。

表 14-1

颜色的 ANSI 转义序列

|

顺序

|

描述

|
| --- | --- |
| 3000 万 | 黑色 |
| 3100 万美元[ | 红色 |
| 3200 万美元[ | 格林(姓氏);绿色的 |
| 33m[ | 黄色 |
| 34m[ | 蓝色 |
| 3500 万美元[ | 品红 |
| 3600 万美元[ | 蓝绿色 |
| 3700 万[ | 白色的 |

\u翻译成用户名,\h代表主机名,\W代表工作目录的基址。如果我们需要最少的提示文本,我们可以用

export PS1="-> "

或者如果我们只需要工作目录库:

export PS1="\W -> "

这导致了一个更小的外观,只显示工作目录的基础。如果您喜欢显示完整工作目录的默认方式,而不仅仅是基本目录,您只需要用小写版本的\w替换\W。PS1 符号列表如表 [14-2 所示。

表 14-2

PS1 提示命令

|

性格;角色;字母

|

描述

|
| --- | --- |
| h | 主机名改为第一个。“ |
| H | 完整主机名 |
| s | Shell 名称,例如“bash” |
| t | 24 小时制的当前时间 |
| @ | 12 小时制的当前时间 |
| u | 用户名 |
| w | 工作目录的完整路径 |
| W | 当前文件夹名称 |

另一种修改提示颜色的方法是使用tput。这种方法实际上更加灵活,因为它允许您使用 256 种颜色。然而,你必须在你的终端上启用 256 色;要快速查看支持的数量,请运行

tput colors

如果你得到一个小于 256 的数字,你需要确保你已经启用了xterm-256color。您可以通过在您的.bashrc中添加下面一行来实现:

export TERM=xterm-256color

确保在更新后运行source ~/.bashrc

启用 256 种颜色后,您现在可以将tput setaf与 256 种颜色代码中的一种一起使用。您可以通过搜索“256 种颜色代码”找到完整的列表然而,我们实际上可以通过在 bash 中运行以下命令来创建一个包含所有颜色的列表:

for c in {0..255}
do
   :
   if ! (( $c % 16 )) ; then
     printf '\n'
   fi
   printf '\e48;5;%dm'"%5s" $c $c; printf '\e[0m'
done

该脚本将遍历从 0 到 255 的每个数字,并根据该代码用背景色打印该数字。运行它应该会产生如图 [14-3 所示的结果。

img/494886_1_En_14_Fig3_HTML.jpg

图 14-3

创建一个包含所有 256 种颜色代码的表格

我们将使用之前的最小 PS1,然后用一个tput命令设置颜色,另一个命令重置颜色:

export PS1="$(tput setaf 166)\W -> $(tput sgr0)"

在您的终端中直接进行试验后,如果您发现您想要永久保存的东西,只需将它添加到您的.bashrc文件的底部。然后,如果你决定你不想要它了,你可以删除有问题的线。

PS2、PS3 和 PS4

除了 PS1 环境变量,还有一个 PS2。要查看您的 PS2,请运行以下命令:

echo $PS2
echo "hi

在第二行,一定不要包括结束”。这将导致 PS2 提示符显示,表明您需要完成前一个命令。注意这两个符号是如何与图 14-4 中的相同。

img/494886_1_En_14_Fig4_HTML.jpg

图 14-4

将 PS2 与交互式 shell 文本提示进行比较

请注意,前面的两个命令显示相同的“>”。

除了 PS1 和 PS2,还有 PS3 和 PS4,但它们并不常用。当 bash 中使用 select 提示符时,会使用 PS3,例如:

PS3=">"
select i in red blue green exit
do
  case $i in
    red) echo "Red";;
    blue) echo "Blue";;
    green) echo "Green";;
    exit) exit;;
  esac
done

运行时,我们会看到一个使用 PS3 值的选择菜单,旁边会提示用户输入文本,如图 14-5 所示。

img/494886_1_En_14_Fig5_HTML.jpg

图 14-5

使用select的脚本中的 PS3 示例

如果 PS3 没有指定值,缺省值将是#?。

最后,PS4 专用于调试带有-x标志的 bash。此标志用于调试;如果我们让用户选择一种颜色并把它放在一个文件中,我们可以用-x标志运行它:

bash -x ./choice.sh

当我们这样做时,我们会看到运行时显示的行,左边是 PS4 的值,在本例中是一个“+”号。示例见图 14-6 。

img/494886_1_En_14_Fig6_HTML.jpg

图 14-6

-x标志用于调试模式时的 PS4 示例

主题

您可以手动检查和更改视觉显示的所有方面,或者安装一个社区项目,使预先创建的终端颜色主题可用。

一些受欢迎的项目包括“Bash-it”和“哦,我的 Bash”;然而,这两个项目都捆绑了大量的功能和配置。其他项目,如高,更少,只提供主题。

这些都需要运行外部 bash 脚本,所以请确保做自己的研究,以检查这些项目在阅读时仍然处于良好状态。也值得自己浏览一些脚本,并检查公共问题跟踪器,以确保项目在试验之前仍然处于良好状态。这可以通过查看项目的最后一次提交或发布来完成。你也可以在一个项目的 GitHub 页面的 issues 选项卡上查看用户最近的反馈。

终端中的实时时钟

另一个巧妙的技巧是添加一个实时时钟,它展示了增加终端趣味的多种可能性。这可以通过运行下面的代码片段来实现(或者将它放在您的.bashrc中使之永久化):

while sleep 1;
do
  tput sc;
  tput cup 0 $(($(tput cols)-11));
  echo -e "\e31m`date +%r`\e[39m";
  tput rc;
done &

这会创建一个每秒运行一次的循环。它获取你的终端的宽度,并将光标移动到右上角的左边 11 个空格。然后用date输出当前时间,最后用tput rc将光标返回正常位置。图 [14-7 显示了一个实时时钟效果的例子。

img/494886_1_En_14_Fig7_HTML.jpg

图 14-7

终端右上角的实时时钟

或者,如果我们不介意时间只在每个命令后更新,我们可以将时间放在提示文本中。为此,您可以使用我们之前使用的一个命令来更新提示颜色,并添加指定当前时间的\t,例如:

export PS1="\e0;32m\t \W \$ \e[m "

运行前面的命令后,您将在提示文本中看到时间。如果您想使用 12 小时制,将t切换到T:

export PS1="\e[0;32m\T \W \$ \e[m "

或者,您可以使用@字符来表示带有 AM/PM 指示器的完整 12 小时格式:

export PS1="\e[0;32m\@ \W \$ \e[m "

三种提示时间格式的示例如图 [14-8 所示。

img/494886_1_En_14_Fig8_HTML.jpg

图 14-8

bash 提示文本中的时间格式

在打开时运行程序

有时人们会在终端上运行程序,开始使用.bashrc来增加美感。这可以包括像fortune这样的事情,或者回显一个包含一些 TODO 项的文本文件。

另一个需要运行的常用命令是neofetch命令。这不是默认安装的,但是可以在大多数包管理器中找到。这是一个高度可定制的系统信息脚本。这是一种在截图中与世界分享他们选择的设置的方式,同时展示他们选择的终端主题。图 14-9 显示了我的机器上 Neofetch 的输出示例。

img/494886_1_En_14_Fig9_HTML.jpg

图 14-9

Neofetch 的输出

图 14-9 是在我的机器上运行neofetch的一个例子。

在 terminal open 上运行这个命令或任何命令就像在您的.bashrc底部添加一行命令一样简单。当打开一个新的 bash 终端时,您从.bashrc运行的任何程序都将运行。

Note

程序screenfetch提供了一个类似于neofetch的替代方案,只是对徽标的渲染略有不同。它也可能比neofetch略快。

导入文件

如果您的.bashrc文件变得很大,您可能希望将其分成多个文件。这允许你共享和重用部件,而不必处理一个长文件。例如,您可能希望将所有别名分离到一个名为.bash_aliases的文件中。只需将别名行移动到一个新文件中,并使用source导入新文件:

source ~/.bash_aliases

放置在.bashrc中的前一段代码将导致.bash_aliases在每次打开新终端时被加载和运行。

。inputrc(输入 rc)

我们在前面的章节中提到过.inputrc是一种将 bash ( 和其他几个程序)键盘快捷键改为基于 Vim 的快捷键,而不是默认的类似 Emacs 的快捷键。

.inputrc文件影响所有使用 GNU readline 库的程序,该库包括几个流行的程序,包括 bash 以及 Ruby、Python 和 MySQL 等编程语言的 REPLs。

如前所述,.inputrc中的一个选项是通过添加行来切换到 Vim 键盘快捷键

set editing-mode vi
set keymap vi

通过打开全局文件/etc/inputrc,我们可以看到.inputrc的所有默认值,该文件为所有用户提供了初始值。这个文件可能包含一些配置以及解释这些配置的注释。

一个可能的修改是当你双击 tab 激活自动完成时关闭声音输出。您可能没有注意到,在许多系统中,当您按 tab 激活自动完成时,会发出声音。这可以通过添加以下内容来关闭

set bell-style none

另一个可能但很少使用的选项是使自动完成不区分大小写,这样,如果您用大写或不大写来写文件夹的名称,它将完成,而不管匹配的文件夹使用什么大小写。

set completion-ignore-case On

你可能已经注意到你经常需要点击 tab 键两次来显示所有的完成。如果您希望立即看到所有可能的完成,您可以添加以下行:

set show-all-if-unmodified On

有时按 tab 会导致文件部分完成,但这时你会碰到有两种或更多可能的方式来完成文件名的地方。通常情况下,它会补全到差值,然后您必须再次按 tab 来查看可能的补全。如果你想让它自动完成所有可能的事情,并在一个结局中显示所有结局,请启用show-all-if-ambiguous:

set show-all-if-ambiguous On

当您运行类似于ls的命令时,您可能会收到颜色编码的结果,这取决于您的系统。如果您也想为自动完成启用此功能,您可以添加以下行:

set colored-stats On

如果您想用一个可视符号来指示文件类型,类似于运行ls -F时显示的类型,您可以添加一行

set visible-stats On

虽然修改.inputrc并不常见,但它确实提供了一些不同的选项,这些选项在其他地方是做不到的。

除了改变通知声音和在 Vim 和 Emacs 风格的键盘快捷键之间切换,你可能永远不需要修改你的.inputrc,尽管也可以修改键盘快捷键的功能或者添加新的快捷键。要获得.inputrc所有可能选项的完整列表,运行

man 3 readline

其他点文件

术语点文件是指以点开头的隐藏文件,用于配置程序。虽然.bashrc是最受欢迎的网络文件之一,但它远不是唯一的。安装的默认程序和附加程序都有各种类型的点文件。可用于定制程序的一些其他示例包括

  • 。wgetrc

  • . curlrc

  • .gitconfig

  • -vim 的

  • . tmux.conf 文件

摘要

在这一章中,我们看了.bashrc.inputrc,这两个点文件可以用来定制 bash 终端。我们看到了一些常见的修改,比如添加路径、定义函数和创建别名。我们还查看了一些不常用的配置文件,如.bash_logout和配置选项,如终端提示符和颜色。

十五、Tmux 工作流

在这一章中,我们将学习 Tmux,终端多路复用器的缩写——一个主要用于管理后台进程的实用程序,但也有许多其他用途。除了保持进程运行之外,Tmux 还可以用于将终端划分成更小的屏幕,创建一个定制的布局,可以同时监视几个窗格。

后台脚本

Tmux 是我最常用的程序之一。它主要用于管理正在运行的 shell 脚本、ssh 会话和任何类型的 bash shell 进程。在过去的几年中,Tmux 变得如此流行,以至于它被预装在一些 Linux 发行版中,比如最新的 Ubuntu Desktop。

如果您的机器上没有安装 Tmux,应该可以通过您的软件包管理器获得:

sudo apt-get install tmux

一旦您开始使用基于终端的应用和进程,您会很快发现您可能想要运行一个进程并保持它运行,而不必在您的用户界面上保持一个专用的终端窗口打开。传统上,这可以通过内置命令的组合来完成。

为了演示,让我们创建一个持续的进程,每 3 秒钟用当前时间更新一个文件:

(while sleep 3; do date > /tmp/time; done)

当前面的命令在活动终端中运行时,按ctrl+z暂停该过程。那就跑

bg

运行bg将再次启动该进程,但是在后台。但是,该进程仍将与终端会话相关联。接下来,让我们获取当前终端会话中运行的作业列表。

jobs

您将获得当前终端中运行的作业列表,每个作业都有一个相关的编号。通过运行以下命令,您可以使用作业号取消它与终端会话的关联:

disown %1

您需要将 1 替换为与您想要脱离的进程相关联的数字。一旦运行了该命令,您就可以安全地关闭终端窗口,该过程将继续运行。您可以通过进入/tmp文件夹并确保time文件每 3 秒更新一次来确认这一点。

使用 Tmux 的后台脚本

手动方法的问题是没有简单的方法来重新附加一个被放弃的进程或程序。相反,建议您使用 Tmux 来管理和切换虚拟终端窗口。要创建新的终端会话,只需运行

tmux

您应该在页面底部看到一个绿色的小条,表示您的窗口是一个 Tmux 会话。现在,作为一个示例程序,运行以下内容:

top

您现在应该看到top正在运行并列出您机器上所有正在运行的进程。现在,我们将从 Tmux 会话中分离出来,并保持窗口在操作系统的后台运行,这样我们以后就可以轻松地重新挂接了。为此,请按 ctrl+b(同时)然后按 d。

Note

这里不要同时按下d按钮,这一点很重要。对于所有 Tmux 命令,首先按下ctrl+b,然后释放,再按下命令专用键。

现在,您将回到默认的终端窗口,该窗口可以关闭,而不会影响在后台运行的 Tmux 会话。

如果您想查看计算机上运行的所有 Tmux 会话,请运行

tmux ls

这将返回 Tmux 会话及其相关 id 的列表。要重新连接到其中一个会话,请运行以下命令(用要连接的会话 ID 替换 1):

tmux a -t 0

这在多种情况下非常有用,包括但不限于

  • 您希望同时连接到多个服务器或物联网设备,以运行可能需要一些时间才能完成的命令。

  • 您希望将命令放在后台,但保留返回调试的能力。

  • 您正在使用基于终端的编辑器,比如 Vim,并且想要在多个文件之间切换而不关闭它们。

带 SSH 的 Tmux

您希望使用 Tmux 的最有用的情况之一是通过 SSH 使用远程服务器或设备。通常,当连接到服务器时,您需要执行长时间运行的任务。由于无法方便地后台处理和重新连接会话,一些人求助于让 SSH 会话在他们的桌面上运行,等待作业完成。

这不仅通过强制用户在命令期间保持计算机打开来限制用户,还引入了连接中断的风险。当一个正常的 SSH 会话中断时,通常运行的脚本会被终止;因此,重新连接后,您需要从头开始。

Tmux 让您可以自由地启动一个命令,断开与会话的连接,然后关闭 SSH。当您返回服务器并连接到会话时,就好像您从未离开过一样。如果您正处于 Tmux 会话中,并且您的 SSH 连接中断了,不必担心,因为它将继续运行,并且在您重新连接时可用。

这使得 Tmux 不仅是长时间运行的命令的理想选择,也是您想要永久运行的脚本(如 web 服务器或脚本)的理想选择。在出错的情况下,通过名称连接到有问题的会话、查看程序输出中的错误、进行必要的更改并重新启动脚本变得很容易。

命名会话

当我们创建第一个 Tmux 会话时,我们看到它被自动命名为0,我们使用tmux a -t 0重新连接。当创建一个新的会话时,也可以给这个会话起一个昵称来帮助你了解它正在运行什么。让我们创建一个名为“top”的会话:

tmux new -s top

现在,如果我们从会话中分离并使用tmux ls,我们将在之前看到“0”的地方“置顶”。如果您已经创建了一个会话,并且想要更改名称,您可以运行

tmux rename-session -t top new-name

只需切换出“top”作为目标会话的名称,切换出“new-name”作为您想要的新名称。

切换 Tmux 会话

高度可定制,有许多快捷的键盘快捷键。大部分键盘快捷键会使用 ctrl+b 后跟一个字母。我最常用的键盘快捷键之一是 ctrl+b 后跟 s。在这种情况下,s代表 switch,允许您在打开的 Tmux 会话之间快速切换,而无需分离。

例如,假设您打开了几个 ssh 会话,并希望在等待进程完成时从一个会话切换到另一个会话。只需运行ctrl+b s,并使用向下箭头选择您想要打开的会话。然后在另一个会话中运行您想要的任何命令,并再次快速按下ctrl+b s切换回来。

杀死会话

有几种方法可以终止现有会话。如果您已经主动连接到会话,只需按下ctrl+d按钮,会话就会像普通终端一样关闭。

或者,您可以用kill-session命令终止一个没有连接的会话。与附加和重命名一样,您将使用-t标志提供有问题的终端的名称:

​​tmux​​ ​​kill-session​​ ​​-t​​ new-name

前面的命令将终止名为“new-name”的会话。也可以通过关闭整个服务器来一次关闭所有会话。为此,运行

​​tmux​​ kill-server

使用该命令时要小心,因为它会在没有警告的情况下立即停止您在 Tmux 会话中运行的任何脚本。

会话中的窗口

可以在一个 Tmux 会话中创建多个窗口,每个窗口运行自己的 bash 会话。在我们讨论创建窗口和在窗口之间导航之前,我们应该澄清 Tmux 中存在的三个层次以及 Tmux 窗口的技术定义,因为它与我们通常认为的窗口略有不同。Tmux 上终端会话的层次结构如表 15-1 所述。

表 15-1

Tmux 层级

|

学期

|

描述

|
| --- | --- |
| 会议 | 一组窗口。是 Tmux 中层次结构的最高级别 |
| 窗户 | Tmux 会话中包含的 bash 会话。一个会话可以包含多个窗口 |
| 窗格 | 窗格包含在窗口中。一个窗口可以分成多个窗格,这样就可以同时查看多个窗格 |

当我们创建一个 Tmux 会话时,默认情况下它自动有一个单独的窗口。要创建第二个窗口,请确保您在 tmux 会话中,然后运行ctrl+bc。这将使你进入一个新的窗口。

窗口通常被比作选项卡,因为它们是可以在会话中轻松切换的工作区。此外,在屏幕的左下角,显示了会话中的所有窗口,活动窗口的末尾有一个“*”。图 15-1 显示了指示运行 Tmux 窗口的文本示例。

img/494886_1_En_15_Fig1_HTML.jpg

图 15-1

Tmux 状态栏中的窗口列表

要更好地查看窗口与我们的会话的关系,请按下ctrl+b,然后按下w。这将打开所有会话和窗口的列表;这是在两者之间转换的简单方法。Tmux 会话列表的示例如图 15-2 所示。

img/494886_1_En_15_Fig2_HTML.jpg

图 15-2

Tmux 中活动会话和窗口的列表

注意这两个窗口是如何作为标签为0的会话的子窗口列出的。您可以按上下箭头键在窗口之间移动,并按 enter 键聚焦于一个窗口。为了强调窗口是会话的孩子,让我们通过按下ctrl+b然后按下d来完全脱离 Tmux。

接下来通过运行tmux创建一个新的会话,当会话打开时,创建一个新的窗口,在ctrl+b后面跟着c。现在,如果我们再次按下ctrl+b,然后按下w,我们将看到类似图 15-3 所示的会话列表。

img/494886_1_En_15_Fig3_HTML.jpg

图 15-3

两个会话,每个会话有两个子窗口

我们有两个会话,每个会话都有两个子窗口。让我们进入标有“(4)”的第三个窗口。现在,如果我们想从这里回到“(5)”,我们可以重新打开窗口列表,但一个更短的方法实际上是前面的ctrl+b后面跟着p。要再次返回“(4)”,您可以按下ctrl+b,然后按下n进入下一步。或者,如果我们想指定具体的窗口,我们可以用窗口号代替pn

这对于根据窗口的用途对会话中的窗口进行排序非常有用,例如,将 SSH 会话的所有窗口都放在一个会话中。

窗格分割

Tmux 还提供了一个强大的辅助功能,允许您将一个窗口分割成单独的部分,称为窗格,每个窗格运行自己的 bash 实例。当需要同时运行多个终端应用或监视多个全屏终端应用时,这非常有用。

要开始,首先确保您打开了一个 Tmux 会话,然后按下ctrl+b,再按下"。这将水平分割你的窗口。图 15-4 显示了一个窗口水平分割的例子。

img/494886_1_En_15_Fig4_HTML.jpg

图 15-4

分成两个窗格的 Tmux 窗口

或者,如果您想水平分割会话,请按下ctrl+b,然后按下%。图 15-5 显示了一个垂直分割窗口的例子。

img/494886_1_En_15_Fig5_HTML.jpg

图 15-5

Tmux 中的垂直分割窗口

也可以拆分一个已经拆分的子部分,以便为每个会话创建尽可能多的窗口。为此,只需再次运行水平或垂直分割命令。参见图 15-6 中一个窗口分成三个 bash 终端的例子。

img/494886_1_En_15_Fig6_HTML.jpg

图 15-6

Tmux 中垂直和水平窗格的组合

如果您决定从 Tmux 分离或在窗口和会话之间切换,您的 pane 设置将被保存。

您可以通过按下ctrl+b然后按任意箭头键在窗格之间切换。或者,ctrl+b后跟o将切换到下一个窗格,一旦到达最后一个窗格,循环回到第一个窗格。

时钟模式

如果你使用窗口分割来分割你的工作空间,你可能最终想要在一个窗口中显示一个实时时钟。Tmux 提供了一个小的额外功能来简化这个过程。当 Tmux 会话在窗口中激活时,按下ctrl+b,然后按下t。时钟模式显示的示例如图 15-7 所示。

img/494886_1_En_15_Fig7_HTML.jpg

图 15-7

单一窗格中的 Tmux 时钟模式

这将使用您的系统时间打开一个实时时钟。要退出时钟模式,请按qesc

帮助页面

Tmux 还带有一个内置的帮助页面,其中包含一个包含每个键盘快捷键的列表;有几个,所以它是多页长。要激活它,请按

ctrl+b, ?

你应该得到一个如图 15-8 所示的可滚动页面;可以用escq退出。

img/494886_1_En_15_Fig8_HTML.jpg

图 15-8

Tmux 帮助页

使用. tmux.conf 进行自定义

可以定制 Tmux 来改变用于触发动作的组合键,以及修改外观和布局。Tmux 的所有定制都是通过编辑~/ .tmux.conf完成的;如果您的系统中不存在该文件,只需创建它,tmux 就会使用它。该配置文件可用于创建新的键盘快捷键,以及更改 tmux 的视觉外观。

Tmux 首先在/etc/tmux.conf中查找适用于所有用户的全局配置,然后在主目录中查找文件.tmux.conf。因此,如果你想在多个用户之间应用设置,你可以使用全局版本。如果你没有一个~/.tmux.conf文件,那么从创建一个开始。

touch ~/.tmux.conf

配置颜色和样式

类似于在.bashrc中改变颜色,我们只能使用尽可能多的颜色。要检查终端上启用了什么颜色,请运行

​​tput​​ ​​colors

如果您得到一个小于 256 的数字,您将希望通过在您的.bashrc文件中添加以下内容来启用 256:

export TERM=xterm-256color

可用的 256 种颜色与上一章相同。除了直接使用色标,我们还有常用颜色的关键字,包括黑色蓝色青色绿色洋红色红色白色黄色

例如,如果我们想让终端底部的 Tmux 条变成蓝色,我们可以在.tmux.conf中添加以下内容:

set-option -g status-bg blue

这将改变背景颜色为蓝色。如果我们想改变 Tmux 条的文本,我们可以添加

set-option -g status-fg white

这将产生一个类似图 15-9 的底部条。

img/494886_1_En_15_Fig9_HTML.jpg

图 15-9

带有修改颜色的 Tmux 状态栏

Note

当更新 tmux 的颜色和样式时,你需要确保在新的样式生效之前所有的 tmux 窗口都已经被终止。如果在后台只打开了一个 tmux 窗口,改变样式,然后打开一个新窗口,旧的值仍然有效。

如果我们想直接使用 256 种颜色代码中的一种,我们可以使用color后跟颜色代码,如下所示:

set-option -g status-bg color14

我们还可以改变打开的窗口的颜色,让它显示不同于状态栏其他部分的颜色。

set-option -g window-status-bg blue
set-option -g window-status-fg black

当您将活动窗口名称设置为不同的颜色时,这将变得更加有用:

set-option -g window-status-current-bg white

这创造了窗口真的像标签的感觉,当你在窗口之间切换时,你得到一些视觉反馈。启用该样式的状态栏示例如图 15-10 所示。

img/494886_1_En_15_Fig10_HTML.jpg

图 15-10

Tmux 状态栏中的当前窗口高亮显示

除了状态栏,您还可以更改窗格边框的颜色。

set-option -g pane-border-bg green
set-option -g pane-border-fg yellow

与 windows 一样,窗格有一个单独的选择器。

set-option -g pane-active-border-bg blue
set-option -g pane-active-border-fg yellow

图 15-11 显示了一个应用这些风格的例子。

img/494886_1_En_15_Fig11_HTML.jpg

图 15-11

修改了 Tmux 中的窗格边框颜色

更改状态栏内容

类似于 bash 中的文本提示可以被改变,Tmux 状态栏中的文本也可以被改变。左侧和右侧由两个不同的变量控制。作为一个例子,让我们使用一些简单的静态文本来更新左右两边。与上一节一样,以下几行可以添加到.tmux.conf文件中:

set -g status-left "Hello"
set -g status-right "World"

这将替换默认的左右状态栏文本,如图 15-12 所示。

img/494886_1_En_15_Fig12_HTML.jpg

图 15-12

在 Tmux 中修改状态栏文本

当然,在大多数情况下,您需要一些交互方面的信息,比如时间、主机名和打开的窗口数量。像.bashrc一样,为这些元素保留特殊代码。状态栏中可使用的代码列表如表 15-2 所示。

表 15-2

状态栏代码

|

密码

|

描述

|
| --- | --- |
| #我 | 当前窗口的索引 |
| #P | 当前窗格的索引 |
| #S | 会话名称 |
| #T | 当前窗口的标题 |
| ## | 用于文字# |
| #H | 主机名直到第一个 |
| #h | 完整主机名 |
| #(命令) | 运行命令并显示输出的第一行 |
| #[属性] | 通过换行修改文本的颜色或属性 |

因此,如果我们希望主机名后面跟着当前窗口的索引,例如,运行

set -g status-left "#h #I"

如果文本由于空间限制而被截断,您可以使用

set -g status-left-length 200

属性标签可以与其他代码和文本结合使用,以更改文本的颜色,例如:

set -g status-left "#[bg=red, fg=white]#h #I"

重新映射命令

如果你发现你经常使用的组合键不舒服,你可以修改它。例如,在切换到 tmux 之前使用 GNU Screen 的人经常发现自己想要使用ctrl+a来代替 Tmux 键盘快捷键之前使用的前缀ctrl+b。要将前缀命令绑定到ctrl+a,应该在配置文件中添加下面一行:

set -g prefix C-a

这将导致ctrl+a被用作命令的前缀,如分离、创建新窗口等。默认情况下,您的ctrl+b也将仍然连接到前缀命令。如果您想从命令中分离一个组合,您必须手动执行另一个步骤。

unbind C-b

如果您在编辑.tmux.conf文件时运行 tmux,您必须手动获取配置才能使其生效。

tmux source-file ~/.tmux.conf

如果您正在使用 Vim,您可能希望添加按键绑定,以便能够使用 h、j、k 和 l 进行导航,每一个都映射到类似于 Vim 中使用的方向。

# Vim Movement
bind h select-pane -L # left
bind j select-pane -D # down
bind k select-pane -U # up
bind l select-pane -R # right

这将允许您使用ctrl+b后接h来切换到您左侧的窗格以及其他键的相关方向。

使用 Tmux 共享屏幕

Tmux 使之成为可能的另一个有趣的用例是屏幕共享终端窗口。如果有两个人使用同一个用户登录到一个服务器或设备,他们都可以完全访问该用户的所有 Tmux 会话。这包括使两个人同时连接到同一个 Tmux 会话的能力,并且当任何一个人与终端交互时,两个人都可以看到实时更新。

这是进行结对编程或与他人一起调试系统的好方法。与其他屏幕共享方法不同,SSH 上的 Tmux 几乎不占用任何带宽,并且它为两个用户提供了交互的能力,而不是简单地让一个人看另一个人。

主题公园

与样式化.bashrc一样,有些项目专门研究 Tmux 的定制和主题化。其中最受欢迎的是“哦,我的 Tmux ”,它除了提供一个令人愉快的主题外,还增加了一些额外的功能,如电池指示器。图 15-13 显示了“哦,我的 Tmux”的默认样式。

img/494886_1_En_15_Fig13_HTML.jpg

图 15-13

哦,我的主题

“哦,我的 Tmux”增加的另一项功能是键盘指示器,它指示前缀ctrl+b何时被按下,Tmux 何时等待命令键。该键盘符号如图 15-14 所示;显示时,表示前缀已被按下,Tmux 正在等待 command 键。

img/494886_1_En_15_Fig14_HTML.jpg

图 15-14

哦,我的 Tmux 前缀按下状态栏中的指标

要安装 Oh My Tmux,只需克隆项目并将.tmux.conf.tmux.conf.local移动到您的主文件夹。如果你想保存任何东西,一定要备份你原来的.tmux.conf

git clone https://github.com/gpakosz/.tmux
cd .tmux
cp .tmux.conf* ~

那么您所要做的就是打开和/或重启 Tmux。

除了样式的改变,你还会有一些额外的按键绑定,比如我们手动配置的 Vim 按键绑定——额外的绑定用于创建带有ctrl+b后跟-的水平窗格或者带有_的垂直窗格的窗口。

以及对ctrl+b的新绑定,后跟+以将窗口内的窗格移动到使用全屏仅显示该窗格的新窗口。有关特性和绑定的完整列表,请参见 Oh My Tmux GitHub 上附带的自述文件。

Tmuxinator

当您开始使用 Tmux 并通过将窗口分割成窗格来创建自定义工作空间时,您可能会发现您有一些想要经常创建的设置。例如,假设我们想要运行一个被分成systemctlhtopnmon的窗口,如图 15-15 所示。

img/494886_1_En_15_Fig15_HTML.jpg

图 15-15

Tmux 中的系统监控工作区

Tmuxinator 是一个 Tmux 启动器,它允许你创建预定义的布局,这样你就可以轻松地打开特定的工作空间,而不需要在每次打开时手动操作。你需要安装 Ruby 编程语言来使用 Tmuxinator。

sudo apt-get install ruby
gem install tmuxinator

Tmuxinator 还需要设置环境变量EDITOR;如果你运行echo $EDITOR并且它是空的,你需要在你的.bashrc文件中设置它。将该值替换为您首选的编辑器:

export EDITOR="vim"

安装了 Tmuxinator 之后,您可以通过运行

tmuxinator new system-monitor

将在您选择的编辑器中打开一个 YAML 文件的模板,包括帮助您使用语法的注释。打开一个有三个窗格的窗口的布局示例如下(它使用了htopnmon,因此您需要确保它们已安装或使用其他程序):

name: system-monitor
root: ~/

windows:
  - monitor:
      layout: main-vertical
      panes:
        - systemctl
        - htop
        - nmon
  - editor: vim

Note

当您在 Tmuxinator 中创建新的布局时,请确保删除所有默认情况下存在的样板代码。样板文件中许多注释的下面是一个示例布局,如果不删除或编辑,它将覆盖您的代码。

前面的示例创建了一个名为“monitor”的窗口,其中包含三个列出了程序的窗格,以及第二个运行 Vim 的窗口。Tmuxinator 还提供了其他的配置变量,比如root定义了窗口或窗格从哪个目录开始,或者 attach 指定了会话是否应该在创建时打开。

有关功能和选项的完整列表,请参见 Tmuxinator GitHub 页面上的自述文件。

摘要

在这一章中,我们研究了在本地和远程处理长时间运行的终端会话时,Tmux 如何改进您的工作流程。除了基础知识之外,我们还看到了 Tmux 如何允许在多个 bash 会话之间分割屏幕,从而为任何目的定制布局。我们使用 tmuxinator 进一步自动化了布局的创建,它允许将布局保存为 YAML 配置文件,并在一个命令中快速打开。

我们还看到 Tmux 有一个类似于 bash 配置文件的配置文件~/.tmux.conf,在这里我们可以覆盖任何键绑定并改变 Tmux 的颜色和样式。使用这里描述的技术中的一小部分,就可以显著地改进您的终端工作流程。

十六、用于处理图像和视频的终端工具

虽然命令行主要是基于文本的,但令人惊讶的是,有一些很棒的工具可以处理图像和视频,这些工具可以与它们的 GUI 对等物相媲美,或者在某些情况下是它们的基础。例如,如果您使用过任何类型的修改或生成图像的网站,它很可能在后端使用 ImageMagick。同样,如果你使用过任何基于 Linux 的视频编辑器,很有可能它是建立在ffmpeg之上的。

考虑到这些基于视觉的程序中有许多只是简单地调用命令行的等价物,您可以通过学习使用命令行版本来完成简单的任务,如修改图像或视频,从而节省一些时间。我们还将看看一些不常用的程序,如 gnuplot,以及如何修改启动时显示的动画。

简介

操纵图像的最强大的工具之一实际上是命令行固有的。ImageMagick 不仅广泛用于命令行,还用于使用 PHP、Python 和 Node.js 等语言的服务器端代码。这些语言本质上只是为功能丰富的命令行实用程序提供了一个包装器。

使用 ImageMagick 可以做的一些事情包括

  • 转换图像

  • 绘制形状

  • 绘制文本并对其进行操作

  • 描绘一幅图像

  • 使图像变形

  • 裁剪图像

  • 图像过滤器

创建带文本的图像

若要开始,请确保安装了 ImageMagick。它可以在大多数包存储库中找到。与许多程序不同,它不是用安装时的名字来调用的。相反,ImageMagick 使其他命令如convert可用。首先,让我们创建一个大小为 400 x 400 像素的空白画布:

convert -size 400x400 xc:white white.png

你现在应该有一个 400 x 400 像素的空白白色图像。

接下来,让我们添加一些文本到我们的图像:

convert white.png -gravity North \
  -pointsize 30 -annotate +0+100 \
  'Basic Linux Terminal' white.png

这里使用的-gravity North选项告诉 ImageMagick 将文本放在图像的顶部;或者,我们可以用南、西或东。让我们使用South在图像底部创建另一段文本;这个上面写着“提示和技巧”:

convert white.png -gravity South \
  -pointsize 30 -annotate +0+100 \
  'Tips and Tricks' white.png

然后pointsize指定字体大小,接着annotate增加文本周围的空间,这样它就不会紧靠图像顶部。

检查文本是否按预期呈现后,尝试旋转文本:

convert white.png  -distort ScaleRotateTranslate 30 white.png

你现在应该有一个类似图 16-1 的结果。

img/494886_1_En_16_Fig1_HTML.jpg

图 16-1

ImageMagick 生成的图像

为了让前面的预览更容易看到,我实际上添加了一个 3 像素的黑色边框,这样更容易看到它的开始和结束。这可以通过命令来完成

convert -bordercolor Black -border 3x3 white.png white.png

获取图像信息

在本书的前面,我们看到我们可以使用file命令来获取文件类型的信息。然而,当谈到图像时,实际上有更多的元数据您可能想看。ImageMagick 提供了另一个名为identify的工具来检查图像细节。最简单的用法是用一个文件作为输入来运行它:

identify white.png

这将返回图像的基本信息,包括类型、尺寸、色谱和大小。您可以通过添加-verbose标志获得更详细的信息;参见图 16-2 获取identify -verbose命令的输出示例。

img/494886_1_En_16_Fig2_HTML.jpg

图 16-2

使用 ImageMagick identify命令的图像数据

您可能会发现-verbose标志实际上返回了太多的数据。如果您想要挑选要显示的特定属性,您可以直接指定它们,例如:

identify -format '%f - %m - %w \n' white.png

前面的示例指定文件名、文件类型和宽度,后跟一个换行符。您可以在 https://imagemagick.org/script/escape.php 找到完整的字母列表及其代表的属性。

给图像加标签

您可能想要执行的另一个常见任务是给照片添加一个小标签;当你计划在网上展示图片,并希望人们知道你是图片的原始来源时,如果图片被保存并在其他地方展示,这将非常方便。

要做到这一点,我们可以简单地使用内置的composite label,它将在我们的照片的左上方添加一些文本,只需一步:

composite label:'github.com/kirkins' white.png labeled.png

结果将看起来像输入图像,在左上角添加了我们的小而持久的标签,如图 16-3 所示。

img/494886_1_En_16_Fig3_HTML.jpg

图 16-3

使用 ImageMagick 向图像添加标签

ffmpeg

这类似于 ImageMagick,但用于视频而不是静态图像。ffmpeg可用于各种常见的视频编辑任务,在包括 Audacity 和 VLC media player 在内的许多流行的视频和音频编辑 GUI 软件套件的代码中实际使用了它。

您可以使用 ffmpeg 做的一些事情包括

  • 转换视频文件类型

  • 压缩视频

  • 加快/减慢视频播放速度

  • 修剪剪辑

  • 提高/降低声音

转换文件类型

ffmpeg提供的最简单和最常见的命令之一是文件类型的简单转换。在许多情况下,转换视频非常简单——只需使用-i标志进行输入,并通过使用输出所需的文件类型扩展名来指定输出类型。例如,如果我们想将 mp4 转换成 webm,只需运行以下命令:

ffmpeg -i video.mp4 video.webm

同样的技术也可以应用于音频文件,例如 mp3 到 ogg:

ffmpeg -i audio.mp3 audio.ogg

甚至可以拍摄视频并将其输出为 gif 格式,尽管您可能希望只转换短视频:

ffmpeg -i video.mp4 picture.gif

另一种稍微复杂一点的常见转换是从视频文件类型转换到纯音频文件类型。在这种情况下,您需要添加代表“视频编号”的-vn标志,例如:

ffmpeg -i video.mp4 -vn song.mp3

压缩视频

在本地录制视频并希望将其上传到网络后,您可能会发现视频文件太大,不适合实际使用。你可以用ffmpeg运行一行程序来压缩它,而不是加载一些笨重的视频编辑软件:

ffmpeg -i input.mp4 -b 1000000 output.mp4

在前面的例子中,我们获取了一个名为input.mp4的视频,并以 1,000,000 比特或每秒 1 兆比特的缩减比特率将其输出为output.mp4。客观地说,一张 DVD 通常是每秒 4-8 兆比特,而蓝光是 24-40 兆比特。大小取决于视频的尺寸和质量。

放慢视频播放速度

如果你曾经想看一些慢动作的东西,但不想做打开一个成熟的视频编辑器的艰苦工作,ffmpeg有一个解决方案给你。任何视频(或声音文件)都可以通过ffmpeg轻松加速或减速。这可以通过以下命令完成:

ffmpeg -i video.webm -filter:v "setpts=2.0*PTS" slow.webm

在前面的命令中,2.0意味着我们的视频扩展到两倍于原始长度。如果我们改为使用setpts=0.5*PTS,我们会有相反的效果,通过压缩到一半的长度来加速视频。

通过使用不同的滤波器,同样可以应用于诸如 mp3 之类的音频:

ffmpeg -i audio.mp3 -filter:a "atempo=2.0" slow.mp3

上述示例只会影响视频,但声音将以正常速度播放。如果你想改变这两个,你需要添加第二个过滤器。例如,要以与视频相同的速度减慢声音,请添加-filter:a "atempo=0.5":

ffmpeg -i video.webm \
  -filter:v "setpts=2.0*PTS" \
  -filter:a "atempo=0.5" slow.webm

或者要将视频和声音的速度都提高两倍,请使用

ffmpeg -i video.webm \
  -filter:v "setpts=0.5*PTS" \
  -filter:a "atempo=2" slow.webm

剪辑视频

你可能想使用ffmpeg的另一个常见任务是修剪视频,这样你就可以从原始视频的某个部分创建一个新的视频。如果我们想将 3 秒钟开始的内容剪切到 8 秒钟的视频中,我们可以运行

ffmpeg -i vid.webm -ss 00:00:03 -t 00:00:08 -async 1 cut.webm

这将产生一个名为cut.webm的新视频文件,其长度为 8 秒,从 3 秒标记到 11 秒标记。同样的命令也可以应用于像 mp3 这样的音频文件。

提高视频的音量

如果你曾经遇到过即使在最大音量下也很难听到音频的视频,下面这个命令就是为你准备的。有了ffmpeg,我们实际上可以放大文件的音频,让它以更大的音量播放。

音量用“dB”来衡量,dB 代表分贝。如果我们想将视频中的音频提高 5 分贝,我们可以运行以下命令:

ffmpeg -i in.mp4 -vcodec copy -af "volume=5dB" out.mp4

同样,我们可以使用负值来降低音量,例如,-5dB将音量调低 5 分贝:

ffmpeg -i in.mp4 -vcodec copy -af "volume=-5dB" out.mp4

使用 youtube-dl 下载视频

现在,您对如何使用 ffmpeg 修改、修剪和处理视频已经有点熟悉了,您可能会发现自己想要处理来自网络上的视频,例如,从 YouTube 下载一首经常听的歌曲并将其转换为 mp3,或者从一个有趣的视频中剪切一个剪辑,将其转换为 gif 与朋友分享。

youtube-dl是一个非常活跃的命令行工具,用于下载 YouTube 视频和 1000 多个不同的网站,包括

  • 维莫

  • 声音云

  • 脸谱网

  • 推特

  • 像福克斯和加拿大广播公司这样的新闻网站

这只是 1000 多个受支持网站中的一小部分。完整名单可在 https://github.com/ytdl-org/youtube-dl/blob/master/docs/supportedsites.md 找到。

安装youtube-dl最常见的方式是通过 Python 的包管理器pip:

sudo -H pip install --upgrade youtube-dl

然而,如果你不想使用pip,也可以用curl从官方网站下载一个可执行文件。要获得最新的安装选项,请在 https://github.com/ytdl-org/youtube-dl 查看 GitHub 上的项目。

最简单的命令,也可能是您最常用的命令,就是简单地使用实用程序,传入您想要下载的视频的 URL:

youtube-dl https://www.youtube.com/watch?v=DfK83xEtJ_k

请注意,默认情况下,将下载最高质量的视频,前一个视频超过 1GB。如果您想下载另一种格式,您可以使用-F标志查看视频的可用格式。返回的可用格式示例如图 16-4 所示。

img/494886_1_En_16_Fig4_HTML.jpg

图 16-4

使用 youtube-dl 查看可用格式

记下您想要的视频的第一列“格式代码”。格式代码可以用-f标志指定,允许你下载一个小得多的版本,从而加快下载速度并节省你的日期(或仅当你想列出时才下载音频)。根据前面的列表,如果我们想下载尽可能小的视频,我们可以选择格式代码 598,它几乎可以立即下载:

youtube-dl -f 598 https://www.youtube.com/watch?v=DfK83xEtJ_k

如前所述,youtube-dl是一个非常活跃的项目,有很多选项和特性。在 GitHub README 上查看一些额外的特性绝对是值得的,但是在大多数情况下,我们在这里看到的将会完成工作。

用 gnuplot 创建图表

另一个可以从命令行执行的基于视觉的任务是将数据可视化为图形——要么在终端上查看数据,要么将数据转换为图像文件以备后用。

一个使这变得容易的程序是gnuplot,它在包管理器中广泛可用。

为了演示如何绘制一个简单的条形图,让我们创建一个名为days.dat的数据文件,包含以下内容:

0 Monday 100
1 Tuesday 220
2 Wednesday 75

接下来打开gnuplot,只需输入命令,无需输入或选项。

gnuplot打开的情况下,首先将模式切换到dumb,使生成的图表在终端显示为文字艺术。默认情况下,图表是在基于qt的 GUI 中生成的,该 GUI 在每个命令后弹出;尽管没有完全基于终端,但是qt版本的图表看起来更好。因此,如果您喜欢使用qt,只需跳过第一个命令:

set terminal dumb

接下来,我们将设置图表的框宽和填充样式:

set boxwidth 0.5
set style fill solid

最后,告诉gnuplot使用以下命令绘制days.dat文件

plot "days.dat" using 1:3:xtic(2) with boxes

这里的1:3指定我们使用数据的第 1 列作为 x 坐标,第 3 列作为 y 坐标。然后xtic(2)说我们应用第 2 列作为每个 x 值的标签。如果我们改为使用xtic(1),我们的日期名称标签将被索引数字所取代。最后,with boxes简单地指定了图表类型。可视化输出的示例如图 16-5 所示。

img/494886_1_En_16_Fig5_HTML.jpg

图 16-5

gnuplot 在终端显示条形图

gnuplot也可以用来绘制数学方程,例如运行plot sin(x)生成如图 16-6 所示的图表。

img/494886_1_En_16_Fig6_HTML.jpg

图 16-6

gnuplot 在终端显示折线图

任何方程都可以这样绘制,例如,用plot 5*x + 3可以生成一个简单的方程,表示一条斜率为 5、y 轴截距为 3 的直线。

gnuplot 到图像文件

能够在终端中显示图表是很好的,但在大多数情况下,您会希望将图表导出为图像,以便在报告或演示中传达信息。以同样的方式,我们设置gnuplot使用哑模式,我们可以设置它导出为一个图像文件。运行以下命令切换到 png 模式:

set terminal png

接下来,你必须告诉gnuplot你想在哪里输出图像文件;否则,您将在屏幕上看到未经处理的原始 png 数据,这一点用也没有。

set output "graph.png"

现在,如果我们按照与制作第一个条形图完全相同的步骤,我们将在工作目录中得到一个“graph.png”文件。每次将图形绘制到文件时,都需要使用前面的命令重新指定输出文件。

由于我们不再在终端工作,您可能会想要为您的图表添加一些颜色。为此,我们将修改原始的 plot 命令

plot "days.dat" using 1:3:0:xtic(2) with boxes lc var

我们在1:3:0中添加了一个新值,它使用索引创建了一个新变量;该变量随后与lc var一起使用,并针对每个条形递增。前面的命令应该会产生如图 16-7 所示的结果。

img/494886_1_En_16_Fig7_HTML.jpg

图 16-7

导出到图像文件的 gnuplot 条形图

内置多种配色方案,包括podoclassicdefault。要更改方案,运行以下程序,用您想要的方案替换podo:

set colorsequence podo

高级示例/演示文件夹

我们已经看了一些用gnuplot绘制线条和条形图绘制数据的基本例子。然而,这只是gnuplot能力的一小部分。该程序可用于创建深入的信息图表。这超出了本书的范围,但是我们将从gnuplot官方演示文件夹中分享几个例子: https://github.com/gnuplot/gnuplot/tree/master/demo 。参见图 16-8 、 16-9 和 16-10 中包含的演示示例。这些演示的代码可以用作绘制您自己的数据的起点。

img/494886_1_En_16_Fig10_HTML.jpg

图 16-10

gnuplot 图表轮廓示例

img/494886_1_En_16_Fig9_HTML.jpg

图 16-9

gnuplot 示例图表 rgb_variable.5.gnu

img/494886_1_En_16_Fig8_HTML.jpg

图 16-8

gnuplot 图表直方图示例

启动动画

我们可以对操作系统进行的另一个有趣的修改是改变启动时的默认动画屏幕。在某些情况下,了解这一点实际上很有用,例如,如果您正在定制嵌入式设备上工作,或者甚至是一个游戏单元,并且希望有一个主题启动屏幕。

一个很好的例子是开源主题 PlymouthTheme-Cat ( https://github.com/krishnan793/PlymouthTheme-Cat ),当安装并启用后,它会用一只动画猫取代你的默认启动屏幕,如图 16-11 所示。

img/494886_1_En_16_Fig11_HTML.jpg

图 16-11

自定义启动动画

使用这个主题需要你的操作系统使用 Plymouth。Plymouth 是一个提供无闪烁图形引导过程的包,默认安装在基于 Debian 和 Fedora 的发行版上。

首先在你的/usr/share/plymouth/themes里安装主题;这可以通过直接克隆到文件夹中来实现:

sudo git clone \ https://github.com/krishnan793/PlymouthTheme-Cat.git \ /usr/share/plymouth/themes/PlymouthTheme-Cat

主题成功下载到主题文件夹后,接下来您需要安装主题:

sudo update-alternatives --install \ /usr/share/plymouth/themes/default.plymouth default.plymouth \ /usr/share/plymouth/themes/PlymouthTheme-Cat/PlymouthTheme-Cat.plymouth 100

安装后,通过运行以下命令将其设置为默认值

sudo update-alternatives --config default.plymouth

这将弹出一个选择菜单;输入选项列表 PlymouthTheme-Cat 的编号,如图 16-12 所示。

img/494886_1_En_16_Fig12_HTML.jpg

图 16-12

选择要使用的普利茅斯主题

最后,您需要更新 initramfs 映像。这是启动时运行的映像,目的是挂载文件系统。

sudo update-initramfs -u

完成后,您现在可以重新启动计算机,并在启动过程中欣赏自定义的猫动画。

制作自定义启动动画

虽然猫的动画肯定做得很好,但你可能想制作自己的自定义动画。尝试自己制作的最简单的方法是查看普利茅斯猫的来源。注意,源文件包含 111 个连续的 PNG 文件,从progress-0.png开始,到progress-111.png结束。按顺序观看,这些图像创建动画。

如果您想创建自己的映像,最好的方法是用您自己的相同尺寸的 PNG 文件替换这些映像,然后重新运行用于安装 Plymouth Cat 的步骤。这将产生一个基于您提供的图像的动画。

一旦您对结果满意,您可以更新PlymouthTheme-Cat.plymouth中的值并重命名文件夹。

我们不会深入讨论如何生成图像文件的细节,但是 GIMP 和 Photoshop 等应用都支持将动画导出为多个 PNG 文件。

摘要

在这一章中,我们看了一些实用程序,它们使得在不打开庞大的编辑器的情况下处理图像和视频成为可能。这对于常见的快速任务非常有用,如转换文件类型、添加水印或修剪视频和音频内容。在某些情况下,就像 gnuplot 一样,我们使用数据创建新的图像,同样不需要打开图像编辑器。

最后,我们看到启动过程中显示的闪屏实际上是由一个名为 Plymouth 的程序控制的。我们下载了一个简单的动画,并将其设置为我们的启动动画。这是一个有趣的修改,在设置定制硬件时非常有用。例如,通过添加自定义动画,可以使自动启动视频游戏模拟器或连接到电视的多媒体盒的 Linux 系统看起来像一个独特的创作。

十七、额外服务

在本书中,我们已经研究了所有类型的命令和实用程序。然而,有几个方便的命令无视任何类别。在这最后一章,我们将看看有趣或有用的命令和工具,不一定适合一个类别。

大卡

另一个简单但有用的命令行程序是cal,它通过命令行提供了一个简单的日历。关于cal的一个很棒的事情是,它作为标准安装在几乎所有的 Linux 发行版上,因为它出现在第一版 Unix 中,并且是 POSIX 标准的一部分。cal最简单的用法是不带任何标志或参数运行它,它只产生一个当月的视觉效果,突出显示当天,如图 17-1 所示。

img/494886_1_En_17_Fig1_HTML.jpg

图 17-1

cal命令的输出

为了可视化一整年,您可以添加-y标志,这将产生一个类似的图形,但会以月份块的形式显示当前年份中的所有月份,如图所示。

在很大程度上,这就是我使用cal的程度,一个我经常使用的小程序。但是,它也提供查看特定年份或月份的能力,例如:

cal 2000      # display the year of 2000
cal june 2009 # display June of 2009

回头看看关于.bashrc的部分,你可能还会考虑添加一行简单的cal来显示一个日历,当你打开你的终端时,突出显示当天——尽管我个人不喜欢这增加的混乱。

电子语

如果你是一个喜欢听文本而不是阅读文本的人,你会非常想了解espeakespeak获取文本输入,并将其作为音频读取或将该音频输出到音频文件。这个包可以在 Ubuntu 包管理器中找到。

sudo apt-get install espeak

安装后,你可以做的最简单的事情就是把一些文本输入到espeak中,然后直接在你的机器上听音频。

echo Hello World | espeak

如果不使用管道,而是希望提供一个包含文本的文件,可以使用如下所示的-f标志:

echo Hello World > text.txt
espeak -f text.txt

默认的声音有点单调,但这是我们在下一节要改进的地方。一些内置的标志包括改变速度之类的东西。速度由代表“每分钟字数”(默认 175 )的-s标志和以毫秒为单位设置字数间隔的-g标志控制(默认 10 )。下面是 100 wpm 慢速和 250 wpm 快速的例子:

echo hello world | espeak -s 100 -g 20 # slow
echo hello world | espeak -s 250 -g 5 # fast

改善说话声音

通过安装来自开源语音引擎 MBROLA 的语音,espeak 使用的语音可以得到大幅改善。不幸的是,MBROLA 的网站不再在线;然而,它仍然可以使用 Wayback 机器与语音文件一起访问。要查看非常过时的网站上的信息,请查看以下链接:

https://web.archive.org/web/20180625050250/http://www.tcts.fpms.ac.be/synthesis/mbrola/

要下载并安装 MBROLA,请运行以下命令:

cd /tmp
wget \
https://web.archive.org/web/20180627172600/http://www.tcts.fpms.ac.be/synthesis/mbrola/bin/pclinux/mbr301h.zip
unzip mbr301h.zip
sudo cp mbrola-linux-i386 /usr/bin/mbrola

接下来我们将下载英语语音文件。如果你想要另一种语言,你必须使用存档的 MBROLA 网站找到合适的文件。要安装英语语音,请运行以下命令:

cd /tmp
wget \
https://web.archive.org/web/20160706052143/http://www.tcts.fpms.ac.be/synthesis/mbrola/dba/en1/en1-980910.zip
unzip en1-980910.zip
sudo cp en1/en1 /usr/share/mbrola/en1

安装了 MBROLA 和英语语音后,您现在可以使用如下所示的-v标志选择语音(建议将速度减慢到每分钟 120 个单词):

echo Hello World | espeak -v mb-en1 -s 120

将语音输出到音频文件

如果您最终使用 espeak 来转换大量文本,您可能希望将其输出为音频文件,而不是直接播放。这让您可以随意暂停、播放和倒带,更不用说将文件移动到其他设备或共享了。如何做到这一点的例子如下(我们假设在同一个目录中有一个名为 text.txt 的文件中有文本;如果没有,从网页上复制一些文本并粘贴到文本文件中):

espeak -f text.txt -w audio.wav

不幸的是,espeak只有输出为 wav 文件的选项,所以如果你想要 mp3 或其他类型,你需要运行一个额外的命令来使用ffmpeg进行转换。

ffmpeg -i audio.wav -vn -ar 44100 -ac 2 -b:a 192k audio.mp3

命令行上的数学

在过去的几章中,我们已经使用了bc,但是它值得一提,因为它经常被忽略。首字母代表基本计算器。它安装在大多数类 Unix 操作系统上,因为它是 POSIX 标准。它提供了在命令行上进行数学运算或编写特定于bc的脚本的能力。

在命令行中,bc由另一个命令的管道输出使用,例如:

echo 1 + 1 | bc

运行前面的脚本将返回输出 2。它支持你在任何计算器上期望的加、减、乘、除的基本运算。此外,您还有一些特殊的命令,例如,获取一个数的平方根:

echo "sqrt(169)" |  bc

注意,当使用任何带括号的bc符号时,我们需要用引号将它括起来;这是为了避免 bash 将其解释为 subshell。bc中另一个可用的特殊命令是 length,它返回一个数的位数:

echo "length(169)" |  bc

前面的脚本返回 3。类似地,有一个函数scale计算小数点右边的位数,例如,下面的函数返回 3:

echo "scale(169.777)" |  bc

除了使用管道,还可以在交互模式下启动bc。为此,使用-l标志运行它:

bc -l

除了作为一个命令行实用程序,bc实际上可以用作一个完整的脚本语言,它支持 C 语法进行数字操作和创建代码重用函数。

另一个命令expr也可以在许多系统中找到,它在没有管道的情况下计算数学语句。然而,不推荐使用expr,因为它已经过时了:

expr 1 + 1

同样,你还会在许多系统上发现dc,它也是一个先于 C 语言的反向波兰符号计算器。

平铺窗口管理器

超级用户应该关注的另一类应用是平铺窗口管理器。平铺窗口管理器取代了 Linux 操作系统的 GUI 界面。)并提供了一种将你的工作空间分割成小块的方法。

平铺窗口管理器被吹捧为帮助操作系统使用一个完全无鼠标的过程。当使用平铺窗口管理器时,任何可以用鼠标完成的事情都可以用键盘更好地完成。由于这个原因,平铺窗口管理器经常被作为提高命令行界面使用效率的一种方式。

就我个人而言,我发现平铺窗口管理器的有用性取决于手头的任务。如果我的工作流涉及到同时运行的十几个不同的终端会话,我几乎总是选择平铺窗口管理器。然而,如果我的工作流涉及 web 浏览器、word 编辑器和一些终端会话,我会选择普通的桌面体验,在tmux中使用终端会话。

在过去,有几个不同的竞争平铺窗口管理器,但目前i3wm似乎是最流行的。在寻找流行的替代品时,我发现i3wm是过去 12 个月中唯一一个稳定发布的 Linux 平铺窗口管理器。出于这个原因,我们将把重点放在i3wm作为最好的和最常见的平铺窗口管理器。如果您对研究其他窗口管理器感兴趣,一些备选方案包括“Awesome window manager”、xmonad、dwm 和 ratpoison。

i3wm 擅长能够在终端会话和终端会话组之间快速切换。例如,我可能有一个用各种工具监视系统的终端页面,创建一种仪表板。然后在另一个窗口中,我可能有一些到不同被测设备的 SSH 会话。

如果你不熟悉平铺窗口管理器,我建议你把它安装在传统桌面旁边,而不是作为你唯一安装的桌面界面。如果你忘记如何做某事,或者在 i3wm 中做某件事情有困难,这将使事情变得更容易。如果是这样的话,你可以随时切换回 Ubuntu 桌面(或者你选择的界面),以后再回到 i3wm。

i3wm可以简单地安装在大多数 Linux 发行版上,只需在您的软件包管理器上运行以下等效程序:

sudo apt-get install i3

安装i3wm后,注销或重启电脑。如果你在 Ubuntu 或 Fedora 上,在登录界面上,你应该会看到一个设置图标,如图 17-2 所示。单击设置图标后,应该会出现一个可能的桌面界面列表。选择标有i3的那个。

img/494886_1_En_17_Fig2_HTML.jpg

图 17-2

在登录屏幕上选择 i3

第一次启用 i3wm 登录时,系统会询问您是否要创建配置文件,如图 17-3 所示。我们建议使用默认设置,将 Windows 键设置为用于键盘快捷键的 i3wm 修饰键。然而,在撰写本文时,我们发现在生成配置时按下<enter>然后选择默认选项比选择<esc>效果更好,而此时选择<esc>似乎会导致问题。

img/494886_1_En_17_Fig3_HTML.jpg

图 17-3

i3 第一个配置对话框

安装后,您可以在大多数平台上通过注销并在登录屏幕上从下拉列表中选择 i3wm 来切换到 i3wm。起初,像使用 Vim 一样使用i3wm可能会令人望而生畏。你遇到了一个空白的黑屏,没有明显的方法打开一个应用。像 Vim 一样,i3wm 是通过键盘快捷键和命令来导航和使用的。表 17-1 显示了i3wm的命令列表(用“win”或 Windows 键替换 alt,如果你已经选择了它)。

表 17-1

i3wm 键盘快捷键

|

捷径

|

描述

|
| --- | --- |
| win+enter | 打开新的终端互动程序 |
| win+d | 在屏幕顶部打开一个对话框,您可以在其中键入应用名称,然后按 enter 键打开它 |
| win+j | 将焦点向左移动一格 |
| win+k | 将焦点下移一格 |
| win+l | 将焦点上移一格 |
| win+; | 将焦点向右移动一格 |
| win+shift+j | 向左移动聚焦磁贴 |
| win+shift+k | 下移聚焦的磁贴 |
| win+shift+l | 向上移动聚焦的磁贴 |
| win+shift+; | 向右移动聚焦磁贴 |
| win+f | 在聚焦磁贴的全屏模式之间切换 |
| win+shift+q | 取消聚焦的磁贴 |
| win+ | 切换到一个工作空间,其中是 0 到 9 之间的任意值。每个数字都是一个单独的工作空间 |
| winktv | 下一个图块将垂直分割空间 |
| win+h | 下一个图块将水平分割空间 |
| win+r | 进入平铺的调整大小模式。从此处,箭头键可用于水平或垂直扩展或压缩图块 |
| win+shift+空格 | 切换磁贴的浮动模式。浮动模式允许你拖动一个窗口而不用考虑网格 |
| win+ | 用鼠标拖动浮动模式图块 |

创建切片

您首先要学习的最基本的命令是创建新的平铺窗口,这等同于打开应用,因为所有的应用都包含在窗口管理器网格的平铺窗口中。如果您正在打开终端,您可以使用win+enter。对于所有其他应用,按win+d;这将在左上方打开一个小对话框,如图 17-4 所示。

img/494886_1_En_17_Fig4_HTML.jpg

图 17-4

i3 应用搜索

当您键入应用的名称时,对话框将显示自动完成的状态,如果在任何时候它显示您的目标程序,请按 open。这将打开你的应用作为一个瓷砖。图 17-5 显示了一个 Firefox 作为标签打开的例子,以及两个终端。

img/494886_1_En_17_Fig5_HTML.jpg

图 17-5

打开多个图块的 i3

打开其他应用将会在您的工作空间中自动创建其他图块,这些图块将分布在网格上。因此,当您添加额外的图块时,程序图块将会调整大小。如果你的屏幕开始变得拥挤,你需要更多的空间,你可以使用工作区,我们稍后会解释。或者,如果您有不再需要的图块,您可以聚焦它们并按下win+shift+q

您的工作区将被编号并显示在屏幕底部的状态栏中。除了您的工作区,状态栏还显示有关时间、互联网连接和可用空间的基本信息。

默认情况下,当添加新标签时,您的磁贴将水平拆分当前聚焦的标签。要切换到垂直分割,请按win+v键,您的下一个创建的图块将垂直分割。要切换回水平分割,请按下win+h。尝试创建新的图块,在垂直和水平之间切换,并根据需要使用win+shift+q删除图块。

一旦你有一个工作空间,分割成多个单幅图块,你可能想要调整单幅图块的大小。如果您按下win+r,您将进入高亮显示区域的调整大小模式,您可以使用箭头键来扩展或缩小该区域。状态栏中还有一个指示器,它会告诉您调整大小模式何时激活。

更改焦点中的磁贴

现在你有多个程序在i3wm中作为图块运行,你可能想知道如何在图块之间切换。您当前在i3wm中使用的磁贴被称为焦点。如果你想在磁贴之间切换焦点,只需按住win键并使用箭头键来导航你的焦点。您应该会在当前聚焦的窗口周围看到一个细细的轮廓。或者,您可以使用字母——jkl;——每个字母对应一个方向。这些键类似于 Vim 中的方向键,但又不完全相同。如果您想修改这些键,使它们与 Vim 相同,请参阅“修改 i3wm 配置文件”一节

移动瓷砖

除了改变您的焦点之外,您可能还想在创建额外的图块时重新排列窗口,或者调整这些图块的大小以创建您的完美设置。移动磁贴的快捷键与移动焦点的快捷键几乎相同,除了你需要同时按住winshift键,而不仅仅是win。所以向右移动,你可以做win+shift+right arrow或者win+shift+;。如上所述,您还可以调整窗口的大小。要进入调整大小模式,请在聚焦于要调整大小的图块时按win+r。一旦进入调整大小模式,您可以使用箭头键来扩展或收缩单幅图块。

i3wm 中的工作区

当你第一次打开i3wm时,你会在左下角看到一个写着“1”的小方块。这个数字代表您当前的工作空间。i3wm上有 10 个工作空间,编号为 1-9,0 为第十个。您可以通过按下win+<number>在工作区之间切换,其中<number>是 0 到 9 之间的任意数字。切换到新的工作区时,您的屏幕将显示为一个新的i3wm实例,没有打开的磁贴。

因此,如果您在工作区 1 中打开四个不同的图块,然后切换到工作区 2,您可以在新的布局上创建新的图块,并随时切换回工作区 1。无论工作区是否在焦点上,工作区内的程序都将继续运行。

浮动瓷砖

虽然图块网格系统本质上是i3wm的核心实用程序,但是可以创建存在于它之外的图块,并且浮动在其他所有东西之上。要在浮动模式中切换图块,将其置于焦点并按下win+shift+space。一旦图块处于浮动模式,您可以按住win并用鼠标拖动它。如果您想将方块返回网格,再次按下win+shift+space

全屏模式

如果您使用的互动程序太小,您可以暂时将互动程序切换到全屏模式,完成后再切换回来。要切换到平铺的全屏模式,只需按下win+f。要切换回来,在全屏模式下按下win+f

修改 i3wm 配置文件

通过修改i3wm的配置文件,可以设置多种设置和配置。配置文件的默认位置是~/.config/i3/config

在 i3wm 配置中绑定键

i3wm中你最想修改的是哪个键负责哪个功能。习惯于 Vim 键绑定的人喜欢做的一个常见改变是重新映射用于聚焦磁贴的键。这是通过在配置文件中使用bindsym关键字来完成的,如下例所示:

bindsym $mod+h focus left
bindsym $mod+j focus down
bindsym $mod+k focus up
bindsym $mod+l focus right

如果您决定这样做,您还需要重新映射默认使用的$mod+h,它用于水平分割窗口。至于使用什么键进行水平分割,这取决于您,但是在本例中,我们将使用"-",如下所示:

bindsym $mod+minus split h

还可以使用相同的组合键在文件中搜索任何现有的绑定,例如“$ mod+k”;如果发现重复,您需要删除一个,因为每个组合键只能映射到一个功能。

对 i3 配置文件进行更改后,您需要重新加载它。要在不重新启动系统的情况下完成此操作,请运行以下命令:

i3-msg reload

在前面的例子中,我们映射了每个 Vim 移动键(加上默认的修饰键“win”)。您可能还想应用类似的更改来移动聚焦窗口,如下所示:

bindsym $mod+Shift+h move left
bindsym $mod+Shift+j move down
bindsym $mod+Shift+k move up
bindsym $mod+Shift+l move right

您还可以将自定义功能绑定到未使用的组合键。例如,假设我们想要一个特殊的组合键来打开一个新的 web 浏览器窗口。我们可以添加如下所示的行:

bindsym $mod+shift+z exec "firefox"

使用前面的模式,您可以将组合键映射到任何应用,甚至您自己的定制脚本。

在 i3wm 配置中更改颜色

正如我们在本书中看到的其他配置文件一样,i3wm配置文件允许修改界面的主题和颜色。我们不会查看每个可能的配置,但以下配置将帮助您入门;这是一个通过改变各种子元素的颜色来修改屏幕底部状态栏的例子(确保替换配置文件中现有的 bar 实例,否则你将得到两个状态栏)。

bar {
        colors {
        background #2f343f
        statusline #2f343f
        separator #4b5262
        focused_workspace       #2f343f #bf616a #d8dee8
        active_workspace        #2f343f #2f343f #d8dee8
        inactive_workspace      #2f343f #2f343f #d8dee8
        urgent_workspacei       #2f343f #ebcb8b #2f343f
    }
    status_command i3status
}

此外,我们可以改变客户端本身的颜色(五色十六进制代码应该包含在一行中)。

client.focused           #bf616a #2f343f #d8dee8 #bf616a #d8dee8
client.focused_inactive  #2f343f #2f343f #d8dee8 #2f343f #2f343f
client.unfocused         #2f343f #2f343f #d8dee8 #2f343f #2f343f
client.urgent            #2f343f #2f343f #d8dee8 #2f343f #2f343f
client.placeholder       #2f343f #2f343f #d8dee8 #2f343f #2f343f
client.background        #2f343f

i3 状态配置文件

虽然大多数对i3wm的定制都是在~/.config/i3/config文件中进行的,但是还有第二个配置文件专门处理状态栏。状态栏特定的配置文件可以在~/.config/i3status/config找到。它不仅允许你改变状态栏的颜色和样式,还允许你改变显示的内容。注意这个文件默认不存在。有关状态栏的其他信息,您可以运行以下命令来查看特定于状态栏的手册页:

man i3status

在这个手册页中,您将找到一个示例配置文件,它可以被复制并用作自定义状态栏的基础。注意,状态栏的所有子组件首先被添加到名为order的变量中,该变量跟踪显示哪些子组件以及显示顺序。

order += "cpu_temperature 0"
order += "load"
order += "tztime local"
order += "tztime berlin"

再往下,每个子组件都用花括号描述。例如,“tztime berlin”组件除了显示系统的本地时间外,还显示柏林时间,如下所示:

tztime berlin {
        format = "%Y-%m-%d %H:%M:%S %Z"
        timezone = "Europe/Berlin"
}

为了拥有一个完整的工作配置文件,您还必须添加“tztime local”组件,该组件的定义如下:

tztime local {
        format = "%Y-%m-%d %H:%M:%S %Z"
}

为了使状态栏更改生效,您需要完全重启 i3,而不是简单地运行 reload 命令。您可以通过运行以下命令来重新启动 i3

i3-msg restart

您可以在手册页中找到几个组件来帮助您入门。如果你正在寻找定制i3wm和作为配置文件基础的额外资源,我推荐你搜索“i3wm config github”

替代 Shell

在列出许多可用的替代 shellss 之前,我想说明一下为什么我不使用任何 shell。首先,我喜欢我默认的工作环境,以反映我可能在“野外”找到的环境也就是说,如果我 SSH 到一台机器或去一家公司并使用他们的服务器,假设他们使用的是标准的 bash,我会感觉很自在。如果我已经习惯了使用另一种 shell,我可能会发现自己在尝试使用默认情况下根本不存在的快捷方式和命令。

第二个主要原因是许多替代 shell 不兼容 POSIX,这意味着专门为这些 shell 之一编写的脚本不能与更广泛的社区共享。我更喜欢使用标准的 POSIX 兼容 bash,因为我知道几乎每个人都可以在自己的本地环境中使用我的计算机上编写的脚本。

也就是说,许多其他人确实更喜欢替代 Shell,因为它们可能提供可用性或其他好处。如果您对探索替代 Shell 感兴趣,这里有一些值得一试的:

  • z Shell

z Shell

最受欢迎的替代 shell 是 Z Shell 或“ZSH”Z Shell 是 bash 的扩展,专注于改善用户体验。Z Shell 的一些特性包括

  • 更智能的自动完成。

  • Git 集成( git 状态提示)。

  • 基于~/的智能 SSH 自动完成。ssh/config & ~/。ssh/已知主机。

  • 打错字时的文件名修正。

  • 各种各样的主题。

  • 所有的cd用的其实都是pushd;因此你可以一直使用popd

  • 其他智能自动完成。

  • 具有 POSIX 兼容模式(尽管默认情况下不兼容)。

这绝不是一个完整的功能列表。

哦,我的 ZSH

我们看了第十四章中的“哦,我的狂欢”;“哦,我的 ZSH”本质上是同样的事情,但 Z 壳。它包含几个专门针对 Z Shell 的预制主题和配置文件。

更多信息请访问 https://github.com/ohmyzsh/ohmyzsh

第二种最受欢迎的替代贝壳是鱼。和 ZSH 一样,Fish 的重点是改善终端用户体验。一些功能包括

  • 自动完成你的类型(考虑你的命令历史

  • 改进的默认颜色主题

  • 更具互动性的自动完成功能

  • 基于 GUI 的配置菜单,可在 web 浏览器中访问

当比较 Fish 和 ZSH 时,一个突出的区别是,ZSH 需要配置来启用它的许多关键功能,而 Fish 是一个更开箱即用的体验。这种对“易用性”的关注也可以在基于 web 浏览器的配置菜单中看到,该菜单允许您交互式地更改颜色主题等内容。

重新映射键

随着您开始越来越多地定制您的 Linux 系统,您可能真的想要改变某些键的行为。例如,由于不经常使用,将 Caps Lock 的用法重新映射到其他用法是很常见的。

进行任何类型的重新映射的第一步都是获取有问题的按钮的键码。最好的方法是运行xev,这将启动一个交互模式,你按下一个按钮,作为回报,会收到一个键码;示例如图 17-6 所示。

img/494886_1_En_17_Fig6_HTML.jpg

图 17-6

使用xev查找键码

在这个例子中,我们将重新映射 Caps Lock 键( keycode 66 )。要编辑映射,打开~/.Xmodmap。这个配置文件负责修改键盘绑定。添加以下代码行,将 Caps Lock 键映射到 hyperkey。

清除大写锁定

keycode 66 = Hyper_L

前面的配置删除了 Caps Lock 键的正常用法,使用其 keycode 将其设置为 hyperkey,并使 hyperkey 成为修饰按钮。

超级键是一个存在于被称为太空学员键盘的旧键盘上的键,如图 17-7 所示。space-cadet 键盘允许用户使用组合键,如“希腊”键,键入 8000 多个不同的字符。键盘对 Lisp 和 Emacs 的设计有很大的影响,尽管没有出现在大多数键盘上,但“超级键”仍然在今天的许多地方被引用。

img/494886_1_En_17_Fig7_HTML.jpg

图 17-7

历史悠久的太空学员键盘上的特殊按键。戴夫·费希尔,罗德岛逆向计算协会,维基共享,知识共享署名-共享 3.0 未经许可

在大多数系统上,修改~/.Xmodmap文件就足以将 Caps Lock 重新映射到 hyperkey。做出更改后,您需要重新启动系统或手动重新加载配置。要手动重新加载,请运行以下命令:

xmodmap ~/.Xmodmap

现在,如果您不带参数地独立运行xmodmap,您应该会得到关于系统上特殊键的信息。“lock”行的第二列中应该没有任何内容,对于标记为“mod4”的行,您应该在末尾看到一个包含“Hyper_L”的键列表。

这里的“mod”代表修饰键,这意味着它可以与其他键结合使用来创建输出,与“alt”和“ctrl”键非常相似。这对下一节很重要,因为它允许我们将 Caps Lock 和其他一些键与自定义命令或脚本相关联。

使用 Xbindkeys 自定义快捷键

既然您已经将 Caps Lock 映射到 hyperkey,您可能想知道您可以用它做什么。将 Caps Lock 换成 hyperkey 的主要用途是获得一个额外的修饰键,类似于 alt 或 ctrl。我们可以将组合键与程序、任务和脚本联系起来。

在 i3 一节中,我们创建了一个用win+shift+z打开 Firefox 的自定义命令。这基本上是相同的想法,除了我们使用大写字母,不需要使用 i3。

要制作键盘快捷键,我们首先需要安装xbindkeys:

sudo apt-get install xbindkeys

接下来,通过运行以下命令,基于默认值创建一个xbindkeys配置文件:

xbindkeys --defaults > ~/.xbindkeysrc

接下来打开~/.xbindkeysrc文件,并在文件末尾添加以下一行:

"firefox"
      Mod4 + f

这里的Mod4代表我们的超级键,因为我们在上一节中将超级键(通过大写字母)与 mod4 相关联。所以我们绑定caps+f来打开 Firefox 浏览器。在我们前进的道路上,我们可以用任何其他程序取代firefox。例如,尝试将以下代码添加到您的~/.xbindkeysrc;运行之后,检查你的/tmp文件夹,你应该会看到一个名为hello的文件。您可以用任何命令替换引号,并将其与下面您想要的任何键盘快捷键相关联:

"touch /tmp/hello"
      Mod4 + t

随着 Caps Lock 键被释放出来用于自定义快捷键,您可以使用几十种可能的组合键,这还没有利用 Caps Lock 键与 shift 或 alt 等其他修饰符的组合。

额外资源

我发现在探索 Linux 终端时有用的其他资源包括

摘要

在这一章中,我们看了一些可以让你的终端使用更进一步的程序。我们查看了内置的cal命令,它几乎可以在任何 Linux 系统上找到,并允许您快速浏览来年。我们看到了如何使用espeak将文本转换成音频文件。

之后,我们看了平铺窗口管理器i3wm、可选的 shells,以及如何修改键盘输入来创建许多映射到程序或自定义脚本的自定义键盘快捷键。

posted @ 2024-08-02 19:35  绝不原创的飞龙  阅读(6)  评论(0编辑  收藏  举报