CompTIA-Linux-认证指南-全-

CompTIA Linux 认证指南(全)

原文:zh.annas-archive.org/md5/1D0BEDF2E9AB87F7188D92631B85ED3E

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Linux+认证证明了技术能力,并提供了对 Linux 操作系统的广泛认识。获得 Linux+认证的专业人士展示了对安装,操作,管理和故障排除服务的重要知识。

CompTIA Linux+认证指南是对该认证的概述,让您深入了解系统架构。您将了解如何安装和卸载 Linux 发行版,然后使用各种软件包管理器。一旦您掌握了所有这些,您将继续在命令行界面(CLI)操作文件和进程,并创建,监视,终止,重新启动和修改进程。随着您的进步,您将能够使用显示管理器,并学习如何创建,修改和删除用户帐户和组,以及了解如何自动执行任务。最后一组章节将帮助您配置日期并设置本地和远程系统日志记录。除此之外,您还将探索不同的互联网协议,以及发现网络配置,安全管理,Shell 脚本和 SQL 管理。

通过本书,您不仅将通过练习问题和模拟考试来掌握所有模块,而且还将为通过 LX0-103 和 LX0-104 认证考试做好充分准备。

本书适合人群

CompTIA Linux+认证指南适用于希望获得 CompTIA Linux+证书的人。本指南还适用于系统管理员和新手 Linux 专业人士,他们有兴趣提高他们的 Linux 和 Shell 脚本技能。不需要 Linux 的先前知识,尽管对 Shell 脚本的一些了解会有所帮助。

本书涵盖的内容

第一章,配置硬件设置,本章重点介绍查看中断,查看/proc/interrupts,查看 CPU 信息,查看/proc/cpuinfo,查看 raid 状态,查看/proc/mdstat,设备目录/dev/proc虚拟目录,lsmod命令和用法,modprobe命令和用法,lspci命令和用法。

第二章,系统引导,本章重点介绍系统引导的过程,查看 GRUB 和 GRUB2 配置文件,重点关注计时器,默认引导条目,在 GRUB/GRUB2 引导菜单中传递参数,chkconfig命令,systemctl,各种启动/停止scripts0

第三章,更改运行级别和引导目标,本章重点介绍运行级别和引导目标的介绍,LINUX 发行版中可用的运行级别和引导目标的类型,运行级别和引导目标之间的区别,在 CLI 中使用运行级别,还在 CLI 中使用引导目标。

第四章,设计硬盘布局,本章重点介绍在 CLI 上创建分区/分割物理硬盘,重点介绍fdisk实用程序的使用,parted实用程序,创建,删除,定义分区类型,使用各种mkfs命令格式化硬盘的步骤。

第五章,安装 Linux 发行版,本章重点介绍安装 Linux 发行版,特别是 CentOS 的 Red Hat 风味和 Ubuntu 的 Debian 风味,读者将通过使用 Live CD 的一种常见方法来安装 Linux 发行版。

第六章,使用 Debian 软件包管理,在 Linux 中,软件可以通过多种方式添加、删除。这里重点介绍了在 Debian 发行版中添加软件的方式,特别是使用 CLI 中的 dpkg、apt-get、aptitude 命令,以及 GUI 中的 synaptic,读者将学习如何在 Debian 发行版中添加、删除、更新、擦除软件。

第七章,使用 YUM 软件包管理,在本章中,我们重点介绍了在 Red Hat 发行版中添加软件的方式,特别是使用 CLI 中的 yum、dnf、rpm 命令,以及 GUI 中的 yumex,读者将学习如何在 Red Hat 环境中添加、删除、更新和擦除软件。

第八章,执行文件管理,在本章中,读者将了解 Linux 提供的各种命令,这些命令是常见发行版用于在 CLI 中操作文件、进程的。这些命令可以分为几类:文件系统导航、文件操作、目录操作、文件位置和文件检查、CPU 硬件标识、进程优先级、操作进程的 CPU 优先级。

第九章,创建、监视、终止和重新启动进程,在 Linux 中,进程或多或少等同于正在运行的程序。init/systemd 是内核启动时运行的第一个进程。本章重点介绍了如何创建进程,监视现有进程的硬件使用情况,终止/杀死进程或在 CLI 中重新启动进程。

第十章,修改进程执行,有时您可能希望优先处理重要程序而不是其他程序,还可以将一些程序发送到后台,允许用户继续使用 shell 或将一些程序带到前台。本章重点介绍了使用 nice 和 renice、fg、bg 命令来实现这一点的方法。

第十一章,显示管理器,本章重点介绍了 Linux 发行版中可用的各种显示管理器,如 X 显示管理器(XDM)、KDE 显示管理器(KDM)、Gnome 显示管理器(GDM)、Light 显示管理器(LightDM),用于处理 GUI 登录,它们都使用 XDMCP - X 显示管理器控制协议,启动本地计算机的 X 服务器。

第十二章,管理用户和组帐户,本章重点介绍了用户和组管理,包括用户帐户创建、修改现有用户帐户、删除用户帐户、组创建、修改用户组、删除组,以及在管理用户和组时要考虑的最佳实践。重点是使用诸如 useradd、usermod、userdel、groupadd、groupmod、groupdel、who、w、change、passwd、last、whoami 等命令,以及配置文件,如/etc/passwd、/etc/shadow、/etc/group、/etc/skel 文件。

第十三章,自动化任务,本章重点介绍了在 Linux 环境中自动化常见的管理任务以及在设置给定任务的自动化时要考虑的常用方法。重点是使用诸如 crontab、at、atq、atrm、anacron 等命令,以及配置文件,如/etc/at.deny、/etc/at.allow、/etc/cron.{daily,hourly,monthly,weekly}、/etc/cron.allow、/etc/anacrontab。

第十四章,维护系统时间和日志,本章重点介绍配置日期和时间以及设置时区。此外,设置在 Linux 发行版中使用rsysloglogrotate进行本地日志记录以及配置日志记录发送到远程syslog服务器进行管理的步骤。涵盖的命令包括tzselecttzconfigdatejournalctl,目录包括/etc/timezone/etc/localtime/usr/share/zoneinfo/etc/logrotate.conf/etc/logrotate.d//etc/systemd/journald.conf/var/log//var/log/journal//etc/rsyslog.conf

第十五章,互联网协议基础,本章重点介绍互联网等网络如何工作的基本原理,通过解释两台计算机如何相互通信,我们深入研究互联网协议(IP)寻址,特别是 IPv4,IPv4 的各种类别,如 A 类,B 类,C 类,CIDR 表示法,然后我们看子网划分。接下来我们看一下 IPv6,IPv6 地址的格式,众所周知的 IPv6 地址,缩短 IPv6 地址的方法。

最后,我们看一下一些著名协议(如 UDP,TCP 和 ICMP)及其端口号之间的区别。

第十六章,网络配置和故障排除,本章重点介绍 Linux 环境中的基本网络配置,包括配置 IPv4 地址,子网掩码,默认网关。接下来我们看一下配置 IPv6 地址,默认网关,然后我们专注于配置客户端 DNS,最后我们专注于网络故障排除。命令如ifupifdownifconfigipip linkip routeroutepingping6netstattraceroutetraceroute6tracepathtracepath6dighosthostname

第十七章,执行安全管理任务,本章重点介绍 Linux 环境中执行安全管理任务,重点放在设置主机安全,授予用户特殊权限与 sudoers,日期加密。涵盖的命令有sudossh-keygenssh-agentssh-addgpg,配置文件包括/etc/sudoers/etc/hosts.allow/etc/hosts.deny~/.ssh/id_rsa~/.ssh/id_rsa.pub/etc/ssh/ssh_host_rsa_key~/.ssh/authorized_keys/etc/ssh_known_hosts

第十八章,Shell 脚本和 SQL 数据管理,本章重点介绍 Linux 环境中的 Shell 脚本和 SQL 数据管理。首先,我们看一下编写脚本时的基本格式,识别脚本的解释器,配置脚本为可执行,使用forwhile循环,if语句。然后我们将注意力集中在 SQL 数据管理上,我们涵盖基本的 SQL 命令,如insertupdateselectdeletefromwheregroup byorder byjoin

第十九章,模拟考试-1,这个模拟考试将包括现实世界的考试问题和答案。您将获得来自真实场景的示例,详细的指导和关键主题的权威覆盖。最近测试的现实考试问题,为您带来为 CompTIA LX0-103/LX0-104 考试做准备的最佳方法。

第二十章,模拟考试-2,这个模拟考试将包括现实世界的考试问题和答案。您将获得来自真实场景的示例,详细的指导和关键主题的权威覆盖。最近测试的现实考试问题,为您带来为 CompTIA LX0-103/LX0-104 考试做准备的最佳方法。

为了充分利用本书

假设一些读者可能对 Linux 操作系统有限或没有知识。还假设一些读者是 Linux 用户,但可能需要对与 Linux 环境交互有所恢复。

巩固每一章记忆的关键是获取各种 Linux 发行版的副本;即 CentOS、Fedora 和 Ubuntu。然后在虚拟环境中安装各种操作系统,如 VMware 或 VirtualBox。接下来,通过在各种 Linux 发行版中练习,跟随每一章(各章节相互独立,因此您可以选择任意一章来学习/练习),以更好地掌握每一章。在练习了各种章节之后,您将在 Linux 环境中变得更加高效;这将使您在混合环境中更加适应,其中既有 Windows 操作系统,也有 Linux 操作系统。

您可以在本书的第五章中的安装 Linux 发行版教程中跟随操作开始安装。

下载彩色图片

我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图片。您可以在这里下载:www.packtpub.com/sites/default/files/downloads/9781789344493_ColorImages.pdf

使用的约定

本书中使用了许多文本约定。

CodeInText:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄。这是一个例子:“要实时查看 shell 中的运行级别,我们可以使用runlevel命令。”

代码块设置如下:

while <condition>
do
          <command1>
          <command2 

任何命令行输入或输出都以以下方式编写:

$[philip@localhost Desktop]$ who -r
run-level 5 2018-06-20 08:20 last=S
[philip@localhost Desktop]$ 

粗体:表示一个新术语,一个重要的词,或者你在屏幕上看到的词。例如,菜单或对话框中的单词会以这种方式出现在文本中。这是一个例子:“从管理面板中选择系统信息。”

警告或重要说明会以这种方式出现。

提示和技巧会以这种方式出现。

联系我们

我们始终欢迎读者的反馈。

一般反馈:如果您对本书的任何方面有疑问,请在消息主题中提及书名,并发送电子邮件至customercare@packtpub.com

勘误:尽管我们已经尽一切努力确保内容的准确性,但错误确实会发生。如果您在这本书中发现了错误,我们将不胜感激地请您向我们报告。请访问www.packt.com/submit-errata,选择您的书,点击勘误提交表格链接,并输入详细信息。

盗版:如果您在互联网上发现我们作品的任何形式的非法副本,我们将不胜感激地请您向我们提供位置地址或网站名称。请通过链接copyright@packt.com与我们联系。

如果您有兴趣成为作者:如果您在某个专题上有专业知识,并且有兴趣撰写或为一本书做出贡献,请访问authors.packtpub.com

评论

请留下评论。一旦您阅读并使用了这本书,为什么不在购买它的网站上留下评论呢?潜在的读者可以看到并使用您的公正意见来做出购买决定,我们在 Packt 可以了解您对我们产品的看法,我们的作者可以看到您对他们的书的反馈。谢谢!

有关 Packt 的更多信息,请访问packt.com

第一章:配置硬件设置

本章涵盖了查看中断。它专注于/proc/interrupts,CPU 信息查看(/proc/cpuinfo),查看已安装的物理内存。它还查看了/proc/meminfofree命令,查看交换内存,以及使用ddmkswapswaponswapoff命令添加和删除额外的交换内存。RAID 状态(查看/proc/mdstat)也有概述,还有设备目录/dev/proc虚拟目录,lsmod命令和用法,modprobe命令及其用法,以及lspci命令和用法。/proc目录是一个虚拟文件系统,在启动时创建,用于存储有关系统的各种硬件信息。

首先,让我们把所有的干扰因素排除在外。浏览各个目录并使用这些命令非常有益,可以让您在 Linux 环境中获取硬件信息。

本章将涵盖以下主题:

  • 查看 CPU,RAM 和交换信息

  • 中断和设备

  • 模块

查看 CPU,RAM 和交换信息

让我们看看如何在 Linux 系统上查看 CPU,RAM 和交换信息。

首先,我们将专注于获取有关 CPU 的信息,因此我们将查看/proc/cpuinfo文件。我们可以从中获取有关 CPU 的详细信息,包括供应商 ID,CPU 系列,型号名称,CPU 速率(以 MHZ 为单位),其缓存大小以及核心数量等。以下是运行cat命令并与/proc/cpuinfo一起的摘录:

关于 CPU 还提供了更多信息:

从前面的输出中,我们可以看到有关我们运行cat /proc/cpuinfo命令的 CPU 的详细信息。

接下来,让我们看看如何收集有关系统中安装的随机存取内存RAM)的物理内存量的信息。我们将专注于两个命令,即cat /proc/meminfofree命令。

再次使用 Linux 系统进行演示,我们将查看/cat /proc/meminfo命令的输出:

以下截图显示了更多的内存使用信息:

从前面的输出中,我们可以看到一些重要的字段,即前三个字段(MemTotalMemFreeMemAvailable),它们反映了我们物理内存(RAM)的当前状态。

现在让我们再看另一个命令,即free命令。这个命令将以更易读的格式给出内存信息。使用我们的测试 Linux 系统,我们将运行free命令:

仅运行free命令将以 KB 为单位给出前面的结果。我们可以在free命令上添加一些选项以使其更加明确。以下是我们可以在 Ubuntu 发行版上使用的free命令的选项列表:

这些是我们可以在 Ubuntu 发行版上使用free命令的一些选项:

同样,如果我们在 CentOS 7 发行版上查看free命令的主页面,我们可以看到类似的选项:

在 CentOS 7 发行版上,我们可以使用free命令传递的一些其他选项如下所示:

让我们尝试一些free命令的选项:

前面的输出是free命令中最常用的选项之一(-h)。我们甚至可以进一步使用(-g)选项来显示以 GB 为单位的物理内存总量:

我们甚至可以使用另一个很棒的选项(-l)来查看低内存和高内存的统计信息:

在前面的截图中,我们不仅显示了 RAM 信息,还显示了我们的交换内存。它显示在最后一行。如果我们只想看到交换内存,我们可以使用另一个命令swapon

以下是在 Ubuntu 发行版上swapon主页上可以使用的一些选项:

在 Ubuntu 发行版上,swapon命令可以传递更多选项,如下截图所示:

以下是在 CentOS 7 发行版上swapon主页上可以使用的一些选项:

在 CentOS 7 发行版上,swapon命令可以传递更多选项,如下截图所示:

我们还可以从/proc目录中查看交换信息,具体在/proc/swaps中:

从前面的输出中,我们可以看到交换空间正在使用/dev/sda4分区。现在,如果由于某种原因我们的物理内存用完了,并且我们已经用完了交换空间,那么我们可以添加更多物理内存或添加更多交换空间。因此,让我们专注于添加更多交换空间的步骤。

我们需要使用dd命令创建一个空白文件。请注意,您需要 root 访问权限才能在 shell 中运行此命令:

trainer@trainer-virtual-machine:~$ dd if=/dev/zero of=/root/myswapfile bs=1M count=1024
dd: failed to open '/root/myswapfile': Permission denied
trainer@trainer-virtual-machine:~$

从前面的输出中,我们可以看到收到了Permission denied的消息,所以让我们切换到 root 并尝试重新运行该命令:

root@trainer-virtual-machine:/home/trainer# dd if=/dev/zero of=/root/myswapfile bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 17.0137 s, 63.1 MB/s
root@trainer-virtual-machine:/home/trainer#

我们刚刚使用名称myswapfile创建了一个swap文件。现在我们需要运行mkswap命令,并在 shell 中调用我们刚刚创建的swap文件:

root@trainer-virtual-machine:~# mkswap myswapfile
Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes)
no label, UUID=e3b8cc8f-ad94-4df9-8608-c9679e6946bb
root@trainer-virtual-machine:~#

现在,最后一步是打开swap文件,以便系统根据需要使用它:

root@trainer-virtual-machine:~# swapon myswapfile
swapon: /root/myswapfile: insecure permissions 0644, 0600 suggested.
root@trainer-virtual-machine:~#

我们收到了一个关于不安全权限的警告消息。我们将在后面的章节中讨论权限。现在,我们将继续使用现有的权限。最后一步是验证swap文件确实可供我们的系统使用:

root@trainer-virtual-machine:~# swapon
NAME                TYPE       SIZE   USED    PRIO
/dev/sda4           partition  5.9G   960K    -1
/root/myswapfile    file       1024M   0B     -2
root@trainer-virtual-machine:~#

现在,我们的系统已经可以使用新创建的swap文件。我们还可以运行free命令,现在会发现交换内存增加了 1GB:

root@trainer-virtual-machine:~# free -h
 total   used   free  shared  buff/cache   available
Mem:  1.9G    848M    72M   13M    1.0G        924M
Swap: 6.8G    960K    6.8G
root@trainer-virtual-machine:~#

为了使更改在重新启动时安全,您需要在/etc/fstab中添加一个条目。

如果我们不再想使用swap文件,我们可以使用swapoff命令将myswapfile从交换内存中删除。以下是我们在 shell 中如何完成这个任务:

root@trainer-virtual-machine:~# swapoff myswapfile
root@trainer-virtual-machine:~#

现在让我们重新运行swapon命令,然后运行free命令来验证myswapfile确实已从交换使用中移除:

root@trainer-virtual-machine:~# swapon
NAME       TYPE      SIZE   USED   PRIO
/dev/sda4 partition  5.9G   1.6M   -1 root@trainer-virtual-machine:~# free -h
 total   used    free   shared  buff/cache available
Mem:   1.9G    931M    133M   17M     917M        845M
Swap:  5.8G    1.6M    5.8G
root@trainer-virtual-machine:~#

正如我们所看到的,myswapfile不再可用于作为交换内存使用。以下是在 Ubuntu 发行版上可以与swapoff命令一起使用的选项:

swapoff命令可以传递更多选项,如下截图所示:

以下是在 CentOS 7 发行版上swapoff命令可以使用的选项:

swapoff命令可以传递更多选项,如下截图所示:

中断和设备

现在让我们转换方向,看看我们的 Linux 系统中可用的中断请求IRQs)和设备。您可以将中断视为我们在需要特定物品时使用的服务热线。我们会打电话给服务热线。对于 Linux 系统中的设备,理论仍然是一样的;每当它需要 CPU 的注意时,它会通过中断发送信号。传统的 32 位架构支持多达 16 个中断:0-15。更新的架构支持的中断远远超过 16 个。

让我们再次查看/proc目录,重点关注/proc/interrupts

以下截图显示了更多的中断:

下面的截图显示了更多的中断:

从前面的输出中,我们可以看到有更多的中断可用。输出从左到右读取,左边表示中断号,向右移动表示正在使用中断的设备或服务。我们可以看到定时器正在使用中断0

现在,让我们把注意力转向设备。在 Linux 系统中使用设备时,设备被表示为文件。这使我们能够与系统中的实际硬件进行通信。有一些常用的设备,比如硬盘、DVD 和 USB 等。硬盘被表示为sd(n);例如:/dev/sda/dev/sdb/dev/sdc等。硬盘分区以sd(n)的形式表示;例如:/dev/sda1/dev/sda2/dev/sdb1等。同样,软盘被表示为fd.。还有一些特殊用途的文件,比如/dev/null/dev/zero/dev/tty*。当你想要从另一个命令发送输出并且不需要输出时,你会使用/dev/null。这被称为重定向。/dev/zero与我们之前介绍的dd命令一起使用,用于创建空文件。/dev/tty*用于远程登录。让我们看看 Linux 环境中如何显示设备。

我们将使用我们的测试 Linux 系统查看/proc/devices

从前面的输出中,硬盘和分区以/dev/sdXY的格式表示,其中X表示硬盘,Y表示分区。我们可以告诉ls命令将输出过滤为仅包含硬盘和分区信息:

root@trainer-virtual-machine:~# ls /dev/sd*
/dev/sda  /dev/sda1  /dev/sda2  /dev/sda3  /dev/sda4
root@trainer-virtual-machine:~#

模块

你是否曾经想过在 Linux 环境中驱动程序发生了什么?好吧,不用再想了。大多数来自 Microsoft Windows 背景的人习惯于通过驱动程序与硬件进行交互。在 Linux 中,我们将驱动程序称为模块。这并不像听起来那么可怕。每当我们使用一块硬件时,我们都会加载和卸载模块。例如,当我们插入 USB 驱动器时,模块会被加载到后台,并在我们移除 USB 驱动器时自动卸载。就是这么灵活。

让我们来看看如何使用lsmod命令查看安装在 Linux 系统中的模块:

以下截图显示了更多可用的模块:

根据前面的输出,我们可以看到在这个 Linux 系统中有许多模块可供使用。我们从左到右读取输出,在Used by列下看到一个0值。这意味着该模块目前未被使用。

现在让我们看看使用rmmod命令删除模块的过程。我们将删除usbhid模块,因为它目前没有在使用。我们可以通过使用lsmod | grep usbhid快速验证这一点:

root@trainer-virtual-machine:~# lsmod | grep usbhid
usbhid                 49152  0

太好了!让我们继续使用rmmod命令删除该模块:

root@trainer-virtual-machine:~# rmmod usbhid
root@trainer-virtual-machine:~#
root@trainer-virtual-machine:~# lsmod | grep usbhid
root@trainer-virtual-machine:~#

好了,usbhid模块现在已经不再加载在 Linux 系统中。但是,它仍然驻留在那里,因为它已经编译进内核了。在 Ubuntu 发行版上,rmmod只有几个选项:

同样,在 CentOS 7 发行版上使用rmmod的选项如下:

为了重新安装usbhid模块,我们将使用另一个常用命令insmod。让我们看看insmod在 shell 中是如何工作的:

root@trainer-virtual-machine:~# insmod usbhid
insmod: ERROR: could not load module usbhid: No such file or directory
root@trainer-virtual-machine:~#

现在,根据前面的输出,似乎有些矛盾,insmod命令无法找到usbhid模块。别担心,这个模块已经编译进内核了。也就是说,我们可以使用另一个有用的命令modprobe。这个命令比insmod更受欢迎,因为modprobe在我们使用modprobe添加模块时实际上在后台调用insmod。有趣的是,modprobe也可以用来移除模块。它通过在后台调用rmmod来实现这一点。

我们可以使用insmod本身来安装usbhid模块。唯一的问题是,您必须指定模块的绝对路径。另一方面,mobprobe使用模块目录,即/lib/modules/$(KERNEL_RELEASE)/,用于模块,并根据/etc/modprobe.d/目录中定义的规则加载模块。

因此,让我们使用modprobe在 shell 中安装usbhid模块。

root@trainer-virtual-machine:~# modprobe -v usbhid
insmod /lib/modules/4.4.0-24-generic/kernel/drivers/hid/usbhid/usbhid.ko
root@trainer-virtual-machine:~#

我们在modprobe命令中使用了-v选项,因为默认情况下它不会显示后台发生的情况。正如您所看到的,modprobe确实在后台调用insmod。现在我们可以使用modprobe删除这个usbhid模块,我们会看到它确实在后台调用rmmod

root@trainer-virtual-machine:~# modprobe -r -v usbhid
rmmod usbhid
root@trainer-virtual-machine:~#

从前面的输出可以明显看出,modprobe确实在后台调用rmmod来移除模块。

以下是在 Ubuntu 发行版上可以与modprobe命令一起使用的一些选项:

modprobe命令可以传递的一些其他选项如下截图所示:

modprobe命令可以传递的一些其他选项如下截图所示:

以下是在 CentOS 7 发行版上可以与modprobe命令一起使用的一些选项:

modprobe命令可以传递的一些其他选项如下截图所示:

modprobe命令可以传递的更多选项如下截图所示:

总结

在本章中,我们关注硬件设置,查看了各个目录中的 CPU、RAM 和交换信息。我们使用了各种命令。此外,我们还涉及了 Linux 系统中可用的各种中断和中断。然后,我们查看了设备,以文件的形式。最后,我们使用了模块。我们看到了 Linux 系统中当前可用的各种模块,并学习了安装和移除模块的步骤。

在下一章中,我们将专注于系统引导过程。此外,将介绍各种引导管理器。这对于每个 Linux 工程师来说都是另一个关键方面。简而言之,没有引导管理器,系统将无法引导,除非我们从某种媒体引导。掌握这些知识将使您作为 Linux 工程师处于领先地位。完成下一章后,您将在认证方面具有更大的优势。希望很快能见到您。

问题

  1. 哪个目录被创建为虚拟文件系统?

A. /dev

B. /lib

C. /proc

D. 以上都不是

  1. 查看 CPU 信息的命令是什么?

A. less /proc

B. more /proc

C. cat /proc

D. cat /proc/cpuinfo

  1. 查看/proc目录中的 RAM 的命令是什么?

A. tail /proc/free

B. less /proc/free

C. cat /proc/meminfo

D. cat /proc/RAM

  1. free命令的哪个选项以友好的格式显示内存信息?

A. free -F

B. free -L

C. free -h

D. free –free

  1. 用于告诉系统文件是swap文件的命令是什么?

A. doswap

B. format swap

C. mkswap

D. swap

  1. 使用哪个命令来激活swap文件?

A. Swap

B. onSwap

C. swap

D. swapon

  1. 显示交换分区信息的命令是什么?

A. mkswap

B. swapon

C. swap

D. swapoff

  1. 哪个设备文件可以重定向消息以发送到丢弃?

A. /dev/discard

B. /dev/null

C. /dev/redirect

D. 以上都不是

  1. 用于显示 Linux 系统中当前可用模块的命令是什么?

A. insmod

B. depmod

C. rmmod

D. lsmod

  1. 使用哪个命令来安装模块,而不必指定绝对路径?

A. rmmod

B. modules

C. modrm

D. modprobe

进一步阅读

  • 该网站将为您提供有关当前 CompTIA Linux+认证的所有必要信息:www.comptia.org/

  • 这个网站将为您提供与 LPI 考试相关的详细信息,特别是通过通过 CompTIA Linux+考试获得的 LPIC - Level 1:www.lpi.org/

  • 这个网站提供了各种可用的 Linux 内核的详细信息:www.kernel.org/

第二章:系统引导

在上一章中,我们涵盖了我们日常管理的常见硬件设置。我们提到了一些命令,可以用来识别 Linux 系统中的硬件。本章将从那里继续,并进一步进行,这次重点是系统引导的过程。它查看了 GRUB 和 GRUB2 配置文件,重点关注了计时器、默认引导项以及向 GRUB/GRUB2 引导菜单传递参数。它还涵盖了 chkconfigpstreepssystemctldmeg 命令,以及各种启动/停止脚本。

本章将涵盖以下主题:

  • 解释引导过程

  • 理解 GRUB 和 GRUB2

  • 使用 GRUB

  • 使用 GRUB2

解释引导过程

在 Linux 中,在启动过程中,会在硬盘上查找引导扇区。一旦找到引导扇区,它会搜索引导加载程序。引导加载程序然后加载引导管理器。在 Linux 中,这通常是 GRUB 或 GRUB2。在这个阶段之后,用户会看到一个引导菜单。最后,用户有机会选择要加载的操作系统或编辑现有条目。可用的选项通常是不同版本的 Linux 内核。有时,它可能是完全不同的 Linux 发行版。然而,在混合环境中,你可能会接触到另一个操作系统,比如 Microsoft Windows。

用户选择 Linux 内核后,根据 Linux 发行版的不同,会启动一个名为 init 的单个进程,它代表初始化init 通常被称为System V init 或 SysV,因为 System V 是第一个商业 Unix 操作系统。大多数早期的 Linux 发行版与 System V 操作系统相同。用于管理 Linux 发行版的另一个守护进程称为 systemd,代表 System Management Daemon。以下是我们刚刚讨论的过程的简单流程:

引导扇区 > 引导加载程序 > 引导菜单 => 操作系统加载

在 Linux 中,你可能会遇到术语守护进程。请放心,这只是指一个进程。

在我们深入之前,让我们记住 initsystemd 之间最大的区别之一:init 逐个启动脚本,而 systemd 同时并行启动多个脚本。话虽如此,在使用 init 的 CentOS 5 系统上,以下是 pstree 命令的输出:

从前面的输出中,我们可以看到所有起源于 init 的进程;因此,它们被视为子进程。

注意:出于简洁起见,一些输出已在整个章节中被省略。

我们还可以利用 ps 命令在我们的 CentOS 5 系统上查看 init 使用的实际进程号:

[philip@localhost Desktop]$ ps -aux
 Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.8/FAQ
 USER PID %CPU  %MEM  VSZ RSS TTY STAT START TIME COMMAND
 root  1   0.3  0.1  19364 1524 ? Ss 05:48   0:01 /sbin/init
 root  2   0.0  0.0   0    0    ? S  05:48   0:00 [kthreadd]
 root  3   0.0  0.0   0    0    ? S  05:48   0:00 [migration/0]
 root  4   0.0  0.0   0    0    ? S  05:48   0:00 [ksoftirqd/0]
 root  5   0.0  0.0   0    0    ? S  05:48   0:00 [migration/0]
 root  6   0.0  0.0   0    0    ? S  05:48   0:00 [watchdog/0]
 root  7   0.2  0.0   0    0    ? S  05:48   0:00 [events/0]
 root  8   0.0  0.0   0    0    ? S  05:48   0:00 [cgroup]
 root  9   0.0  0.0   0    0    ? S  05:48   0:00 [khelper]
 root  10  0.0  0.0   0    0    ? S  05:48   0:00 [netns]
 root  11  0.0  0.0   0    0    ? S  05:48   0:00 [async/mgr]
 root  12  0.0  0.0   0    0    ? S  05:48   0:00 [pm]
 root  13  0.0  0.0   0    0    ? S  05:48   0:00 [sync_supers]
 root  14  0.0  0.0   0    0    ? S  05:48   0:00 [bdi-default]
 root  15  0.0  0.0   0    0    ? S  05:48   0:00 [kintegrityd/]
 root  16  0.5  0.0   0    0    ? S  05:48   0:01 [kblockd/0]

从前面的输出中,我们可以看到第一个启动的进程是 PID 1,它确实是 init 进程。

以下是我们可以与 ps 命令一起使用的一些选项:

[philip@localhost Desktop]$ ps --help
 ********* simple selection ********* ********* selection by list *********
 -A all processes -C by command name
 -N negate selection -G by real group ID (supports names)
 -a all w/ tty except session leaders -U by real user ID (supports names)
 -d all except session leaders -g by session OR by effective group name
 -e all processes -p by process ID
 T all processes on this terminal -s processes in the sessions given
 a all w/ tty, including other users -t by tty
 g OBSOLETE -- DO NOT USE -u by effective user ID (supports names)
 r only running processes U processes for specified users
 x processes w/o controlling ttys t by tty
 *********** output format ********** *********** long options ***********
 -o,o user-defined -f full --Group --User --pid --cols --ppid
 -j,j job control s signal --group --user --sid --rows --info
 -O,O preloaded -o v virtual memory --cumulative --format --deselect
 -l,l long u user-oriented --sort --tty --forest --version
 -F extra full X registers --heading --no-heading --context
 ********* misc options *********
 -V,V show version L list format codes f ASCII art forest
 -m,m,-L,-T,H threads S children in sum -y change -l format
 -M,Z security data c true command name -c scheduling class
 -w,w wide output n numeric WCHAN,UID -H process hierarchy
 [philip@localhost Desktop]$ 

现在,让我们把注意力转向 systemd。我们将在我们的 Linux 系统上运行 pstree 命令:

从前面的输出中,我们可以看到系统生成的所有其他进程。这些被称为子进程。

我们也可以在 CentOS 7 发行版上运行 pstree 命令,并看到类似的结果:

[philip@localhost ~]$ pstree
 systemd─┬─ModemManager───2*[{ModemManager}]
 ├─NetworkManager─┬─dhclient
 │ └─3*[{NetworkManager}]
 ├─VGAuthService
 ├─abrt-watch-log
 ├─abrtd
 ├─accounts-daemon───2*[{accounts-daemon}]
 ├─alsactl
 ├─anacron
 ├─at-spi-bus-laun─┬─dbus-daemon───{dbus-daemon}
 │ └─3*[{at-spi-bus-laun}]
 ├─at-spi2-registr───2*[{at-spi2-registr}]
 ├─atd
 ├─auditd─┬─audispd─┬─sedispatch
 │ │ └─{audispd}
 │ └─{auditd}
 ├─avahi-daemon───avahi-daemon
 ├─chronyd
 ├─colord───2*[{colord}]
 ├─crond
 ├─cupsd
 ├─2*[dbus-daemon───{dbus-daemon}]
 ├─dbus-launch
 ├─dconf-service───2*[{dconf-service}]
 ├─dnsmasq───dnsmasq

在几乎所有较新的 Linux 发行版中,systemd 已经取代了 init

现在,让我们使用 ps 命令查看 Linux 系统上 systemd 使用的进程号:

root@ubuntu:/home/philip# ps -aux
 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
 root 1 0.0 0.5 185620 4996 ? Ss Jun19 0:05 /lib/systemd/systemd --system --d
 root 2 0.0 0.0 0 0 ? S Jun19 0:00 [kthreadd]
 root 3 0.0 0.0 0 0 ? S Jun19 0:06 [ksoftirqd/0]
 root 5 0.0 0.0 0 0 ? S< Jun19 0:00 [kworker/0:0H]
 root 7 0.0 0.0 0 0 ? S Jun19 0:06 [rcu_sched]
 root 8 0.0 0.0 0 0 ? S Jun19 0:00 [rcu_bh]
 root 9 0.0 0.0 0 0 ? S Jun19 0:00 [migration/0]
 root 10 0.0 0.0 0 0 ? S Jun19 0:00 [watchdog/0]
 root 11 0.0 0.0 0 0 ? S Jun19 0:00 [kdevtmpfs]
 root 12 0.0 0.0 0 0 ? S< Jun19 0:00 [netns]
 root 13 0.0 0.0 0 0 ? S< Jun19 0:00 [perf]
 root 14 0.0 0.0 0 0 ? S Jun19 0:00 [khungtaskd]
 root 15 0.0 0.0 0 0 ? S< Jun19 0:00 [writeback]
 root 16 0.0 0.0 0 0 ? SN Jun19 0:00 [ksmd]
 root 17 0.0 0.0 0 0 ? SN Jun19 0:01 [khugepaged]
 root 18 0.0 0.0 0 0 ? S< Jun19 0:00 [crypto]
 root 19 0.0 0.0 0 0 ? S< Jun19 0:00 [kintegrityd]
 root 20 0.0 0.0 0 0 ? S< Jun19 0:00 [bioset]
 root 21 0.0 0.0 0 0 ? S< Jun19 0:00 [kblockd]
 root 22 0.0 0.0 0 0 ? S< Jun19 0:00 [ata_sff]
 root 23 0.0 0.0 0 0 ? S< Jun19 0:00 [md]
 root 24 0.0 0.0 0 0 ? S< Jun19 0:00 [devfreq_wq]

Some output is omitted for the sake of brevity.

从前面的输出中,我们可以清楚地看到系统确实被列为第一个启动的进程。

systemd 模拟 init。例如,我们可以使用 service 命令启动/停止守护进程。

现在,为了查看在 Linux 发行版上启动的进程,我们可以在我们的 CentOS 7 发行版上运行 chkconfig 命令:

[philip@localhost Desktop]$ chkconfig
 NetworkManager 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 abrt-ccpp 0:off 1:off 2:off 3:on 4:off 5:on 6:off
 abrtd 0:off 1:off 2:off 3:on 4:off 5:on 6:off
 acpid 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 atd 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 auditd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 blk-availability 0:off 1:on 2:on 3:on 4:on 5:on 6:off
 bluetooth 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 cpuspeed 0:off 1:on 2:on 3:on 4:on 5:on 6:off
 crond 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 cups 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 dnsmasq 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 firstboot 0:off 1:off 2:off 3:on 4:off 5:on 6:off
 haldaemon 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 htcacheclean 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 httpd 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 ip6tables 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 iptables 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 irqbalance 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 kdump 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 lvm2-monitor 0:off 1:on 2:on 3:on 4:on 5:on 6:off
 mdmonitor 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 messagebus 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 netconsole 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 netfs 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 network 0:off 1:off 2:on 3:on 4:on 5:on 6:off

在前面的输出中,我们只显示使用init的守护程序。这对于运行原生init的系统非常有用,比如早期的 Linux 发行版。

以下是可以与使用init的旧 Linux 发行版一起传递的chkconfig命令的最常用选项:

--level levels 指定操作应适用于的运行级别。它以 0 到 6 的数字字符串给出。例如,--level 35指定运行级别 3 和 5。
--add name 此选项通过chkconfig添加一个新的服务进行管理。添加新服务时,chkconfig确保该服务在每个运行级别中都有启动或杀死条目。如果任何运行级别缺少这样的条目,chkconfig将根据init脚本中的默认值创建适当的条目。请注意,LSB 分隔的INIT INFO部分中的默认条目优先于initscript中的默认运行级别;如果存在任何required-startrequired-stop条目,则脚本的启动和停止优先级将根据这些依赖关系进行调整。
--del name 服务从chkconfig管理中删除,并且/etc/rc[0-6].d中与之相关的任何符号链接都将被删除。请注意,将来安装此服务的软件包可能会运行chkconfig --add,这将重新添加这些链接。要禁用服务,请运行chkconfig name off
--override name 如果服务名称的配置与在/etc/chkconfig.d/name中没有覆盖文件的情况下指定--add选项完全相同,并且现在/etc/chkconfig.d/name存在并且与基本initscript不同,这将更改服务名称的配置,使其遵循覆盖而不是基本配置。
--list name 此选项列出chkconfig知道的所有服务,以及它们在每个运行级别中是停止还是启动的。如果指定了名称,则只显示有关服务名称的信息。

为了查看在较新的 Linux 发行版中启动的守护程序,我们将使用systemctl命令:

[philip@localhost ~]$ systemctl
 add-requires hybrid-sleep reload-or-restart
 add-wants is-active reload-or-try-restart
 cancel is-enabled rescue
 cat is-failed reset-failed
 condreload isolate restart
 condrestart is-system-running set-default
 condstop kexec set-environment
 daemon-reexec kill set-property
 daemon-reload link show
 default list-dependencies show-environment
 delete list-jobs snapshot
 disable list-sockets start
 edit list-timers status
 emergency list-unit-files stop
 enable list-units suspend
 exit mask switch-root
 force-reload poweroff try-restart
 get-default preset unmask
 halt reboot unset-environment
 help reenable
 hibernate reload
 [philip@localhost ~]$ 

从前面的输出中,我们可以看到可以与systemctl命令一起传递的各种选项;我们将使用systemctllist-unit-files选项:

[philip@localhost ~]$ systemctl list-unit-files
 UNIT FILE                           STATE
 proc-sys-fs-binfmt_misc.automount   static
 dev-hugepages.mount                 static
 dev-mqueue.mount                    static
 proc-fs-nfsd.mount                  static
 proc-sys-fs-binfmt_misc.mount       static
 sys-fs-fuse-connections.mount       static
 sys-kernel-config.mount             static
 sys-kernel-debug.mount              static
 tmp.mount                           disabled
 var-lib-nfs-rpc_pipefs.mount        static
 brandbot.path                       disabled
 cups.path                           enabled
 systemd-ask-password-console.path   static
 systemd-ask-password-plymouth.path  static
 systemd-ask-password-wall.path      static

为了简洁起见,省略了一些输出:

 umount.target                    static
 virt-guest-shutdown.target       static
 chrony-dnssrv@.timer             disabled
 fstrim.timer                     disabled
 mdadm-last-resort@.timer         static
 systemd-readahead-done.timer     indirect
 systemd-tmpfiles-clean.timer     static
392 unit files listed.

从前面的输出中,我们可以看到列出了 392 个单元。我们可以更具体地查找只启用/运行的服务:

[philip@localhost ~]$ systemctl list-unit-files | grep enabled
 cups.path                                   enabled
 abrt-ccpp.service                           enabled
 abrt-oops.service                           enabled
 abrt-vmcore.service                         enabled
 abrt-xorg.service                           enabled
 abrtd.service                               enabled
 accounts-daemon.service                     enabled
 atd.service                                 enabled
 auditd.service                              enabled
 autovt@.service                             enabled
 avahi-daemon.service                        enabled
 bluetooth.service                           enabled
 chronyd.service                             enabled
 crond.service                               enabled
 cups.service                                enabled
 dbus-org.bluez.service                      enabled
 dbus-org.fedoraproject.FirewallD1.service   enabled
 dbus-org.freedesktop.Avahi.service          enabled
 dbus-org.freedesktop.ModemManager1.service  enabled
 dbus-org.freedesktop.NetworkManager.service enabled
 dbus-org.freedesktop.nm-dispatcher.service  enabled
 display-manager.service                     enabled
 dmraid-activation.service                   enabled
 firewalld.service                           enabled

我们还可以使用systemctl命令查看守护程序的状态、守护程序被执行的目录以及守护程序的进程 IDPID)。我们将使用status选项:

[philip@localhost ~]$ systemctl status sshd.service
 ● sshd.service - OpenSSH server daemon
 Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
 Active: active (running) since Wed 2018-06-20 09:35:31 PDT; 1h 43min ago
 Docs: man:sshd(8)
 man:sshd_config(5)
 Main PID: 1072 (sshd)
 CGroup: /system.slice/sshd.service
 └─1072 /usr/sbin/sshd -D
 [philip@localhost ~]$ 

我们也可以使用systemctl命令停止、启动、重启、启用和禁用守护程序。假设我们想使用systemctl命令停止ssd服务。我们只需这样做:

[philip@localhost ~]$ systemctl stop sshd

现在,当我们在 CentOS 7 系统上按下Enter键时,我们将收到一个身份验证提示,因为我们正在尝试以标准用户身份停止sshd服务:

sshd被认为是一个系统服务。此外,在systemd的上下文中,一个单元是一个服务,反之亦然。

现在我们将输入 root 密码:

现在sshd服务已经停止:

[philip@localhost ~]$ systemctl stop sshd
 [philip@localhost ~]$

现在让我们重新检查sshd服务的状态,以确认它确实已经停止,使用systemctl命令:

[philip@localhost ~]$ systemctl status sshd.service
 ● sshd.service - OpenSSH server daemon
 Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
 Active: inactive (dead) since Wed 2018-06-20 11:20:16 PDT; 21min ago
 Docs: man:sshd(8)
 man:sshd_config(5)
 Main PID: 1072 (code=exited, status=0/SUCCESS)
 [philip@localhost ~]$ 

从前面的代码中,我们可以得出sshd服务已经停止。

DMESG

现在,当系统启动时,屏幕上会快速显示与我们的系统各个方面相关的许多消息,从硬件到服务。在故障排除时,能够查看这些消息将非常有用。收集尽可能多的信息以帮助故障排除总是很有用。

我们还可以利用另一个强大的命令,即dmesg命令:

philip@ubuntu:~$ dmesg
 [ 0.000000] Initializing cgroup subsys cpuset
 [ 0.000000] Initializing cgroup subsys cpu
 [ 0.000000] Initializing cgroup subsys cpuacct
 [ 0.000000] Linux version 4.4.0-128-generic (buildd@lcy01-amd64-019) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9) ) #154-Ubuntu SMP Fri May 25 14:15:18 UTC 2018 (Ubuntu 4.4.0-128.154-generic 4.4.131)
 [ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.4.0-128-generic root=UUID=adb5d090-3400-4411-aee2-dd871c39db38 ro find_preseed=/preseed.cfg auto noprompt priority=critical locale=en_US quiet

为了简洁起见,省略了一些输出:

[ 13.001702] audit: type=1400 audit(1529517046.911:8): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/bin/evince" pid=645 comm="apparmor_parser"
 [ 19.155619] e1000: ens33 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
 [ 19.156584] IPv6: ADDRCONF(NETDEV_CHANGE): ens33: link becomes ready
 [ 105.095992] do_trap: 33 callbacks suppressed
 [ 105.095996] traps: pool[2056] trap int3 ip:7f778e83c9eb sp:7f776b1eb6f0 error:0
 philip@ubuntu:~$

从前面的输出中,我们可以看到各种信息,包括 CPU 检测、PCI 驱动程序和以太网等。

GRUB 和 GRUB2

现在,我们将转变方向,讨论引导管理器的工作是呈现引导菜单,用户可以从中选择要加载或编辑的操作系统/ Linux 内核。首先,我们将重点放在 GRUB 上,然后转到 GRUB2。

GRUB

GRUB 代表Grand Unified Bootloader。GRUB 主要用于引导 Linux 发行版。但是,GRUB 可以与其他引导加载程序一起使用。一个常见的用例是与 Microsoft 操作系统双引导,它通过将控制权移交给 Windows 引导加载程序来实现这一点。

GRUB 使用/boot/grub/grub.conf文件。有时您会看到/boot/grub/menu.lst,但是这个文件只是/boot/grub/grub.conf的符号链接。使用 CentOS 6.5 发行版,运行以下命令:

[root@localhost ~]# ls -l /boot/grub
 total 274
 -rw-r--r--. 1 root root 63 Jun 20 01:47    device.map
 -rw-r--r--. 1 root root 13380 Jun 20 01:47 e2fs_stage1_5
 -rw-r--r--. 1 root root 12620 Jun 20 01:47 fat_stage1_5
 -rw-r--r--. 1 root root 11748 Jun 20 01:47 ffs_stage1_5
 -rw-------. 1 root root 769 Jun 20 01:48   grub.conf
 -rw-r--r--. 1 root root 11756 Jun 20 01:47 iso9660_stage1_5
 -rw-r--r--. 1 root root 13268 Jun 20 01:47 jfs_stage1_5
 lrwxrwxrwx. 1 root root 11 Jun 20 01:47    menu.lst -> ./grub.conf
 -rw-r--r--. 1 root root 11956 Jun 20 01:47 minix_stage1_5
 -rw-r--r--. 1 root root 14412 Jun 20 01:47 reiserfs_stage1_5
 -rw-r--r--. 1 root root 1341 Nov 14 2010   splash.xpm.gz
 -rw-r--r--. 1 root root 512 Jun 20 01:47    stage1
 -rw-r--r--. 1 root root 126100 Jun 20 01:47 stage2
 -rw-r--r--. 1 root root 12024 Jun 20 01:47  ufs2_stage1_5
 -rw-r--r--. 1 root root 11364 Jun 20 01:47  vstafs_stage1_5
 -rw-r--r--. 1 root root 13964 Jun 20 01:47  xfs_stage1_5
 [root@localhost ~]#

从前面的输出中,我们可以看到/boot/grub/grub.conf,还有符号链接/boot/grub/menu.lst

我们可以查看实际的/boot/grub/grub.conf文件:

[root@localhost ~]# cat /boot/grub/grub.conf
 # grub.conf generated by anaconda
 #
 # Note that you do not have to rerun grub after making changes to this file
 # NOTICE: You have a /boot partition. This means that
 # all kernel and initrd paths are relative to /boot/, eg.
 # root (hd0,0)
 # kernel /vmlinuz-version ro root=/dev/sda2
 # initrd /initrd-[generic-]version.img
 #boot=/dev/sda
 default=0
 timeout=5
 splashimage=(hd0,0)/grub/splash.xpm.gz
 hiddenmenu
 title CentOS (2.6.32-431.el6.x86_64)
 root (hd0,0)
 kernel /vmlinuz-2.6.32-431.el6.x86_64 ro root=UUID=05527d71-25b6-4931-a3bb-8fe505f3fa64 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
 initrd /initramfs-2.6.32-431.el6.x86_64.img
 [root@localhost ~]#

从前面的输出中,常见的选项将是以下内容。default=0表示它是菜单中要启动的第一个条目。timeout=5给出了菜单显示的秒数(在这种情况下为 5),在加载 Linux 内核或 Windows 引导加载程序从 GRUB 手中接管之前。splashimage=(hd0,0)/grub/splash.xpm.gz是引导菜单的背景图像。root (hd0,0)指的是第一个硬盘和第一个硬盘上的第一个分区。

GRUB2

GRUB2 在菜单呈现方式上使用了更加程序化的方法。乍一看,GRUB2 可能看起来令人生畏,但请放心,它并不像看起来那么复杂。语法类似于编程语言,有很多if...then语句。以下是 CentOS 7 系统上/boot/grub/grub.cfg的样子:

[root@localhost ~]# cat /boot/grub2/grub.cfg
 #
 # DO NOT EDIT THIS FILE
 #
 # It is automatically generated by grub2-mkconfig using templates
 # from /etc/grub.d and settings from /etc/default/grub
 #
### BEGIN /etc/grub.d/00_header ###
 set pager=1
if [ -s $prefix/grubenv ]; then
 load_env
 fi
 if [ "${next_entry}" ] ; then
 set default="${next_entry}"
 set next_entry=
 save_env next_entry
 set boot_once=true
 else
 set default="${saved_entry}"
 fi

出于简洁起见,以下部分输出被省略。以下显示了/boot/grub/grub.cfg的最后部分:

### BEGIN /etc/grub.d/10_linux ###
 menuentry 'CentOS Linux (3.10.0-693.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-693.el7.x86_64-advanced-16e2de7b-b679-4a12-888e-55081af4dad8' {
 load_video
 set gfxpayload=keep
 insmod gzio
 insmod part_msdos
 insmod xfs
 set root='hd0,msdos1'
 if [ x$feature_platform_search_hint = xy ]; then
 search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1' 40c7c63f-1c93-438a-971a-5331e265419b
 else
 search --no-floppy --fs-uuid --set=root 40c7c63f-1c93-438a-971a-5331e265419b
 fi
 linux16 /vmlinuz-3.10.0-693.el7.x86_64 root=UUID=16e2de7b-b679-4a12-888e-55081af4dad8 ro crashkernel=auto rhgb quiet LANG=en_US.UTF-8
 initrd16 /initramfs-3.10.0-693.el7.x86_64.img
 }
 ### END /etc/grub.d/10_linux ###

因此,要解释/boot/grub/grub.cfg文件,我们要查找以menuentry开头的行。这些行开始了操作系统的实际菜单条目,例如 Linux 发行版或 Windows 操作系统。

条目被包含在大括号{}中。

与 GRUB 一起工作

现在我们将与 GRUB 进行交互。我们将添加一个自定义引导条目。这将在重新启动时呈现。我们将使用vi命令,它将在可视编辑器中打开/boot/grub/grub.conf

在使用 GRUB 之前,始终备份您的/boot/grub/grub.conf

[root@localhost ~]# cat /boot/grub/grub.conf
 # grub.conf generated by anaconda
 #
 # Note that you do not have to rerun grub after making changes to this file
 # NOTICE: You have a /boot partition. This means that
 # all kernel and initrd paths are relative to /boot/, eg.
 # root (hd0,0)
 # kernel /vmlinuz-version ro root=/dev/sda2
 # initrd /initrd-[generic-]version.img
 #boot=/dev/sda
 default=0
 timeout=5
 splashimage=(hd0,0)/grub/splash.xpm.gz
 hiddenmenu
 title CentOS (2.6.32-431.el6.x86_64)
 root (hd0,0)
 kernel /vmlinuz-2.6.32-431.el6.x86_64 ro root=UUID=05527d71-25b6-4931-a3bb-8fe505f3fa64 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
 initrd /initramfs-2.6.32-431.el6.x86_64.img
 [root@localhost ~]# vi /boot/grub/grub.conf

现在我们在vi中。我们将按下键盘上的I进入插入模式,使用下箭头键向下滚动,直到达到最后一行,然后按Enter进入新行:

# grub.conf generated by anaconda
 #
 # Note that you do not have to rerun grub after making changes to this file
 # NOTICE: You have a /boot partition. This means that
 # all kernel and initrd paths are relative to /boot/, eg.
 # root (hd0,0)
 # kernel /vmlinuz-version ro root=/dev/sda2
 # initrd /initrd-[generic-]version.img
 #boot=/dev/sda
 default=0
 timeout=5
 splashimage=(hd0,0)/grub/splash.xpm.gz
 hiddenmenu
 title CentOS (2.6.32-431.el6.x86_64)
 root (hd0,0)
 kernel /vmlinuz-2.6.32-431.el6.x86_64 ro root=UUID=05527d71-25b6-4931-a3bb-8fe505f3fa64 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
 initrd /initramfs-2.6.32-431.el6.x86_64.img
~
 ~
 ~
 -- INSERT --

接下来,我们将使用以下关键字启动我们的条目:titlerootkernelinitrd。我们将插入我们自己的自定义值,如下所示:

# grub.conf generated by anaconda
 #
 # Note that you do not have to rerun grub after making changes to this file
 # NOTICE: You have a /boot partition. This means that
 # all kernel and initrd paths are relative to /boot/, eg.
 # root (hd0,0)
 # kernel /vmlinuz-version ro root=/dev/sda2
 # initrd /initrd-[generic-]version.img
 #boot=/dev/sda
 default=0
 timeout=5
 splashimage=(hd0,0)/grub/splash.xpm.gz
 hiddenmenu
 title CentOS (2.6.32-431.el6.x86_64)
 root (hd0,0)
 kernel /vmlinuz-2.6.32-431.el6.x86_64 ro root=UUID=05527d71-25b6-4931-a3bb-8fe505f3fa64 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
 initrd /initramfs-2.6.32-431.el6.x86_64.img
 title CompTIA Linux+ (Our.Custom.Entry)
 root (hd0,0)
 kernel /vmlinuz-2.6.32-431.el6.x86 ro
 initrd /initramfs-2.6.32-431.el6.x86_64.img
 -- INSERT --

现在我们将保存并退出vi。我们使用:wq来保存我们的更改并退出vi

title CompTIA Linux+ (Our.Custom.Entry)
 root (hd0,0)
 kernel /vmlinuz-2.6.32-431.el6.x86 ro
 initrd /initramfs-2.6.32-431.el6.x86_64.img
 :wq

根据前面的输出,这是我们自定义条目的分解:

  • title定义了我们的自定义引导条目。

  • root (hd0,0) 告诉它搜索第一个硬盘和第一个硬盘上的第一个分区。

  • kernel /vmlinuz-2.6.32-431.el6.x86 ro 告诉 GRUB 查找 Linux 内核的位置。在这种情况下,它是vmlinuz-2.6.32-431.el6.x86 roro表示以只读方式加载内核)。

  • inidrd /initramfs-2.6.32-431.el6.x86_64.img指定要使用的初始 RAM 磁盘文件(这有助于系统启动)。

最后一步是重新启动我们的 CentOS 系统,并显示 GRUB 引导菜单:

从前面的输出中,我们可以看到我们的新自定义引导条目显示在 GRUB 中,这很棒。我们可以实时交互,就在 GRUB 菜单上。假设我们想要在这些条目中添加或删除选项。我们只需按下E键,如下所示:

现在我们可以再次按E键编辑该项。假设我们想指定根文件系统位于/dev/;我们可以按照以下截图所示进行操作:

现在,我们可以按Enter键保存我们的更改,按Esc键返回到上一个屏幕;我们将看到新添加的选项:

从前面的输出中,我们可以看到在 GRUB 引导菜单中实时工作以及如何在 GRUB 中添加自定义引导项是多么容易。

在 GRUB 中,第一个硬盘和第一个分区被标识为(hd0, 0),而在 Linux shell 中,第一个硬盘和第一个分区被标识为(sda1)

使用 GRUB2

我们以与 GRUB 略有不同的方式在 GRUB2 中添加自定义引导项。在 GRUB2 中,我们不是编辑实际的/boot/grub/grub.cfg,而是使用/etc/default/grub/etc/grub.d。让我们列出/etc/grub.d以查看所有可用的文件:

philip@ubuntu:~$ ls -l /etc/grub.d/
 total 76
 -rwxr-xr-x 1 root root 9791 Apr 15 2016 00_header
 -rwxr-xr-x 1 root root 6258 Mar 15 2016 05_debian_theme
 -rwxr-xr-x 1 root root 12261 Apr 15 2016 10_linux
 -rwxr-xr-x 1 root root 11082 Apr 15 2016 20_linux_xen
 -rwxr-xr-x 1 root root 1992 Jan 28 2016 20_memtest86+
 -rwxr-xr-x 1 root root 11692 Apr 15 2016 30_os-prober
 -rwxr-xr-x 1 root root 1418 Apr 15 2016 30_uefi-firmware
 -rwxr-xr-x 1 root root 214 Apr 15 2016 40_custom
 -rwxr-xr-x 1 root root 216 Apr 15 2016 41_custom
 -rw-r--r-- 1 root root 483 Apr 15 2016 README
 philip@ubuntu:~$

在使用 GRUB2 之前,始终备份您的/boot/grub/grub.cfg

从前面的输出中,我们可以看到许多文件。它们的名称以数字开头,并且数字是按顺序读取的。假设我们想在 GRUB2 中添加一个自定义的引导项。我们将创建一个自定义项并命名为/etc/grub/40_custom。我们将在vi中看到以下代码:

#!/bin/sh
 exec tail -n +3 $0
 # This file provides an easy way to add custom menu entries. Simply type the
 # menu entries you want to add after this comment. Be careful not to change
 # the 'exec tail' line above.
 echo "Test Entry"
 cat << EOF
 menuentry "CompTIA_LINUX+" {
 set root ='hd0,0'
}
 EOF

从前面的输出中,我们可以看到语法与编程有些相似。在 GRUB2 中,它是一种完整的编程语言。下一步是保存我们的更改,然后运行grub-mkconfig(名称暗示我们在谈论旧版 GRUB,但实际上是指 GRUB2)。这取决于 Linux 发行版。在 CentOS 7 中,您将看到以grub2开头的命令:

root@ubuntu:/home/philip# grub-mkconfig
 Generating grub configuration file ...
 #
 # DO NOT EDIT THIS FILE
 #
 # It is automatically generated by grub-mkconfig using templates
 # from /etc/grub.d and settings from /etc/default/grub
 #
### BEGIN /etc/grub.d/00_header ###
 if [ -s $prefix/grubenv ]; then
 set have_grubenv=true
 load_env
 fi

出于简洁起见,以下部分输出被省略:

### BEGIN /etc/grub.d/40_custom ###
 # This file provides an easy way to add custom menu entries. Simply type the
 # menu entries you want to add after this comment. Be careful not to change
 # the 'exec tail' line above.
 echo "Test Entry"
 cat << EOF
 menuentry "CompTIA_LINUX+" {
 set root ='hd0,0'
}
 EOF

当我们运行此命令时,grub-mkconfig命令会找到自定义项。然后生成一个新的引导菜单。在系统下一次重启时,我们将看到新的引导菜单。我们还可以更改/etc/default/grub中的选项,包括默认操作系统、计时器等。以下是/etc/default/grub的内容:

root@ubuntu:/home/philip# cat /etc/default/grub
 # If you change this file, run 'update-grub' afterwards to update
 # /boot/grub/grub.cfg.
 # For full documentation of the options in this file, see:
 # info -f grub -n 'Simple configuration'
GRUB_DEFAULT=0
 GRUB_HIDDEN_TIMEOUT=0
 GRUB_HIDDEN_TIMEOUT_QUIET=true
 GRUB_TIMEOUT=10
 GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
 GRUB_CMDLINE_LINUX_DEFAULT="quiet"
 GRUB_CMDLINE_LINUX="find_preseed=/preseed.cfg auto noprompt priority=critical locale=en_US"

根据前面的输出,计时器值设置为10。还要注意默认值为0。在配置文件中继续向下,我们看到以下代码:

# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"
# Uncomment to disable graphical terminal (grub-pc only)
#GRUB_TERMINAL=console
# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480
# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true
# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"
# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"

现在,让我们重新启动 Ubuntu 系统并查看 GRUB2 引导菜单:

从前面的截图中,我们现在可以在 GRUB2 中看到我们的自定义菜单选项。我们甚至可以通过按 E 键滚动浏览条目并编辑它们。

在 GRUB2 中,第一个硬盘从0开始,第一个分区从1开始,与旧版 GRUB 不同。

总结

在本章中,我们看了一下引导过程。然后讨论了initsystemd。我们使用了pstree命令并看到了加载的第一个进程。此外,我们使用了ps命令来识别进程号。然后,我们查看了通常会在屏幕上滚动的引导消息,使用dmesg命令。显示的消息为我们提供了关于引导时加载的内容的提示。此外,我们可以使用显示的消息来帮助我们进行故障排除。接下来,我们讨论了 GRUB 和 GRUB2,查看了 GRUB 的结构,特别是/boot/grub/grub/conf。我们看了如何在 GRUB 中添加自定义菜单项。我们看了如何在引导菜单中实时与 GRUB 交互。之后,我们看了 GRUB2,重点是/boot/grub/grub.cfg的结构。此外,我们还看了在 GRUB2 配置中起作用的其他位置:/etc/default/grub//etc/grub.d/目录。然后,我们使用/etc/grub.d/40_custom文件在/etc/grub.d/中添加了自定义菜单项。之后,我们使用grub-mkconfig(Ubuntu 发行版)更新了 GRUB2。最后,我们实时与 GRUB2 引导菜单进行了交互。

在下一章中,我们将专注于运行级别和引导目标。这些是我们作为 Linux 工程师需要充分理解的关键主题。我们将使用各种方法在命令行上管理系统。我们将涵盖runlevelinitsystemctl等命令。在下一章中,有很多有用的信息可以获得。了解运行级别的工作原理至关重要。此外,还有引导目标的概念。在大多数较新的发行版中,您将接触到引导目标。这将帮助您在命令行环境中管理 Linux 系统。在下一章中,您的技能将继续增长。这将进一步使您更接近成功,获得认证。

问题

  1. 引导加载程序位于硬盘的哪个位置?

A. 引导扇区

B. 次要分区

C. 逻辑分区

D. 以上都不是

  1. 哪个是第一个商业 Unix 操作系统?

A. systemd

B. upstart

C. System X

D. System V

  1. 哪个命令显示从父进程开始的进程,然后是子进程?

A. dnf

B. systemctl

C.  pstree

D. ps

  1. 在 CentOS 5 系统上启动的第一个进程是什么?

A. systemd

B. init

C. kickstart

D. upstart

  1. 在 Linux 内核的较新版本中,init被什么取代了?

A. telinit

B. systemctl

C. systemb

D. systemd

  1. 哪个命令列出了在 CentOS 7 发行版上运行的进程?

A. systemd list-unit-files

B. systemX list-unit-files

C. systemctl list-unit-files

D. service status unit-files

  1. 哪个命令列出了系统引导时加载的硬件驱动程序?

A. cat /var/log/messages

B. tail –f /var/log/startup

C. head /var/messages

D. dmesg

  1. 在 CentOS 5 发行版中,GRUB 配置文件位于哪个目录?

A. /boot/

B. /grub/boot/

C. /boot/grub/

D. /grub/grub-config/

  1. 在 GRUB 中添加自定义菜单项时,是什么启动了自定义菜单项?

A. title

B. menu entry

C. 操作系统

D. default =0

  1. 在 GRUB2 中添加自定义菜单项时,是什么启动了自定义菜单项?

A. title

B. root = /vmlinuz/

C. menuentry

D. menu entry

  1. 哪个字母键用于在 GRUB 引导菜单中实时编辑条目?

A. C

B. E

C. B

D. A

进一步阅读

  • 您可以在www.centos.org.获取有关 CentOS 发行版的更多信息,如安装、配置最佳实践等。

  • 以下网站为您提供了许多有用的提示和 Linux 社区用户的最佳实践,特别是适用于 Debian 发行版,如 Ubuntu:askubuntu.com.

  • 以下链接为您提供了一般信息,涉及适用于 CentOS 和 Ubuntu 的各种命令。您可以在那里发布您的问题,其他社区成员将会回答:www.linuxquestions.org.

第三章:更改运行级别和引导目标

在上一章中,我们关注了引导过程。之后,重点转移到了 Linux 发行版中可用的各种引导管理器。特别是,我们使用了迄今为止最流行的引导管理器 GRUB 和 GRUB2。我们查看了它们各自的配置文件,重点关注了计时器、默认引导条目以及在 GRUB/GRUB2 引导菜单中传递参数。最后,我们创建了单独的示例,以便为 GRUB 和 GRUB2 的引导菜单添加一个自定义引导条目。本章重点介绍了运行级别和引导目标的概念,以及 Linux 发行版中可用的运行级别和引导目标的类型,以及运行级别和引导目标之间的区别。我们还将看看如何在 CLI 中使用运行级别和引导目标。

在本章中,我们将涵盖以下主题:

  • 运行级别简介

  • 引导目标简介

  • 使用运行级别

  • 使用引导目标

运行级别简介

运行级别的概念可以追溯到 SysV 时代,每个运行级别都有一个目的。不同的任务需要在系统引导时运行各种守护进程。这在服务器环境中特别有用,我们试图尽量减少服务器的开销。通常我们会为服务器分配一个角色。这样做可以减少在给定服务器上需要安装的应用程序数量。例如,Web 服务器通常会有一个用于向用户提供内容的应用程序和一个用于查找的数据库。

另一个典型的用例是打印服务器。这通常只用于管理打印作业。也就是说,从运行级别的角度来看,我们通常会减少在给定服务器内运行的服务数量。对于那些来自 Windows 背景的人来说,想想安全模式。通常,我们会进入安全模式以最小化加载的程序和驱动程序。运行级别进一步扩展了这个想法,我们可以告诉 Linux 发行版我们想要在给定的运行级别中启动/停止什么。有趣的是,我们在 Linux 发行版中可以使用多个运行级别。您会在使用 SysV init 的 Linux 发行版中找到运行级别。

看一下下表:

**运行级别 ** **0  ** ** 1   ** 2 3 4 5 6
守护进程 关闭 开启 开启 开启 开启 开启 关闭

根据上表,每当一个守护进程处于“关闭”状态时,这意味着该守护进程在该运行级别中不会运行。同样,每当一个守护进程处于“开启”状态时,它被配置为在特定的运行级别中运行。

守护进程和服务通常可以互换使用。

运行级别通常具有各种启动/停止脚本,每当在支持init的 Linux 发行版中选择运行级别时都会运行这些脚本。我们可以查看 CentOS 6.5 系统,看看使用了哪个运行级别。我们将查看/etc/inittab配置文件:

[philip@localhost Desktop]$ cat /etc/inittab
 # inittab is only used by upstart for the default runlevel.
 #
 # ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
 #
 # System initialization is started by /etc/init/rcS.conf
 #
 # Individual runlevels are started by /etc/init/rc.conf
 #
 # Ctrl-Alt-Delete is handled by /etc/init/control-alt-delete.conf
 #
 # Terminal gettys are handled by /etc/init/tty.conf and /etc/init/serial.conf,
 # with configuration in /etc/sysconfig/init.
 #
 # For information on how to write upstart event handlers, or how
 # upstart works, see init(5), init(8), and initctl(8).
 #
 # Default runlevel. The runlevels used are:
 # 0 - halt (Do NOT set initdefault to this)
 # 1 - Single user mode
 # 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
 # 3 - Full multiuser mode
 # 4 - unused
 # 5 - X11
 # 6 - reboot (Do NOT set initdefault to this)
 #
 id:5:initdefault:
 [philip@localhost Desktop]$

从前面的输出中,CentOS 发行版支持七个运行级别。特别是,运行级别 5 是向用户呈现图形用户界面的运行级别。

其他流行的运行级别是0用于停止或关闭系统,1用于单用户模式(通常用于恢复)和6用于重新启动系统。上面写着id:5:initdefault:的那一行告诉 CentOS 在系统引导时使用哪个运行级别。

现在让我们看看支持init的 Ubuntu 6.06 发行版上的/etc/inittab

从前面的输出中,我们可以关注一下这一行,上面写着id:2:initdefault:2告诉 Linux 内核在系统引导时使用运行级别 2。默认情况下,Ubuntu 6.06 使用运行级别 2。实际上,在 Ubuntu 中,运行级别 2-5 被认为是多用户的;在运行级别 2-5 之间没有区别。

在 CentOS 6.5 中,我们可以使用chkconfig命令来检查各种运行级别中运行的守护进程;这将给出各种服务的简要摘要:

[philip@localhost Desktop]$ chkconfig
 NetworkManager 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 abrt-ccpp 0:off 1:off 2:off 3:on 4:off 5:on 6:off
 abrtd 0:off 1:off 2:off 3:on 4:off 5:on 6:off
 acpid 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 atd 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 auditd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 blk-availability 0:off 1:on 2:on 3:on 4:on 5:on 6:off
 bluetooth 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 cpuspeed 0:off 1:on 2:on 3:on 4:on 5:on 6:off
 crond 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 cups 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 dnsmasq 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 firstboot 0:off 1:off 2:off 3:on 4:off 5:on 6:off
 haldaemon 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 htcacheclean 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 httpd 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 ip6tables 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 iptables 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 irqbalance 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 kdump 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 lvm2-monitor 0:off 1:on 2:on 3:on 4:on 5:on 6:off
 mdmonitor 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 messagebus 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 netconsole 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 netfs 0:off 1:off 2:off 3:on 4:on 5:on 6:off
 network 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 ntpd 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 ntpdate 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 portreserve 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 postfix 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 psacct 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 quota_nld 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 rdisc 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 restorecond 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 rngd 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 rsyslog 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 saslauthd 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 smartd 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 snmpd 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 snmptrapd 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 spice-vdagentd 0:off 1:off 2:off 3:off 4:off 5:on 6:off
 sshd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 sysstat 0:off 1:on 2:on 3:on 4:on 5:on 6:off
 udev-post 0:off 1:on 2:on 3:on 4:on 5:on 6:off
 vmware-tools 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 vmware-tools-thinprint 0:off 1:off 2:on 3:on 4:on 5:on 6:off
 wdaemon 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 winbind 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 wpa_supplicant 0:off 1:off 2:off 3:off 4:off 5:off 6:off
 [philip@localhost Desktop]$

从前面的输出中,我们可以看到各种服务。有些在多个运行级别中运行,而有些完全关闭。例如,网络服务;它设置为0:关闭 1:关闭 2:开启 3:开启 4:开启 5:开启 6:关闭。这告诉系统在运行级别 2-5 中启动网络服务,在运行级别 0-1 和 6 中关闭网络服务。大多数服务仅在运行级别 2-5 中运行。

我们可以查看/etc/rc.d/,看看各种脚本是如何设置的,以便启动/停止:

[philip@localhost Desktop]$ ls -l /etc/rc.d
 total 60
 drwxr-xr-x. 2 root root 4096 Jun 20 01:49 init.d
 -rwxr-xr-x. 1 root root 2617 Nov 22 2013 rc
 drwxr-xr-x. 2 root root 4096 Jun 20 01:49 rc0.d
 drwxr-xr-x. 2 root root 4096 Jun 20 01:49 rc1.d
 drwxr-xr-x. 2 root root 4096 Jun 20 01:49 rc2.d
 drwxr-xr-x. 2 root root 4096 Jun 20 01:49 rc3.d
 drwxr-xr-x. 2 root root 4096 Jun 20 01:49 rc4.d
 drwxr-xr-x. 2 root root 4096 Jun 20 01:49 rc5.d
 drwxr-xr-x. 2 root root 4096 Jun 20 01:49 rc6.d
 -rwxr-xr-x. 1 root root 220 Jun 20 01:48 rc.local
 -rwxr-xr-x. 1 root root 19688 Nov 22 2013 rc.sysinit
 [philip@localhost Desktop]$ 

根据前面的输出,每个相应运行级别(0-6)都有各自的目录。此外,我们甚至可以进一步深入文件系统层次结构并暴露子目录。让我们选择/etc/rc.d/rc5.d并暴露其内容:

[philip@localhost Desktop]$ ls -l /etc/rc.d/rc5.d/
 total 0
 lrwxrwxrwx. 1 root root 16 Jun 20 01:44 K01smartd -> ../init.d/smartd
 lrwxrwxrwx. 1 root root 17 Jun 20 01:44 K05wdaemon -> ../init.d/wdaemon
 lrwxrwxrwx. 1 root root 16 Jun 20 01:44 K10psacct -> ../init.d/psacct
 lrwxrwxrwx. 1 root root 19 Jun 20 01:41 K10saslauthd -> ../init.d/saslauthd
 lrwxrwxrwx. 1 root root 22 Jun 20 01:41 K15htcacheclean -> ../init.d/htcacheclean
 lrwxrwxrwx. 1 root root 15 Jun 20 01:41 K15httpd -> ../init.d/httpd
 lrwxrwxrwx. 1 root root 17 Jun 20 01:41 K50dnsmasq -> ../init.d/dnsmasq
 lrwxrwxrwx. 1 root root 20 Jun 20 01:40 K50netconsole -> ../init.d/netconsole
 lrwxrwxrwx. 1 root root 15 Jun 20 01:41 K50snmpd -> ../init.d/snmpd
 lrwxrwxrwx. 1 root root 19 Jun 20 01:41 K50snmptrapd -> ../init.d/snmptrapd
 lrwxrwxrwx. 1 root root 17 Jun 20 01:47 K73winbind -> ../init.d/winbind
 lrwxrwxrwx. 1 root root 14 Jun 20 01:41 K74ntpd -> ../init.d/ntpd
 lrwxrwxrwx. 1 root root 17 Jun 20 01:41 K75ntpdate -> ../init.d/ntpdate
 lrwxrwxrwx. 1 root root 19 Jun 20 01:44 K75quota_nld -> ../init.d/quota_nld
 lrwxrwxrwx. 1 root root 24 Jun 20 01:44 K84wpa_supplicant -> ../init.d/wpa_supplicant
 lrwxrwxrwx. 1 root root 21 Jun 20 01:40 K87restorecond -> ../init.d/restorecond
 lrwxrwxrwx. 1 root root 15 Jun 20 01:40 K89rdisc -> ../init.d/rdisc
 lrwxrwxrwx. 1 root root 14 Jun 20 01:44 K99rngd -> ../init.d/rngd
 lrwxrwxrwx. 1 root root 17 Jun 20 01:43 S01sysstat -> ../init.d/sysstat
 lrwxrwxrwx. 1 root root 22 Jun 20 01:43 S02lvm2-monitor -> ../init.d/lvm2-monitor
 lrwxrwxrwx. 1 root root 22 Jun 20 01:49 S03vmware-tools -> ../init.d/vmware-tools
 lrwxrwxrwx. 1 root root 19 Jun 20 01:41 S08ip6tables -> ../init.d/ip6tables
 lrwxrwxrwx. 1 root root 18 Jun 20 01:40 S08iptables -> ../init.d/iptables
 lrwxrwxrwx. 1 root root 17 Jun 20 01:40 S10network -> ../init.d/network
 lrwxrwxrwx. 1 root root 16 Jun 20 01:44 S11auditd -> ../init.d/auditd
 lrwxrwxrwx. 1 root root 21 Jun 20 01:38 S11portreserve -> ../init.d/portreserve
 lrwxrwxrwx. 1 root root 17 Jun 20 01:41 S12rsyslog -> ../init.d/rsyslog
 lrwxrwxrwx. 1 root root 18 Jun 20 01:44 S13cpuspeed -> ../init.d/cpuspeed

在整个章节中,出于简洁起见,一些输出被省略了。

从前面的输出中,运行级别 5 有许多守护进程。我们通过使用命名约定来识别守护进程。以K开头的文件用于终止/停止进程,以S开头的文件用于启动进程。此外,大多数脚本都是符号链接,指向/etc/rc.d/init.d/目录。

同样地,我们可以在较新的 CentOS 发行版中暴露各种启动/停止脚本。例如,让我们选择 CentOS 6.5 并解剖其中一个目录。在 CentOS 6.5 系统上,这是其中一个停止脚本的显示:

[philip@localhost Desktop]$ cat /etc/rc.d/rc5.d/S13irqbalance
 #! /bin/sh
 ### BEGIN INIT INFO
 # Provides: irqbalance
 # Default-Start: 3 4 5
 # Default-Stop: 0 1 6
 # Short-Description: start and stop irqbalance daemon
 # Description: The irqbalance daemon will distribute interrupts across
 # the cpus on a multiprocessor system with the purpose of
 # spreading the load
 ### END INIT INFO
 # chkconfig: 2345 13 87 # This is an interactive program, we need the current locale # Source function library.
 . /etc/init.d/functions

正如我们所看到的,这些脚本涉及的内容更多。继续向下移动,我们可以看到以下代码:

# Check that we're a priviledged user
 [ `id -u` = 0 ] || exit 0
prog="irqbalance"
[ -f /usr/sbin/irqbalance ] || exit 0
# fetch configuration if it exists
 # ONESHOT=yes says to wait for a minute, then look at the interrupt
 # load and balance it once; after balancing exit and do not change
 # it again.
 # The default is to keep rebalancing once every 10 seconds.
 ONESHOT=
 [ -f /etc/sysconfig/irqbalance ] && . /etc/sysconfig/irqbalance
 case "$IRQBALANCE_ONESHOT" in
 y*|Y*|on) ONESHOT=--oneshot ;;
 *) ONESHOT= ;;
 esac
RETVAL=0
start() {
 if [ -n "$ONESHOT" -a -f /var/run/irqbalance.pid ]; then
 exit 0
 fi
 echo -n $"Starting $prog: "
 if [ -n "$IRQBALANCE_BANNED_CPUS" ];
 then
 export IRQBALANCE_BANNED_CPUS=$IRQBALANCE_BANNED_CPUS
 fi
 daemon irqbalance --pid=/var/run/irqbalance.pid $IRQBALANCE_ARGS $ONESHOT
 RETVAL=$?
 echo
 return $RETVAL
 }
stop() {
 echo -n $"Stopping $prog: "
 killproc irqbalance
 RETVAL=$?
 echo
 [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/irqbalance
 return $RETVAL
 }
restart() {
 stop
 start
 }
# See how we were called.
 case "$1" in
 start)
 start
 ;;
 stop)
 stop
 ;;
 status)
 status irqbalance
 ;;
 restart|reload|force-reload)
 restart
 ;;
 condrestart)
 [ -f /var/lock/subsys/irqbalance ] && restart || :
 ;;
 *)
 echo $"Usage: $0 {start|stop|status|restart|reload|condrestart|force-reload}"
 exit 1
 ;;
 esac
exit $?
 [philip@localhost Desktop]$

最后,从前面的输出中,我们可以清楚地看到这些脚本是以程序方式编写的。

引导目标简介

引导目标的概念是一个全新的游戏规则。引导目标在使用systemd时使用。我们可以看到性能提高了,因为只有对特定套接字的请求在需要时才会启动。此外,systemd模拟了init以实现兼容性,而在后台systemd正在进行工作。当我们使用引导目标时,我们使用单元。对于给定的引导目标,存在许多守护进程。让我们看看 Ubuntu 发行版中可用的引导目标:

root@ubuntu:/home/philip# systemctl list-units --type target
 UNIT           LOAD    ACTIVE   SUB  DESCRIPTION
 basic.target      loaded active active Basic System
 cryptsetup.target loaded active active Encrypted Volumes
 getty.target      loaded active active Login Prompts
 graphical.target  loaded active active Graphical Interface
 local-fs-pre.target loaded active active Local File Systems (Pre)
 local-fs.target   loaded active active Local File Systems
 multi-user.target loaded active active Multi-User System
 network.target    loaded active active Network
 nss-user-lookup.target loaded active active User and Group Name Lookups
 paths.target     loaded active active Paths
 remote-fs-pre.target loaded active active Remote File Systems (Pre)
 remote-fs.target loaded active active Remote File Systems
 slices.target   loaded active active Slices
 sockets.target  loaded active active Sockets
 sound.target    loaded active active Sound Card
 swap.target     loaded active active Swap
 sysinit.target  loaded active active System Initialization
 time-sync.target loaded active active System Time Synchronized
 timers.target   loaded active active Timers
LOAD = Reflects whether the unit definition was properly loaded.
 ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
 SUB = The low-level unit activation state, values depend on unit type.
19 loaded units listed. Pass --all to see loaded but inactive units, too.
 To show all installed unit files use 'systemctl list-unit-files'.
 root@ubuntu:/home/philip#

从前面的输出中,只会显示当前加载的目标。graphical.target类似于init中的运行级别 5。要查看所有引导目标,我们可以这样做:

root@ubuntu:/home/philip# systemctl list-units --type target --all
 UNIT             LOAD ACTIVE SUB DESCRIPTION
 basic.target       loaded active active Basic System
 cryptsetup.target  loaded active active Encrypted Volumes
 emergency.target   loaded inactive dead Emergency Mode
 failsafe-graphical.target loaded inactive dead Graphical failsafe fallback
 final.target       loaded inactive dead Final Step
 getty.target       loaded active active Login Prompts
 graphical.target   loaded active active Graphical Interface
 halt.target        loaded inactive dead Halt
 local-fs-pre.target loaded active active Local File Systems (Pre)
 local-fs.target    loaded active active Local File Systems
 multi-user.target    loaded active active Multi-User System
 network-online.target loaded inactive dead Network is Online
 network-pre.target    loaded inactive dead Network (Pre)
 network.target            loaded active active Network
 nss-user-lookup.target    loaded active active User and Group Name Lookups
 paths.target                loaded active active Paths
 reboot.target               loaded inactive dead Reboot
 remote-fs-pre.target        loaded active active

从前面的输出中,我们可以看到活动的引导目标,以及不活动的引导目标。

现在,假设我们想要查看与特定目标相关的实际守护进程。我们将运行以下命令:

root@ubuntu:/home/philip# systemctl list-dependencies graphical.target

从前面的输出中,我们可以看到graphical.target中有许多守护进程。其中一个守护进程是NetworkManager.service,用于系统内的网络。阅读这个的方式是:

  • 绿色圆圈:表示服务当前正在运行

  • 红色圆圈:表示服务目前未运行

使用运行级别

我们可以像在本章中看到的那样,为各种任务使用各种运行级别。让我们使用 CentOS 6.5 发行版。要实时在 shell 中查看运行级别,我们可以使用runlevel命令:

[philip@localhost Desktop]$ runlevel
N 5
[philip@localhost Desktop]$

从前面的输出中,N表示先前的运行级别。在我们的情况下,我们没有改变运行级别。5表示我们当前处于运行级别 5。我们还可以运行另一个命令来显示运行级别。我们可以使用带有-r选项的who命令,如下所示:

[philip@localhost Desktop]$ who -r
 run-level 5 2018-06-20 08:09
 [philip@localhost Desktop]$

从前面的输出中,我们可以看到更详细的描述,即使用who –r命令的run-level 5

现在,我们可以通过利用inittelinit命令来改变我们的 CentOS 6.5 发行版的运行级别。让我们看看如何从运行级别 5 更改到运行级别 1:

[philip@localhost Desktop]$ who -r
 run-level 5 2018-06-20 08:09
 [philip@localhost Desktop]$ init 1

当我们按下Enter时,我们会收到一个错误;原因是,在 CentOS 6.5 发行版中,我们需要 root 权限将运行级别 5 更改为运行级别 1:

[philip@localhost Desktop]$ init 1
 init: Need to be root
 [philip@localhost Desktop]$

现在,让我们以 root 用户的身份进行身份验证并重试init 1命令:

[philip@localhost Desktop]$ su -
 Password:
 [root@localhost ~]# init 1

现在,我们将被放置到运行级别 1,这将删除 GUI 并直接进入 shell。这个运行级别 1 通常被称为单用户,我们将用于恢复:

从前面的输出中,我们运行了runlevelwho -r命令,并验证了我们确实在运行级别 1 中。

现在,让我们将系统恢复到 GUI 状态,即运行级别 5:

现在,当我们在 GUI 中运行runlevel命令时,我们将看到之前的运行级别 1 替换runlevel命令中的NS

[philip@localhost Desktop]$ runlevel
 S 5
 [philip@localhost Desktop]$

同样,我们可以使用who -r选项运行who命令以查看更多信息:

[philip@localhost Desktop]$ who -r
run-level 5 2018-06-20 08:20 last=S
[philip@localhost Desktop]$ 

现在,假设我们想在某个运行级别打开一个守护程序。我们将使用dnsmasq进行演示。首先,让我们验证dnsmasq服务当前是否关闭:

[philip@localhost Desktop]$ chkconfig | grep dnsmasq
dnsmasq 0:off 1:off 2:off 3:off 4:off 5:off 6:off
[philip@localhost Desktop]$ 

太好了!现在让我们只在运行级别 3-5 中打开dnsmasq守护程序:

[philip@localhost Desktop]$ chkconfig --levels 345 dnsmasq on
You do not have enough privileges to perform this operation.
[philip@localhost Desktop]$ 

从前面的输出中,我们得到了一个错误,因为我们需要 root 权限才能在相应的运行级别中打开/关闭守护程序。让我们以 root 用户身份重试:

[philip@localhost Desktop]$ su -
Password:
[root@localhost ~]# chkconfig --levels 345 dnsmasq on
[root@localhost ~]#

太好了!现在让我们重新运行chkconfig命令,并只查找dnsmasq守护程序:

[root@localhost ~]# chkconfig | grep dnsmasq
dnsmasq 0:off 1:off 2:off 3:on 4:on 5:on 6:off
[root@localhost ~]# 

从前面的输出中,我们可以看到dnsmasq守护程序现在在运行级别 3-5 中设置为on

使用引导目标

我们可以使用systemctl命令来处理引导目标。我们在本章前面提到了systemctl。让我们使用 Ubuntu 发行版。我们可以通过以下方式实时查看在 shell 中当前默认运行的target

philip@ubuntu:~$ systemctl get-default
graphical.target
philip@ubuntu:~$

从前面的输出中,我们可以看到graphical.target是默认运行的目标。现在,如果我们想在不同的目标之间切换,我们可以使用systemctl命令。让我们切换到multi-user.target

philip@ubuntu:~$ systemctl isolate multi-user.target

一旦我们按下Enter键,系统将要求我们进行身份验证:

我们也可以运行systemctl来验证multi-user.target的状态:

我们可以使用systemctl命令将系统返回到 GUI 环境:

此外,我们可以使用systemctl命令查看一个目标的结构:

philip@ubuntu:~$ systemctl show network.target
 Id=network.target
 Names=network.target
 WantedBy=networking.service systemd-networkd.service NetworkManager.service
 Conflicts=shutdown.target
 Before=network-online.target rc-local.service
 After=NetworkManager.service network-pre.target systemd-networkd.service network
 Documentation=man:systemd.special(7) http://www.freedesktop.org/wiki/Software/sy
 Description=Network
 LoadState=loaded
 ActiveState=active
 SubState=active
 FragmentPath=/lib/systemd/system/network.target
 UnitFileState=static
 UnitFilePreset=enabled
 StateChangeTimestamp=Wed 2018-06-20 10:50:52 PDT
 StateChangeTimestampMonotonic=18205063
 InactiveExitTimestamp=Wed 2018-06-20 10:50:52 PDT
 InactiveExitTimestampMonotonic=18205063
 ActiveEnterTimestamp=Wed 2018-06-20 10:50:52 PDT
 ActiveEnterTimestampMonotonic=18205063
 ActiveExitTimestampMonotonic=0
 InactiveEnterTimestampMonotonic=0
 CanStart=no

从前面的输出中,一个关键值是WantedBy。这告诉我们谁依赖于network.target。我们可以看到NetworkManager.service依赖于network.target。还有关于StateChangeTimestampDocumentationLoadStateDescription等的详细信息。

总结

在本章中,我们与运行级别进行了交互。我们看到了各种可用的运行级别,并在运行级别之间进行了切换。我们看到了默认的运行级别(运行级别 5),并使用了runlevelwhoinit命令进行交互。然后,我们专注于引导目标。我们查看了默认的引导目标,并看到了每个引导目标下的各种单元。然后我们在引导目标之间进行了更改,并看到需要进行身份验证。我们使用了带有各种选项的systemctl命令,以及runlevelwho命令。我们验证了我们确实在另一个引导目标中。我们得出结论,graphical.target类似于运行级别 5,而mutli-user.target类似于运行级别 3。最后,我们简要地看了一下引导目标的结构。

在下一章中,我们将专注于硬盘布局的设计。在进行任何部署之前,硬盘布局至关重要。因此,下一章在这方面承载了很大的重要性,需要对我们如何管理硬盘进行深思熟虑。我们将涵盖fdiskparted等技术。您将从下一章中掌握的技术将有助于您作为 Linux 工程师在未来的部署中。从下一章中获得的这种赋权是建立信心的关键因素,有助于您未来在认证方面取得成功。

问题

  1. 在 CentOS 发行版中,GUI 显示在哪个运行级别?

  2. 1

  3. 5

  4. 2

  5. 3

  6. 在 Ubuntu 发行版中打印当前运行级别的命令是什么?

  7. run-level

  8. systemdctl

  9. runlevel

  10. who –b

  11. 哪个备用命令显示运行级别信息?

  12. who -v

  13. who -l

  14. who -b

  15. who –r

  16. 在阅读运行级别输出时,N代表什么?

  17. 当前运行级别

  18. 在更改为当前运行级别之前的先前运行级别

  19. 在更改为先前运行级别之前的先前当前运行级别

  20. 当前正在使用的运行级别

  21. 阅读运行级别输出时,S代表什么?

  22. 单一登录用户

  23. 超级用户

  24. 单入口超级用户

  25. 单用户

  26. 用于更改运行级别的命令是什么?

  27. int

  28. init

  29. runlevel

  30. change-run-level

  31. 还可以使用哪个命令来更改运行级别?

  32. runlevel

  33. shutdown

  34. telinit

  35. telnit

  36. 用于查看默认引导目标的命令是什么?

  37. systemctl get-default

  38. systemctl set-default

  39. systemctl-default

  40. systemctl-get-default

  41. 哪个命令可以用于列出给定目标的守护进程?

  42. systemctl list-dependencies

  43. systemctl list-dependencies –type list

  44. systemctl list-dependencies –type target

  45. systemctl list-dependencies target

  46. 哪个命令在不同目标之间切换?

  47. systemctl isolate target

  48. systemctl isolate multi-user.target

  49. systemctl isolate-target-multi-user

  50. systemctl isolate-multiuser.target

  51. 哪个命令显示目标的状态?

  52. systemctl status multi-user.target

  53. systemctl status-multi-user.target

  54. systemctl-status multi-user.target

  55. systemctl-status-multiuser.target

进一步阅读

  • 您可以在www.centos.org.获取有关 CentOS 发行版的更多信息,例如安装、配置最佳实践等。

  • 以下网站为您提供了许多有用的提示和 Linux 社区用户的最佳实践,特别是针对 Debian 发行版,如 Ubuntu:askubuntu.com.

  • 以下链接提供了一般信息,涉及适用于 CentOS 和 Ubuntu 的各种命令。您可以在以下链接发布问题,其他社区成员将会回答:www.linuxquestions.org.

第四章:设计硬盘布局

在前一章中,我们专注于运行级别和引导目标。我们与运行initsystemd的 Linux 系统进行了交互。我们看到了如何启动服务,以及如何在运行级别和引导目标之间切换。我们查看了各种启动和停止脚本,还查看了脚本的结构。

本章重点介绍在 CLI 中创建分区和分割物理硬盘。我们将特别关注fdisk实用程序和parted实用程序的使用。然后,我们将逐步介绍使用各种mkfs命令创建、删除和定义分区类型以及格式化硬盘的步骤。最后,我们将探讨挂载和卸载分区的方法。

因此,我们将在本章中涵盖以下主题:

  • 使用fdisk实用程序

  • 使用parted实用程序

  • 格式化硬盘的步骤

  • 挂载和卸载分区

使用 fdisk 实用程序

在 Linux 中,每当我们使用硬盘时,我们很可能会在某个时候分区硬盘分区简单地意味着分离硬盘。这使我们能够拥有不同大小的分区,并使我们能够满足各种软件安装要求。此外,当我们分区硬盘时,每个分区都被操作系统视为完全独立的硬盘。fdisk(固定磁盘或格式化磁盘)是一个基于命令行的实用程序,可用于操作硬盘。使用fdisk,您可以查看、创建、删除和更改等操作。

首先,让我们在 Ubuntu 分发中公开硬盘:

philip@ubuntu:~$ ls /dev/ | grep sd
sda
sda1
sda2
sda5
philip@ubuntu:~$

从前面的输出中,系统中的硬盘由/dev/sda表示。第一个分区是/dev/sda1,第二个分区是/dev/sda2,依此类推。为了查看分区信息,我们将运行以下命令:

philip@ubuntu:~$ fdisk -l /dev/sda
fdisk: cannot open /dev/sda: Permission denied
philip@ubuntu:~$

从前面的输出中,我们得到了Permission denied。这是因为我们需要 root 权限来查看和更改硬盘的分区。让我们以 root 用户重试:

philip@ubuntu:~$ sudo su
[sudo] password for philip:
root@ubuntu:/home/philip#
root@ubuntu:/home/philip# fdisk -l /dev/sda
Disk /dev/sda: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xf54f42a0

Device   Boot Start     End       Sectors  Size Id  Type
/dev/sda1  *   2048     39845887  39843840 19G 83   Linux
/dev/sda2      39847934 41940991  2093058  1022M  5 Extended
/dev/sda5      39847936 41940991  2093056 1022M 82 Linux swap / Solaris
root@ubuntu:/home/philip#

从前面的输出中,阅读的方式如下:

磁盘/dev/sda:20 GiB,21,474,836,480 字节,41,943,040 扇区:这是实际的物理硬盘:

设备 **引导 ** **开始 ** ** 结束** ** 扇区** 大小 ** ID** 类型 注释
/dev/sda1 * 2048 39,845,887 39,843,840 19 G 83 Linux 第一分区为 19 GB
/dev/sda2 39,847,934 41,940,991 2,093,058 1,022 M 5 扩展 第二分区为 1,022 MB
/dev/sda5   39,847,936 41,940,991 2,093,056 1,022 M 82 Linux swap / Solaris 第五分区为 1,022 MB

现在,为了能够进行任何更改,我们将再次使用fdisk命令。这次我们将省略-l选项:

root@ubuntu:/home/philip# fdisk /dev/sda

Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help):

从前面的代码中,我们现在在fdisk实用程序中,并且收到了一条不错的消息。

在进行任何更改之前,请确保您了解删除分区周围的危险;如果删除存储系统文件的分区,系统可能会变得不稳定,例如/boot//

要查看可用选项,我们可以按m键:

Command (m for help): m
Help:
 DOS (MBR)
 a   toggle a bootable flag
 b   edit nested BSD disklabel
 c   toggle the dos compatibility flag
Generic
 d   delete a partition
 F   list free unpartitioned space
 l   list known partition types
 n   add a new partition
 p   print the partition table
 t   change a partition type
 v   verify the partition table
 i   print information about a partition

Misc
 m   print this menu
 u   change display/entry units
 x   extra functionality (experts only)
Script
 I   load disk layout from sfdisk script file
 O   dump disk layout to sfdisk script file

Save & Exit
 w   write table to disk and exit
 q   quit without saving changes
Create a new label
 g   create a new empty GPT partition table
 G   create a new empty SGI (IRIX) partition table
 o   create a new empty DOS partition table
 s   create a new empty Sun partition table

Command (m for help):

从前面的输出中,我们可以看到各种选择。我们甚至可以使用l来查看已知的分区类型:

从前面的截图中,我们可以看到各种可用于使用的不同分区类型。常见类型包括5 Extended7 NTFS NTSF82 Linux swap,83(Linux),a5 FreeBSDee GPTef EFI等。

现在,要查看已创建的分区,我们可以使用p

我已经向该系统添加了第二个硬盘,因此让我们验证一下:

root@ubuntu:/home/philip# ls /dev/ | grep sd
sda
sda1
sda2
sda5
sdb
root@ubuntu:/home/philip#

太棒了!我们现在可以看到/dev/sdb。我们将使用fdisk处理这个新硬盘:

root@ubuntu:/home/philip# fdisk /dev/sdb

Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x0079e169.
Command (m for help):

现在,让我们按下p,这将打印/dev/sdb上的当前分区:

Command (m for help): p
Disk /dev/sdb: 15 GiB, 16106127360 bytes, 31457280 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0079e169

Command (m for help):

如您所见,/dev/sdb上没有分区。为了创建一个分区,我们将使用n键:

Command (m for help): n
Partition type
 p   primary (0 primary, 0 extended, 4 free)
 e   extended (container for logical partitions)
Select (default p):

这将要求我们声明分区的类型。fdisk实用程序提供了主分区和扩展分区类型。还有一个逻辑分区类型。为了安装操作系统,我们将选择p,代表主分区类型

您不会在逻辑分区类型上安装操作系统。

如您所见,我们使用n来创建新分区。需要注意的一个重要点是,到目前为止我们创建的分区都是 Linux 类型的分区。如果出于某种原因我们想要更改分区类型,我们可以使用t来更改它。让我们将/dev/sdb2更改为HPFS/NTFS/exFAT分区。我们将在fdisk实用程序中使用type 7

Command (m for help): t
Partition number (1-3, default 3): 2
Partition type (type L to list all types): l
0  Empty  24  NEC DOS 81  Minix / old Lin bf  Solaris 
1  FAT12  27  Hidden NTFS Win 82  Linux swap / So c1  DRDOS/sec (FAT-
2  XENIX root  39  Plan 9  83  Linux  c4  DRDOS/sec (FAT-
3  XENIX usr   3c  PartitionMagic 84 OS/2 hidden or c6 DRDOS/sec (FAT-
4  FAT16 <32M  40  Venix 80286     85  Linux extended  c7  Syrinx 
5  Extended   41  PPC PReP Boot   86  NTFS volume set da  Non-FS data 
6  FAT16    42  SFS  87  NTFS volume set db  CP/M / CTOS / .
7  HPFS/NTFS/exFAT

太棒了!现在我们可以看到分区类型为type 7

Partition type (type L to list all types): 7
Changed type of partition 'Empty' to 'HPFS/NTFS/exFAT'.
Command (m for help): p
Disk /dev/sdb: 15 GiB, 16106127360 bytes, 31457280 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x2584b986
Device       Boot     Start    End      Sectors Size  Id   Type
/dev/sdb1    2048     10487807  10485760  5G      83        Linux
/dev/sdb2    10487808 18876415  8388608   4G      7     HPFS/NTFS/exFAT
/dev/sdb3    18876416 31457279  12580864  6G      0           Empty

此外,我们将把/dev/sdb3分区更改为类型ef

现在当我们重新运行p命令时,我们可以看到我们新创建的分区类型设置为ef

Device     Boot      Start     End     Sectors Size Id Type
/dev/sdb1   2048     10487807  10485760  5G    83 Linux
/dev/sdb2   10487808 18876415  8388608   4G    7 HPFS/NTFS/exFAT
/dev/sdb3   18876416 31457279  12580864  6G    ef EFI (FAT-12/16/32)

现在,如果我们决定安装操作系统,那么我们将不得不使其中一个分区可引导。我们将使第三个分区/dev/sdb3可引导:

Command (m for help): a 
Partition number (1-3, default 3): 3
The bootable flag on partition 3 is enabled now.
Command (m for help): p
Disk /dev/sdb: 15 GiB, 16106127360 bytes, 31457280 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x2584b986
Device     Boot    Start      End  Sectors Size Id Type
/dev/sdb1           2048 10487807 10485760   5G 83 Linux
/dev/sdb2       10487808 18876415  8388608   4G  7 HPFS/NTFS/exFAT
/dev/sdb3  *    18876416 31457279 12580864   6G ef EFI (FAT-12/16/32)

从前面的输出中,/dev/sdb3现在标记为可引导。

最后,要更改或保存我们的更改,我们将按w,保存并退出:

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

使用 parted 实用程序

parted实用程序是针对我们有一个大于 2TB 的硬盘或硬盘的情况。此外,我们可以调整分区;fdisk实用程序无法调整分区。几乎所有较新的 Linux 发行版都支持parted实用程序。parted来自 GNU;它是一个基于文本的分区实用程序,可以与各种磁盘类型一起使用,例如 MBR、GPT 和 BSD 等。

在对分区进行任何更改之前,请备份数据。

首先,我们将在/dev/sdb上使用parted命令:

root@ubuntu:/home/philip# parted /dev/sdb
GNU Parted 3.2
Using /dev/sdb
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted)                                                                 

从这里,我们进入了parted实用程序。与fdisk实用程序类似,parted实用程序是交互式的。现在让我们假设我们想查看help菜单,我们可以在 CLI 中列出help

(parted) help 
 align-check TYPE N check partition N for TYPE(min|opt) alignment
 help [COMMAND] print general help, or help on COMMAND
 mklabel,mktable LABEL-TYPE create a new disklabel (partition table)
 mkpart PART-TYPE [FS-TYPE] START END make a partition
 name NUMBER NAME name partition NUMBER as NAME
 print [devices|free|list,all|NUMBER] display the partition table, available devices, free space, all found partitions, or a particular partition
 quit exit program 
 rescue START END rescue a lost partition near START and END
 resizepart NUMBER END resize partition NUMBER
 rm NUMBER delete partition NUMBER
 select DEVICE choose the device to edit
 disk_set FLAG STATE change the FLAG on selected device
 disk_toggle [FLAG] toggle the state of FLAG on selected device
 set NUMBER FLAG STATE change the FLAG on partition NUMBER
 toggle [NUMBER [FLAG]] toggle the state of FLAG on partition NUMBER
 unit UNIT set the default unit to UNIT
 version display the version number and copyright information of GNU Parted
(parted)

从前面的输出中,我们有一长串命令供我们使用。

在对分区进行任何更改之前,请备份数据。

现在,要查看/dev/sdb的当前分区表,我们将输入print

(parted) print
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 16.1GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
Number  Start   End     Size    Type  File system  Flags
 1     1049kB  5370MB 5369MB  primary
 2     5370MB  9665MB 4295MB  primary
 3     9665MB  16.1GB 6441MB  primary boot, esp
(parted) 

这将打印出/dev/sdb的分区表。但是,我们可以使用print命令和list选项来查看系统中所有可用的硬盘。让我们试试看:

(parted) print list
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 16.1GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
Number  Start   End     Size    Type    File system  Flags
 1      1049kB  5370MB  5369MB  primary
 2      5370MB  9665MB  4295MB  primary
 3      9665MB  16.1GB  6441MB  primary            boot, esp
 Model: VMware, VMware Virtual S (scsi)
Disk /dev/sda: 21.5GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
Number  Start   End     Size    Type      File system     Flags
 1      1049kB  20.4GB  20.4GB  primary   ext4            boot
 2      20.4GB  21.5GB  1072MB  extended
 5      20.4GB  21.5GB  1072MB  logical   linux-swap(v1)
(parted)

太好了!如您所见,/dev/sda现在也被列出。接下来,让我们看看如何调整分区大小。为了实现这一点,我们将利用另一个强大的命令,即resizepart命令,这个命令本身的命名也很合适。

我们将选择第二个分区进行练习;我们将说resizepart 2,并将其减少到 2GB:

 (parted) resizepart
 Partition number? 2
 End? [5370MB]? 7518
 (parted) print
 Disk /dev/sdb: 16.1GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
Number Start End Size Type File system Flags
 1 1049kB 5370MB 5369MB primary
 2 5370MB 7518MB 2148MB primary
 3 9665MB 16.1GB 6441MB primary boot, esp
(parted)            

从前面的输出中,您可以看到parted实用程序非常强大。我们已经有效地从第二个分区中拿走了 2GB(大约)。现在,如果您考虑一下,我们有 2GB 的可用空间。

硬盘空间在大型数据中心中至关重要,因此在为服务器进行配置时请记住这一点。

现在,为了演示我们如何使用 2GB 的可用空间,让我们创建另一个分区。parted实用程序非常强大,它可以识别从其他磁盘实用程序(如fdisk)创建的分区。在parted中,我们将使用mkpart命令来创建一个分区:

(parted)
(parted) mkpart 
Partition type?  primary/extended? 

到目前为止,您可以看到fdiskparted之间存在相似之处,它们都会询问分区是主分区还是扩展分区。这在我们处理操作系统安装时非常重要。为了我们的目的,我们将创建另一个主分区:

Partition type?  primary/extended? primary
File system type?  [ext2]?
Start?

现在,在这一点上,我们将不得不指定我们即将创建的分区的起始大小。我们将使用第二个分区结束的大小:

File system type? [ext2]? 
Start? 7518 
End? 9665 
(parted) 

太棒了!现在让我们重新运行print命令:

(parted) print 
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 16.1GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
Number Start   End     Size    Type     File system  Flags
 1      1049kB  5370MB  5369MB  primary
 2      5370MB  7518MB  2148MB  primary
 4      7518MB  9665MB  2146MB  primary  ext2         lba
 3      9665MB  16.1GB  6441MB  primary               boot, esp
(parted)

从前面的输出中,我们现在可以看到我们新创建的大约 2GB 的分区。

现在我们可以将boot标志从当前的第三个分区/dev/sdb3移动到第四个分区/dev/sdb4。我们将使用set命令:

(parted) set 
Partition number? 4 
Flag to Invert?

从这里开始,我们必须告诉parted实用程序,我们要移动boot标志:

Flag to Invert? boot 
New state?  [on]/off?

现在,我们需要确认我们的更改,on是默认值,所以我们按Enter

New state?  [on]/off? 
(parted) print 
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 16.1GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
Number  Start   End     Size    Type     File system  Flags
 1      1049kB  5370MB  5369MB  primary
 2      5370MB  7518MB  2148MB  primary
 4      7518MB  9665MB  2146MB  primary  ext2         boot, lba
 3      9665MB  16.1GB  6441MB  primary               esp
(parted)                                             

太棒了!现在我们可以看到boot标志已经移动到第四个分区/dev/sdb4

最后,要保存我们的更改,我们只需输入quit

(parted) quit 
Information: You may need to update /etc/fstab.
root@ubuntu:/home/philip#     

您需要在/etc/fstab中添加条目,以便自动挂载分区到它们各自的挂载点。

格式化硬盘的步骤

创建分区后,下一步是通过文件系统使分区可访问。在 Linux 中,当我们格式化分区时,系统会擦除分区,这使系统能够在分区上存储数据。

在 Linux 系统中有许多文件系统类型可用。我们使用mkfs命令结合所需的文件系统类型。要查看可用的文件系统,我们可以这样做:

从前面的屏幕截图中,在这个 Ubuntu 发行版中,主要是ext4类型是当前使用的文件系统。我们还可以使用带有-f选项的lsblk命令来验证这一点:

root@ubuntu:/home/philip# lsblk -f

从前面的屏幕截图中,我们可以看到两个硬盘,/dev/sda/dev/sdb。此外,我们看到了一个FSTYPE列。这标识了当前正在使用的文件系统。我们可以看到整个/dev/sdb(1-4)FSTYPE为空。

我们也可以使用blkid命令查看系统正在使用的文件系统:

从给定的输出中,TYPE=部分显示正在使用的文件系统。请注意,对于/dev/sdb(1-4)TYPE=都是缺失的。这意味着我们尚未格式化/dev/sdb上的任何分区。

现在让我们开始格式化我们的分区。我们将在/dev/sdb1上使用ext4文件系统:

root@ubuntu:/home/philip# mkfs.ext4 /dev/sdb1
mke2fs 1.42.13 (17-May-2015)
Creating filesystem with 1310720 4k blocks and 327680 inodes
Filesystem UUID: fc51dddf-c23d-4160-8e49-f8a275c9b2f0
Superblock backups stored on blocks:
 32768, 98304, 163840, 229376, 294912, 819200, 884736
Allocating group tables: done 
Writing inode tables: done 
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
root@ubuntu:/home/philip#

从前面的输出中,mkfs实用程序,特别是mkfs.ext4,在原始分区上创建文件系统;然后为/dev/sdb1分区分配一个 UUID 以唯一标识它。

在格式化分区之前,您需要具有 root 权限。

接下来,让我们在/dev/sdb2上使用ext3文件系统:

root@ubuntu:/home/philip# mkfs.ext3 /dev/sdb2
mke2fs 1.42.13 (17-May-2015)
Creating filesystem with 524288 4k blocks and 131328 inodes
Filesystem UUID: fd6aab0f-0f16-4922-86c1-11fcb54fc466
Superblock backups stored on blocks:
 32768, 98304, 163840, 229376, 294912
Allocating group tables: done 
Writing inode tables: done 
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
root@ubuntu:/home/philip#

现在我们将在/dev/sdb3上使用ext2,在/dev/sdb4上使用ntfs

root@ubuntu:/home/philip# mkfs.ext2 /dev/sdb3
mke2fs 1.42.13 (17-May-2015)
Creating filesystem with 1572608 4k blocks and 393216 inodes
Filesystem UUID: b7e075df-541d-468d-ab16-e3ec2e5fb5f8
Superblock backups stored on blocks:
 32768, 98304, 163840, 229376, 294912, 819200, 884736
Allocating group tables: done 
Writing inode tables: done 
Writing superblocks and filesystem accounting information: done
root@ubuntu:/home/philip# mkfs.ntfs /dev/sdb4
Cluster size has been automatically set to 4096 bytes.
Initializing device with zeroes: 100% - Done.
Creating NTFS volume structures.
mkntfs completed successfully. Have a nice day.
root@ubuntu:/home/philip#

您还可以使用mk2fs来创建ext2文件系统。

太棒了!现在我们刚刚格式化了/dev/sdb1/dev/sdb2dev/sdb3/dev/sdb4。如果我们现在使用lsblk命令和-f选项重新运行,我们将看到两个分区的文件系统类型(FSTYPE)已经填充:

root@ubuntu:/home/philip# lsblk -f
NAME   FSTYPE LABEL UUID                                 MOUNTPOINT
sda 
├─sda1 ext4         adb5d090-3400-4411-aee2-dd871c39db38 /
├─sda2 
└─sda5 swap         025b1992-80ba-46ed-8490-e7aa68271e7b [SWAP]
sdb 
├─sdb1 ext4         fc51dddf-c23d-4160-8e49-f8a275c9b2f0
├─sdb2 ext3         fd6aab0f-0f16-4922-86c1-11fcb54fc466
├─sdb3 ext2         b7e075df-541d-468d-ab16-e3ec2e5fb5f8
└─sdb4 ntfs         1D9E4A6D4088D79A 
sr0 
root@ubuntu:/home/philip#

从前面的输出中,我们可以看到FSTYPE反映了我们所做的更改。

我们还可以重新运行blkid命令,查看为/dev/sdb1/dev/sdb2创建的 UUID:

root@ubuntu:/home/philip# blkid
/dev/sda1: UUID="adb5d090-3400-4411-aee2-dd871c39db38" TYPE="ext4" PARTUUID="f54f42a0-01"
/dev/sda5: UUID="025b1992-80ba-46ed-8490-e7aa68271e7b" TYPE="swap" PARTUUID="f54f42a0-05"
/dev/sdb1: UUID="fc51dddf-c23d-4160-8e49-f8a275c9b2f0" TYPE="ext4" PARTUUID="7e707ac0-01"
/dev/sdb2: UUID="fd6aab0f-0f16-4922-86c1-11fcb54fc466" SEC_TYPE="ext2" TYPE="ext3" PARTUUID="7e707ac0-02"
/dev/sdb3: UUID="2a8a5768-1a7f-4ab4-8aa1-f45d30df5631" TYPE="ext2" PARTUUID="7e707ac0-03"
/dev/sdb4: UUID="1D9E4A6D4088D79A" TYPE="ntfs" PARTUUID="7e707ac0-04"
root@ubuntu:/home/philip#

如您所见,系统现在可以存储有关各个分区的信息。

挂载和卸载分区

在格式化分区后的最后一步是挂载分区。我们使用mount命令来挂载分区,使用unmount命令来卸载分区。mount命令还用于查看系统中当前的挂载点。但是,在重新启动后,除非我们在/etc/fstab目录中创建了条目,否则所有分区都将被卸载。

/etc/fstab中保存任何更改都需要 root 权限。在进行任何更改之前,也要备份任何配置文件。

挂载命令

我们可以发出mount命令而不带任何参数来查看当前的挂载点:

root@ubuntu:/home/philip# mount
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
udev on /dev type devtmpfs (rw,nosuid,relatime,size=478356k,nr_inodes=119589,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=99764k,mode=755)
/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
pstore on /sys/fs/pstore type pstore (rw,nosuid,nodev,noexec,relatime)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup(rw,relatime,user_id=0,group_id=0,default_permissions,allow_other)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=99764k,mode=700,uid=1000,gid=1000)
gvfsd-fuse on /run/user/1000/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)
root@ubuntu:/home/philip#

出于简洁起见,部分输出被省略。

从前面的输出中,我们可以看到许多挂载点(挂载点只是将分区/驱动器与文件夹/目录关联起来)。我们可以过滤mount命令,只显示/dev/

root@ubuntu:/home/philip# mount | grep /dev
udev on /dev type devtmpfs (rw,nosuid,relatime,size=478356k,nr_inodes=119589,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
mqueue on /dev/mqueue type mqueue (rw,relatime)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
root@ubuntu:/home/philip#

根据过滤器,我们可以看到/dev/sda1目前挂载在/目录上。如您所知,/目录是根目录。所有其他目录都属于/目录。

我们还可以使用带有-h选项的df命令查看更简洁的输出:

root@ubuntu:/home/philip# df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            468M     0  468M   0% /dev
tmpfs            98M  6.2M   92M   7% /run
/dev/sda1        19G  5.1G   13G  29% /
tmpfs           488M  212K  487M   1% /dev/shm
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           488M     0  488M   0% /sys/fs/cgroup
tmpfs            98M   44K   98M   1% /run/user/1000
root@ubuntu:/home/philip#

太好了!现在这是以结构化格式呈现的,更容易阅读。根据输出,只有/dev/sda1分区当前被挂载。

现在我们可以继续挂载/dev/sdb1/mnt上。/mnt是一个空目录,我们在想要挂载分区时使用它。

一次只能挂载一个分区。

我们将运行以下mount命令:

root@ubuntu:/# mount /dev/sdb1 /mnt
root@ubuntu:/#

请注意,没有任何选项,mount命令可以正常工作。现在让我们重新运行mount命令,并过滤只显示/dev

root@ubuntu:/# mount | grep /dev
udev on /dev type devtmpfs (rw,nosuid,relatime,size=478356k,nr_inodes=119589,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
mqueue on /dev/mqueue type mqueue (rw,relatime)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
/dev/sdb1 on /mnt type ext4 (rw,relatime,data=ordered)
root@ubuntu:/#

根据前面的输出,我们可以看到/dev/sdb1目前挂载在/mnt上。

我们还可以利用带有h选项的df命令来查看类似的结果:

root@ubuntu:/# df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            468M     0  468M   0% /dev
tmpfs            98M  6.2M   92M   7% /run
/dev/sda1        19G  5.1G   13G  29% /
tmpfs           488M  212K  487M   1% /dev/shm
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           488M     0  488M   0% /sys/fs/cgroup
tmpfs            98M   44K   98M   1% /run/user/1000
/dev/sdb1       4.8G   10M  4.6G   1% /mnt
root@ubuntu:/#

从前面的输出中,我们可以看到分区的大小以及与分区关联的挂载点。

现在让我们创建两个目录,用于/dev/sdb2/dev/sdb4分区:

root@ubuntu:/# mkdir /folder1
root@ubuntu:/# mkdir /folder2
root@ubuntu:/# ls
bin  dev   folder2  initrd.img.old  lost+found  opt run srv usr      vmlinuz.old
boot etc  home lib   media    proc  sbin  sys  var
cdrom  folder1  initrd.img  lib64     mnt         root  snap  tmp  vmlinuz
root@ubuntu:/#

现在我们将把/dev/sdb2/dev/sdb4挂载到/folder1/folder2目录中:

root@ubuntu:/# mount /dev/sdb2 /folder1
root@ubuntu:/# mount /dev/sdb4 /folder2
root@ubuntu:/#
root@ubuntu:/# mount | grep /dev
/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/sdb1 on /mnt type ext4 (rw,relatime,data=ordered)
/dev/sdb2 on /folder1 type ext3 (rw,relatime,data=ordered)
/dev/sdb4 on /folder2 type fuseblk (rw,relatime,user_id=0,group_id=0,allow_other,blksize=4096)
root@ubuntu:/#

太好了!现在我们可以看到我们的挂载点在mount命令中显示出来。同样,我们可以使用带有-h选项的df命令以可读的格式显示:

root@ubuntu:/# df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            468M     0  468M   0% /dev
tmpfs            98M  6.2M   92M   7% /run
/dev/sda1        19G  5.1G   13G  29% /
tmpfs           488M  212K  487M   1% /dev/shm
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           488M     0  488M   0% /sys/fs/cgroup
tmpfs            98M   44K   98M   1% /run/user/1000
/dev/sdb1       4.8G   10M  4.6G   1% /mnt
/dev/sdb2       2.0G  3.1M  1.9G   1% /folder1
/dev/sdb4       2.0G   11M  2.0G   1% /folder2
root@ubuntu:/#

正如您所看到的,挂载分区的步骤非常简单。但是,在某些发行版上,您将不得不指定文件系统类型。在网络中,挂载共享是一种常见的操作。挂载共享的一个例子如下:

root@ubuntu:/#mount //172.16.175.144/share /netshare -t cifs  -o user=philip,password=pass123,uid=1000,gid=1000,rw

卸载命令

在挂载了分区并进行了更改之后,清理和卸载分区总是一个好主意。我们使用unmount命令来卸载分区。

在运行unmount命令之前,始终更改/移出目录。

让我们卸载/dev/sdb1。格式如下:

root@ubuntu:/# umount /dev/sdb1
root@ubuntu:/#
root@ubuntu:/# mount | grep /dev
udev on /dev type devtmpfs (rw,nosuid,relatime,size=478356k,nr_inodes=119589,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
mqueue on /dev/mqueue type mqueue (rw,relatime)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime)
/dev/sdb2 on /folder1 type ext3 (rw,relatime,data=ordered)
/dev/sdb4 on /folder2 type fuseblk (rw,relatime,user_id=0,group_id=0,allow_other,blksize=4096)
root@ubuntu:/#

现在我们可以看到/dev/sdb1不再挂载;我们也可以使用df命令来确认:

root@ubuntu:/# df -h
Filesystem Size Used Avail Use% Mounted on
udev 468M 0 468M 0% /dev
tmpfs 98M 7.5M 91M 8% /run
/dev/sda1 19G 5.2G 13G 30% /
tmpfs 488M 212K 487M 1% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 488M 0 488M 0% /sys/fs/cgroup
tmpfs 98M 48K 98M 1% /run/user/1000
/dev/sdb2 2.0G 3.1M 1.9G 1% /folder1
/dev/sdb4 2.0G 11M 2.0G 1% /folder2
root@ubuntu:/#

我们还可以使用lsblk命令来确认相同的情况:

root@ubuntu:/# lsblk -f
NAME   FSTYPE LABEL UUID       MOUNTPOINT
sda 
├─sda1 ext4         adb5d090-3400-4411-aee2-dd871c39db38 /
├─sda2 
└─sda5 swap         025b1992-80ba-46ed-8490-e7aa68271e7b [SWAP]
sdb 
├─sdb1 ext4         fc51dddf-c23d-4160-8e49-f8a275c9b2f0
├─sdb2 ext3         fd6aab0f-0f16-4922-86c1-11fcb54fc466 /folder1
├─sdb3 ext2         2a8a5768-1a7f-4ab4-8aa1-f45d30df5631
└─sdb4 ntfs         1D9E4A6D4088D79A                     /folder2
sr0 
root@ubuntu:/#

现在让我们也卸载/dev/sdb2

root@ubuntu:/# umount /folder1

从前面的截图中,您会注意到,我使用了目录/folder1而不是分区/dev/sdb2;这完全取决于您;它们都被接受。此外,我们可以从lsblk命令中看到,/dev/sdb2没有列出挂载点。

现在,假设您希望在系统重新启动期间保持挂载点。那么,请放心,我们可以通过在/etc/fstab中创建条目来实现这一点。

首先,让我们在/etc/fstab中为/dev/sdb4创建一个条目。我们将使用/dev/sdb4的 UUID 来帮助我们。让我们运行blkid并保存/dev/sdb4的 UUID:

root@ubuntu:/# blkid
/dev/sdb4: UUID="1D9E4A6D4088D79A" TYPE="ntfs" PARTUUID="7e707ac0-04"
root@ubuntu:/#

现在让我们编辑/etc/fstab文件:

# /etc/fstab: static file system information. #
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda1 during installation
UUID=adb5d090-3400-4411-aee2-dd871c39db38 / ext4 errors=remount-ro 0       1
# swap was on /dev/sda5 during installation
UUID=025b1992-80ba-46ed-8490-e7aa68271e7b none swap sw 0   0
/dev/fd0  /media/floppy0  auto   rw,user,noauto,exec,utf8 0  0
UUID=1D9E4A6D4088D79A   /folder2   ntfs    0       0

现在最后一个条目引用了/dev/sdb4。格式以分区开头,由UUID表示,然后是挂载点文件系统转储通过

当系统重新启动时,/dev/sdb4将被挂载到/folder2上。这样可以避免重复输入。

总结

在本章中,我们看了如何格式化硬盘以及各种可用的分区实用程序。我们使用fdisk实用程序创建了分区,并打开了boot标志。然后我们看了parted实用程序,以及如何创建分区;此外,我们还看到了如何调整分区的大小。这在数据中心环境中非常有用。然后我们格式化了我们的分区,这使我们能够开始存储数据。我们研究了使用各种mkfs命令。然后我们专注于如何挂载我们的分区。在我们的挂载点上保存数据后,我们卸载了我们的分区/挂载点。最后,我们看到了如何通过在/etc/fstab文件中创建条目来避免重复输入;这在启动时为我们挂载了我们的分区。

接下来,在下一章中,我们将介绍安装各种 Linux 发行版。我们将特别关注红帽发行版,即 CentOS。另一方面,我们将介绍 Debian 发行版,特别是 Ubuntu 以及安装 Linux 发行版的最佳技术,这些技术在不同的发行版之间略有不同。此外,我们将介绍双引导环境,让我们面对现实吧,迟早你会在 Linux 职业生涯中接触到 Windows 操作系统。不过,你不用担心,因为我们会逐步详细介绍安装过程的每一步。完成下一章后,你肯定会在跨所有平台上安装 Linux 发行版的方法上变得更加熟练。安装 Linux 发行版所获得的技能将对您作为 Linux 工程师大有裨益。

问题

  1. 哪个字母用于列出硬盘的分区,而不进入fdisk实用程序?

A. fdisk –a /dev/sda

B. fdisk –c /dev/sda

C. fdisk –l /dev/sda

D. fdisk –r /dev/sda

  1. 哪个字母用于在fdisk实用程序内创建分区?

A. b

B. c

C. r

D. n

  1. 哪个字母用于在fdisk实用程序内切换引导标志?

A. b

B. a

C. d

D. c

  1. 哪个字母用于在fdisk实用程序内打印已知的分区类型?

A. l

B. r

C. n

D. b

  1. 哪个字母用于在fdisk实用程序内创建分区?

A. p

B. n

C. c

D. d

  1. 哪个字母用于在fdisk实用程序内写入更改?

A. q

B. c

C. d

D. w

  1. 哪个命令用于启动parted实用程序?

A. part -ad

B. parted

C. part -ed

D. part

  1. 哪个选项用于在parted实用程序内显示分区表?

A. display

B. parted

C. print

D. console

  1. 哪个选项用于从 CLI 中挂载分区?

A. mount /dev/sdb1

B. mnt /dev/sdb1

C. mt /dev/sdb1

D. mont /dev/sdb1

  1. 哪个命令在 CLI 上显示已知分区的 UUID?

A. blkid

B. df -h

C. du -h

D. mount

进一步阅读

  • 您可以通过查看以下内容获取有关 CentOS 发行版的更多信息,例如安装、配置最佳实践等:www.centos.org

  • 以下网站为您提供了许多有用的技巧和 Linux 社区用户的最佳实践,特别是适用于 Debian 发行版(如 Ubuntu)的:askubuntu.com

  • 最后,这个链接为您提供了与在 CentOS 和 Ubuntu 上运行的各种命令相关的一般信息。您可以在那里发布您的问题,其他社区成员将会回答:www.linuxquestions.org

第五章:安装 Linux 发行版

在上一章中,我们看了准备好用的硬盘。我们使用了fdiskparted实用程序。我们看到了创建和删除分区的步骤。我们还看到了如何调整分区的大小。然后,我们将注意力转向格式化分区以供使用。我们看了今天 Linux 发行版上可用的各种文件系统。之后,我们看了如何挂载分区以开始存储数据。然后我们看了如何卸载分区。最后,我们在/etc/fstab文件中创建条目,以便在系统启动时加载我们的挂载点。在本章中,我们现在的重点是实际安装 Linux 发行版,以及从头开始安装 Linux 时涉及的过程。然后,我们将专注于在 Windows 操作系统旁边安装 Linux。最后,我们将看看如何在另一个 Linux 发行版旁边安装 Linux。

在本章中,我们将学习以下主题:

  • 了解 LiveCD 的用途

  • 作为全新安装安装 Linux 发行版

  • 在 Windows 操作系统旁边安装 Linux 发行版

  • 与另一种 Linux 发行版并存安装 Linux 发行版

了解 LiveCD 的用途

当我们启动系统时,在安装 Linux 发行版时,我们有许多选项可供选择。我们可以使用 LiveCD 来安装 Linux,而不是擦除我们的硬盘。请记住,体验可能看起来好像我们正在安装 Linux 发行版,但实际上我们实际上是将文件临时加载到 RAM 中,而 LiveCD 则表现得好像它安装在实际硬盘上一样。这就是 LiveCD 的主要概念。

我们将在此演示中使用 Ubuntu 发行版。首先,我们将设置系统从 CD/DVD 启动。然后我们启动系统:

在这里,我们有许多选项可供选择。第一个选项将把 Linux 发行版加载到内存中。其他选项,如“安装 Ubuntu”,将用于正常安装。我们还可以检查光盘是否有缺陷等。

现在,使用光标,突出显示“尝试 Ubuntu 而不安装”,然后按Enter。之后,系统将启动到 Linux 发行版:

从这里,我们可以执行各种任务,就像在已安装的操作系统上一样。当您的硬件资源不足或您有非常老旧的硬件无法支持最新的操作系统时,这就有了好处。放心,有许多适用于这种环境的 Linux 发行版可供选择。

另外,请注意我们可以从驱动器中取出 CD/DVD,系统将继续工作而不会出现任何错误。大多数情况下,我们将使用 LiveCD 执行管理任务。

作为全新安装安装 Linux 发行版

当我们只想执行一些管理任务时,在 LiveCD 中工作是可以的。为此,我们可以将 Linux 发行版作为完整安装进行安装;在硬盘上安装 Linux。为了继续 LiveCD 演示,我们将使用桌面上的“安装 Ubuntu...”选项来执行全新安装。这将呈现以下设置:

  1. 从这里开始,我们必须选择继续安装的语言。有很多语言可供选择。在我们的情况下,我们将接受默认的英语,并选择继续:

  1. 现在,我们有选项在安装过程中下载更新和/或安装用于图形等的第三方软件。对于这一部分,您需要一个活动的互联网连接;原因是系统将去下载最近发布的更新。此外,当我们添加不属于系统的其他硬件时,它们需要模块(类似驱动程序),这些模块不会默认安装。因此,有第二个选项来下载第三方软件。在我们的情况下,因为我们在实验室环境中,我们将取消这些选项并选择继续:

您需要一个活动的互联网连接来下载更新。

  1. 在这里,我们有选项在整个硬盘上安装 Linux 发行版。如果出于某种原因,我们想要向硬盘添加一个或多个分区,那么我们将选择“其他”。此外,如果我们试图在 Windows 上进行双引导或在另一个 Linux 发行版上进行并排安装,我们将选择此选项:

  1. 对于新安装,让我们选择“其他”并创建自己的分区,并指定我们要挂载的内容:

  1. 太棒了!我们的环境中只有一个硬盘。我们将选择新分区表。让我们首先创建一个 200MB 的分区并挂载/boot;这是存储引导文件的地方:

/boot创建一个分区总是一个好主意,以保护引导文件。

  1. 接下来,让我们创建一个 13GB 的分区,并指定它应该挂载到/目录上。此外,我们还指定分区类型为主分区,并将分区格式化为ext3文件系统:

  1. 接下来,让我们创建一个 5GB 的分区,并指定它应该挂载到/home。这是用户文件的存储位置:

  1. 太棒了!最后,让我们利用剩余的空间,让 Linux 发行版分配给交换内存:

从前面的截图中,您会注意到没有挂载点选项可用。这是因为我们指定剩余的空间应该用作交换区。系统将根据需要使用交换区(我们在前面的章节中看到过;即第一章,配置硬件设置,在查看 CPU、RAM、交换信息部分)。

  1. 分区完成后,我们可以选择继续。这将显示一个警告消息:

接下来,我们将看到区域设置,并搜索您的国家并填写。在我的情况下,我在圭亚那;这个国家位于南美洲,所以我选择圭亚那然后继续。

  1. 之后,会出现键盘选择,您需要选择适当的设置。这将带我们来到设置的关键部分:用户创建屏幕。我们为计算机指定一个名称,并创建一个带有超级秘密密码的用户帐户:

太棒了!现在我们正要安装一个新的 Linux 发行版。

  1. 您可以通过选择位于“正在安装系统”旁边的下拉箭头来随时检查正在下载或安装的文件:

现在安装将下载各种语言包(需要互联网连接)。之后,设置将继续将必要的文件安装到硬盘上。

最后,系统会要求我们重新启动以启动系统,使用新安装的 Linux 发行版。

安装完成后,拔掉 CD、DVD 或 USB 驱动器,然后再系统启动之前。

在 Windows 操作系统旁边安装 Linux 发行版

在大多数环境中,您可能会遇到已经安装了其他操作系统(如 Windows)的系统。理想情况下,您不会完全删除 Windows 安装,因为您可能需要一些仅在 Windows 安装上运行的软件,或者可能是公司政策要求在系统上安装 Windows。在这种情况下,您可以在 Windows 旁边安装 Linux 发行版,而不会擦除 Windows 分区。这是可能的,因为 Linux 有能力识别 Windows 分区类型,如 NTFS。Linux 不会以任何方式改变 Windows 分区。

让我们启动现有的 Windows 系统,并配置系统从 Ubuntu ISO 映像启动,看看我们如何实现双启动安装:

  1. 从这里开始,Ubuntu 安装将识别 Windows 10 操作系统。我们将选择最后一个选项“其他”:

  1. 接下来,我们将创建/boot分区:

  1. 之后,我们将创建/分区:

从上面的屏幕截图中,我们可以看到我们刚刚成功创建了/分区。您可能已经注意到我们创建分区的模式。将系统文件与用户文件分开始终是一个好主意。

  1. 接下来,我们将创建/home分区:

  1. 最后,我们将创建交换空间并使用剩余的空间:

  1. 最后一步是选择立即安装:

从上面的屏幕截图中,我们将不得不确认我们是否要将更改写入磁盘。我们将选择“继续”。

我们可以随时返回并通过选择返回进行更改分区表。

现在,我们必须填写位置设置,类似于进行全新安装。我会再次选择圭亚那。

接下来,我们必须像之前一样创建一个用户帐户。必要的 Linux 文件将被安装到我们的双启动系统上。

  1. 之后,我们将被提示重新启动系统,并将在 GRUB2 的双启动菜单中受到欢迎,如下面的屏幕截图所示:

在某些情况下,如果我们将 Linux 作为第一个操作系统,然后安装 Windows,有时 Windows 会删除 Linux 的启动项。解决此问题的最佳工具是运行grub-install

在另一种 Linux 旁边安装 Linux

在某些环境中,您可能需要适应不同的 Linux 发行版。您可以在不丢失当前的 Linux 发行版的情况下安装另一个发行版。

让我们使用现有的 Ubuntu 系统并安装 CentOS 7 以演示如何进行双启动:

  1. 首先,我们设置系统从 CentOS 7 ISO 映像启动:

  1. 从这里,我们选择第一个选项并按Enter。这将启动 CentOS 7 的设置:

然后选择我们的语言并选择继续。

  1. 在“安装摘要”页面上,关键重要的部分是“软件选择”和“系统”:

  1. 默认情况下,CentOS 7 将进行最小安装。我们想要进行完整安装,因此选择“软件选择”:

从上面的屏幕截图中,默认情况下选择了最小安装。我在“基本环境”下选择了 GNOME 桌面,并选择了选中的附加组件。完成选择后,我将点击“完成”。

您可以选择为特定基本环境添加一些或所有附加组件。

  1. 在双启动环境中特别重要的下一部分在“系统”部分下:安装目的地。

  2. 这里是我们将对硬盘进行分区的地方:

  1. 默认情况下,系统将选择自动对硬盘进行分区。如果我们保留这个选项,允许系统为我们创建分区,那么系统将根据每个分区的推荐大小创建分区。为了演示的目的,我们将选择“我将配置分区”。这将说明在 CentOS 7 环境中创建分区涉及的各个步骤。接下来,我们将选择“完成”。这将带来分区屏幕:

从前面的屏幕截图中,我们可以看到 CentOS 7 安装已经检测到了 Ubuntu 安装。

对于这个 CentOS 7 安装,我们将/boot挂载到 CentOS 7 的/boot挂载点。

在删除分区时要小心,因为这可能会对系统的运行状态产生一些不利影响。换句话说,您可能会意外删除一些存储在分区上的关键配置文件,或者更糟糕的是,您的系统可能无法启动。

  1. 接下来,我们为 CentOS 7 创建/分区:

  1. 然后我们创建/home分区:

  1. 最后,我们使用剩余的空间创建交换空间:

  1. 完成后,我们选择“完成”:

  1. 现在,我们必须通过选择“接受更改”来确认我们的更改:

  1. 当我们选择开始安装时,实际的安装将开始。我们将不得不创建一个用户帐户:

  1. 然后我们需要设置一个 root 密码:

  1. 我们应该设置一个没有人能猜到的复杂密码:

  1. 现在,我们要允许 CentOS 7 执行安装——给它一些时间。最后,我们被提示重新启动,所以我们会选择重新启动。

  2. 最后,我们迎来了双引导菜单,显示了 CentOS 7 和 Ubuntu,如下面的屏幕截图所示:

如您所见,我们现在可以选择加载哪个 Linux 发行版。

总结

在本章中,我们深入探讨了 Linux 发行版的安装。我们讨论了 LiveCD 的概念。我们讨论了使用 LiveCD 的场景;也就是说,当我们想要测试、当我们有硬件资源或正在执行一些管理任务时。然后我们演示了使用 LiveCD。请记住,实际的 Linux 发行版是从硬盘以外的介质运行的。它通过将一些文件加载到 RAM 中来实现这一点。LiveCD 提供的一个明显优势是它不会干扰您的基础操作系统。然后我们将注意力转向进行 Linux 发行版的全新安装。执行全新安装的步骤在不同的发行版之间有所不同。之后,我们专注于在 Windows 和 Linux 之间进行双引导,特别是 Windows 10 和 Ubuntu。最后,我们结束了本章,通过在 Linux 发行版之间进行双引导,特别是 CentOS 和 Ubuntu,来结束本章。

接下来,我们将要涵盖红帽世界的另一面:Debian 环境。换句话说,我们将主要关注 Ubuntu 环境下的软件包管理,涵盖诸如dpkgaptaptitude等使用的各种技术。我希望您能加入我,一起迈向实现认证目标的激动人心的新篇章。

问题

  1. 在使用 LiveCD 时,临时文件存储在哪里?

A. 硬盘

B. LiveCD

C. RAM

D. 以上都不是

  1. 哪个选项可以启动 Ubuntu LiveCD?

A. 从第一个硬盘启动

B. 测试完整性

C. 立即安装

D. 试用 Ubuntu 而不安装

  1. 在 Ubuntu LiveCD 的桌面上,您会选择哪个选项进行全新安装?

A. 安装 Ubuntu…

B. 试用 Ubuntu 并安装

C. 重新启动并从硬盘启动

D. 全新安装

  1. 在进行全新安装时下载更新时,需要什么?

A. 复杂编码

B. 一个活动的互联网连接

C. 从安装媒体复制文件到硬盘

D. 不需要任何要求

  1. 哪个选项允许我们在安装类型下创建自己的分区?

A. 其他

B. 擦除整个硬盘

C. 复制整个硬盘

D. 加密整个硬盘

  1. 系统要能够启动,需要哪种类型的分区?

A. 逻辑

B. 扩展

C. 主要

D. 次要

  1. 为什么我们应该将/boot分区与其他分区分开?

A. 能够在/boot中下载我们的视频 B. 防止系统因意外删除/boot中的文件而无法启动 C. 证明我们知道如何分区

D. 证明所有系统文件都安装在/boot

  1. 哪个命令被选择来在 CentOS 7 安装中创建自定义分区?

A. 自动配置分区

B. 我会配置分区

C. 加密我的数据

D. 创建逻辑卷

  1. 如果 Windows 安装在尝试进行双重启动时删除了 GRUB,那么使用哪个命令来安装 GRUB?

A. grub-install

B. grub

C. grub-update

D. grub-configure

  1. 对于 CentOS 7,默认的软件选择是什么?

A. GNOME 桌面

B. KDE 桌面

C. XFCE 桌面

D. 最小安装

进一步阅读

  • 您可以在以下网址获取有关 CentOS 发行版的更多信息,例如安装、配置最佳实践等:www.centos.org

  • 这个网站为您提供了许多有用的技巧和 Linux 社区用户的最佳实践,特别是针对 Debian 发行版,如 Ubuntu:askubuntu.com

  • 这个最后的链接为您提供了一般信息,涉及适用于 CentOS 和 Ubuntu 的各种命令。您可以在那里发布您的问题,其他社区成员会回答:www.linuxquestions.org

第六章:使用 Debian 软件包管理

在上一章中,我们重点介绍了安装 Linux 发行版的步骤。我们首先使用了 LiveCD 的概念,而不是常规安装。我们看到了系统如何在没有硬盘的情况下启动。然后我们讨论了为什么要使用 LiveCD。之后,我们将注意力转移到演示如何执行 Linux 发行版的全新安装。重点放在了分区上,特别是常见的挂载点。接下来,我们看到了如何在 Windows 操作系统旁边进行安装。在此之后,我们进行了 Linux 发行版之间的并排安装。

在本章中,我们将继续我们的课程,重点关注软件安装周围的要点。我们将首先看一下 Debian 风格的软件包管理。首先,我们将从dpkg命令开始,并查看使用dpkg命令的各种方法。此外,我们将查看可以与dpkg命令一起使用的各种选项。接下来,我们将把注意力转向apt-get实用程序。这是另一个在 Debian 环境中安装应用程序的流行命令。我们将密切关注可以与apt-get命令一起使用的选项。之后,重点将转向aptitude实用程序。最后,我们将通过查看synaptic实用程序来结束。与前面的命令类似,我们将重点关注在 Debian 环境中部署软件的语法。本章讨论的所有实用程序都是在 Debian 环境中管理软件常用的。

在本章中,我们将涵盖以下主题:

  • dpkg命令

  • apt-get命令

  • aptitude命令

  • synaptic实用程序

dpkg命令

首先,dpkg实用程序是一个低级系统工具,用于提取、分析、解压缩、安装和删除扩展名为.deb的软件包。在每个.deb文件中由dpkg读取的脚本非常重要,因为它们向程序提供有关软件包安装、删除和配置的信息。dpkg实用程序位于基于 Debian 的发行版中的软件包管理系统的基础。Debian 软件包dpkg提供了dpkg实用程序,以及运行时包装系统所必需的其他几个程序;即:dpkg-debdpkg-splitdpkg-querydpkg-statoverridedpkg-divertdpkg-trigger。我们可以瞥一眼/var/log/dpkg.log文件。其中有大量关于触发器和软件包经过各种解压缩和配置阶段的详细信息。

让我们看看/var/log/dpkg.log

philip@ubuntu:~$ cat /var/log/dpkg.log
2018-07-02 06:43:57 startup archives unpack
2018-07-02 06:44:01 install linux-image-4.4.0-130-generic:amd64 <none> 4.4.0-130.156
2018-07-02 06:44:01 status half-installed linux-image-4.4.0-130-generic:amd64 4.4.0-130.156
2018-07-02 06:44:09 status unpacked linux-image-4.4.0-130-generic:amd64 4.4.0-130.156
2018-07-02 06:44:09 status unpacked linux-image-4.4.0-130-generic:amd64 4.4.0-130.156
2018-07-02 06:44:09 install linux-image-extra-4.4.0-130-generic:amd64 <none> 4.4.0-130.156
2018-07-02 06:44:09 status half-installed linux-image-extra-4.4.0-130-generic:amd64 4.4.0-130.156
2018-07-02 06:44:20 status unpacked linux-image-extra-4.4.0-130-generic:amd64 4.4.0-130.156
2018-07-02 06:44:20 status unpacked linux-image-extra-4.4.0-130-generic:amd64 4.4.0-130.156
2018-07-02 06:44:21 upgrade linux-generic:amd64 4.4.0.128.134 4.4.0.130.136
2018-07-02 06:44:21 status half-configured linux-generic:amd64 4.4.0.128.134
2018-07-02 06:44:21 status unpacked linux-generic:amd64 4.4.0.128.134
2018-07-02 06:44:21 status half-installed linux-generic:amd64 4.4.0.128.134
2018-07-02 06:44:21 status half-installed linux-generic:amd64 4.4.0.128.134
2018-07-02 06:44:21 status unpacked linux-generic:amd64 4.4.0.130.136
2018-07-02 06:44:21 status unpacked linux-generic:amd64 4.4.0.130.136
2018-07-02 06:44:21 upgrade linux-image-generic:amd64 4.4.0.128.134 4.4.0.130.136
2018-07-02 06:44:21 status half-configured linux-image-generic:amd64 4.4.0.128.134
2018-07-02 06:44:21 status unpacked linux-image-generic:amd64 4.4.0.128.134
2018-07-02 06:44:21 status half-installed linux-image-generic:amd64 4.4.0.128.134

从前面的输出中,我们了解了dpkg实用程序正在管理的各种软件包。如果我们想要查看系统上的软件包列表,我们可以使用l选项:

philip@ubuntu:~$ dpkg -l
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                          Version             Architecture        Description
+++-=============================-===================-===================-================================================================
ii  a11y-profile-manager-indicato 0.1.10-0ubuntu3      amd64               Accessibility Profile Manager - Unity desktop indicator
ii  account-plugin-facebook       0.12+16.04.20160126 all                 GNOME Control Center account plugin for single signon - facebook
ii  account-plugin-flickr         0.12+16.04.20160126 all                 GNOME Control Center account plugin for single signon - flickr
ii  account-plugin-google         0.12+16.04.20160126 all                 GNOME Control Center account plugin for single signon
ii  accountsservice               0.6.40-2ubuntu11.3  amd64               query and manipulate user account information
ii  activity-log-manager          0.9.7-0ubuntu23.16\. amd64               blacklist configuration user interface for Zeitgeist
ii  adduser                       3.113+nmu3ubuntu4   all                 add and remove users and groups
ii  adium-theme-ubuntu            0.3.4-0ubuntu1.1    all                 Adium message style for Ubuntu
ii  app-install-data              15.10               all                 Ubuntu applications (data files)
ii  app-install-data-partner      16.04               all                 Application Installer (data files for partner applications/repos
ii  apparmor                      2.10.95-0ubuntu2.9  amd64               user-space parser utility for AppArmor
ii  appmenu-qt:amd64              0.2.7+14.04.2014030 amd64               application menu for Qt
ii  appmenu-qt5                   0.3.0+16.04.2017021 amd64               application menu for Qt5
ii  apport                        2.20.1-0ubuntu2.18  all                 automatically generate crash reports for debugging
ii  apport-gtk                    2.20.1-0ubuntu2.18  all                 GTK+ frontend for the apport crash report system

在前面的输出中,我们从左到右阅读输出。现在我们应该把注意力集中在输出的最右边。这是描述部分;软件包以人类可读的摘要形式呈现,说明了当前安装在该系统上的每个软件包。

我们还可以通过过滤dpkg命令来缩小输出范围;让我们只查找xterm程序:

philip@ubuntu:~$ dpkg -l xterm
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                          Version             Architecture        Description
+++-=============================-===================-===================-================================================================
ii  xterm                         322-1ubuntu1        amd64               X terminal emulator
philip@ubuntu:~$        

我们可以使用--get-selections验证软件包是否已安装:

philip@ubuntu:~$ dpkg --get-selections
a11y-profile-manager-indicator    install
account-plugin-facebook           install
account-plugin-flickr             install
account-plugin-google             install
accountsservice                   install
acl                               install
acpi-support                      install
acpid                             install
activity-log-manager              install
adduser                           install
adium-theme-ubuntu                install
adwaita-icon-theme                install
aisleriot                         install
alsa-base                         install
alsa-utils                        install
amd64-microcode                   install
anacron                           install
apg                               install
app-install-data                  install
app-install-data-partner          install
apparmor                          install
appmenu-qt:amd64                  install
appmenu-qt5                       install
apport                            install

我们可以使用L选项查看软件包拥有的文件。让我们继续我们的示例:

philip@ubuntu:~$ dpkg -L xterm
/.
/etc
/etc/X11
/etc/X11/app-defaults
/etc/X11/app-defaults/UXTerm-color
/etc/X11/app-defaults/UXTerm
/etc/X11/app-defaults/KOI8RXTerm-color
/etc/X11/app-defaults/KOI8RXTerm
/etc/X11/app-defaults/XTerm-color
/usr/share/man/man1/koi8rxterm.1.gz
/usr/share/man/man1/resize.1.gz
/usr/share/man/man1/xterm.1.gz
/usr/share/man/man1/lxterm.1.gz
philip@ubuntu:~$

我们可以使用s选项在系统中搜索特定的软件包:

philip@ubuntu:~$ dpkg -s apache
dpkg-query: package 'apache' is not installed and no information is available
Use dpkg --info (= dpkg-deb --info) to examine archive files,
and dpkg --contents (= dpkg-deb --contents) to list their contents.
philip@ubuntu:~$ dpkg --info apache
dpkg-deb: error: failed to read archive 'apache': No such file or directory
philip@ubuntu:~$

在这种情况下,Apache 在这个系统上默认没有安装。

我已经为这个演示下载了一个tftp客户端。让我们验证一下tftp客户端是否已安装在这个系统上:

philip@ubuntu:~/Downloads$ dpkg -l tftp
dpkg-query: no packages found matching tftp
philip@ubuntu:~/Downloads$

现在我们将使用dpkg命令安装一个软件包。让我们尝试使用i选项安装tftp客户端软件包:

philip@ubuntu:~/Downloads$ dpkg -i tftp_0.17-18_i386.deb
dpkg: error: requested operation requires superuser privilege
philip@ubuntu:~/Downloads$

从前面的输出中,您可以看到我们需要 root 权限来安装或删除软件包。让我们以 root 身份重试:

root@ubuntu:/home/philip/Downloads# ls -l | grep tftp
-rw-rw-r-- 1 philip philip  17208 Jul 18 08:15 tftp_0.17-18_i386.deb
root@ubuntu:/home/philip/Downloads# 
root@ubuntu:/home/philip/Downloads# dpkg -i tftp_0.17-18_i386.deb
Selecting previously unselected package tftp:i386.
(Reading database ... 241431 files and directories currently installed.)
Preparing to unpack tftp_0.17-18_i386.deb ...
Unpacking tftp:i386 (0.17-18) ...
Setting up tftp:i386 (0.17-18) ...
Processing triggers for man-db (2.7.5-1) ...
root@ubuntu:/home/philip/Downloads#

太棒了!现在,让我们使用dpkg命令和l选项重试一下:

root@ubuntu:/home/philip/Downloads# dpkg -l tftp
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                          Version             Architecture        Description
+++-=============================-===================-===================-================================================================
ii  tftp:i386                     0.17-18             i386                Trivial file transfer protocol client
root@ubuntu:/home/philip/Downloads#

太棒了!我们现在可以看到我们的tftp客户端已列出。我们还可以运行带有--get-selectionsdpkg来验证:

root@ubuntu:/home/philip/Downloads# dpkg --get-selections | grep tftp
tftp:i386                                                            install
root@ubuntu:/home/philip/Downloads#

当您使用dpkg安装软件包时,有时可能会遇到依赖性问题。为了解决这个问题,您需要在使用dpkg安装软件包之前下载并安装每个依赖项。

我们还可以使用dpkg命令删除软件包。让我们删除在上一个示例中安装的tftp软件包。我们将使用-r选项:

root@ubuntu:/home/philip/Downloads# dpkg -r tftp
(Reading database ... 241438 files and directories currently installed.)
Removing tftp:i386 (0.17-18) ...
Processing triggers for man-db (2.7.5-1) ...
root@ubuntu:/home/philip/Downloads#

现在,让我们验证一下tftp包确实已被卸载:

root@ubuntu:/home/philip/Downloads# dpkg -l tftp
dpkg-query: no packages found matching tftp
root@ubuntu:/home/philip/Downloads#

太棒了!但是,当我们使用-r选项时,它不会删除配置文件。为了删除软件包以及配置文件,我们应该使用-P(清除)选项。下面是它的工作原理:

root@ubuntu:/home/philip/Downloads# dpkg -P tftp
(Reading database ... 241438 files and directories currently installed.)
Removing tftp:i386 (0.17-18) ...
Processing triggers for man-db (2.7.5-1) ...
root@ubuntu:/home/philip/Downloads#

我们还可以提取软件包的内容而不安装它。我们应该使用-x选项:

root@ubuntu:/home/philip/Downloads# dpkg -x tftp_0.17-18_i386.deb ./tftp_0.17-18_i386
root@ubuntu:/home/philip/Downloads# ls
root@ubuntu:/home/philip/Downloads# ls tftp_0.17-18_i386
usr
root@ubuntu:/home/philip/Downloads# ls tftp_0.17-18_i386/usr/
bin  share
root@ubuntu:/home/philip/Downloads#
root@ubuntu:/home/philip/Downloads# ls tftp_0.17-18_i386/usr/bin/
tftp
root@ubuntu:/home/philip/Downloads# ls tftp_0.17-18_i386/usr/share/
doc/ man/
root@ubuntu:/home/philip/Downloads# ls tftp_0.17-18_i386/usr/share/
doc  man
root@ubuntu:/home/philip/Downloads#

在使用dpkg实用程序下载任何软件包并安装之前,我们需要知道系统的正确硬件架构。幸运的是,我们可以使用dpkg-architecture命令:

root@ubuntu:/home/philip/Downloads# dpkg-architecture
DEB_BUILD_ARCH=amd64
DEB_BUILD_ARCH_BITS=64
DEB_BUILD_ARCH_CPU=amd64
DEB_BUILD_ARCH_ENDIAN=little
DEB_BUILD_ARCH_OS=linux
DEB_BUILD_GNU_CPU=x86_64
DEB_BUILD_GNU_SYSTEM=linux-gnu
DEB_BUILD_GNU_TYPE=x86_64-linux-gnu
DEB_TARGET_ARCH_CPU=amd64
DEB_TARGET_ARCH_ENDIAN=little
DEB_TARGET_ARCH_OS=linux
DEB_TARGET_GNU_CPU=x86_64
DEB_TARGET_GNU_SYSTEM=linux-gnu
DEB_TARGET_GNU_TYPE=x86_64-linux-gnu
DEB_TARGET_MULTIARCH=x86_64-linux-gnu
root@ubuntu:/home/philip/Downloads#

根据前面的输出,我们可以看到这个系统支持 32 位或 64 位软件包。我们还可以获取有关软件包用途的有用信息。我们需要使用带有-s选项的dpkg-query命令:

root@ubuntu:/home/philip/Downloads# dpkg-query -s tftp
Package: tftp
Status: install ok unpacked
Priority: optional
Section: net
Installed-Size: 80
Maintainer: Alberto Gonzalez Iniesta <agi@inittab.org>
Architecture: i386
Source: netkit-tftp
Version: 0.17-18
Config-Version: 0.17-18
Replaces: netstd
Depends: netbase, libc6 (>= 2.3)
Description: Trivial file transfer protocol client
Tftp is the user interface to the Internet TFTP (Trivial File Transfer
Protocol), which allows users to transfer files to and from a remote machine.
The remote host may be specified on the command line, in which case tftp uses
host as the default host for future transfers.
root@ubuntu:/home/philip/Downloads#

从前面的输出中,我们在底部得到了有关tftp软件包用途的描述。

apt-get 命令

高级软件包工具APT)是一个命令行工具,用于与dpkg软件包系统进行简单交互。 APT 是管理基于 Debian 的 Linux 发行版(如 Ubuntu)中软件的理想方法。它有效地管理依赖关系,维护大型配置文件,并正确处理升级和降级以确保系统稳定性。dpkg本身无法正确处理依赖关系。apt-get执行安装、软件包搜索、更新和许多其他操作,以使系统可用的软件包保持最新。保持软件包最新非常重要,因为使用过时的软件包可能会导致系统安全问题。apt-get实用程序需要 root 权限,类似于dpkg实用程序。

首先,在进行任何软件安装之前,最好的做法是更新软件包数据库。我们应该运行apt-get update:

root@ubuntu:/home/philip/Downloads# apt-get update
Get:1 http://security.ubuntu.com/ubuntu xenial-security InRelease [107 kB]
Hit:2 http://us.archive.ubuntu.com/ubuntu xenial InRelease 
Get:3 http://security.debian.org/debian-security wheezy/updates InRelease [54.0 kB]
Get:4 http://us.archive.ubuntu.com/ubuntu xenial-updates InRelease [109 kB] 
Ign:3 http://security.debian.org/debian-security wheezy/updates InRelease 
Get:5 http://us.archive.ubuntu.com/ubuntu xenial-backports InRelease [107 kB]
Get:6 http://security.debian.org/debian-security wheezy/updates/main amd64 Packages [589 kB]
Get:21 http://us.archive.ubuntu.com/ubuntu xenial-updates/multiverse amd64 DEP-11 Metadata [5,964 B]
Get:22 http://us.archive.ubuntu.com/ubuntu xenial-backports/main amd64 DEP-11 Metadata [3,328 B]
Get:23 http://us.archive.ubuntu.com/ubuntu xenial-backports/universe amd64 DEP-11 Metadata [5,096 B]
Fetched 6,189 kB in 6s (1,031 kB/s) 
Reading package lists... Done 
root@ubuntu:/home/philip/Downloads#

根据前面的输出,第一部分将是HitGetIgn。现在,Hit表示软件包版本没有变化,Get表示有新版本可用。然后Ign表示软件包被忽略。出现Ign的原因有很多,从软件包太新到检索文件时出现错误。通常,这些错误是无害的。

现在,在安装应用程序之前,我们可以使用apt-cache命令搜索它。假设我们想安装一个即时通讯应用程序。我们可以这样做:

root@ubuntu:/home/philip/Downloads# apt-cache search messenger
adium-theme-ubuntu - Adium message style for Ubuntu
totem-plugins - Plugins for the Totem media player
ayttm - Universal instant messaging client
banshee-extension-telepathy - Telepathy extension for Banshee
droopy - mini web server to let others upload files to your computer
dsniff - Various tools to sniff network traffic for cleartext insecurities
ekg2 - instant messenger and IRC client for UNIX systems
ekg2-api-docs - instant messenger and IRC client for UNIX systems - API documentation
ekg2-core - instant messenger and IRC client for UNIX systems - main program
yate-qt4 - YATE-based universal telephony client
yowsup-cli - command line tool that acts as WhatsApp client
empathy-skype - Skype plugin for libpurple messengers (Empathy-specific files)
pidgin-skype - Skype plugin for libpurple messengers (Pidgin-specific files)
pidgin-skype-common - Skype plugin for libpurple messengers (common files)
pidgin-skype-dbg - Skype plugin for libpurple messengers (debug symbols)
root@ubuntu:/home/philip/Downloads#                                                        

根据前面的输出,我们可以看到有各种即时通讯软件包可供安装。如果出于某种原因,我们想查看所有可用的软件包,我们可以使用pkgnames选项:

root@ubuntu:/home/philip/Downloads# apt-cache pkgnames | less
libdatrie-doc
libfstrcmp0-dbg
librime-data-sampheng
xxdiff-scripts
globus-xioperf
edenmath.app
libghc-ansi-wl-pprint-doc
libjson0
zathura-cb
root@ubuntu:/home/philip/Downloads# 

我们可以看到各种可以安装到这个系统上的包。通过指定正确的包名称,我们可以看到每个包的简要描述:

root@ubuntu:/home/philip/Downloads# apt-cache search zathura-cb
zathura-cb - comic book archive support for zathura
root@ubuntu:/home/philip/Downloads# apt-cache search virtaal
virtaal - graphical localisation editor
root@ubuntu:/home/philip/Downloads# apt-cache search python-logbook
python-logbook - logging system for Python that replaces the standard library's module
python-logbook-doc - logging system for Python that replaces the standard library's module (doc)
root@ubuntu:/home/philip/Downloads#

根据前面的输出,我们可以看到我们使用search选项传递的各种包的描述。我们还可以使用show选项检查包的详细信息:

root@ubuntu:/home/philip/Downloads# apt-cache show python-logbook
Package: python-logbook
Priority: optional
Section: universe/python
Source: logbook
Version: 0.12.3-1
Depends: python:any (<< 2.8), python:any (>= 2.7.5-5~)
Suggests: python-logbook-doc
Filename: pool/universe/l/logbook/python-logbook_0.12.3-1_all.deb
Size: 47896
MD5sum: 865ee97095b97f74e362ce3d93a26a9e
SHA1: 812b08f4e4e4dbcd40264a99fa4cd4dff4f62961
SHA256: 3091d5c491e54007da8b510a6f2e463b63f62364938c4f371406cb4511b6232c
Origin: Ubuntu
root@ubuntu:/home/philip/Downloads#

我们甚至可以将这些信息过滤,只查找依赖关系。我们应该使用showpkg选项:

root@ubuntu:/home/philip/Downloads# apt-cache showpkg python-logbook
Package: python-logbook
Versions:
0.12.3-1 (/var/lib/apt/lists/us.archive.ubuntu.com_ubuntu_dists_xenial_universe_binary-amd64_Packages) (/var/lib/apt/lists/us.archive.ubuntu.com_ubuntu_dists_xenial_universe_binary-i386_Packages)
Dependencies:
0.12.3-1 - python:any (3 2.8) python:any (2 2.7.5-5~) python-logbook-doc (0 (null))
Provides:
0.12.3-1 -
Reverse Provides:
root@ubuntu:/home/philip/Downloads#

我们还可以使用stats选项查看此系统上缓存的统计信息:

root@ubuntu:/home/philip/Downloads# apt-cache stats
Total package names: 73419 (1,468 k)
Total package structures: 113356 (4,988 k)
 Normal packages: 84328
 Total buckets in PkgHashTable: 50503
 Unused: 11792
 Used: 38711
 Utilization: 76.6509%
 Average entries: 2.92826
 Longest: 15
 Shortest: 1
Total buckets in GrpHashTable: 50503
 Unused: 11792
 Used: 38711
 Utilization: 76.6509%
 Average entries: 1.89659
 Longest: 8
 Shortest: 1
root@ubuntu:/home/philip/Downloads#

现在,我们可以下载一个包而不安装它。我们可以使用apt-getdownload选项:

root@ubuntu:/tmp# apt-get download zathura-cb
Get:1 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 zathura-cb amd64 0.1.5-1 [8,812 B]
Fetched 8,812 B in 0s (40.0 kB/s)
root@ubuntu:/tmp# ls | grep zathura
zathura-cb_0.1.5-1_amd64.deb
root@ubuntu:/tmp#

我们还可以安装已下载的软件包。我们需要使用apt-get命令指定路径:

root@ubuntu:/tmp# apt-get install ./zathura-cb_0.1.5-1_amd64.deb
Reading package lists... Done
Building dependency tree 
Reading state information... Done
You might want to run 'apt-get -f install' to correct these.
The following packages have unmet dependencies:
openssh-server:i386 : Depends: openssh-client:i386 (= 1:6.0p1-4+deb7u7)
 Recommends: ncurses-term:i386
 Recommends: openssh-blacklist:i386 but it is not installable
 Recommends: openssh-blacklist-extra:i386 but it is not installable
openssh-sftp-server:i386 : Breaks: openssh-server (< 1:6.5p1-5)
Breaks: openssh-server:i386 (< 1:6.5p1-5)
E: Unmet dependencies. Try using -f.
root@ubuntu:/tmp#

有时候,您可能会遇到前面示例中所见的问题。修复这个问题的最简单方法是使用-f选项重新运行apt-get命令,不包括软件包名称:

root@ubuntu:/tmp# apt-get -f install
Reading package lists... Done
Building dependency tree 
Reading state information... Done
Correcting dependencies... Done
The following packages were automatically installed and are no longer required:
Do you want to continue? [Y/n] y
Preconfiguring packages ...
(Reading database ... 241439 files and directories currently installed.)
Preparing to unpack .../openssh-server_1%3a7.2p2-4ubuntu2.4_i386.deb ...
Unpacking openssh-server:i386 (1:7.2p2-4ubuntu2.4) over (1:6.0p1-4+deb7u7) ...
Processing triggers for ufw (0.35-0ubuntu2) ...
Processing triggers for systemd (229-4ubuntu21.2) ...
Processing triggers for ureadahead (0.100.0-19) ...
Processing triggers for man-db (2.7.5-1) ...
Setting up openssh-server:i386 (1:7.2p2-4ubuntu2.4) ...
Setting up tftp:i386 (0.17-18) ...
root@ubuntu:/tmp#

看吧!正如我们所看到的,安装成功了。这就是apt-get实用程序的伟大之处。它找到了需要的依赖项,并提供安装它们以解决报告的问题。我们还可以同时安装多个应用程序。我们只需将每个软件包名称放在同一行上,用空格分隔:

root@ubuntu:/tmp# apt-get install virtaal vsftpd
Reading package lists... Done
Building dependency tree 
Reading state information... Done
The following packages were automatically installed and are no longer required:
 libllvm3.8 libpango1.0-0 libpangox-1.0-0 libqmi-glib1 linux-headers-4.4.0-21 linux-headers-4.4.0-21-generic linux-image-4.4.0-21-generic
 linux-image-extra-4.4.0-21-generic
Use 'sudo apt autoremove' to remove them.
The following additional packages will be installed: 
 javascript-common libglade2-0 libjs-jquery libjs-sph
Do you want to continue? [Y/n] y
Get:1 http://us.archive.ubuntu.com/ubuntu xenial/main amd64 libglade2-0 amd64 1:2.6.4-2 [44.6 kB]
Get:2 http://us.archive.ubuntu.com/ubuntu xenial/main amd64 javascript-common all 11 [6,066 B]
Get:3 http://us.archive.ubuntu.com/ubuntu xenial/main amd64 libjs-jquery all 1.11.3+dfsg-4 [161 kB]
Get:4 http://us.archive.ubuntu.com/ubuntu xenial/main amd64 libjs-underscore all 1.7.0~dfsg-1ubuntu1 [46.7 kB]
Get:5 http://us.archive.ubuntu.com/ubuntu xenial-updates/main amd64 libjs-sphinxdoc all 1.3.6-2ubuntu1.1 [57.6 kB]
Get:6 http://us.archive.ubuntu.com/ubuntu xenial-updates/main amd64 libpq5 amd64 9.5.13-0ubuntu0.16.04 [78.7 kB]
Setting up virtaal (0.7.1-1) ...
Setting up python-iniparse (0.4-2.2) ...
Setting up vsftpd (3.0.3-3ubuntu2) ...
Processing triggers for libc-bin (2.23-0ubuntu10) ...
Processing triggers for systemd (229-4ubuntu21.2) ...
Processing triggers for ureadahead (0.100.0-19) ...
root@ubuntu:/tmp#

太棒了!现在您可以看到apt-get实用程序的强大之处。我们还可以通过使用upgrade选项升级当前安装的所有软件包:

root@ubuntu:/tmp# apt-get upgrade
Reading package lists... Done
Building dependency tree 
Reading state information... Done
Calculating upgrade... Done
The following packages were automatically installed and are no longer required:
The following packages were automatically installed and are no longer required:
 libllvm3.8 libpango1.0-0 libpangox-1.0-0 libqmi-glib1 linux-headers-4.4.0-21 linux-headers-4.4.0-21-generic linux-image-4.4.0-21-generic
 linux-image-extra-4.4.0-21-generic
Use 'sudo apt autoremove' to remove them.
The following packages have been kept back: 
 libegl1-mesa libgbm1 libgl1-mesa-dri libwayland-egl1-mesa libxatracker2
The following packages will be upgraded:
 apt apt-transport-https apt-utils base-files cups cups-bsd cups-client cups-common cups-core-drivers cups-daemon cups-ppdc
63 upgraded, 0 newly installed, 0 to remove and 5 not upgraded.
Need to get 67.1 MB/160 MB of archives.
After this operation, 1,333 kB disk space will be freed.
Do you want to continue? [Y/n] y
root@ubuntu:/tmp#

我们还可以删除先前使用过的一些软件包,以确保特定软件包已正确安装。在我们的情况下,如果我们重新运行upgrade选项,我们应该会看到这个:

root@ubuntu:/tmp# apt-get upgrade
Reading package lists... Done
Building dependency tree 
Reading state information... Done
Calculating upgrade... Done
The following packages were automatically installed and are no longer required:
libllvm3.8 libpango1.0-0 libpangox-1.0-0 libqmi-glib1 linux-headers-4.4.0-21 linux-headers-4.4.0-21-generic linux-image-4.4.0-21-generic
linux-image-extra-4.4.0-21-generic
Use 'sudo apt autoremove' to remove them.
The following packages have been kept back:
libegl1-mesa libgbm1 libgl1-mesa-dri libwayland-egl1-mesa libxatracker2
0 upgraded, 0 newly installed, 0 to remove and 5 not upgraded.
root@ubuntu:/tmp#

我们应该按建议使用autoremove选项释放一些磁盘空间:

root@ubuntu:/tmp# apt-get autoremove
Reading package lists... Done
Building dependency tree 
Reading state information... Done
The following packages will be REMOVED:
libllvm3.8 libpango1.0-0 libpangox-1.0-0 libqmi-glib1 linux-headers-4.4.0-21 linux-headers-4.4.0-21-generic linux-image-4.4.0-21-generic
linux-image-extra-4.4.0-21-generic
0 upgraded, 0 newly installed, 8 to remove and 5 not upgraded.
After this operation, 339 MB disk space will be freed.
Do you want to continue? [Y/n] y
(Reading database ... 244059 files and directories currently installed.)
Removing libllvm3.8:amd64 (1:3.8-2ubuntu4) ...
Removing libpango1.0-0:amd64 (1.38.1-1) ...
Removing libpangox-1.0-0:amd64 (0.0.2-5) ...
done
Processing triggers for libc-bin (2.23-0ubuntu10) ...
root@ubuntu:/tmp#

我们还可以使用clean选项释放磁盘空间:

root@ubuntu:/tmp# apt-get clean
root@ubuntu:/tmp#

我们可以看到,命令运行得非常快。

定期清理磁盘空间是最佳实践。

我们还可以使用remove选项删除一个应用程序。这将删除应用程序,但不会删除配置:

root@ubuntu:/tmp# apt-get remove virtaal
Reading package lists... Done
Building dependency tree 
Reading state information... Done
The following packages were automatically installed and are no longer required:
javascript-common libglade2-0 libjs-jquery libjs-sphinxdoc libjs-underscore libpq5 libtidy-0.99-0 python-babel python-babel-localedata
python-bs4 python-cairo python-chardet python-dateutil python-diff-match-patch python-egenix-mxdatetime python-egenix-mxtools
python-enchant python-gi python-glade2 python-gobject python-gobject-2 python-gtk2 python-html5lib python-iniparse python-levenshtein
python-lxml python-pkg-resources python-psycopg2 python-pycurl python-simplejson python-six python-tz python-utidylib python-vobject
python-xapian translate-toolkit
Use 'sudo apt autoremove' to remove them.
The following packages will be REMOVED:
virtaal
0 upgraded, 0 newly installed, 1 to remove and 5 not upgraded.
After this operation, 3,496 kB disk space will be freed.
Do you want to continue? [Y/n] y
root@ubuntu:/tmp#

然后我们会运行autoremove选项来清理不必要的软件包。

自动删除选项

通常,当我们卸载一个软件包时,会有一些不必要的软件包最初安装,以便特定软件包能够正常运行。这些不需要的软件包占用了硬盘空间;我们可以使用autoremove选项来回收空间:

root@ubuntu:/tmp# apt-get autoremove virtaal
Reading package lists... Done
Building dependency tree 
Reading state information... Done
Package 'virtaal' is not installed, so not removed
The following packages will be REMOVED:
javascript-common libglade2-0 libjs-jquery libjs-sphinxdoc libjs-underscore libpq5 libtidy-0.99-0 python-babel python-babel-localedata
python-bs4 python-cairo python-chardet python-dateutil python-diff-match-patch python-egenix-mxdatetime python-egenix-mxtools
python-enchant python-gi python-glade2 python-gobject python-gobject-2 python-gtk2 python-html5lib python-iniparse python-levenshtein
python-lxml python-pkg-resources python-psycopg2 python-pycurl python-simplejson python-six python-tz python-utidylib python-vobject
python-xapian translate-toolkit
0 upgraded, 0 newly installed, 36 to remove and 5 not upgraded.
After this operation, 34.6 MB disk space will be freed.
Do you want to continue? [Y/n] y
Processing triggers for libc-bin (2.23-0ubuntu10) ...
Processing triggers for man-db (2.7.5-1) ...
Processing triggers for doc-base (0.10.7) ...
Processing 4 removed doc-base files...
root@ubuntu:/tmp#

太棒了!我们可以使用purge选项删除软件包及其配置。

清除选项

当使用purge选项时,不仅会删除软件包,还会删除软件包配置文件。这是理想的,因为大多数情况下,当我们使用uninstall卸载软件包时,它会在系统中留下不需要的配置文件。以下是我们如何使用purge选项:

root@ubuntu:/tmp# apt-get purge virtaal
Reading package lists... Done
Building dependency tree 
Reading state information... Done
The following packages will be REMOVED:
 virtaal*
0 upgraded, 0 newly installed, 1 to remove and 5 not upgraded.
After this operation, 0 B of additional disk space will be used.
Do you want to continue? [Y/n] y
Removing virtaal (0.7.1-1) ...
Purging configuration files for virtaal (0.7.1-1) ...
root@ubuntu:/tmp#

太棒了!

定期使用clean选项运行apt-get命令总是一个好主意。

每当我们使用apt实用程序安装软件包时,它会使用存储库将软件包下载到缓存中。默认情况下,当我们安装 Debian 发行版时,安装会附带官方存储库。这些存储在/etc/apt/sources.list文件中。让我们来看看那个文件:

root@ubuntu:/tmp# cat /etc/apt/sources.list
#deb cdrom:[Ubuntu 16.04 LTS _Xenial Xerus_ - Release amd64 (20160420.1)]/ xenial main restricted
 # See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://us.archive.ubuntu.com/ubuntu/ xenial main restricted
# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial main restricted
 ## Major bug fix updates produced after the final release of the
## distribution.
deb http://us.archive.ubuntu.com/ubuntu/ xenial-updates main restricted
# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial-updates main restricted
## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## universe WILL NOT receive any review or updates from the Ubuntu security
## team.
deb http://us.archive.ubuntu.com/ubuntu/ xenial universe
# deb-src http://us.archive.ubuntu.com/ubuntu/ xenial universe
# deb-src http://security.ubuntu.com/ubuntu xenial-security universe
deb http://security.ubuntu.com/ubuntu xenial-security multiverse
# deb-src http://security.ubuntu.com/ubuntu xenial-security multiverse
root@ubuntu:/tmp#

deb开头的条目指的是搜索软件包的位置。以deb-src开头的条目指的是源软件包。

aptitude 命令

Aptitude 是 APT 的前端,它是 Debian 软件包管理器。它最适合在没有图形界面的 shell 环境中使用。aptitude命令允许用户查看软件包列表,并执行安装、删除或升级软件包等软件包管理任务。还有交互模式;此外,它可以用作类似于apt-get的命令行工具。

我们可以通过简单输入aptitude命令而不传递任何选项来看到这一点:

在前面的截图中显示的屏幕上,我们可以使用键盘或鼠标进行交互导航。顶部有一个菜单。我们可以从菜单中选择操作并查看可用选项:

我们还可以直接从菜单中转到软件包,并查看类似于从命令行进行软件包管理的选项:

正如我们所看到的,当我们使用这种方法进行软件包管理时,aptitude非常直观。

我们还可以使用命令行来管理软件包。如果我们更喜欢在菜单类型的环境中输入命令,那么我们需要使用aptitude命令传递选项。aptitude命令支持大多数我们会使用apt-get命令传递的选项。让我们从search选项开始:

搜索选项

当我们执行search选项时,aptitude命令会根据search选项后指定的标准搜索可能的匹配项:

root@ubuntu:/home/philip# aptitude search vlc
p   browser-plugin-vlc                                 - multimedia plugin for web browsers based on VLC 
p   browser-plugin-vlc:i386                            - multimedia plugin for web browsers based on VLC 
p   libvlc-dev                                         - development files for libvlc 
p   libvlc-dev:i386                                    - development files for libvlc 
p   libvlc5                                            - multimedia player and streamer library 
p   vlc                                                - multimedia player and streamer 
p   vlc:i386                                           - multimedia player and streamer 
root@ubuntu:/home/philip#     

根据前面的输出,我们可以看到aptitude命令与 APT 的模式相似。我们还可以通过传递update选项来安装和更新软件包列表:

root@ubuntu:/home/philip# aptitude update
Hit http://us.archive.ubuntu.com/ubuntu xenial InRelease 
Get: 1 http://security.ubuntu.com/ubuntu xenial-security InRelease [107 kB]
Get: 2 http://us.archive.ubuntu.com/ubuntu xenial-updates InRelease [109 kB] 
Get: 3 http://us.archive.ubuntu.com/ubuntu xenial-backports InRelease [107 kB] 
Get: 4 http://us.archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages [809 kB]
Get: 5 http://security.ubuntu.com/ubuntu xenial-security/main amd64 Packages [524 kB]
Get: 6 http://us.archive.ubuntu.com/ubuntu xenial-updates/main i386 Packages [738 kB]
Get: 7 http://security.ubuntu.com/ubuntu xenial-security/main i386 Packages [461 kB]
root@ubuntu:/home/philip#

在更新软件包列表后,我们可以通过传递safe-upgrade选项来升级软件包:

root@ubuntu:/home/philip# aptitude safe-upgrade
Resolving dependencies... 
The following NEW packages will be installed:
 libllvm6.0{a}
The following packages will be REMOVED:
 libllvm5.0{u}
The following packages will be upgraded:
 libegl1-mesa libgbm1 libgl1-mesa-dri libwayland-egl1-mesa libxatracker2
5 packages upgraded, 1 newly installed, 1 to remove and 0 not upgraded.
Need to get 21.6 MB of archives. After unpacking 14.1 MB will be used.
Do you want to continue? [Y/n/?] y
Installing new version of config file /etc/drirc ...
Setting up libegl1-mesa:amd64 (18.0.5-0ubuntu0~16.04.1) ...
Setting up libwayland-egl1-mesa:amd64 (18.0.5-0ubuntu0~16.04.1) ...
Processing triggers for libc-bin (2.23-0ubuntu10) ... 
Current status: 0 (-5) upgradable.
root@ubuntu:/home/philip#

我们还可以通过传递install选项来安装软件包:

root@ubuntu:/home/philip# aptitude install vlc
The following NEW packages will be installed:
i965-va-driver{a} liba52-0.7.4{a} libaacs0{a} libass5{a} libavcodec-ffmpeg56{a} libavformat-ffmpeg56{a}
libavutil-ffmpeg54{a} libbasicusageenvironment1{a} libbdplus0{a} libbluray1{a} libcddb2{a} libchromaprint0{a}
libcrystalhd3{a} libdc1394-22{a} libdca0{a} libdirectfb-1.2-9{a} libdvbpsi10{a} libdvdnav4{a} libdvdread4{a}
vlc-plugin-notify{a} vlc-plugin-samba{a}
0 packages upgraded, 73 newly installed, 0 to remove and 0 not upgraded.
Need to get 23.7 MB of archives. After unpacking 119 MB will be used.
Do you want to continue? [Y/n/?] y
Setting up va-driver-all:amd64 (1.7.0-1ubuntu0.1) ...
Processing triggers for libc-bin (2.23-0ubuntu10) ...
Processing triggers for vlc-nox (2.2.2-5ubuntu0.16.04.4) ... 
root@ubuntu:/home/philip#

太棒了!我们还可以删除软件包。我们只需传递remove选项:

root@ubuntu:/home/philip# aptitude remove vlc
The following packages will be removed: 
 i965-va-driver{u} liba52-0.7.4{u} libaacs0{u} libass5{u} libavcodec-ffmpeg56{u} libavformat-ffmpeg56{u}
 libzvbi-common{u} libzvbi0{u} mesa-va-drivers{u} va-driver-all{u} vlc vlc-data{u} vlc-nox{u} vlc-plugin-notify{u} vlc-plugin-samba{u}
Do you want to continue? [Y/n/?] y
Processing triggers for desktop-file-utils (0.22-1ubuntu5.2) ...
Processing triggers for libc-bin (2.23-0ubuntu10) ...
Processing triggers for hicolor-icon-theme (0.15-0ubuntu1) ... 
root@ubuntu:/home/philip#

太棒了!正如你所看到的,aptitude命令对于任何 Linux 管理员都非常有用。

synaptic 实用程序

这是一种基于 APT 的图形化软件包管理形式。这个强大的图形界面实用程序使我们能够在易于使用的环境中安装、更新或删除软件包。使用synaptic实用程序使我们能够管理软件包,而无需在命令提示符下工作。让我们来看看 Ubuntu 18 系统中的synaptic实用程序。synaptic实用程序在 Ubuntu 18 中默认未安装。我们可以使用apt-cache命令在安装之前查看有关synaptic实用程序的信息:

root@ubuntu:/home/philip# apt-cache showpkg synaptic
 Package: synaptic
 Versions:
 0.83 (/var/lib/apt/lists/us.archive.ubuntu.com_ubuntu_dists_xenial_universe_binary-amd64_Packages)
 Description Language:
 File: /var/lib/apt/lists/us.archive.ubuntu.com_ubuntu_dists_xenial_universe_binary-amd64_Packages
 MD5: d4fb8e90c9684f1113e56123c017d85f
 Reverse Depends:
 aptoncd,synaptic 0.57.7
 apt,synaptic
 mate-menu,synaptic
 lubuntu-desktop,synaptic
 cinnamon-desktop-environment,synaptic
 update-notifier,synaptic 0.75.12
 apt,synaptic
 update-manager,synaptic
 Dependencies:
 0.83 - libapt-inst2.0 (2 0.8.16~exp12) libapt-pkg5.0 (2 1.1~exp9) libc6 (2 2.14) libept1.5.0 (0 (null)) libgcc1 (2 1:3.0) libgdk-pixbuf2.0-0 (2 2.22.0) libglib2.0-0 (2 2.14.0) libgtk-3-0 (2 3.3.16) libpango-1.0-0 (2 1.14.0) libstdc++6 (2 5.2) libvte-2.91-
 root@ubuntu:/home/philip#

根据前面的屏幕截图,我们可以看到synaptic实用程序依赖于许多依赖项。让我们使用apt-get命令安装synaptic实用程序:

root@ubuntu:/home/philip# apt-get install synaptic
 Reading package lists... Done
 Building dependency tree
 Reading state information... Done
 The following NEW packages will be installed:
 docbook-xml libept1.5.0 librarian0 rarian-compat sgml-data synaptic
 0 upgraded, 6 newly installed, 0 to remove and 81 not upgraded.
 Need to get 1,785 kB of archives.
 After this operation, 11.6 MB of additional disk space will be used.
 Do you want to continue? [Y/n] y
Setting up docbook-xml (4.5-7.3) ...
 Processing triggers for sgml-base (1.26+nmu4ubuntu1) ...
 root@ubuntu:/home/philip#

我们刚刚安装了synaptic实用程序。我们可以从 Ubuntu 18 系统左上角的搜索您的计算机按钮启动synaptic实用程序,以探索其功能,如下面的屏幕截图所示:

一旦我们选择synaptic软件包管理器,它将提示我们进行身份验证,如下面的屏幕截图所示:

认证后,我们将看到synaptic实用程序。我们可以使用搜索按钮来查找特定的软件包。以下屏幕截图描述了搜索功能对话框:

干得漂亮!如前面的屏幕截图所示,我们可以通过简单输入所需的软件包名称来进行搜索。与命令行对应物相比,使用图形界面要容易得多。要进行搜索,我们只需选择搜索按钮。此外,我们可以通过简单选择重新加载按钮来从synaptic实用程序内更新软件包数据库:

太棒了!正如你所看到的,synaptic实用程序非常直观。它可以以类似于其他图形界面程序的方式进行导航。

摘要

在本章中,我们专注于软件包管理的各种方法。首先,我们深入研究了软件包管理的传统方式;也就是使用dpkg实用程序。我们探讨了查看系统上当前软件包的方法。我们还涉及查询特定软件包的方法。然后我们看了软件包安装文件的各种位置。除此之外,我们还进行了一个实际的软件包安装。然后我们验证了软件包确实已安装。接着是删除软件包。接下来,我们将注意力转向更常见的软件包管理方法;即 APT。我们使用最佳实践,即始终将update选项与apt一起传递。然后我们专注于搜索软件包的方法。除此之外,我们还查看了当前的软件包。此外,我们还专注于获取有关特定软件包的一些有用信息。

接着是安装软件包。然后我们发现可以在单个apt-get命令中安装多个软件包。接着是演示如何更新软件包。此外,我们还看到了如何使用apt-get命令删除软件包。最后,我们使用了aptitudeaptitude命令本身提供了一个用户交互式、菜单驱动的环境。我们还研究了如何在aptitude命令中传递选项。最初,我们更新了软件包列表。然后升级了软件包。除此之外,我们还了解了搜索软件包的技巧。然后使用命令行执行了软件包安装。在此之后,我们进行了一个命令行上删除软件包的演示。最后,我们以命令行的替代方式结束,即synaptic实用程序。基于 APT 的synaptic实用程序是用于软件包管理的 GUI。

在下一章中,我们将深入探讨 Red-Hat 软件包管理的世界;特别是 Fedora。我们将介绍各种技术,如rpmyumdnfyumex,用于管理软件包。我希望您能加入,因为我相信在阅读下一章后,您将更好地掌握 Red Hat 世界中的软件包管理。这将最终让您更接近认证。

问题

  1. dpkg命令的哪个选项用于显示dpkg在系统上管理的软件包?

A. dpkg -a

B. dpkg -l

C. dpkg -i

D. dpkg –d

  1. dpkg-query的哪个选项用于显示软件包的可读描述?

A. dpkg-query -a

B. dpkg-query-c

C. dpkg-query -s

D. dpkg-query-r

  1. 哪个日志文件用于显示dpkg软件包相关的消息?

A. cat /var/log/dpkg.log

B. cat /var/dpkg/dpkg.log

C. cat /var/dpkg-query/dpkg.log

D. cat /var/log/dpkg.dpkg

  1. 哪个选项用于显示使用dpkg命令安装的软件包?

A. dpkg --get-selections

B. dpkg –set-selections

C. dpkg –get-selection

D. dpkg-query –get-selection

  1. 哪个选项用于使用dpkg命令添加软件包?

A. dpkg -e

B. dpkg –r

C. dpkg -Add

D. dpkg -i

  1. 哪个选项用于使用dpkg命令删除软件包及其配置文件?

A. dpkg -p

B. dpkg-e

C. dpkg -P

D. dpkg-a

  1. 哪个选项用于更新apt缓存?

A. apt-get -c

B. apt-get update

C. apt-get upgrade

D. apt-get -u

  1. 哪个命令用于在缓存中搜索软件包?

A. apt-get search

B. apt-cache search

C. apt-get -update

D. apt-get clean

  1. 哪个选项用于使用apt命令删除软件包及其配置?

A. apt-get remove

B. apt-get purge

C. apt-get --remove

D. apt-get --update

  1. 哪个选项用于使用aptitude命令更新软件包列表?

A. aptitude purge

B. aptitude clean

C. aptitude update

D. aptitude --clean

进一步阅读

  • 这个网站为您提供了关于 Debian 发行版的有用信息:wiki.debian.org

  • 这个网站为您提供了 Debian 发行版的技巧和最佳实践:www.debian.org

  • 下一个网站为您提供了 Linux 社区用户的许多有用的技巧和最佳实践,特别是针对 Debian 发行版,如 Ubuntu:askubuntu.com

  • 这个网站为您提供了许多有用的资源,涉及其他 Linux 用户在各种任务中遇到的各种问题:unix.stackexchange.com

第七章:使用 YUM 软件包管理

在上一章中,软件包管理是我们的焦点。我们了解了 Debian 软件包管理器。在 Debian 环境中,有许多安装软件包的方法。我们关注的是在 Debian 环境中管理软件包的常见方法。

在本章中,我们继续我们的旅程。这次我们关注 Red Hat 对软件包管理的方法。我们首先关注非常流行的Yellowdog Updater, Modified,也称为YUM。接下来,我们将把注意力转向dnf实用程序。dnf实用程序的作用类似于 YUM。然后是用于管理软件包的rpm实用程序。最后,我们将介绍yumex实用程序。

在本章中,我们将涵盖以下主题:

  • yum

  • dnf

  • rpm

  • yumex

YUM

Yellowdog Updater, Modified,通常称为YUM。YUM 是用于使用 Red Hat 发行版的系统的开源命令行方法。YUM 使我们作为 Linux 管理员能够在基于 RPM 的发行版上执行自动更新、软件包和依赖关系管理。YUM 在性质上类似于其 Debian 对应物 APT。YUM 实用程序利用各种软件仓库。

软件仓库,通常称为软件仓库,存储各种软件包。使用 YUM 的主要原因之一是它检测是否需要任何特定软件包的依赖文件。然后,它提示用户所需的文件,并提供将它们作为软件包安装的一部分安装的选项,用户应该从一开始就启动。

有趣的一点是 YUM 与 RPM 软件包一起工作。

首先,我们可以使用list选项查看 YUM 数据库中的可用软件包:

[philip@localhost ~]$ yum list | less
Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast
Loading mirror speeds from cached hostfile
 * base: centos.mirror.iweb.ca
 * extras: centos.mirror.iweb.ca
 * updates: centos.mirror.iweb.ca
Installed Packages
GConf2.x86_64                    3.2.6-8.el7                @anaconda
GeoIP.x86_64                     1.5.0-11.el7               @anaconda
ModemManager.x86_64              1.6.0-2.el7                @anaconda
ModemManager-glib.x86_64         1.6.0-2.el7                @anaconda
NetworkManager.x86_64            1:1.8.0-9.el7              @anaconda
NetworkManager-adsl.x86_64       1:1.8.0-9.el7              @anaconda
NetworkManager-glib.x86_64       1:1.8.0-9.el7              @anaconda
NetworkManager-libnm.x86_64      1:1.8.0-9.el7              @anaconda
NetworkManager-libreswan.x86_64  1.2.4-2.el7                @anaconda
NetworkManager-libreswan-gnome.x86_64 1.2.4-2.el7               @anaconda
NetworkManager-ppp.x86_64        1:1.8.0-9.el7              @anaconda
NetworkManager-team.x86_64       1:1.8.0-9.el7              @anaconda
NetworkManager-tui.x86_64        1:1.8.0-9.el7              @anaconda
NetworkManager-wifi.x86_64       1:1.8.0-9.el7              @anaconda
PackageKit.x86_64                1.1.5-1.el7.centos         @anaconda

从前面的输出中,仓库数据已经过时,确切地说是两周前。这可以通过使用 YUM 运行makecache fast来解决:

[philip@localhost ~]$ yum makecache fast
Loaded plugins: fastestmirror, langpacks
Existing lock /var/tmp/yum-philip-FdEYSO/x86_64/7/yum.pid: another copy is running as pid 2322.
Another app is currently holding the yum lock; waiting for it to exit...
 The other application is: yum
 Memory :  24 M RSS (415 MB VSZ)
 Started: Tue Jul 31 05:49:03 2018 - 00:11 ago
 State  : Traced/Stopped, pid: 2322
Another app is currently holding the yum lock; waiting for it to exit...
 The other application is: yum
 Memory :  24 M RSS (415 MB VSZ)
 Started: Tue Jul 31 05:49:03 2018 - 00:13 ago
 State  : Traced/Stopped, pid: 2322
Another app is currently holding the yum lock; waiting for it to exit...
 The other application is: yum
 Memory :  24 M RSS (415 MB VSZ)
 Started: Tue Jul 31 05:49:03 2018 - 00:15 ago
 State  : Traced/Stopped, pid: 2322
^C
Exiting on user cancel.
[philip@localhost ~]$

如果在尝试更新缓存时遇到此消息,则可以删除锁定文件,从而解决此问题:

[philip@localhost ~]$ rm /var/tmp/yum-philip-FdEYSO/x86_64/7/yum.pid [philip@localhost ~]$ yum makecache fast
Loaded plugins: fastestmirror, langpacks
http://ftp.jaist.ac.jp/pub/Linux/CentOS/7/os/x86_64/repodata/repomd.xml: [Errno 14] curl#6 - "Could not resolve host: ftp.jaist.ac.jp; Name or service not known"
Trying other mirror.
base                                                                             | 3.6 kB  00:00:00 
extras                                                                                                                         | 3.4 kB  00:00:00 
http://centos.mirror.iweb.ca/7/updates/x86_64/repodata/repomd.xml: [Errno 14] curl#6 - "Could not resolve host: centos.mirror.iweb.ca; Name or service not known"
Trying other mirror.
updates                                                                                                                       | 3.4 kB  00:00:00 
(1/2): extras/7/x86_64/primary_db                                                                                              | 172 kB  00:00:10 
(2/2): updates/7/x86_64/primary_db                                                                                             | 4.3 MB  00:00:13 
Loading mirror speeds from cached hostfile
 * base: centos.mirror.iweb.ca
 * extras: centos.mirror.iweb.ca
 * updates: centos.mirror.iweb.ca
Metadata Cache Created
[philip@localhost ~]$

太棒了!我们可以看到缓存已经更新。我们可以进一步缩小 YUM 显示的软件包范围;为此,我们使用installed选项:

[philip@localhost ~]$ yum list installed | less
Loaded plugins: fastestmirror, langpacks
Installed Packages
GConf2.x86_64                3.2.6-8.el7                     @anaconda
GeoIP.x86_64                 1.5.0-11.el7                    @anaconda
ModemManager.x86_64          1.6.0-2.el7                     @anaconda
ModemManager-glib.x86_64     1.6.0-2.el7                     @anaconda
NetworkManager.x86_64        1:1.8.0-9.el7                   @anaconda
NetworkManager-adsl.x86_64   1:1.8.0-9.el7                   @anaconda
NetworkManager-glib.x86_64    1:1.8.0-9.el7                  @anaconda
NetworkManager-libnm.x86_64   1:1.8.0-9.el7                  @anaconda
NetworkManager-libreswan.x86_64 1.2.4-2.el7                  @anaconda
NetworkManager-libreswan-gnome.x86_64 1.2.4-2.el7            @anaconda
NetworkManager-ppp.x86_64       1:1.8.0-9.el7                @anaconda
NetworkManager-team.x86_64      1:1.8.0-9.el7                @anaconda
NetworkManager-tui.x86_64       1:1.8.0-9.el7                @anaconda
NetworkManager-wifi.x86_64      1:1.8.0-9.el7                @anaconda
PackageKit.x86_64               1.1.5-1.el7.centos           @anaconda
PackageKit-command-not-found.x86_64 1.1.5-1.el7.centos       @anaconda
PackageKit-glib.x86_64           1.1.5-1.el7.centos          @anaconda
PackageKit-gstreamer-plugin.x86_64  1.1.5-1.el7.centos       @anaconda

从输出中,软件包按软件包名称、软件包版本和安装程序显示。我们也可以以组格式查看软件包。我们使用grouplist选项:

[philip@localhost ~]$ yum grouplist
Loaded plugins: fastestmirror, langpacks
There is no installed groups file.
Maybe run: yum groups mark convert (see man yum)
Loading mirror speeds from cached hostfile
 * base: centos.mirror.iweb.ca
 * extras: centos.mirror.iweb.ca
 * updates: centos.mirror.iweb.ca
Available Environment Groups:
 Minimal Install
 Compute Node
 Infrastructure Server
 File and Print Server
 Basic Web Server
 Virtualization Host
 Server with GUI
 GNOME Desktop
 KDE Plasma Workspaces
 Development and Creative Workstation
Available Groups:
 Compatibility Libraries
 Console Internet Tools
 Development Tools
 Graphical Administration Tools
 Legacy UNIX Compatibility
 Scientific Support
 Security Tools
 Smart Card Support
 System Administration Tools
 System Management
Done
[philip@localhost ~]$

太棒了!要查看有关特定软件包的信息,我们可以使用info选项:

[philip@localhost ~]$ yum info firefox
Installed Packages
Name        : firefox
Arch        : x86_64
Version     : 52.2.0
Release     : 2.el7.centos
Size        : 149 M
Repo        : installed
From repo   : anaconda
Summary     : Mozilla Firefox Web browser
URL         : http://www.mozilla.org/projects/firefox/
License     : MPLv1.1 or GPLv2+ or LGPLv2+
Description : Mozilla Firefox is an open-source web browser, designed for standards
 : compliance, performance and portability.
Available Packages
Name        : firefox
Arch        : i686
Version     : 60.1.0
Name        : firefox
Arch        : x86_64
Version     : 60.1.0
Description : Mozilla Firefox is an open-source web browser, designed for standards
 : compliance, performance and portability.
[philip@localhost ~]$

从前面的输出中,有许多与软件包相关的有用信息。

我们可以使用provides选项为文件标识软件包:

[philip@localhost ~]$ yum provides /etc/my.cnf
Loaded plugins: fastestmirror, langpacks
1:mariadb-libs-5.5.56-2.el7.i686 : The shared libraries required for MariaDB/MySQL clients
Repo        : base
Matched from:
Filename    : /etc/my.cnf
1:mariadb-libs-5.5.56-2.el7.x86_64 : The shared libraries required for MariaDB/MySQL clients
Repo        : base
Matched from:
Filename    : /etc/my.cnf
1:mariadb-libs-5.5.56-2.el7.x86_64 : The shared libraries required for MariaDB/MySQL clients
Repo        : @anaconda
Matched from:
Filename    : /etc/my.cnf
[philip@localhost ~]$

根据输出,很明显/etc/my.cnf属于mariadb-libs-5.5.56-2.el7.x86_64。我们还可以使用search选项搜索软件包:

[philip@localhost ~]$ yum search gedit
Loaded plugins: fastestmirror, langpacks
* updates: centos.mirror.iweb.ca
================================================================= N/S matched: gedit =================================================================
gedit-devel.i686 : Support for developing plugins for the gedit text editor
gedit-devel.x86_64 : Support for developing plugins for the gedit text editor
gedit-plugins-data.x86_64 : Common data required by plugins
Name and summary matches only, use "search all" for everything.
[philip@localhost ~]$

现在,为了更新我们的系统,我们首先使用clean all选项:

在进行软件包维护之前,您需要 root 权限。

[root@localhost philip]# yum clean all
Loaded plugins: fastestmirror, langpacks
Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast
Cleaning repos: base extras updates
Cleaning up everything
Cleaning up list of fastest mirrors
[root@localhost philip]#

接下来,我们使用check-update选项:

[root@localhost philip]# yum check-update
Loaded plugins: fastestmirror, langpacks
http://ftp.hosteurope.de/mirror/centos.org/7/os/x86_64/repodata/repomd.xml: [Errno 14] curl#6 - "Could not resolve host: ftp.hosteurope.de; Name or service not known"
Trying other mirror.
base                                                                                                                           | 3.6 kB  00:00:00 
extras                                                                                                                         | 3.4 kB  00:00:00 
updates                                                                                                                        | 3.4 kB  00:00:00 
(1/4): base/7/x86_64/group_gz                                                                                                  | 166 kB  00:00:09 
(2/4): extras/7/x86_64/primary_db                                                                                              | 172 kB  00:00:08 
(3/4): updates/7/x86_64/primary_db                                                                                             | 4.3 MB  00:00:14 
(4/4): base/7/x86_64/primary_db                                                                                                | 5.9 MB  00:00:16 
Determining fastest mirrors
* base: mirror.us.leaseweb.net
* extras: mirror.us.leaseweb.net
* updates: mirror.us.leaseweb.net
ModemManager.x86_64                                                          1.6.10-1.el7              base    accountsservice.x86_64                                                         0.6.45-7.el7              base    accountsservice-libs.x86_64                                                    0.6.45-7.el7              base    acl.x86_64                                                                     2.2.51-14.el7             base    attr.x86_64                                                                    2.4.46-13.el7             base    avahi-gobject.x86_64                                                           0.6.31-19.el7             base    avahi-libs.x86_64                                                              0.6.31-19.el7             base    yum.noarch                                                                     3.4.3-158.el7.centos      base    yum-plugin-fastestmirror.noarch                                                1.1.31-45.el7             base    yum-utils.noarch                                                               1.1.31-45.el7             base    Obsoleting Packages grub2.x86_64                                                                   1:2.02-0.65.el7.centos.2  base    grub2-tools.x86_64                                                         1:2.02-0.64.el7.centos    @anaconda grub2-tools-minimal.x86_64                                                     1:2.02-0.65.el7.centos.2  base 
[root@localhost philip]#

为了简洁起见,某些输出已被省略。我们也可以使用install选项来安装软件包:

[root@localhost philip]# yum install talk.x86_64
Loaded plugins: fastestmirror, langpacks
* updates: mirror.us.leaseweb.net
Resolving Dependencies
--> Running transaction check
Dependencies Resolved
=====================================================================
Package      Arch     Version      Repository   Size
=====================================================================
Installing:
talk         x86_64   0.17-46.el7     base     24 k
Transaction Summary
=====================================================================
Install  1 Package
Total download size: 24 k
Installed size: 31 k
Is this ok [y/d/N]: y
Downloading packages:
talk-0.17-46.el7.x86_64.rpm                                                                                                    |  24 kB  00:00:04 
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : talk-0.17-46.el7.x86_64                                                                                                            1/1
Verifying  : talk-0.17-46.el7.x86_64                                                                                                            1/1
Installed:
 talk.x86_64 0:0.17-46.el7 
Complete!
[root@localhost philip]# 

太棒了!我们也可以按相反的顺序删除软件包。为此,我们使用remove选项:

[root@localhost philip]# yum remove talk.x86_64
Loaded plugins: fastestmirror, langpacks
Resolving Dependencies
--> Running transaction check
---> Package talk.x86_64 0:0.17-46.el7 will be erased
--> Finished Dependency Resolution
Dependencies Resolved
=====================================================================
Package        Arch    Version   Repository    Size
=====================================================================
Removing:
talk         x86_64  0.17-46.el7    @base      31 k
Transaction Summary
=====================================================================
Remove  1 Package
Installed size: 31 k
Is this ok [y/N]: y
Downloading packages:
Transaction test succeeded
Running transaction
Erasing    : talk-0.17-46.el7.x86_64                                                                                                            1/1
Verifying  : talk-0.17-46.el7.x86_64                                                                                                            1/1
Removed:
talk.x86_64 0:0.17-46.el7 
Complete!
[root@localhost philip]#

如果出于某种原因,我们想要更新系统上的所有软件包,我们使用update选项:

[root@localhost philip]# yum update
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: mirror.us.leaseweb.net
 * extras: mirror.us.leaseweb.net
 * updates: mirror.us.leaseweb.net
Resolving Dependencies
---> Package python-gobject.x86_64 0:3.22.0-1.el7_4.1 will be an update
---> Package python-gobject-base.x86_64 0:3.22.0-1.el7 will be updated
---> Package python-libs.x86_64 0:2.7.5-58.el7 will be updated
---> Package python-libs.x86_64 0:2.7.5-69.el7_5 will be an update
---> Package python-netaddr.noarch 0:0.7.5-7.el7 will be updated
libwayland-server x86_64 1.14.0-2.el7 base 38 k
unbound-libs x86_64 1.6.6-1.el7 base 405 k
volume_key-libs x86_64 0.3.9-8.el7 base 140 k
Transaction Summary
======================================================================================================================================================
Install 6 Packages (+20 Dependent packages)
Upgrade 586 Packages
Total download size: 691 M
Is this ok [y/d/N]: y

最后,我们可以通过传递repolist选项来查看 YUM 仓库:

[root@localhost philip]# yum repolist
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: mirror.us.leaseweb.net
repo id           repo name            status
base/7/x86_64     CentOS-7 - Base      9,911
extras/7/x86_64   CentOS-7 - Extras    363
updates/7/x86_64  CentOS-7 - Updates   1,004
repolist: 11,278
[root@localhost philip]#

DNF

Dandified YUM或 DNF 是软件包管理实用程序的名称。DNF 是 YUM 的下一代版本。它用于基于 RPM 的发行版。DNF 在 Fedora 18 中引入,并且自 Fedora 22 版本以来一直是 Fedora 的默认软件包管理器。实际上,当我们在 Fedora 的后续版本中运行 YUM 命令时,实际上是在后台运行dnfdnf实用程序提供了性能、内存使用和依赖关系解析等功能。

要开始,我们可以使用--version选项检查我们的 Fedora 28 系统上的dnf版本:

[root@localhost philip]# dnf --version
2.7.5
Installed: dnf-0:2.7.5-12.fc28.noarch at Wed 25 Apr 2018 06:35:34 AM GMT
Built    : Fedora Project at Wed 18 Apr 2018 02:29:51 PM GMT
Installed: rpm-0:4.14.1-7.fc28.x86_64 at Wed 25 Apr 2018 06:34:14 AM GMT
Built    : Fedora Project at Mon 19 Feb 2018 09:29:01 AM GMT
[root@localhost philip]# 

根据前面的输出,我们安装了版本 2.7.5 的dnf实用程序。我们甚至可以通过传递repolist选项来查看系统上的存储库:

[root@localhost philip]# dnf repolist
Last metadata expiration check: 0:01:09 ago on Tue 31 Jul 2018 03:10:57 PM EDT.
repo id     repo name                      status
*fedora     Fedora 28 - x86_64             57,327
*updates    Fedora 28 - x86_64 - Updates   16,337
[root@localhost philip]#

除此之外,我们甚至可以在 Fedora 28 中暴露 YUM 命令,以证明它是dnf实用程序的别名。我们可以列出/usr/bin并搜索 YUM:

[root@localhost philip]# ll /usr/bin | grep yum
lrwxrwxrwx. 1 root root           5 Apr 18 10:29 yum -> dnf-3
[root@localhost philip]#

根据前面的输出,YUM 是 Fedora 28 系统中的一个别名。我们还可以检查存储库是否已启用。为此,我们使用repolist all选项:

[root@localhost philip]# dnf repolist all

现在,要查看系统上所有可用的软件包,我们使用list选项:

[root@localhost philip]# dnf list
Last metadata expiration check: 0:06:37 ago on Tue 31 Jul 2018 03:10:57 PM EDT.
Installed Packages
GConf2.x86_64             3.2.6-20.fc28                 @anaconda
GeoIP.x86_64              1.6.12-3.fc28                 @anaconda
GeoIP-GeoLite-data.noarch 2018.04-1.fc28                @anaconda
ImageMagick.x86_64        1:6.9.9.38-1.fc28             @anaconda
ImageMagick-libs.x86_64   1:6.9.9.38-1.fc28             @anaconda
LibRaw.x86_64             0.18.8-1.fc28                 @anaconda
ModemManager.x86_64       1.6.12-3.fc28                 @anaconda
ModemManager-glib.x86_64  1.6.12-3.fc28                 @anaconda
NetworkManager.x86_64      1:1.10.6-1.fc28               @anaconda
NetworkManager-adsl.x86_64 1:1.10.6-1.fc28               @anaconda
NetworkManager-bluetooth.x86_64 1:1.10.6-1.fc28               @anaconda
NetworkManager-config-connectivity-fedora.noarch  1:1.10.6-1.fc28               @anaconda
NetworkManager-libnm.x86_64 1:1.10.6-1.fc28 @anaconda
NetworkManager-openconnect.x86_64 1.2.4-9.fc28                  @anaconda
NetworkManager-openconnect-gnome.x86_64  1.2.4-9.fc28                  @anaconda
zziplib-utils.x86_64                                              0.13.68-1.fc28 fedora 
zzuf.x86_64 0.15-5.fc28  fedora 
[root@localhost philip]#

我们可以执行类似于 YUM 的搜索;为此,我们使用search选项:

[root@localhost philip]# dnf search firefox
Last metadata expiration check: 0:11:22 ago on Tue 31 Jul 2018 03:10:57 PM EDT.
============================================ Summary & Name Matched: firefox =============================================
firefox.x86_64 : Mozilla Firefox Web browser
================================================ Summary Matched: firefox ================================================
icecat.x86_64 : GNU version of Firefox browser
mozilla-ublock-origin.noarch : An efficient blocker for Firefox
mozilla-https-everywhere.noarch : HTTPS enforcement extension for Mozilla Firefox
mozilla-requestpolicy.noarch : Firefox and Seamonkey extension that gives you control over cross-site requests
python-mozrunner.noarch : Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird)
[root@localhost philip]#

太棒了!此外,要查看哪个软件包提供了特定的实用程序,我们使用provides选项:

[root@localhost philip]# dnf provides /bin/ksh
Last metadata expiration check: 0:14:22 ago on Tue 31 Jul 2018 03:10:57 PM EDT.
ksh-20120801-247.fc28.x86_64 : The Original ATT Korn Shell
Repo        : updates
Matched from:
Provide    : /bin/ksh
ksh-20120801-245.fc28.x86_64 : The Original ATT Korn Shell
Repo        : fedora
Matched from:
Provide    : /bin/ksh
[root@localhost philip]#

除此之外,我们可以使用info选项查看特定软件包的信息:

root@localhost philip]# dnf info libreoffice
Available Packages
Name         : libreoffice
Epoch        : 1
Version      : 6.0.6.1
Summary      : Free Software Productivity Suite
URL          : http://www.libreoffice.org/
License      : (MPLv1.1 or LGPLv3+) and LGPLv3 and LGPLv2+ and BSD and (MPLv1.1 or GPLv2 or LGPLv2 or Netscape) and Public
 : Domain and ASL 2.0 and MPLv2.0 and CC0
Description  : LibreOffice is an Open Source, community-developed, office productivity suite.
 : It includes the key desktop applications, such as a word processor,
 : spreadsheet, presentation manager, formula editor and drawing program, with a
 : user interface and feature set similar to other office suites.  Sophisticated
 : and flexible, LibreOffice also works transparently with a variety of file
 : formats, including Microsoft Office File Formats.
[root@localhost philip]#

根据前面的截图,我们可以看到有关给定软件包的许多有用信息。我们还可以使用check-update选项检查系统更新:

[root@localhost philip]# dnf check-update
Last metadata expiration check: 0:18:17 ago on Tue 31 Jul 2018 03:10:57 PM EDT.
GeoIP-GeoLite-data.noarch                                        2018.06-1.fc28                      updates 
LibRaw.x86_64                                                    0.18.13-1.fc28                      updates 
rkManager-openvpn.x86_64            1:1.8.4-1.fc28                                  updates 
NetworkManager-openvpn-gnome.x86_64                              1:1.8.4-1.fc28                      updates 
grub2-tools-extra.x86_64                                         1:2.02-38.fc28                      updates 
grub2-tools.x86_64                  1:2.02-34.fc28                                  @anaconda
grub2-tools-minimal.x86_64                                       1:2.02-38.fc28                      updates 
grub2-tools.x86_64                  1:2.02-34.fc28                                  @anaconda
kernel-headers.x86_64                                            4.17.9-200.fc28                     updates 
kernel-headers.x86_64               4.16.3-301.fc28                                 @anaconda
[root@localhost philip]#

要安装软件包,我们使用install选项:

[root@localhost philip]# dnf install BitchX.x86_64
Last metadata expiration check: 0:20:30 ago on Tue 31 Jul 2018 03:10:57 PM EDT.
Dependencies resolved.
==========================================================================================================================
Package                    Arch                       Version                           Repository                  Size
==========================================================================================================================
Installing:
BitchX                     x86_64                     1.2.1-15.fc28                     fedora                     1.6 M
Transaction Summary
==========================================================================================================================
Install  1 Package
Total download size: 1.6 M
Installed size: 3.3 M
Is this ok [y/N]: y
Installed:
 BitchX.x86_64 1.2.1-15.fc28 
Complete!
[root@localhost philip]#

干得好!正如你现在所看到的,这些选项与它们较旧的 YUM 对应项相似。同样,要删除一个软件包,我们使用remove选项:

[root@localhost philip]# dnf remove BitchX.x86_64
Dependencies resolved.
==========================================================================================================================
Package Arch Version Repository Size
==========================================================================================================================
Removing:
BitchX x86_64 1.2.1-15.fc28 @fedora 3.3 M
Transaction Summary
==========================================================================================================================
Remove 1 Package
Freed space: 3.3 M
Is this ok [y/N]: y
Running transaction check
Preparing : 1/1
Erasing : BitchX-1.2.1-15.fc28.x86_64 1/1
Verifying : BitchX-1.2.1-15.fc28.x86_64 1/1
Removed:
BitchX.x8
6_64 1.2.1-15.fc28
Complete!
[root@localhost philip]#

我们还可以删除仅用于满足依赖关系的软件包。为此,我们使用autoremove选项:

[root@localhost philip]# dnf autoremove
Last metadata expiration check: 0:25:12 ago on Tue 31 Jul 2018 03:10:57 PM EDT.
Dependencies resolved.
Nothing to do.
Complete!
[root@localhost philip]#  

如果我们想要查看已执行的各种dnf命令,我们可以使用history选项:

[root@localhost philip]# dnf history
ID     | Command line             | Date and time    | Action(s)      | Altered
-------------------------------------------------------------------------------
3 | remove BitchX.x86_64     | 2018-07-31 15:33 | Erase          |    1 
2 | install BitchX.x86_64    | 2018-07-31 15:31 | Install        |    1 
1 |                          | 2018-04-25 02:33 | Install        | 1596 EE
[root@localhost philip]#

当我们试图跟踪系统中发生了什么变化时,这是非常有用的。在对系统进行任何更新之前,做一些清理工作总是一个好主意。我们可以使用clean all选项:

[root@localhost philip]# dnf clean all
18 files removed
[root@localhost philip]#

最后,要更新系统上的所有软件包,我们使用update选项:

[root@localhost philip]# dnf update
Last metadata expiration check: 0:11:49 ago on Tue 31 Jul 2018 03:48:23 PM EDT.
Dependencies resolved.
==========================================================================================================================
Package                                         Arch         Version                                 Repository     Size
==========================================================================================================================
Upgrading:
GeoIP-GeoLite-data   noarch 2018.06-1.fc28                        updates         551 k
LibRaw         x86_64       0.18.13-1.fc28                          updates
libkcapi        x86_64       1.1.1-6.fc28                            updates        44 k
libkcapi-hmaccalc         x86_64       1.1.1-6.fc28                            updates        26 k
libnice         x86_64       0.1.14-7.20180504git34d6044.fc28        updates       173 k
libvirt-daemon-config-network    x86_64       4.1.0-3.fc28                            updates        10 k
rpm-sign-libs  x86_64       4.14.1-9.fc28                           updates        73 k
xmlsec1-nss    x86_64       1.2.25-4.fc28                           updates        79 k
Transaction Summary
==========================================================================================================================
Install   11 Packages
Upgrade  736 Packages
Total download size: 1.0 G
Is this ok [y/N]: y

我们还可以传递upgrade选项,这是更新的:

[root@localhost philip]# dnf upgrade
Last metadata expiration check: 0:11:49 ago on Tue 31 Jul 2018 03:48:23 PM EDT.
Dependencies resolved.
==========================================================================================================================
Package                                         Arch         Version                                 Repository     Size
==========================================================================================================================
Upgrading:
GeoIP-GeoLite-data                              noarch       2018.06-1.fc28                          updates       551 k
LibRaw                                          x86_64       0.18.13-1.fc28                          updates
libkcapi                                        x86_64       1.1.1-6.fc28                            updates        44 k
libkcapi-hmaccalc                               x86_64       1.1.1-6.fc28                            updates        26 k
libnice                                         x86_64       0.1.14-7.20180504git34d6044.fc28        updates       173 k
libvirt-daemon-config-network                   x86_64       4.1.0-3.fc28                            updates        10 k
rpm-sign-libs                                   x86_64       4.14.1-9.fc28                           updates        73 k
xmlsec1-nss                                     x86_64       1.2.25-4.fc28                           updates        79 k
Transaction Summary
==========================================================================================================================
Install   11 Packages
Upgrade  736 Packages
Total download size: 1.0 G
Is this ok [y/N]: y

正如我们所看到的,这个过程是相同的。

RPM

Red Hat Package Manager,也称为RPM,是一个在基于 RPM 的 Linux 发行版中安装、卸载和管理软件包的程序。有各种实用程序在后台使用rpm实用程序,比如yumdnf等。它的性质类似于其对应的dpkg实用程序。每当有依赖性要求时,通常必须手动查找必要的文件并安装它们。rpm管理的所有软件包都以rpm扩展名结尾。

首先,我们可以检查软件包的rpm签名,并使用--check-sig选项:

[root@localhost Downloads]# rpm --checksig gnome-calculator-3.22.3-1.el7.x86_64.rpm
gnome-calculator-3.22.3-1.el7.x86_64.rpm: rsa sha1 (md5) pgp md5 OK
[root@localhost Downloads]#

根据前面的输出,签名已通过rpm实用程序的检查。我们还可以检查特定软件包的依赖关系。我们使用qpR选项:

[root@localhost Downloads]# rpm -qpR gnome-calculator-3.22.3-1.el7.x86_64.rpm
/bin/sh
/bin/sh
libatk-1.0.so.0()(64bit)
libc.so.6()(64bit)
libc.so.6(GLIBC_2.14)(64bit)
libc.so.6(GLIBC_2.2.5)(64bit)
libc.so.6(GLIBC_2.3.4)(64bit)
libgmp.so.10()(64bit)
rtld(GNU_HASH)
rpmlib(PayloadIsXz) <= 5.2-1
[root@localhost Downloads]#

请注意,q表示查询,p表示列出软件包提供的功能,R表示列出软件包依赖的功能。

为了查看最近安装的所有软件包,我们可以结合使用qa--last

[root@localhost Downloads]# rpm -qa --last
gpg-pubkey-f4a80eb5-53a7ff4b                  Tue 31 Jul 2018 08:30:07 AM PDT
words-3.0-22.el7.noarch                       Wed 20 Jun 2018 09:29:01 AM PDT
iwl6000-firmware-9.221.4.1-56.el7.noarch      Wed 20 Jun 2018 09:29:01 AM PDT
iwl6050-firmware-41.28.5.1-56.el7.noarch      Wed 20 Jun 2018 09:29:00 AM PDT
iwl6000g2b-firmware-17.168.5.2-56.el7.noarch  Wed 20 Jun 2018 09:29:00 AM PDT
iwl4965-firmware-228.61.2.24-56.el7.noarch    Wed 20 Jun 2018 09:29:00 AM PDT
iwl3945-firmware-15.32.2.9-56.el7.noarch      Wed 20 Jun 2018 09:29:00 AM PDT
iwl100-firmware-39.31.5.1-56.el7.noarch       Wed 20 Jun 2018 09:29:00 AM PDT
iwl7265-firmware-22.0.7.0-56.el7.noarch       Wed 20 Jun 2018 09:28:59 AM PDT
fontpackages-filesystem-1.44-8.el7.noarch     Wed 20 Jun 2018 09:15:44 AM PDT
centos-release-7-4.1708.el7.centos.x86_64     Wed 20 Jun 2018 09:15:44 AM PDT
[root@localhost Downloads]#

我们还可以通过传递软件包名称来搜索特定软件包:

[root@localhost Downloads]# rpm -qa ntp
ntp-4.2.6p5-25.el7.centos.2.x86_64
[root@localhost Downloads]#

在这种情况下,我们搜索ntp软件包。我们可以获取有关特定软件包的更多信息。我们可以传递qi选项:

[root@localhost Downloads]# rpm -qi ntp
Name : ntp
Version : 4.2.6p5
Vendor : CentOS
URL : http://www.ntp.org
Summary : The NTP daemon and utilities
Description :
The Network Time Protocol (NTP) is used to synchronize a computer's
time with another reference time source. This package includes ntpd
(a daemon which continuously adjusts system time) and utilities used
to query and configure the ntpd daemon.
 [root@localhost Downloads]#

有趣的是,在安装软件包之前,我们实际上可以获取有关该软件包的信息,然后决定是中止还是继续安装:

[root@localhost Downloads]# rpm -qa gnome-calculator
gnome-calculator-3.22.3-1.el7.x86_64
[root@localhost Downloads]# rpm -e gnome-calculator
[root@localhost Downloads]# rpm -qa gnome-calculator
[root@localhost Downloads]#

我们查询了 GNOME 计算器,因为它是预装在这个 CentOS 7 系统中的。然后我们删除了该软件包并再次查询。现在我们将在下载的rpm软件包上传递qip

[root@localhost Downloads]# rpm -qip gnome-calculator-3.22.3-1.el7.x86_64.rpm
Name        : gnome-calculator
Version     : 3.22.3
Release     : 1.el7
Architecture: x86_64
Install Date: (not installed)
Group       : Unspecified
Size        : 5053847
Summary     : A desktop calculator
Description :
gnome-calculator is a powerful graphical calculator with financial,
logical and scientific modes. It uses a multiple precision package
to do its arithmetic to give a high degree of accuracy.
[root@localhost Downloads]#

看哪!正如我们所看到的,rpm实用程序非常强大。要安装软件包,我们使用-i--install选项:

[root@localhost Downloads]# rpm --install gnome-calculator-3.22.3-1.el7.x86_64.rpm
 [root@localhost Downloads]# rpm -qa  gnome-calculator
gnome-calculator-3.22.3-1.el7.x86_64
[root@localhost Downloads]#

根据前面的输出,我们可以看到我们的软件包已成功使用rpm实用程序安装。

我们可以查看特定软件包的所有文件:

[root@localhost Downloads]# rpm -ql gnome-calculator
/usr/bin/gcalccmd
/usr/bin/gnome-calculator
/usr/lib64/gnome-calculator
/usr/share/applications/gnome-calculator.desktop
/usr/share/man/man1/gnome-calculator.1.gz
[root@localhost Downloads]#

同样,我们可以通过传递-e选项来删除一个软件包。我们还可以通过添加-v选项来查看删除软件包的过程:

[root@localhost Downloads]# rpm -ev gnome-calculator
Preparing packages...
gnome-calculator-3.22.3-1.el7.x86_64
[root@localhost Downloads]#

太棒了!最后,我们可以使用-qf选项确定特定配置文件属于哪个软件包:

[root@localhost Downloads]#  rpm -qf /etc/rsyslog.conf
rsyslog-8.24.0-12.el7.x86_64
[root@localhost Downloads]#

yumex

YUM extender,或者简称为yumex,是yumdnf实用程序的前端。默认情况下,yumex不会预装在 Fedora 28 中。这可以通过在 shell 中安装yumex实用程序来轻松解决:

[root@localhost philip]# dnf install yumex-dnf
Last metadata expiration check: 0:01:38 ago on Thu 02 Aug 2018 10:30:42 AM EDT.
Dependencies resolved.
==========================================================================================================================
Package                              Arch           Version                                        Repository       Size
==========================================================================================================================
Installing:
dnfdragora                           noarch         1.0.1-10.git20180108.b0e8a66.fc28         fedora          364 k
Installing dependencies:
checkpolicy                          x86_64         2.8-1.fc28                                     updates         336 k
dnfdaemon                            noarch         0.3.18-6.fc28                                  fedora           64 k
python3-dnfdaemon                    noarch         0.3.18-6.fc28                                  fedora           23 k
python3-libsemanage                  x86_64         2.7-12.fc28                                    fedora          125 k
Transaction Summary
==========================================================================================================================
Install  23 Packages
Total download size: 5.6 M
Installed size: 17 M
Is this ok [y/N]: y

正如您所看到的,在 Fedora 28 上安装yumex非常简单。对于 CentOS 7,我们首先安装企业版 Linux 的额外软件包EPEL):

[root@localhost philip]# yum install epel-release
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: mirror.as24220.net
 * extras: mirror.as24220.net
 * updates: mirror.as24220.net
Resolving Dependencies
--> Running transaction check
---> Package epel-release.noarch 0:7-11 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
================================================================================
Package                Arch             Version         Repository        Size
================================================================================
Installing:
epel-release           noarch           7-11            extras            15 k
Transaction Summary
================================================================================
Install  1 Package
Total download size: 15 k
Installed size: 24 k
Is this ok [y/d/N]: y
Downloading packages:
epel-release-7-11.noarch.rpm                               |  15 kB   00:03 
Installing : epel-release-7-11.noarch                                     1/1
Verifying  : epel-release-7-11.noarch                                     1/1
Installed:
epel-release.noarch 0:7-11 
Complete!
[root@localhost philip]#

接下来,我们安装实际的yumex实用程序:

[root@localhost philip]# yum install yumex
Loaded plugins: fastestmirror, langpacks
epel/x86_64/metalink | 4.0 kB 00:00 
epel | 3.2 kB 00:00 
(1/3): epel/x86_64/group_gz | 88 kB 00:01 
(2/3): epel/x86_64/updateinfo | 927 kB 00:02 
(3/3): epel/x86_64/primary | 3.6 MB 00:00:16 
Loading mirror speeds from cached hostfile
 * base: mirror.as24220.net
.net
epel 12639/12639
Resolving Dependencies
--> Running transaction check
---> Package yumex.noarch 0:3.0.17-1.el7 will be installed
--> Processing Dependency: pexpect for package: yumex-3.0.17-1.el7.noarch
---> Package python2-pyxdg.noarch 0:0.25-6.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
============
Package Arch Version Repository Size
===========
Installing:
yumex noarch 3.0.17-1.el7 epel 444 k
Installing for dependencies:
pexpect noarch 2.3-11.el7 base 142 k
python2-pyxdg noarch 0.25-6.el7 epel 89 k
Transaction Summary
======================================================================================================================================================
Install 1 Package (+2 Dependent packages)
Total download size: 675 k
Installed size: 2.7 M
Is this ok [y/d/N]: y
Downloading packages:
warning: /var/cache/yum/x86_64/7/epel/packages/python2-pyxdg-0.25-6.el7.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY-:--:-- ETA
------------------------------------------------------------------------------------------------------------------------------------------------------
Total 167 kB/s | 675 kB 00:00:04 
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
Importing GPG key 0x352C64E5:
Userid : "Fedora EPEL (7) <epel@fedoraproject.org>"
Fingerprint: 91e9 7d7c 4a5e 96f1 7f3e 888f 6a2f aea2 352c 64e5
 Package : epel-release-7-11.noarch (@extras)
 From : /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
Is this ok [y/N]: y
Transaction test succeeded
Running transaction
 Installing : yumex-3.0.17-1.el7.noarch 3/3
warning: /etc/yumex.conf created as /etc/yumex.conf.rpmnew
 Verifying : yumex-3.0.17-1.el7.noarch 1/3
 Verifying : pexpect-2.3-11.el7.noarch 3/3
Installed:
 yumex.noarch 0:3.0.17-1.el7 
Dependency Installed:
pexpect.noarch 0:2.3-11.el7 python2-pyxdg.noarch 0:0.25-6.el7 
Complete!
[root@localhost philip]#

在 CentOS 7 上安装yumex的步骤与 Fedora 28 几乎相似。最后,我们可以在 shell 或 GUI 中启动yumex实用程序。我们将演示 shell 方法:

[root@localhost philip]# yumex &
[1] 2884
[root@localhost philip]# Don't run yumex as root it is unsafe (Use --root to force)

从前面的输出中,清楚地表明我们不应该以 root 身份运行yumex实用程序。相反,我们将以非 root 用户身份运行yumex实用程序:

root@localhost philip]# exit
exit
[philip@localhost ~]$ yumex &
[1] 2937
[philip@localhost ~]$ 07:48:33 : INFO - Using config file : /home/philip/.config/yumex/yumex.conf
07:48:33 : INFO - Using config file : /home/philip/.config/yumex/yumex.conf
(<class 'dbus.exceptions.DBusException'>, DBusException('Rejected send message, 2 matched rules; type="method_call", sender=":1.115" (uid=1000 pid=2937 comm="/usr/bin/python -tt /usr/bin/yumex ") interface="(unset)" member="GetDevices" error name="(unset)" requested_reply="0" destination=":1.8" (uid=0 pid=633 comm="/usr/sbin/NetworkManager --no-daemon ")',), <traceback object at 0x2ac5ef0>)
(<class 'dbus.exceptions.DBusException'>, DBusException('Rejected send message, 2 matched rules; type="method_call", sender=":1.115" (uid=1000 pid=2937 comm="/usr/bin/python -tt /usr/bin/yumex ") interface="(unset)" member="GetDevices" error name="(unset)" requested_reply="0" destination=":1.8" (uid=0 pid=633 comm="/usr/sbin/NetworkManager --no-daemon ")',), <traceback object at 0x2ac6ef0>)

具有讽刺意味的是,我们被提示输入 root 密码——对一些人来说可能会感到困惑,但对我们来说不会。这是因为我们以非 root 用户身份启动了yumex实用程序。对于yumex实用程序的运行,我们需要 root 权限。原因是它管理软件包。非 root 用户默认情况下无法管理软件包。因此,我们将进行身份验证,然后我们将看到nifty yumex实用程序的界面:

我们立即注意到,我们有一个漂亮的用户友好的 GUI,可以在其中工作。顶部有一个菜单栏和一个用于查找特定软件包的搜索字段。我们只需输入软件包的名称,例如:

太棒了!我们得到了一个给定软件包的很好描述,我们可以选择复选框,然后点击应用,软件包就会被安装。

总结

在本章中,我们深入探讨了红帽世界内的软件包管理;特别是yumdnfrpmyumex实用程序。我们首先介绍了yum并查看了可用的软件包;接下来,需要更新yum缓存,因此我们进行了更新。之后,我们格式化软件包以以组格式显示。

接着,我们公开了给定软件包的信息。然后,我们通过选择一个文件并发现它来自哪个软件包来进行了一些逆向工程。然后演示了搜索软件包的步骤。之后,我们在执行系统更新之前删除了不需要的文件。

此外,我们进行了一个演示,演示了安装软件包,然后说明了删除软件包的步骤。最后,我们使用 YUM 执行了系统更新。然后我们介绍了dnf实用程序,并看到了dnfyum之间的相似之处。Fedora 28 演示表明yum只是dnf的别名。

接下来,我们看了使用dnf查看repo列表的方法,以及搜索给定软件包的方法。与yum类似,使用配置文件,我们找到了相应的配置文件软件包。最后,我们演示了如何使用yum添加软件包。还演示了删除软件包的反面。

通过与rpm一起工作,我们看到了如何检查软件包的签名。此外,我们公开了给定软件包的信息,并演示了使用rpm实用程序安装和删除软件包。最后,重点放在了yumex上。yumex实用程序是yumdnf的前端。它不是默认预安装的。在 Fedora 28 环境中演示了安装yumex的演示;同样,我们看到了在 CentOS 7 中安装yumex实用程序所需的必要步骤。最后,我们使用yumex实用程序,搜索给定软件包并查看该软件包的描述。

在下一章中,我们将使用 shell 中的各种实用工具。您将更好地准备好浏览文件系统,创建文件、目录等。我们将查看文件权限,查看隐藏文件和目录,并在 shell 中执行搜索。下一章涵盖的技能对于任何 Linux 工程师在命令行环境中高效工作至关重要。完成下一章后,您将更加自信地进行文件管理。这将使您能够在追求认证的过程中征服另一个里程碑。

问题

  1. 哪个选项与yum命令一起用于显示系统上的包?

A. yum --display

B. yum --list

C. yum list

D. yum --verbose

  1. 哪个命令用于更新cache

A. yum makecache fast

B. yum cache --update

C. yum –update --cache

D. yum –make --list

  1. 哪个命令可以用来识别配置文件中的包?

A. yum --get-information

B. yum --display-information

C. yum --provides

D. yum provides

  1. 哪个选项用于显示使用dpkg命令安装的包?

A. dpkg --get-selections

B. dpkg –set-selections

C. dpkg –get-selection

D. dpkg-query –get-selection

  1. 哪个命令用于删除不再需要的任何temp文件?

A. yum remove cache

B. yum clean all

C. yum clean temp

D. yum remove temp

  1. 哪个命令用于更新系统?

A. yum update

B. yum auto-update

C. yum clean update

D. yum purge update

  1. 哪个命令用于显示已启用和已禁用的仓库?

A. dnf --repo-list

B. dnf repolist all

C. dnf list repo

D. dnf --repo-list --all

  1. 哪个命令用于检查更新?

A. dnf check-update

B. dnf --update-check

C. dnf --list-update

D. dnf --get-list -updates

  1. 哪个命令用于在安装包之前公开包的信息?

A. rpm -qa

B. rpm -qic

C. rpm -qip

D. rpm -qe

  1. 哪个命令用于删除一个包?

A. rpm --remove

B. rpm --erase

C. rpm --delete

D. aptitude --purge

进一步阅读

  • 您可以在centos.org获取有关 CentOS 发行版的更多信息,例如安装、配置最佳实践等。

  • 有关 Fedora 的更多信息以及下载副本并进行一些实际操作,请参见:getfedora.org

第八章:执行文件管理

在上一章中,我们处理了 Red Hat 世界中的软件包管理。特别是,我们涵盖了yumdnfrpmyumex实用程序。

在本章中,我们的重点将转向文件管理。我们将探讨在 shell 中工作的方法。我们将致力于创建,修改和删除文件。此外,我们将使用目录,演示如何创建,移动和删除目录。接下来,我们将涉及对文件和目录进行搜索。最后,我们将涵盖管道和重定向。

本章将涵盖以下主题:

  • 在 CLI 中查看和移动文件和目录

  • 创建,复制,移动,重命名和删除文件

  • 创建和删除目录

  • 查找文件和目录

  • 管道和重定向

在 CLI 中查看和移动文件和目录

首先,您需要熟悉在 CLI 中的工作。在前几章中,我们与 shell 进行了交互。现在,我们希望在 CLI 中变得高效。当我们首次打开终端时,我们被放置在用户的主目录中,如下所示:

[philip@localhost ~]$

在上述输出中,我们被放置到用户philip的主目录中。可以通过发出打印工作目录(pwd)命令来确认这一点,如下所示:

[philip@localhost ~]$ pwd
/home/philip
[philip@localhost ~]$

在上述输出中,我们确认了我们确实在/home/philip目录中。但是,更有趣的是。/home/philip内有各种目录。我们可以通过使用列表(ls)命令来确认这一点,如下所示:

[philip@localhost ~]$ ls
Desktop  Documents  Downloads  Music  Pictures  Public  Templates  Videos
[philip@localhost ~]$

上述输出中列出的目录(文件夹)是为系统中的每个用户创建的。现在,目录的显示方式并没有告诉我们很多。为了深入了解,我们可以再次发出ls命令;这次,我们将传递-l选项。-l选项会显示文件类型,用户权限,组权限,用户所有权,组所有权,大小和上次修改日期等信息,如下所示:

[philip@localhost ~]$ ls -l
total 32
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Desktop
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Documents
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Downloads
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Music
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Pictures
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Public
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Templates
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Videos
[philip@localhost ~]$

我们可以从上述输出中获得一些有用的信息。例如,每个目录都有权限;我们还可以看到所有权和大小。此外,在 Linux 中,我们有所谓的隐藏文件/文件夹。当我们执行列表时,默认情况下不会显示它们;要获取它们,我们必须添加-a选项:

[philip@localhost ~]$ ls -al
drwx------. 15 philip philip 4096 Aug  2 10:28 .
drwxr-xr-x.  3 root   root   4096 Jul 31 14:58 ..
-rw-r--r--.  1 philip philip   18 Mar 15 09:56 .bash_logout
-rw-r--r--.  1 philip philip  193 Mar 15 09:56 .bash_profile
-rw-r--r--.  1 philip philip  231 Mar 15 09:56 .bashrc
drwx------. 14 philip philip 4096 Jul 31 14:59 .cache
drwx------. 14 philip philip 4096 Jul 31 14:59 .config
drwxr-xr-x.  2 philip philip 4096 Jul 31 14:59 Desktop
drwxr-xr-x.  2 philip philip 4096 Jul 31 14:59 Documents
drwxr-xr-x.  2 philip philip 4096 Jul 31 14:59 Downloads
-rw-------.  1 philip philip   16 Jul 31 14:58 .esd_auth
-rw-------.  1 philip philip  620 Aug  2 10:28 .ICEauthority
drwx------.  3 philip philip 4096 Jul 31 14:59 .local
drwxr-xr-x.  4 philip philip 4096 Apr 25 02:33 .mozilla
drwxr-xr-x.  2 philip philip 4096 Jul 31 14:59 Music
drwxr-xr-x.  2 philip philip 4096 Jul 31 14:59 Pictures
drwxrw----.  3 philip philip 4096 Jul 31 14:59 .pki
[philip@localhost ~]$

太棒了!这样,我们可以知道文件或目录是否被隐藏;这些文件/目录的名称前面有一个句点。为了在目录之间移动,我们使用cd命令。更改目录或cd允许我们导航 Linux 文件系统。所以,让我们继续到/home/philip/Documents。我们使用以下命令:

[philip@localhost ~]$ cd /home/philip/Documents
[philip@localhost Documents]$

还有另一种在目录之间移动的方法。我们使用的第一种方法称为绝对路径;这意味着我们指定了到目录的完整路径。在目录之间移动的下一种方法是指定相对路径,如下所示:

[philip@localhost ~]$ cd Documents/
[philip@localhost Documents]$

相对方法要求您必须在子目录的父目录中才能工作。

一旦我们进入子目录,我们可以执行ls命令,如下所示:

[philip@localhost Documents]$ ls
[philip@localhost Documents]$

当前,该目录中没有内容。为了返回到父目录,我们可以使用cd命令,如下所示:

[philip@localhost Documents]$ cd /home/philip
[philip@localhost ~]$ pwd
/home/philip
[philip@localhost ~]$

在上述输出中,我们指定了路径。这种方法总是有效的。我们还可以以另一种方式使用cd命令,如下所示:

[philip@localhost Documents]$ cd ..
[philip@localhost ~]$

在上述方法中,我们使用了双点。双点表示父目录。如果我们指定了一个单点,结果将如下所示:

[philip@localhost Documents]$ cd .
[philip@localhost Documents]$

单点引用当前目录本身。无论您在哪里,都可以使用以下方法:

[philip@localhost Documents]$ cd ~
[philip@localhost ~]$

波浪号(~)字符将始终将我们带回用户的主目录。为了说明这一点,我们将进入/etc目录,如下所示:

[philip@localhost ~]$ cd /etc
[philip@localhost etc]$ pwd
/etc
[philip@localhost etc]$

现在,我们将再次发出cd命令,传递波浪号(~):

[philip@localhost etc]$ cd ~
[philip@localhost ~]$ pwd
/home/philip
[philip@localhost ~]$

太棒了!您现在可以看到波浪号(~)字符的威力。在文件系统层次结构的顶部是根目录。我们通常将根目录称为/;这不应与/root目录混淆。后者是 root 用户的主目录。从/开始创建所有其他目录。我们可以这样进入/

[philip@localhost ~]$ cd /
[philip@localhost /]$ pwd
/
[philip@localhost /]$

在上述输出中,我们位于文件系统的根目录。我们可以以类似的方式查看此目录,如下所示:

[philip@localhost /]$ ls
bin   dev  home  lib64       media  opt   root  sbin  sys  usr
boot  etc  lib   lost+found  mnt    proc  run   srv   tmp  var
[philip@localhost /]$

您会注意到这里有一些熟悉的目录,比如/home/dev。有趣的是,我们可以看到列出了/root目录。我们可以切换到该目录并执行列表,如下所示:

[philip@localhost /]$ cd /root
bash: cd: /root: Permission denied
[philip@localhost /]$ 

由于我们没有权限查看/root目录,所以出现了上述错误。让我们以 root 用户的身份进行身份验证并重试,如下所示:

[root@localhost /]# cd /root
[root@localhost ~]#

看吧!我们现在位于/root目录。这一次,当我们列出时,我们会立刻注意到这不是/目录:

[root@localhost ~]# ls
anaconda-ks.cfg
[root@localhost ~]#

根据上述输出,浏览目录结构相当直观。

创建、复制、移动、重命名和删除文件

这一部分听起来有点复杂。不用担心;它涵盖了创建和删除文件的技术。它还涵盖了复制和重命名文件的方法。

我们每天使用各种文件。我们可以在/home/philip/Documents/NewTest目录上执行ls命令,如下所示:

philip@localhost Documents]$ cd NewTest/
[philip@localhost NewTest]$ ll -a
total 8
drwxrwxr-x. 2 philip philip 4096 Aug  6 12:04 .
drwxr-xr-x. 3 philip philip 4096 Aug  6 13:45 ..
[philip@localhost NewTest]$

目前,该目录内没有任何文件。在 Linux 中,我们可以从 shell 中创建文件;我们可以使用touch命令来实现这一点:

[philip@localhost NewTest]$ touch OurFile
[philip@localhost NewTest]$ ll
total 0
-rw-rw-r--. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$

该文件是使用一些默认权限创建的。特别地,-rw-rw-r--表示用户(-rw)、组(-rw)和其他人(-r--)。第一个破折号(-)是文件类型的引用。在这种情况下,它是一个常规文件。(rw-)表示用户/所有者具有读取和写入权限。第二组rw-表示组也具有读取和执行权限。最后,r--表示其他人(所有其他人)具有读取权限。另外,philip philip部分指的是文件的所有者和文件所属的组。我们可以使用chmod命令更改此文件的权限。假设我们想要给其他人(所有其他人)读取和写入权限。我们可以这样做:

[philip@localhost NewTest]$ chmod o+w OurFile
[philip@localhost NewTest]$ ll
total 0
-rw-rw-rw-. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$

太棒了!我们现在可以看到其他权限为rw-。除了使用o+w之外,还有另一种更改权限的方法,那就是使用数字值。我将使用数字格式将其他人改回r--,如下所示:

[philip@localhost NewTest]$ chmod 664 OurFile
[philip@localhost NewTest]$ ll
total 0
-rw-rw-r--. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$

我们可以将上述代码解读如下:在664中,6等于读取和写入,6等于读取和写入,4等于读取。第一个数字是用户的占位符。第二个数字是组的占位符,最后一个数字是其他的占位符。为了进一步说明这一点,我们可以去掉读取并保留写入组权限,如下所示:

[philip@localhost NewTest]$ chmod 624 OurFile
[philip@localhost NewTest]$ ll
total 0
-rw--w-r--. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$

同样地,我们可以通过增加数值来添加权限。让我们选择其他人;我们将给其他人读取和执行权限,如下所示:

[philip@localhost NewTest]$ chmod 625 OurFile
[philip@localhost NewTest]$ ll
total 0
-rw--w-r-x. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$

太棒了!我们甚至可以在单个命令中为用户、组或其他人提供所有权限(读取、写入和执行)。让我们从用户开始,如下所示:

[philip@localhost NewTest]$ ll
total 0
-rwx-w-r-x. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$

现在,我们可以看到用户具有读取、写入和执行权限。我通过将读取等于4、写入等于2和执行等于1相加得到值7。我们现在将给组所有权限,如下所示:

[philip@localhost NewTest]$ chmod 775 OurFile
[philip@localhost NewTest]$ ll
total 0
-rwxrwxr-x. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$

太棒了!我们还可以在单个命令中删除用户、组或其他人的所有权限。让我们删除其他人的权限(读取、写入和执行),如下所示:

[philip@localhost NewTest]$ chmod 770 OurFile
[philip@localhost NewTest]$ ll
total 0
-rwxrwx---. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$

放置零(0)会取消特定部分(用户、组或其他)的所有权限。您可以看到权限的强大。同样,我们可以使用字母,就像之前看到的那样。u表示用户,g表示组,o表示其他。我们可以按如下方式从组中删除执行权限:

[philip@localhost NewTest]$ chmod g-x OurFile
[philip@localhost NewTest]$ ll
total 0
-rwxrw----. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$

我们可以使用加号(+)符号(添加权限)或减号(-)符号(删除权限)。我们还可以将文件从一个位置复制到另一个位置,或者在同一个位置内部。如果文件的目的地在与源相同的位置内部,则必须给出不同的名称。

cp命令用于复制。我们将复制文件并将其放在/home/philip/Documents/中,如下所示:

[philip@localhost NewTest]$ cp OurFile /home/philip/Documents/NewFile
[philip@localhost NewTest]$ ll /home/philip/Documents/
-rwxrw----. 1 philip philip 0 Aug 6 14:34 NewFile
drwxrwxr-x. 2 philip philip 4096 Aug 6 13:52 NewTest
[philip@localhost NewTest]$

太棒了!

目录的权限前面有一个d

我们还可以移动文件;mv命令用于移动文件。让我们移动/home/philip/Documents/NewFile并将其放在/home/philip/Documents/NewTest中:

[philip@localhost NewTest]$ mv /home/philip/Documents/NewFile .
[philip@localhost NewTest]$ ll
-rwxrw----. 1 philip philip 0 Aug  6 14:34 NewFile
-rwxrw----. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$  

我们使用的方法是为位置指定一个句点(.)。这表示当前工作目录;因此,我们可以使用句点(.)而不是键入完整的目标路径。

我们还可以使用mv命令重命名文件。让我们重命名NewFile

[philip@localhost NewTest]$ mv NewFile RenameFile
[philip@localhost NewTest]$ ll
total 0
-rwxrw----. 1 philip philip 0 Aug  6 13:52 OurFile
-rwxrw----. 1 philip philip 0 Aug  6 14:34 RenameFile
[philip@localhost NewTest]$

哇!我们还可以重命名文件并将其放在另一个目录中,如下所示:

[philip@localhost NewTest]$ mv RenameFile /home/philip/Documents/
[philip@localhost NewTest]$ ll
-rwxrw----. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$

该文件不再位于当前目录中,而是位于/home/philip/Documents目录中:

[philip@localhost NewTest]$ ll /home/philip/Documents/
total 4
drwxrwxr-x. 2 philip philip 4096 Aug  6 14:57 NewTest
-rwxrw----. 1 philip philip    0 Aug  6 14:34 RenameFile
[philip@localhost NewTest]$

太棒了!我们还可以使用rm命令删除文件。让我们删除/home/philip/Documents/NewTest/OurFile,如下所示:

[philip@localhost NewTest]$ ll
total 0
-rwxrw----. 1 philip philip 0 Aug  6 13:52 OurFile
[philip@localhost NewTest]$ rm OurFile
[philip@localhost NewTest]$ ll
total 0
[philip@localhost NewTest]$

创建和删除目录

我们可以使用另一个常用命令来创建目录。mkdir命令可用于创建目录。让我们使用ls命令进行列表,如下所示:

[philip@localhost ~]$ ls
Desktop Documents Downloads Music Pictures Public Templates Videos
[philip@localhost ~]$

现在,让我们在/home/philip内创建自己的目录:

[philip@localhost ~]$ mkdir NewTest
[philip@localhost ~]$ ll
total 36
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Desktop
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Documents
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Downloads
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Music
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Pictures
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Public
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Templates
drwxrwxr-x. 2 philip philip 4096 Aug  6 12:04 NewTest
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Videos
[philip@localhost ~]$

在前面的代码中,我们的新目录列在底部。您还会注意到我们使用了ll命令;这只是ls -l命令的别名。可以通过使用which命令快速验证这一点,如下所示:

philip@localhost ~]$ which ll
alias ll='ls -l --color=auto'
 /usr/bin/ls
[philip@localhost ~]$

干得好!我们可以使用cd命令进入我们新创建的目录:

[philip@localhost ~]$ cd NewTest/
[philip@localhost NewTest]$ ls
[philip@localhost NewTest]$ pwd
/home/philip/NewTest
[philip@localhost NewTest]$

接下来,假设我们已经创建了一个目录并且打错了字。不用担心;我们可以利用mv命令,它可以重命名目录。让我们尝试重命名/home/Test目录:

[philip@localhost NewTest]$ pwd
/home/philip/Documents/NewTest
[philip@localhost NewTest]$ mv /home/philip/Documents/NewTest/ /home/philip/
[philip@localhost NewTest]$ pwd
/home/philip/Documents/NewTest
[philip@localhost NewTest]$

我们遇到这个错误是因为我们在目录内。让我们尝试带有-v选项的命令:

[philip@localhost NewTest]$ mv -v /home/philip/Documents/NewTest/ /home/philip/
mv: cannot stat '/home/philip/Documents/NewTest/'
[philip@localhost NewTest]$

为了解决这个问题,我们需要跳出目录,然后重新尝试mv命令,如下所示:

[philip@localhost ~]$ mv /home/philip/Documents/NewTest/ .
[philip@localhost ~]$ ll
total 36
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Desktop
drwxr-xr-x. 2 philip philip 4096 Aug  6 15:12 Documents
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Downloads
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Music
drwxrwxr-x. 2 philip philip 4096 Aug  6 15:00 NewTest
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Pictures
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Public
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Templates
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Videos
[philip@localhost ~]$

太棒了!现在,NewTest文件不再存在于/home/philip/Documents/中;这可以通过执行以下命令来显示:

[philip@localhost ~]$ ll Documents/
total 0
-rwxrw----. 1 philip philip 0 Aug  6 14:34 RenameFile
[philip@localhost ~]$

我们还可以使用mv命令重命名目录。诀窍是在调用mv命令时指定目录名称,如下所示:

[philip@localhost ~]$ mv NewTest/ ReName
[philip@localhost ~]$ ll
total 36
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Desktop
drwxr-xr-x. 2 philip philip 4096 Aug  6 15:12 Documents
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Downloads
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Music
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Pictures
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Public
drwxrwxr-x. 2 philip philip 4096 Aug  6 15:00 ReName
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Templates
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Videos
[philip@localhost ~]$

重命名目录就是这么简单。我们还可以更改目录的权限。让我们从组中删除读取、写入和执行权限,如下所示:

[philip@localhost ~]$ chmod -R 705 ReName/
[philip@localhost ~]$ ll
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Desktop
drwxr-xr-x. 2 philip philip 4096 Aug  6 15:12 Documents
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Downloads
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Music
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Pictures
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Public
drwx---r-x. 2 philip philip 4096 Aug  6 15:00 ReName
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Templates
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Videos
[philip@localhost ~]$

太棒了!-R选项告诉chmod命令将权限应用于/home/philip/ReName目录内的所有内容。当我们完成一个目录时,我们可以删除它。rmdir命令用于删除目录。让我们删除/home/philip/ReName目录,如下所示:

[philip@localhost ~]$ rmdir ReName/
[philip@localhost ~]$ ll
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Desktop
drwxr-xr-x. 2 philip philip 4096 Aug  6 15:12 Documents
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Downloads
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Music
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Pictures
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Public
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Templates
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Videos
[philip@localhost ~]$

基于前面的代码,没有遇到错误。在你的环境中可能不是这样。通常情况下,您要么有文件,要么有其他目录位于您试图删除的目录中。让我们快速创建一个目录,并在其中放置三个文件。然后,我们将尝试删除该目录:

[philip@localhost ~]$ mkdir TempDir
[philip@localhost ~]$ ll
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Desktop
drwxrwxr-x. 2 philip philip 4096 Aug  6 15:46 TempDir
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Templates
drwxr-xr-x. 2 philip philip 4096 Jul 31 14:59 Videos
[philip@localhost ~]$ touch TempDir/File1
[philip@localhost ~]$ touch TempDir/File2
[philip@localhost ~]$ touch TempDir/File3
[philip@localhost ~]$ ll TempDir/
total 0
-rw-rw-r--. 1 philip philip 0 Aug  6 15:47 File1
-rw-rw-r--. 1 philip philip 0 Aug  6 15:47 File2
-rw-rw-r--. 1 philip philip 0 Aug  6 15:47 File3
[philip@localhost ~]$  

现在,我们将重试rm命令并查看差异:

[philip@localhost ~]$ rmdir TempDir/
rmdir: failed to remove 'TempDir/': Directory not empty
[philip@localhost ~]$

瞧,我们遇到了一个错误。当目录不为空时,这是很常见的。我们可以很容易地解决这个问题;这次,我们将使用带有-rrm命令,这意味着删除其后的所有内容。我们还可以添加-v选项,它将显示任何潜在权限问题的详细信息:

[philip@localhost ~]$ ll TempDir/
total 0
-rw-rw-r--. 1 philip philip 0 Aug  6 15:53 File1
-rw-rw-r--. 1 philip philip 0 Aug  6 15:53 File2
-rw-rw-r--. 1 philip philip 0 Aug  6 15:53 File3
[philip@localhost ~]$ rm -rv TempDir/
removed 'TempDir/File3'
removed 'TempDir/File1'
removed 'TempDir/File2'
removed directory 'TempDir/'
[philip@localhost ~]$ ll TempDir/
ls: cannot access 'TempDir/': No such file or directory
[philip@localhost ~]$

太棒了!

您可以使用-f删除整个目录,而无需确认。

查找文件和目录

通常,我们会在图形用户界面中搜索文件和目录。我们也可以在 shell 中执行搜索。首先,我们可以使用find命令;让我们搜索具有.conf扩展名的文件。搜索功能如下:

[philip@localhost ~]$ find /etc -iname "*.cfg"
find: ‘/etc/grub.d': Permission denied
find: ‘/etc/cups/ssl': Permission denied
/etc/libblockdev/conf.d/00-default.cfg
find: ‘/etc/audit': Permission denied
find: ‘/etc/dhcp': Permission denied
find: ‘/etc/sssd': Permission denied
/etc/grub2.cfg
find: ‘/etc/audisp': Permission denied
find: ‘/etc/polkit-1/rules.d': Permission denied
find: ‘/etc/polkit-1/localauthority': Permission denied
find: ‘/etc/openvpn/server': Permission denied
find: ‘/etc/openvpn/client': Permission denied
 [philip@localhost ~]$

现在,如果您遇到这些错误,这表明您需要一些高级权限。让我们再次尝试搜索,作为 root 用户:

[philip@localhost ~]$ su
Password:
[root@localhost philip]# find /etc -iname "*.cfg"'
/etc/libblockdev/conf.d/00-default.cfg
/etc/grub2-efi.cfg
/etc/vdpau_wrapper.cfg
/etc/grub2.cfg
[root@localhost philip]#

太棒了!我们甚至可以扩大我们想要执行搜索的区域。让我们搜索整个文件系统,如下所示:

[root@localhost philip]# find / -iname "*.cfg"
/home/philip/.config/yelp/yelp.cfg
/run/media/philip/Fedora-WS-Live-28-1-1/EFI/BOOT/grub.cfg
/run/media/philip/Fedora-WS-Live-28-1-1/isolinux/isolinux.cfg
find: ‘/run/user/1000/gvfs': Permission denied
/usr/lib64/libreoffice/share/config/soffice.cfg
/usr/lib64/libreoffice/help/en-US/schart.cfg
/usr/lib64/libreoffice/help/en-US/smath.cfg
/usr/lib64/libreoffice/help/en-US/sbasic.cfg
grub2.cfg
/boot/grub2/grub.cfg
[root@localhost philip]

出于简洁起见,本章中省略了一些输出。

我们也可以根据名称的一部分进行搜索。让我们搜索以gru开头的任何文件:

[root@localhost philip]# find /boot -iname "gru*"
/boot/efi/EFI/fedora/grubia32.efi
/boot/efi/EFI/fedora/grubenv
/boot/efi/EFI/fedora/grubx64.efi
/boot/grub2
/boot/grub2/grub.cfg
/boot/grub2/grubenv
[root@localhost philip]#

在前面的输出中,我们在/boot目录中进行了搜索。空文件通常只是静静地放在目录中,没有被使用。我们可以使用find命令来搜索空文件。传递-type选项以指定我们要搜索的内容:

[root@localhost philip]# find /home/philip/Documents  -empty
/home/philip/Documents/RenameFile
[root@localhost philip]#

太棒了!但是,等等;我们可以通过传递-delete选项来进行一些清理,以删除find命令从我们的搜索中返回的任何文件。我们可以这样做:

使用-delete选项时要小心,因为它会在某些情况下删除文件,甚至删除目录。在运行带有-delete选项的find之前,始终备份数据。

[root@localhost philip]# find /home/philip/Documents  -empty -delete
[root@localhost philip]# ll /home/philip/Documentsls: cannot access '/home/philip/Documents': No such file or directory

在前面的输出中,您会注意到/home/philip/Documents/RenameFile以及/home/philip/Documents已被删除。每当您传递-delete选项时都要非常小心。尽管在我们的情况下,我们正在使用实验环境,请务必记住这一点。在尝试传递-delete选项之前备份数据。

我们还可以根据权限搜索文件或目录。是的!我们将使用find命令传递-readable-writable-executable选项。它将如下所示:

[root@localhost philip]# find /etc/yum.repos.d/ -readable
/etc/yum.repos.d/
/etc/yum.repos.d/fedora-updates.repo
/etc/yum.repos.d/fedora.repo
/etc/yum.repos.d/fedora-cisco-openh264.repo
/etc/yum.repos.d/fedora-updates-testing.repo
 [root@localhost philip]# ll /etc/yum.repos.d/
total 16
-rw-r--r--. 1 root root  707 Apr 23 13:03 fedora-cisco-openh264.repo
-rw-r--r--. 1 root root 1331 Apr 23 13:03 fedora.repo
-rw-r--r--. 1 root root 1392 Apr 23 13:03 fedora-updates.repo
-rw-r--r--. 1 root root 1450 Apr 23 13:03 fedora-updates-testing.repo
[root@localhost philip]#

太棒了!您可以看到find命令的结果与具有read权限的文件的列表匹配。同样,我们可以搜索具有执行权限的文件和目录,如下所示:

[root@localhost philip]# ll /etc/init.d/
total 52
-rw-r--r--. 1 root root 18561 Jan  2  2018 functions
-rwxr-xr-x. 1 root root  7288 Apr 25 02:39 livesys
-rwxr-xr-x. 1 root root  1054 Apr 25 02:39 livesys-late
-rwxr-xr-x. 1 root root  4334 Jan  2  2018 netconsole
-rwxr-xr-x. 1 root root  7613 Jan  2  2018 network
-rw-r--r--. 1 root root  1161 Apr 18 17:59 README[root@localhost philip]# find /etc/init.d/ -perm -o+x
/etc/init.d/
/etc/init.d/livesys
/etc/init.d/livesys-late
/etc/init.d/netconsole
/etc/init.d/network
[root@localhost philip]#

在前面的输出中,只显示了其他人具有执行权限的文件。

此外,我们可以搜索具有写权限的文件和目录,如下所示:

[root@localhost philip]# find /etc/init.d/ -perm -o+w
[root@localhost philip]#

干得好!结果为空,因为没有文件或目录对其他人有写权限。同样,我们可以使用数字进行搜索。我们可以搜索执行权限,如下所示:

[root@localhost philip]# find /etc/init.d/ -perm -005
/etc/init.d/
/etc/init.d/livesys
/etc/init.d/livesys-late
/etc/init.d/netconsole
/etc/init.d/network
[root@localhost philip]#

在前面的输出中,只显示具有执行权限的目录。我们可以搜索具有写权限的文件和目录,如下所示:

[root@localhost philip]# find /etc/init.d/ -perm -002
[root@localhost philip]#

有趣的是,结果如预期般返回,因为其他人没有写权限。同样,我们可以搜索组的写权限,如下所示:

[root@localhost philip]# ll /etc/init.d/
total 52
-rw-r--r--. 1 root root 18561 Jan  2  2018 functions
-rwxr-xr-x. 1 root root  7288 Apr 25 02:39 livesys
-rwxr-xr-x. 1 root root  1054 Apr 25 02:39 livesys-late
-rwxr-xr-x. 1 root root  4334 Jan  2  2018 netconsole
-rwxr-xr-x. 1 root root  7613 Jan  2  2018 network
-rw-r--r--. 1 root root  1161 Apr 18 17:59 README
[root@localhost philip]# find /etc/init.d/ -perm -020
[root@localhost philip]#

太棒了!结果为空,因为组没有写权限。最后,我们可以搜索用户的写权限;这将产生以下结果:

[root@localhost philip]# find /etc/init.d/ -perm -200
/etc/init.d/
/etc/init.d/functions
/etc/init.d/livesys
/etc/init.d/README
/etc/init.d/livesys-late
/etc/init.d/netconsole
/etc/init.d/network
[root@localhost philip]#

干得好!语法是-perm,后跟用户(第一个数字)、组(第二个数字)和其他人(最后一个数字)。

搜索文件和目录的另一种流行方法是使用locate命令。locate实用程序在结果方面比find实用程序更快,这是因为locate命令使用数据库来执行查找。数据库称为mlocate。我们可以执行对我们创建的文件的简单搜索,如下所示:

[philip@localhost ~]$ locate TestFile
[philip@localhost ~]$

在前面的输出中,locate 命令不知道指定的文件。不用担心;我们只需要更新数据库,如下所示:

[philip@localhost ~]$ updatedb
updatedb: can not open a temporary file for `/var/lib/mlocate/mlocate.db'
[philip@localhost ~]$

如果遇到这个错误,这意味着您需要以 root 用户身份运行命令,如下所示:

[philip@localhost ~]$ su
Password:
[root@localhost philip]# updatedb
[root@localhost philip]#
Now, let's retry the locate command for the given file:
[root@localhost philip]# locate TestFile
/home/philip/Documents/TestFile1
[root@localhost philip]#

就是这样!我们也可以按扩展名搜索。为此,我们可以使用通配符,如下所示:

[root@localhost philip]# locate *.key
/etc/brlapi.key
/etc/trusted-key.key
/usr/lib64/libreoffice/help/en-US/sbasic.key
/usr/lib64/libreoffice/help/en-US/scalc.key
/usr/lib64/libreoffice/help/en-US/schart.key
/usr/lib64/libreoffice/help/en-US/sdatabase.key
/usr/lib64/libreoffice/help/en-US/sdraw.key
/usr/lib64/libreoffice/help/en-US/simpress.key
/usr/lib64/libreoffice/help/en-US/smath.key
/usr/lib64/libreoffice/help/en-US/swriter.key
/usr/share/doc/openssh/PROTOCOL.key
/usr/share/doc/python3-pycurl/tests/certs/server.key
[root@localhost philip]#

在前面的输出中,只显示了小写名称的结果;我们可以通过传递 -i 来解决这个问题,这告诉 locate 命令忽略大小写:

[root@localhost philip]# locate -i *.key
/etc/brlapi.key
/etc/trusted-key.key
/usr/lib64/libreoffice/help/en-US/sbasic.key
/usr/lib64/libreoffice/help/en-US/scalc.key
/usr/lib64/libreoffice/help/en-US/schart.key/usr/lib64/libreoffice/help/en-US/sdatabase.key
/usr/lib64/libreoffice/help/en-US/sdraw.key
/usr/lib64/libreoffice/help/en-US/simpress.key
/usr/lib64/libreoffice/help/en-US/smath.key
/usr/lib64/libreoffice/help/en-US/swriter.key
/usr/share/doc/openssh/PROTOCOL.key
/usr/share/doc/python3-pycurl/tests/certs/server.key
[root@localhost philip]#

在这种情况下,由于文件是小写,结果是相同的。我们还可以控制输出的显示方式;我们可以传递 --null 选项,如下所示:

[root@localhost philip]# locate --null *types
/etc/ethertypes/etc/mime.types/etc/firewalld/icmptypes/etc/selinux/targeted/contexts/customizable_types/etc/selinux/targeted/contexts/securetty_types/usr/include/bits/types/usr/lib/firewalld/icmptypes/usr/lib64/libreoffice/program/types/usr/lib64/libreoffice/share/filter/vml-shape-types/usr/lib64/perl5/bits/types/usr/lib64/python2.7/ctypes/usr/lib64/python2.7/ctypes/macholib/REAshare/icons/hicolor/512x512/mimetypes/usr/share/icons/hicolor/64x64/mimetypes/usr/share/icons/hicolor/72x72/mimetypes/usr/share/icons/hicolor/96x96/mimetypes/usr/share/icons/hicolor/scalable/mimetypes/usr/share/icons/locolor/16x16/mimetypes/usr/share/icons/locolor/32x32/mimetypes/usr/share/mime/types
[root@localhost philip]#

在前面的输出中,我们可以看到期望的结果。最后,我们可以查看有关数据库的信息;为此,我们可以使用 -S 选项:

[root@localhost philip]# locate -S
Database /var/lib/mlocate/mlocate.db:
12,517 directories
162,475 files
8,292,135 bytes in file names
3,883,960 bytes used to store database
[root@localhost philip]#

干得好!除了大小,我们还可以看到数据库的位置。

管道和重定向

通常,当我们查看各种命令的输出时,输出有点模糊。不用担心;我们有所谓的管道和重定向。基本上,当使用管道 (|) 时,我们获取一个命令的输出并将其作为另一个命令的输入。重定向 (>, <, >>, 2>, 和 2>&1) 类似于从命令获取输出,但这次我们将其发送到一个位置,比如一个文件或另一个位置,等等。

首先,让我们使用 ls 命令;代码如下:

[root@localhost philip]# ls /etc
abrt               default    gdbinit.d        kernel                    networks           rc4.d      subuid-
adjtime            depmod.d   gdm               krb5.conf                 nfs.conf           rc5.d      sudoers
aliases            dhcp        geoclue          krb5.conf.d      nfsmount.conf      rc6.d     sudoers.d
alsa               DIR_COLORS  glvnd          ld.so.cache     nsswitch.conf      rc.d         sysconfig
alternatives       DIR_COLORS.256color          gnupg          ld.so.conf         nsswitch.conf.bak  rdma   sysctl.conf
[root@localhost philip]#

我们可以通过引入另一个强大的命令——less 命令,一页一页地查看输出:

[root@localhost philip]# ls /etc | less
cron.daily
cron.deny
cron.hourly
cron.monthly
crontab
cron.weekly
crypto-policies
crypttab
csh.cshrc
csh.login
cups
cupshelpers
:
[root@localhost philip]#

为了退出 less 命令,我们可以在键盘上使用 q。使用 less 命令的好处在于我们可以前后移动,而不是 more 命令,它只能向前移动。我们还可以使用管道 (|) 字符传递另一个命令期望的值。我们可以使用 wc 命令来说明这一点,如下所示:

[root@localhost philip]# ls /etc | wc -w
263
[root@localhost philip]#

在前面的输出中,我们获取了 ls 命令的输出并将其作为 wc 命令的输入。wc 命令用于计算单词数;-w 选项用于显示总单词数。

接下来,我们可以以多种方式使用重定向;在 Linux 中,我们有三种类型的流,如下所示:

  • 标准输入 = 输入 <

  • 标准输出 = 输出 >

  • 标准错误 = 标准错误 2>

此外,我们可以混合和匹配流,稍后在本节中您将看到。让我们从标准输入开始;我们可以使用 wc 命令并从文件中调用输入,如下所示:

[root@localhost philip]# wc -w < /boot/grub2/grub.cfg
435
[root@localhost philip]#

太棒了!/boot/grub2/grub.cfg 的字数被传递给 wc 命令。继续进行标准输出,我们可以获取命令的输出并将其存储到文件中。让我们使用 ls 命令,如下所示:

[root@localhost philip]# ls /etc/init.d/ > /home/philip/Documents/ls.txt
[root@localhost philip]#

在前面的输出中,我们列出了 /etc/init.d/ 并将输出保存到了 /home/philip/Documents/ls.txt。可以通过以下方式进行验证:

[root@localhost philip]# cat /home/philip/Documents/ls.txt
functions
livesys
livesys-late
netconsole
network
README
[root@localhost philip]#

现在,假设我们使用 ls 命令来查看另一个目录;这将覆盖 /home/philip/Documents/ls.txt 的现有内容:

[root@localhost philip]# ls /boot/grub2/ > /home/philip/Documents/ls.txt
[root@localhost philip]# cat /home/philip/Documents/ls.txt
device.map
fonts
grub.cfg
grubenv
i386-pc
localethemes
[root@localhost philip]#

正如你所看到的,事实就在眼前。解决这个问题的方法是告诉标准输出我们想要追加输出,而不是覆盖它:

[root@localhost philip]# ls /var/ >> /home/philip/Documents/ls.txt
[root@localhost philip]# cat /home/philip/Documents/ls.txt
device.map
fonts
grub.cfg
grubenv
i386-pc
locale
themes
account
adm
cache
crash
db
empty
ftp
games
gopher
kerberos
lib
spool
tmp
www
yp
[root@localhost philip]#

好了!所以,我们使用 >> 将数据追加到现有文件中。接下来,我们可以将命令的标准输入结果与标准输出合并。如下所示:

[root@localhost philip]# wc -w < /var/log/boot.log  > /home/philip/Documents/STDIN_STDOUT.txt
[root@localhost philip]# cat /home/philip/Documents/STDIN_STDOUT.txt
2021
[root@localhost philip]#

干得好!我们还可以将标准错误重定向到一个文件。让我们使用文件命令,如下所示:

[root@localhost philip]# ls -l /tmp TestFileWithError 2> /home/philip/Documents/STDERR.txt
/tmp:
drwx------. 3 root root 60 Aug 2 10:23 systemd-private-a7a23120abff44c8bca6807f1711c1c2-bolt.service-7uNmVr
drwx------. 3 root root 60 Aug 2 10:22 systemd-private-a7a23120abff44c8bca6807f1711c1c2-chronyd.service-LPD8zu
drwx------. 3 root root 60 Aug 2 10:23 systemd-private-a7a23120abff44c8bca6807f1711c1c2-colord.service-13Vcs8
drwx------. 3 root root 60 Aug 2 10:28 systemd-private-a7a23120abff44c8bca6807f1711c1c2-fwupd.service-XOnyvf
drwx------. 3 root root 60 Aug 2 10:22 systemd-private-a7a23120abff44c8bca6807f1711c1c2-rtkit-daemon.service-ZD5mO7
drwx------. 2 philip philip 40 Aug 2 10:31 tracker-extract-files.1000
drwx------. 2 root root 40 Aug 2 10:22 vmware-root
[root@localhost philip]#

在前面的输出中,似乎命令已经执行。事实上,/tmp 的列表已经显示,但是文件 TestFileWithError 的错误没有被显示出来。错误被发送到了 /home/philip/Documents/STDERR.txt。可以通过以下方式进行验证:

[root@localhost philip]# cat /home/philip/Documents/STDERR.txt
ls: cannot access 'TestFileWithError': No such file or directory
[root@localhost philip]#

干得好!我们还可以将标准输出与标准错误合并到一个文件中。这是通过告诉 shell 我们想要将标准错误与标准输出一起存储在文件 2>&1 中实现的。可以这样做:

[root@localhost philip]# ls -l  /tmp TestFileWithError > /home/philip/Documents/STDERR.txt 2>&1
[root@localhost philip]# cat /home/philip/Documents/STDERR.txt
ls: cannot access 'TestFileWithError': No such file or directory
/tmp:
total 0
drwx------. 3 root   root   60 Aug  2 10:23 systemd-private-a7a23120abff44c8bca6807f1711c1c2-bolt.service-7uNmVr
drwx------. 3 root   root   60 Aug  2 10:22 systemd-private-a7a23120abff44c8bca6807f1711c1c2-chronyd.service-LPD8zu
drwx------. 3 root   root   60 Aug  2 10:23 systemd-private-a7a23120abff44c8bca6807f1711c1c2-colord.service-13Vcs8
drwx------. 3 root   root   60 Aug  2 10:28 systemd-private-a7a23120abff44c8bca6807f1711c1c2-fwupd.service-XOnyvf
drwx------. 3 root   root   60 Aug  2 10:22 systemd-private-a7a23120abff44c8bca6807f1711c1c2-rtkit-daemon.service-ZD5mO7
drwx------. 2 philip philip 40 Aug  7 14:45 tracker-extract-files.1000
drwx------. 2 root   root   40 Aug  2 10:22 vmware-root
[root@localhost philip]#

在上面的输出中,我们可以看到文件开头的错误,然后是/tmp的列表。最后,可以显示命令的输出并同时将输出重定向到文件;这是由另一个强大的命令——tee命令实现的。以下显示了tee命令的使用:

[root@localhost philip]# cat  /etc/hosts.allow | tee /home/philip/Documents/The_Tee_command.txt
#
# hosts.allow     This file contains access rules which are used to
#      allow or deny connections to network services that
#      either use the tcp_wrappers library or that have been
#      started through a tcp_wrappers-enabled xinetd.
#
#       See 'man 5 hosts_options' and 'man 5 hosts_access'
#       for information on rule syntax.
#       See 'man tcpd' for information on tcp_wrappers
[root@localhost philip]#
[root@localhost philip]# cat /home/philip/Documents/The_Tee_command.txt
#
# hosts.allow     This file contains access rules which are used to
#         allow or deny connections to network services that
#         either use the tcp_wrappers library or that have been
#        started through a tcp_wrappers-enabled xinetd.
#
#     See 'man 5 hosts_options' and 'man 5 hosts_access'
#     for information on rule syntax.
#     See 'man tcpd' for information on tcp_wrappers
[root@localhost philip]#

在上面的输出中,您可以看到tee命令的强大之处。

总结

这一章非常详细。我必须说我在这一章的工作中玩得很开心。我们涵盖了文件系统结构。您学会了如何使用cd命令导航文件系统。然后,我们看了如何识别工作目录。之后,我们介绍了查看目录内容的方法。除此之外,我们还揭示了默认情况下未显示的目录中的隐藏文件和目录。

接下来,我们讨论了如何在 shell 中创建文件。此外,您还了解了文件的各种权限以及如何更改这些权限。接着,我们转向了 Linux 环境中的目录。我们探讨了创建、移动、重命名和删除目录的各种方法。下一个主题涉及搜索文件和目录的技术。首先,我们广泛使用了find命令。接下来,我们探讨了locate命令。最后,我们在 shell 环境的背景下使用了管道和重定向。您看到了如何利用命令的输出并将其作为另一个命令的输入。然后,您看到了如何重定向到文件,包括 STDOUT 和 STDERR。最后,我们看了另一个强大的命令:tee命令。

在下一章中,我们将在 shell 环境的背景下研究进程。特别是,我们将研究一种管理进程的技术。将涵盖一些流行的命令,如topservicesystemctl,用于识别和管理进程。下一章将简洁明了,我们将专注于在 shell 环境中工作时每个 Linux 工程师都应该了解的方法。您将获得的技能将在您迈向认证之路上增加更多的信心。

问题

  1. 以下哪个目录是root目录?

A. /root/

B. /root

C. /home/root

D. /

  1. 以下哪个命令用于切换到另一个目录?

A. pwd

B. chage

C. cd

D. change dir

  1. 以下哪个命令将打印当前工作目录?

A. print dir

B. pwd

C. display

D. cd

  1. 以下哪个命令用于打印目录的内容?

A. ls

B. which

C. whereis

D. cat

  1. 以下哪个选项可以用于使用ls命令显示文件和目录的权限?

A. -r

B. -b

C. -a

D. -l

  1. 以下哪个选项可以用于使用ls命令显示隐藏文件和目录?

A. -l

B. -b

C. -a

D. -u

  1. 以下哪个命令用于删除一个目录,即使它不是空的?

A. rmdir

B. rm

C. remove

D. mv

  1. 以下哪个选项用于查找并删除空文件和目录,使用find命令?

A. empty -remove

B. -empty -clean

C. -empty -delete

D. -empty -cycle

  1. 以下哪个命令用于更新locate命令使用的数据库?

A. updatelocate

B. updatedatabase

C. locateupdate

D. updatedb

  1. 以下哪个命令显示命令的输出并同时将结果保存到文件中?

A. less

B. more

C. wc

D. tee

进一步阅读

  • 您可以在以下网站获取有关文件操作的各种发行版的更多信息:unix.stackexchange.com

  • 要获取来自 Linux 社区用户的许多有用的技巧和最佳实践,请参阅:journalxtras.com

  • 有关适用于 CentOS 和 Ubuntu 的各种命令的一般信息,以及发布问题供其他社区成员回答的能力,请参考www.linuxquestions.org

第九章:创建、监视、终止和重新启动进程

在上一章中,我们详细讨论了文件管理。然后,我们介绍了如何在 shell 中创建文件。此外,我们还看到了文件的各种权限,并学习了如何更改它们。接着,我们转向 Linux 环境中的目录。最后,我们在 shell 环境的上下文中使用了管道和重定向。此外,我们还了解了另一个强大的命令——tee命令。

在本章中,我们将探讨用于管理各种进程的各种技术。首先,我们将使用非常流行的命令——ps命令实时调查进程。这个ps命令在第二章中简要介绍了一下,启动系统,在解释引导过程部分。在本章中,我们更加强调ps命令,探索可以传递的更多选项,从而暴露重要信息。之后,我们进入管理守护进程的方法;首先,我们从非常流行的top命令开始。这种处理进程的方法在整个 Linux 社区广泛使用。这主要是因为top命令提供各种守护进程的实时统计信息。除此之外,我们还可以控制守护进程的行为。接着,我们转向另一种管理进程的常见方法:service命令。最后,我们介绍了管理守护进程的最新方法;即systemctl命令。这在第二章中简要介绍了,启动系统,在解释引导过程部分。在本章中,我们更深入地探讨了使用systemctl命令进行守护进程管理的常见做法。

在本章中,我们将涵盖以下主题:

  • ps命令

  • 使用top命令查看和管理进程

  • 使用service命令管理进程

  • 使用systemctl命令管理进程

ps 命令

ps命令代表进程状态,是当今环境中最流行的命令之一。它显示系统中正在运行的当前进程;当我们在 Linux 环境中工作时,我们经常忽视使一切成为可能的底层进程。ps命令显示的所有信息都来自一个非常流行的目录;即/proc文件系统。/proc文件系统实际上并不是一个真正的文件系统;它实际上是一个虚拟文件系统。它在启动时加载,几乎可以在今天的每个 Linux 发行版中找到/proc文件系统。让我们深入了解ps命令。

首先,我们可以显示在当前 shell 中启动的任何进程:

[philip@localhost ~]$ ps
 PID         TTY        TIME        CMD
 2220        pts/0      00:00:00    bash
 95677       pts/0      00:00:00    ps
[philip@localhost ~]$

根据前面的输出,我们在当前 shell 中没有启动任何其他进程,除了ps命令本身和 Bash shell。我们还可以使用ps命令列出当前系统中的所有进程;我们将传递-A参数:

[philip@localhost ~]$ ps -A
 PID    TTY      TIME       CMD
 1   ?        00:00:31   systemd
 2   ?        00:00:00   kthreadd
 3   ?        00:00:02   ksoftirqd/0
 5   ?        00:00:00   kworker/0:0H
 7   ?        00:00:00   migration/0
 8   ?        00:00:00   rcu_bh
 9   ?        00:00:12   rcu_sched
 10  ?        00:00:11   watchdog/0
 12  ?        00:00:00   kdevtmpfs
 13  ?        00:00:00   netns
 14  ?        00:00:00   khungtaskd
 15  ?        00:00:00   writeback
 95730  ?        00:00:00   kworker/0:3
 95747  ?        00:00:00   sleep
 95748  pts/0    00:00:00   ps
[philip@localhost ~]$

当我们使用-A-e参数运行ps命令时,它只会打印出每个进程的进程 ID 和名称。但是,我们可以进一步扩展这个输出。我们可以传递-a-u。这将打印出当前用户在终端中打开的进程:

[philip@localhost ~]$ ps -au

要查看系统中当前用户拥有的所有进程,我们传递-x选项:

[philip@localhost ~]$ ps -x
PID  TTY  STAT  TIME COMMAND
1487  ?    Sl   0:00 /usr/bin/gnome-keyring-daemon --daemonize --login
1491  ?    Ssl  0:01 /usr/libexec/gnome-session-binary --session gnome-classic
1498  ?    S    0:00 dbus-launch --sh-syntax --exit-with-session
1499  ?    Ssl  0:00 /bin/dbus-daemon --fork --print-pid 4 --print-address 6 --session
1567  ?    Sl   0:00 /usr/libexec/gvfsd
1572  ?    Sl   0:00 /usr/libexec/gvfsd-fuse /run/user/1000/gvfs -f -o big_writes
1664  ?    Ss   0:00 /usr/bin/ssh-agent /bin/sh -c exec -l /bin/bash -c "env
GNOME_SHELL_SESSION_MODE=classic gnome-session --session gnome-cla
1683  ?    Sl   0:00 /usr/libexec/at-spi-bus-launcher
1688  ?    Sl   0:00 /bin/dbus-daemon --config-file=/usr/share/defaults/at-spi2/accessibility.conf --nofork --print-address 3

我们还可以将用户作为参数的一部分指定为-u

[philip@localhost ~]$ ps -au root
 PID  TTY   TIME      CMD
 1   ?     00:00:31  systemd
 2   ?     00:00:00  kthreadd
 3   ?     00:00:02  ksoftirqd/0
 5   ?     00:00:00  kworker/0:0H

我们还可以看到所有用户以及每个守护进程的可执行文件的路径;我们传递-auxaux-;这是伯克利软件发行BSD)语法。BSD 是 Unix 的另一种风味。以下是 Linux 语法的示例:

[philip@localhost ~]$ ps -aux
USER    PID %CPU %MEM  VSZ     RSS   TTY  STAT  START   TIME 
COMMAND
root      1    0.0  0.4  193700  4216  ?    Ss    Aug08  0:31 /usr/lib/systemd/systemd --switched-root --system --deserialize 21
root      2    0.0  0.0   0      0     ?    S     Aug08  0:00 
[kthreadd]
root      3    0.0  0.0   0      0     ?    S     Aug08  0:02 [ksoftirqd/0]
root      5    0.0  0.0   0      0     ?    S     Aug08  0:00 [kworker/0:0H]
dbus      570  0.0  0.2  36524  2236   ?    Ssl   Aug08  0:14 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activati
chrony    571  0.0  0.0  115640 672    ?     S    Aug08  0:00 /usr/sbin/chronyd
avahi     585  0.0  0.0  30072  28     ?     S    Aug08  0:00 avahi-daemon: chroot helper
philip    2209 0.0  0.0 313472  644    ?     Sl   Aug08  0:00 /usr/libexec/gvfsd-metadata
philip    2213 0.0  1.0 720692 10608   ?     Sl   Aug08   0:05 /usr/libexec/gnome-terminal-server

太棒了!根据前面的输出,我们可以看到各种用户帐户。一些帐户是实际的系统帐户,例如dbus帐户。我们还可以指定用户帐户 ID:

[philip@localhost ~]$ ps -ux 1000
USER PID  %CPU  %MEM    VSZ    RSS  TTY  STAT START   TIME 
COMMAND
philip   1487  0.0   0.0    462496 996   ?    Sl   Aug08   0:00 /usr/bin/gnome-keyring-daemon --daemonize --login
philip  1491   0.0   0.1    761348 1512  ?    Ssl  Aug08   0:01 /usr/libexec/gnome-session-binary --session gnome-classic
philip  1498   0.0   0.0    13976   0    ?    S    Aug08   0:00 
dbus-launch --sh-syntax --exit-with-session
philip  1499   0.0   0.1    36284   1276 ?    Ssl  Aug08   0:00 /bin/dbus-daemon --fork --print-pid 4 --print-address 6 --session
philip  1567   0.0  0.0     386352   0   ?    Sl   Aug08   0:00 /usr/libexec/gvfsd
philip  1572   0.0  0.0     415548   52  ?    Sl   Aug08   0:00 /usr/libexec/gvfsd-fuse /run/user/1000/gvfs -f -o big_writes

除此之外,还可以显示由特定组拥有的进程。是的!通过传递组名或 ID 来实现。如果我们传递组名,那么我们使用-g

[philip@localhost ~]$ ps -fg postfix
UID        PID    PPID  C  STIME  TTY      TIME      CMD
postfix    1110   1108  0  Aug08   ?    00:00:00  qmgr -l -t unix -u
postfix    95714  1108  0  06:12   ?    00:00:00  pickup -l -t unix -u
[philip@localhost ~]$

要传递组 ID,我们传递-G选项:

[philip@localhost ~]$ ps -fg 89
UID         PID    PPID   C  STIME  TTY         TIME   CMD
[philip@localhost ~]$
[philip@localhost ~]$ ps -fG 89
UID         PID    PPID  C   STIME  TTY   TIME       CMD
postfix     1110   1108  0   Aug08  ?     00:00:00   qmgr -l -t unix -u
postfix     95714  1108  0   06:12  ?     00:00:00   pickup -l -t unix -u
[philip@localhost ~]$

干得好!我们还可以通过指定进程 IDPID)来搜索进程。我们传递-f,它将打印一个长列表,以及-p选项,它期望一个数值:

[philip@localhost ~]$ ps -fp 1982
UID       PID   PPID  C  STIME   TTY  TIME      CMD
philip    1982  1     0  Aug08   ?    00:00:00  /usr/libexec/tracker-store
[philip@localhost ~]$

有趣的是,我们甚至可以在同一行上指定多个进程;我们用逗号分隔进程:

[philip@localhost ~]$ ps -fp 1982,2001,2219
UID         PID   PPID  C  STIME   TTY  TIME     CMD
philip     1982   1     0  Aug08   ?    00:00:00 /usr/libexec/tracker-store
philip     2001   1730  0  Aug08   ?    00:00:00 /usr/libexec/ibus-engine-simple
philip     2219   2213  0  Aug08    ?   00:00:00 gnome-pty-helper
[philip@localhost ~]$

干得好!还可以通过传递-o选项来查找命令指定的进程 ID:

[philip@localhost ~]$ ps -fp 955 -o comm=sshd
[philip@localhost ~]$

根据前面的输出,仅显示了相应 PID 的实际可执行文件。

还可以使用ps命令获取内存和 CPU 信息;我们传递-e选项以及-o选项。然后,我们需要传递我们感兴趣的列名称。以下是我们如何完成这个任务:

[philip@localhost ~]$ ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head     -14
PID    PPID    CMD                           %MEM   %CPU
1710   1491    /usr/bin/gnome-shell           17.9   0.0
1926   1491    /usr/bin/gnome-software --g    7.1    0.0
1042   989     /usr/bin/X :0 -background n    2.5    0.0
95581  633     /sbin/dhclient -d -q -sf /u    1.3    0.0
2213   1       /usr/libexec/gnome-terminal    1.1    0.0
605    1       /usr/lib/polkit-1/polkitd -    1.1    0.0
1872   1491    /usr/libexec/gnome-settings    0.8    0.0
633    1       /usr/sbin/NetworkManager --    0.8    0.0
1890   1491    nautilus-desktop --force       0.7    0.0
2050   1915    /usr/libexec/evolution-cale    0.6    0.0
1291   1       /usr/libexec/packagekitd       0.6    0.0
632    1       /usr/bin/python -Es /usr/sb    0.4    0.0
1990   1915    /usr/libexec/evolution-cale    0.4    0.0
[philip@localhost ~]$

太棒了!根据前面的输出,我们指定了pid,ppid,cmd,%mem,%cpu。除此之外,还添加了--sort选项。这将查找使用最多系统 RAM 的进程,并从最高到最低显示这些进程。此外,我们添加了head命令;这将只显示内容的顶部部分。

我们指定只想看到前 14 行。但是,ps命令的输出不是实时刷新的;我们可以使用另一个流行的命令来查看输出实时刷新,而不是我们必须重新运行命令。我们使用watch命令来完成这个任务:

[philip@localhost ~]$ watch -n 1 'ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head'

运行前面的命令的输出如下:

根据前面的截图,我们已经对输出进行了排序,以查看在系统中占用大部分 CPU 的进程。我们可以以分层视图查看ps命令的输出;我们将添加-f--forest选项:

[philip@localhost ~]$ ps -af --forest
UID         PID   PPID  C  STIME  TTY     TIME      CMD
philip      99053 2220  0  07:29  pts/0   00:00:00  ps -af --forest
[philip@localhost ~]$ ps -axf --forest
PID TTY      STAT   TIME COMMAND
 2 ?        S      0:00 [kthreadd]
 3 ?        S      0:02  \_ [ksoftirqd/0]
 517?        S<sl   0:00 /sbin/auditd
519 ?        S<sl   0:01  \_ /sbin/audispd
521 ?        S<     0:00   \_ /usr/sbin/sedispatch
543 ?        SNsl   0:04     /usr/libexec/rtkit-daemon
1664 ?        Ss    0:00    \_ /usr/bin/ssh-agent /bin/sh -c exec -l /bin/bash -c "env GNOME_SHELL_SESSION_MODE=classic gnome-session --sessi
1710 ?        Sl     5:01    \_ /usr/bin/gnome-shell
1730 ?        Sl     0:00    |  \_ ibus-daemon --xim --panel disable
1743 ?        Sl     0:00    |     \_ /usr/libexec/ibus-dconf
2001 ?        Sl     0:00    |       \_ /usr/libexec/ibus-engine-simple
1872 ?        Sl     0:18     \_ /usr/libexec/gnome-settings-daemon

杀死命令

kill命令用于终止进程。我们可以利用刚刚介绍的ps命令来识别进程,然后调用kill命令来结束进程。以下是我们如何使用kill命令停止进程的方法:

[philip@localhost ~]$ ps -p 1788
PID   TTY       TIME     CMD
1788   ?        00:00:00 goa-daemon
[philip@localhost ~]$
[philip@localhost ~]$ kill -9 1788
[philip@localhost ~]$ ps -fp 1788
UID         PID   PPID  C STIME TTY        TIME CMD
[philip@localhost ~]$

太棒了!我们使用了9数字,这意味着发送SIGKILL。要查看我们可以传递的各种信号,我们可以使用kill命令的-l选项:

[philip@localhost ~]$ kill -l
1) SIGHUP      2) SIGINT       3) SIGQUIT    4) SIGILL    5) SIGTRAP         6) SIGABRT     7) SIGBUS       8) SIGFPE     9) SIGKILL  10) SIGUSR111) SIGSEGV       12) SIGUSR2      13) SIGPIPE   14) SIGALRM 15) SIGTERM 
16) SIGSTKFLT 17) SIGCHLD      18) SIGCONT   19) SIGSTOP 20) SIGTSTP
21) SIGTTIN   22) SIGTTOU      23) SIGURG    24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF      28) SIGWINCH  29) SIGIO   30) SIGPWR 
31) SIGSYS     34) SIGRTMIN    35) SIGRTMIN+1 36) SIGRTMIN+2 
37) SIGRTMIN+3 38) SIGRTMIN+4  39) SIGRTMIN+5 40) SIGRTMIN+6 
41) SIGRTMIN+7 42) SIGRTMIN+8  43) SIGRTMIN+9 44) SIGRTMIN+10            45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14            49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12            53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8             57) SIGRTMAX-7  58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4               61) SIGRTMAX-3  62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX 
[philip@localhost ~]$

要使用信号名称停止进程,我们传递-s选项:

[philip@localhost ~]$ ps -fp 1990
UID     PID   PPID  C STIME  TTY   TIME      CMD
philip  1990  1915  0 Aug08  ?     00:00:00  /usr/libexec/evolution-calendar-factory-subprocess --factory contacts --bus-name org.gnome.evolution
[philip@localhost ~]$ kill -s SIGKILL 1915
[philip@localhost ~]$ ps -fp 1915
UID       PID   PPID  C STIME TTY          TIME CMD
[philip@localhost ~]$

在调用kill命令时,停止使用SIGTERM时应该小心。

pstree 命令

还有另一种ps命令的变体,可用于查看系统中的进程——pstree命令。这将以分层布局呈现所有进程。它看起来是这样的:

根据前面的截图,一些进程是父进程:它们有子进程。我们还可以通过传递-h选项来突出显示特定进程:

[root@localhost Desktop]# pstree -h 1735
rsyslogd───3*[{rsyslogd}]
[root@localhost Desktop]#The Process Grep commonly known as pgrep is another popular method

我们还可以仅显示特定于用户的进程;我们传递用户名

根据前面的截图,我们可以看到用户父进程是gdm-x-session;然后有子进程,从Xorg开始,向下移动树。

pgrep 命令

进程 Grep,通常称为pgrep,是另一种在 shell 中查找进程 ID 的流行方法。如果我们知道进程名称,那么我们可以使用pgrep命令指定它:

[root@localhost Desktop]# pgrep rsyslogd
545
[root@localhost Desktop]#

根据前面的命令,我们可以看到rsyslogd的 PID。我们还可以找到特定用户的进程。为此,我们传递-u选项:

[root@localhost Desktop]# pgrep -u root rsyslogd
545
[root@localhost Desktop]#

干得好!

pkill 命令

pkill命令是另一种用于终止进程的已知方法。它使我们能够在终止给定进程时使用进程名称。在其最简单的形式中,它如下:

[philip@localhost ~]$ pgrep rsyslogd
545
[philip@localhost ~]$ pkill rsyslogd
pkill: killing pid 545 failed: Operation not permitted
[philip@localhost ~]$ su
Password:
[root@localhost philip]# pkill rsyslogd
[root@localhost philip]# pgrep rsyslogd
[root@localhost philip]#

厉害了!根据前面的代码输出,我们可以看到pkill命令的有效性。

使用 top 命令查看和管理进程

top命令,意思是进程表,在性质上类似于 Windows 任务管理器。您会发现许多 Linux 发行版支持top命令。top命令主要用于获取系统的 CPU 和内存利用率。输出是通过创建一个由用户指定标准选择的运行进程列表来构造的;输出是实时的。每个进程的 PID 都列在第一列中。让我们开始吧:

[philip@localhost ~]$ top
top - 12:50:44 up 5 days, 11:44,  2 users,  load average: 0.01, 0.02, 0.05
Tasks: 165 total,   1 running, 164 sleeping,   0 stopped,   0 zombie
%Cpu(s): 12.1 us,  1.4 sy,  0.0 ni, 86.1 id,  0.0 wa,  0.0 hi,  0.4 si,  0.0 st
KiB Mem :   999696 total,    95804 free,   633636 used,   270256 buff/cache
KiB Swap:  2097148 total,  1852900 free,   244248 used.   137728 avail Mem
PID   USER    PR    NI VIRT    RES  SHR S %CPU %MEM   TIME+  COMMAND                                                                          1710 philip   20    0  1943720 175920  15680 S  9.3 17.6 5:32.99 gnome-shell 
1042 root     20    0  306324  26188  1864 S  5.6 2.6 1:13.99 X                                                                                 2213 philip   20    0  721204  11976  5992 S  2.7 1.2 0:15.04 gnome-terminal-                                                                  1934 philip   20   0  389192  6308  1952 S  0.3  0.6   5:25.10 vmtoolsd
103282 philip 20   0  157716   2260   1540 R  0.3  0.2   0:00.28 top                                                                              1  root       20   0  193700   4248   2484 S  0.0  0.4   0:33.67 systemd                                                                          2 root        20   0       0      0      0 S  0.0  0.0   0:00.21 kthreadd                                                                          

在最右边,有一个COMMAND列;这显示了可执行文件。我们可以过滤我们想要显示的用户及其相应的进程;我们在top中使用-u选项:

[philip@localhost ~]$ top -u philip
top - 12:55:24 up 5 days, 11:49,  2 users,  load average: 0.25, 0.08, 0.06
Tasks: 164 total,   2 running, 162 sleeping,   0 stopped,   0 zombie
%Cpu(s): 55.4 us,  6.8 sy,  0.0 ni, 36.5 id,  1.4 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   999696 total,    73184 free,   641804 used,   284708 buff/cache
KiB Swap:  2097148 total,  1856364 free,   240784 used.   128952 avail Mem
PID   USER  PR NI VIRT    RES    SHR   S %CPU %MEM  TIME+  COMMAND 
1710 philip 20 0 1943720 177568  16612 S 42.7 17.8 5:39.32 gnome-shell 
2213 philip 20 0 721204  12256   6228  S  2.6  1.2  0:15.61 gnome-terminal-                                                                  1934 philip 20 0 389192  6308   1952  S  0.3  0.6   5:25.37 vmtoolsd 
103360 philip  20   0  157716   2260   1544 R  0.3  0.2   0:00.06 top                                                                               1487 philip  20  0 462496   1504  1004 S  0.0  0.2 0:00.08 gnome-keyring-d                                                                  1491 philip  20 0 761348 2140 1220 S 0.0 0.2  0:01.77 gnome-session-b                                                                  1498 philip  20 0 13976   0     0  S  0.0  0.0 0:00.00 dbus-launch                                                                      1499 philip  20   0  36284 160 600 S  0.0  0.2   0:00.72 dbus-daemon                                                                      1567 philip  20   0  386352    864    592 S0.0 0.1 0:00.02 gvfsd                                                                             

根据前面的输出,只显示了用户philip的进程。我们可以通过在top命令中按C来查看所有进程的绝对路径。这是按下C时得到的截图:

太棒了!现在我们可以看到每个进程的位置。我们还可以更改输出的刷新频率;默认值是每三秒。我们从top命令中按下D键:

根据前面的屏幕截图,当按下D键时,会出现一行新的内容:Change delay from 3.0 to。这提示我们要指定一个数字。我在这里输入2,这样更新将每两秒刷新一次。现在,当我再次按下D键时,我们会注意到提示中的差异:

干得好!要查看top的帮助,我们可以按H

我们可以更改top实用程序中内存的显示方式;根据当前的内存输出,当我们按下M时,显示将切换:

top - 13:09:50 up 5 days, 12:03,  2 users, load average: 0.00, 0.04, 0.05
Tasks: 164 total,   1 running, 163 sleeping,   0 stopped,   0 zombie
%Cpu(s):  4.1 us,  0.7 sy,  0.0 ni, 95.2 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

根据前面的屏幕截图,内存部分被隐藏了。当我们再次按下M键时,这将改变:

太棒了!如果我们再次按下M键,我们会看到一种图形设计:

干得好!现在我们有漂亮的条形图,指示了 RAM 和交换的内存使用情况。同样,我们可以通过 CPU 更改输出的显示;为此,我们按T

top - 13:19:23 up 5 days, 12:13,  2 users,  load average: 0.30, 0.11, 0.07
Tasks: 163 total,   3 running, 160 sleeping,   0 stopped,   0 zombie
2 sleeping,   0 stopped,   0 zombie
%Cpu(s):   9.6/1.4    11[|||||||||||                                                                                         ]
KiB Mem :   999696 total,    73524 free,   641328 used,   284844 buff/cache
KiB Swap:  2097148 total,  1856532 free,   240616 used.   129444 avail Mem

太棒了!当我们按T时,它会将条形图变成阴影输出:

除此之外,进程还可以以分层输出的方式显示;我们按Shift + V

要关闭层次视图,我们只需再次切换Shift + V

我们还可以使用top命令停止一个进程;我们按K,这是在top命令中杀死进程的快捷键:

基于前面的命令,会出现一行新的内容:PID to signal/kill [default pid = 1710],我们需要指定一个进程 ID:

KiB Swap:2097148 total, 1856800 free, 240348 used. 129084 avail Mem
Send pid 1718 signal [15/sigterm]
PID  USER   PR NI VIRT   RES    SHR   S %CPU %MEM  TIME+   COMMAND                                                                          1710 philip 20 0 1944552 176788 16840 S  1.5 17.7  6:36.40 gnome-shell                                                                       2213 philip 20 0 721724  16020   8740 S  0.5 1.6   0:22.60 gnome-terminal-

现在我们需要指定要发送给进程的信号;默认是15/sigterm。我们将接受默认值;这将在不必退出top实用程序的情况下终止进程。

使用service命令管理进程

service命令最初用于在systemd之前的早期 Linux 发行版上运行 SysVinit 脚本。根据您要完成的任务,您用于启动、停止或重新启动服务的方法将取决于您的发行版是使用systemd还是init。大多数 Linux 工程师更喜欢使用service命令而不是在系统环境中处理进程的较新方法。因此,在大多数较新的发行版中支持service命令。service命令的语法是:

service <process> <status>

要查看运行 SysV 脚本的系统上的所有服务,我们将使用 CentOS 6.5 系统:

[philip@localhost Desktop]$ service --status-all
abrt-ccpp hook is installed
abrtd (pid  2254) is running...
abrt-dump-oops is stopped
acpid (pid  1964) is running...
atd (pid  2273) is running...
auditd (pid  1710) is running...
Usage: /etc/init.d/bluetooth {start|stop}
cpuspeed is stopped
crond (pid  2262) is running...
cupsd (pid  1874) is running...
dnsmasq (pid  2087) is running...
firstboot is not scheduled to run
hald (pid  1975) is running...
htcacheclean is stopped
httpd is stopped
winbindd is stopped
wpa_supplicant (pid  1875) is running...
[philip@localhost Desktop]$

service命令读取的脚本以rc开头。我们可以快速查看所有相关脚本:

[philip@localhost Desktop]$ ls -l /etc | grep rc.
lrwxrwxrwx.  1 root root     11 Jun 20 01:37 init.d -> rc.d/init.d
lrwxrwxrwx.  1 root root      7 Jun 20 01:40 rc -> rc.d/rc
lrwxrwxrwx.  1 root root     10 Jun 20 01:40 rc0.d -> rc.d/rc0.d
lrwxrwxrwx.  1 root root     10 Jun 20 01:40 rc1.d -> rc.d/rc1.d
lrwxrwxrwx.  1 root root     10 Jun 20 01:40 rc2.d -> rc.d/rc2.d
lrwxrwxrwx.  1 root root     10 Jun 20 01:40 rc3.d -> rc.d/rc3.d
lrwxrwxrwx.  1 root root     10 Jun 20 01:40 rc4.d -> rc.d/rc4.d
lrwxrwxrwx.  1 root root     10 Jun 20 01:40 rc5.d -> rc.d/rc5.d
lrwxrwxrwx.  1 root root     10 Jun 20 01:40 rc6.d -> rc.d/rc6.d
drwxr-xr-x. 10 root root   4096 Jun 20 05:50 rc.d
lrwxrwxrwx.  1 root root     13 Jun 20 01:40 rc.local -> rc.d/rc.local
lrwxrwxrwx.  1 root root     15 Jun 20 01:40 rc.sysinit -> rc.d/rc.sysinit
[philip@localhost Desktop]$

要控制进程的状态,我们可以这样做:

[philip@localhost Desktop]$ service crond status
crond (pid  4457) is running...
[philip@localhost Desktop]$

根据前面的命令,这个特定进程目前正在运行。我们可以更改这一点;假设我们想要停止crond进程。我们只需用stop替换status

[philip@localhost Desktop]$ service crond stop
User has insufficient privilege.
[philip@localhost Desktop]$

根据前面的输出,我们遇到了一个障碍;这可以很容易地通过成为 root 用户来解决:

[root@localhost Desktop]# service crond stop
Stopping crond:                                            [  OK  ]
[root@localhost Desktop]#

太棒了!现在我们可以重新运行service命令;这次使用status选项:

[root@localhost Desktop]# service crond status
crond is stopped
[root@localhost Desktop]#

然后我们完成了。服务已经停止。要开始备份这个进程,我们只需用start替换stop

[root@localhost Desktop]# service crond start
Starting crond:                                            [  OK  ]
[root@localhost Desktop]#

现在让我们再次尝试启动这个进程:

[root@localhost Desktop]# service crond status
crond (pid  6606) is running...
[root@localhost Desktop]#

干得好!如果出于某种原因,我们对进程进行了更改并需要重新启动进程,那么我们可以通过多种方式来做到。我们可以停止进程,然后再次启动它:

[root@localhost Desktop]# service crond stop
Stopping crond:                                            [  OK  ]
[root@localhost Desktop]# service crond start
Starting crond:                                            [  OK  ]
[root@localhost Desktop]#

此外,我们可以使用restart选项:

[root@localhost Desktop]# service crond restart
Stopping crond:                                            [  OK  ]
Starting crond:                                            [  OK  ]
[root@localhost Desktop]#

最后,我们可以使用reload选项;这个选项将重新读取已经进行的任何更改的配置文件:

[root@localhost Desktop]# service crond reload
Reloading crond:                                           [  OK  ]
[root@localhost Desktop]# service crond status
crond (pid  6703) is running...
[root@localhost Desktop]#

太棒了!

使用 systemctl 命令管理进程

在大多数使用 system 的新发行版上,我们将使用systemctl命令来管理进程。Linux 开发人员也留下了对service命令的支持;如果我们尝试使用service命令终止一个进程,那么我们会发现它实际上会将我们的请求重定向到systemctl命令。让我们试试看:

[root@localhost philip]# service crond status
Redirecting to /bin/systemctl status crond.service
crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2018-08-02 07:13:38 PDT; 1 weeks 5 days ago
 Main PID: 991 (crond)
CGroup: /system.slice/crond.service
 └─991 /usr/sbin/crond -n
Aug 02 07:13:38 localhost.localdomain systemd[1]: Started Command Scheduler.
Aug 02 07:13:38 localhost.localdomain systemd[1]: Starting Command Scheduler...
Aug 02 07:13:38 localhost.localdomain crond[991]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 15% if used.)
Aug 02 07:13:43 localhost.localdomain crond[991]: (CRON) INFO (running with inotify support)
[root@localhost philip]#

太棒了!根据输出,我们可以看到service命令实际上正在被重定向:

[root@localhost philip]# service crond status
Redirecting to /bin/systemctl status crond.service
crond.service - Command Scheduler

现在让我们尝试使用管理进程的新方法;我们将使用systemctl命令。格式如下:

systemctl <action><process>

我们可以在 shell 中使用这个:

[root@localhost philip]# systemctl status atd
atd.service - Job spooling tools
Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2018-08-02 07:13:38 PDT; 1 weeks 5 days ago
Main PID: 993 (atd)
CGroup: /system.slice/atd.service
 └─993 /usr/sbin/atd -f
Aug 02 07:13:38 localhost.localdomain systemd[1]: Started Job spooling tools.
Aug 02 07:13:38 localhost.localdomain systemd[1]: Starting Job spooling tools...
[root@localhost philip]#

使用systemctl启动一个进程,我们传递start选项:

[root@localhost philip]# systemctl start rsyslog.service
[root@localhost philip]#

我们可以通过传递status选项来检查进程的状态:

[root@localhost philip]# systemctl status rsyslog.service
rsyslog.service - System Logging Service
Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor preset: enabled)
 Active: active (running) since Tue 2018-08-14 08:29:22 PDT; 5s ago
 Docs:
man:rsyslogd(8)
 http://www.rsyslog.com/doc/
Main PID: 117499 (rsyslogd)
 CGroup: /system.slice/rsyslog.service
 └─117499 /usr/sbin/rsyslogd -n
Aug 14 08:29:22 localhost.localdomain systemd[1]: Starting System Logging Service...
Aug 14 08:29:22 localhost.localdomain rsyslogd[117499]:  [origin software="rsyslogd" swVersion="8.24.0" x-pid="117499" x-info="http://www.rs...] start
Aug 14 08:29:22 localhost.localdomain systemd[1]: Started System Logging Service.
Hint: Some lines were ellipsized, use -l to show in full.
[root@localhost philip]#

您会注意到,与早期 Linux 发行版中的旧 service 命令相比,systemctl命令的输出要直观得多。我们也可以使用systemctl命令停止一个进程;我们传递stop选项:

[root@localhost philip]# systemctl stop rsyslog.service
[root@localhost philip]# systemctl status rsyslog.service
rsyslog.service - System Logging Service
Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Tue 2018-08-14 08:38:38 PDT; 8s ago
Docs: man:rsyslogd(8)
http://www.rsyslog.com/doc/
Process: 117499 ExecStart=/usr/sbin/rsyslogd -n $SYSLOGD_OPTIONS (code=exited, status=0/SUCCESS)
Main PID: 117499 (code=exited, status=0/SUCCESS)
Aug 14 08:29:22 localhost.localdomain systemd[1]: Starting System Logging Service...
Aug 14 08:29:22 localhost.localdomain rsyslogd[117499]:  [origin software="rsyslogd" swVersion="8.24.0" x-pid="117499" x-info="http://www.rs...] start
Aug 14 08:29:22 localhost.localdomain systemd[1]: Started System Logging Service.
Aug 14 08:38:38 localhost.localdomain rsyslogd[117499]:  [origin software="rsyslogd" swVersion="8.24.0" x-pid="117499" x-info="http://www.rs...nal 15.
Aug 14 08:38:38 localhost.localdomain systemd[1]: Stopping System Logging Service...
Aug 14 08:38:38 localhost.localdomain systemd[1]: Stopped System Logging Service.
Hint: Some lines were ellipsized, use -l to show in full.
[root@localhost philip]#

此外,我们可以重新启动或重新加载一个进程:

[root@localhost philip]# systemctl restart rsyslog.service
[root@localhost philip]# systemctl status rsyslog.service
rsyslog.service -
System Logging Service
Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor preset: enabled)
 Active: active (running) since Tue 2018-08-14 08:39:37 PDT; 2s ago
 Docs: man:rsyslogd(8)
 http://www.rsyslog.com/doc/
Main PID: 117730 (rsyslogd)
CGroup: /system.slice/rsyslog.service
 └─117730 /usr/sbin/rsyslogd -n
Aug 14 08:39:37 localhost.localdomain systemd[1]: Starting System Logging Service...
Aug 14 08:39:37 localhost.localdomain rsyslogd[117730]:  [origin software="rsyslogd" swVersion="8.24.0" x-pid="117730" x-info="http://www.rs...] start
Aug 14 08:39:37 localhost.localdomain systemd[1]: Started System Logging Service.
Hint: Some lines were ellipsized, use -l to show in full.
[root@localhost philip]#

根据前面的输出,当我们传递restart选项时,它只是启动了进程。使用systemctl命令处理的进程在使用systemctl命令时被视为单元。我们可以通过传递list-units文件来查看这些单元:

[root@localhost philip]# systemctl list-units --all --state=active
UNIT    LOAD   ACTIVE SUB       DESCRIPTION
proc-sys-fs-binfmt_misc.automount                              loaded active waiting   Arbitrary Executable File Formats File System Automount Point
dev-cdrom.device                                               loaded active plugged   VMware_Virtual_IDE_CDROM_Drive
dev-disk-by\x2did-ata\x2dVMware_Virtual_IDE_CDROM_Drive_10000000000000000001.device loaded active plugged   VMware_Virtual_IDE_CDROM_Drive
dev-disk-by\x2dpath-pci\x2d0000:00:07.1\x2data\x2d2.0.device   loaded active plugged   VMware_Virtual_IDE_CDROM_Drive
dev-disk-by\x2dpath-pci\x2d0000:00:10.0\x2dscsi\x2d0:0:0:0.device loaded active plugged   VMware_Virtual_S
dev-disk-by\x2dpath-pci\x2d0000:00:10.0\x2dscsi\x2d0:0:0:0\x2dpart1.device loaded active plugged   VMware_Virtual_S 1
dev-disk-by\x2dpath-pci\x2d0000:00:10.0\x2dscsi\x2d0:0:0:0\x2dpart2.device loaded active plugged   VMware_Virtual_S 2
dev-disk-by\x2dpath-pci\x2d0000:00:10.0\x2dscsi\x2d0:0:0:0\x2dpart3.device loaded active plugged   VMware_Virtual_S 3
dev-disk-by\x2duuid-16e2de7b\x2db679\x2d4a12\x2d888e\x2d55081af4dad8.device loaded active plugged   VMware_Virtual_S 3
sys-devices-virtual-net-virbr0\x2dnic.device                   loaded active plugged   /sys/devices/virtual/net/virbr0-nic
[root@localhost philip]#

各种进程存储在/usr/lib/systemd/system中:

[root@localhost philip]# ls /usr/lib/systemd/system
abrt-ccpp.service       iscsiuio.socket          shutdown.target
abrtd.service           kdump.service            shutdown.target.wants
abrt-oops.service       kexec.target             sigpwr.target
abrt-pstoreoops.service kexec.target.wants       sleep.target
abrt-vmcore.service     kmod-static-nodes.service  -.slice
abrt-xorg.service       kpatch.service            slices.target
accounts-daemon.service ksm.service               smartcard.target
alsa-restore.service    ksmtuned.service          smartd.service
alsa-state.service      libstoragemgmt.service    sockets.target
alsa-store.service      libvirtd.service          sockets.target.wants
[root@localhost philip]#

正如您所看到的,有各种各样的进程是使用systemctl命令进行管理的。

总结

在本章中,我们处理了与在 shell 中处理进程相关的各个方面。我们从ps命令开始。展示了在 shell 中显示当前运行的进程的方法。接下来,我们看到了如何打印系统上运行的所有进程。然后是暴露每个进程使用的命令。然后,我们专注于过滤特定用户的输出,也可以通过用户 ID 进行过滤。之后,我们触及了对进程进行过滤,也可以通过进程 ID 进行过滤。除此之外,我们还处理了按组进行过滤。然后,我们将显示更改为树状布局。

此外,我们看到了如何获取内存和 CPU 信息;我们调用watch命令实时更新结果。最后,我们看到了如何使用ps命令结合kill命令终止一个进程。接下来,我们触及了pstree命令;这以分层格式呈现进程。我们甚至操纵了它的输出来缩小到特定的进程;此外,我们还检查了特定用户的进程。

在此之后,我们触及了pgrep命令,也称为进程 grep。这是另一种查找进程 ID 的方法;可以提供进程名称,也可以指定要显示的用户。在此之后,我们触及了pkill命令;顾名思义,它用于终止一个进程。我们在演示中看到了这一点。之后,我们使用top命令,使用各种技术来操作结果的输出,并探讨了如何在top命令中终止一个进程。

接下来,我们使用了service命令;我们谈到了我们通常在哪里找到它,并查看了它在较新的 Linux 发行版中的支持。使用service命令进行了各种演示。最后,我们使用了systemctl命令;这是迄今为止在使用系统的较新 Linux 发行版中管理进程的最佳方法,而不是使用 SysVinit 脚本的较旧的 Linux 发行版。

在下一章中,我们将深入探讨管理进程。有时我们希望优先考虑一个进程而不是另一个。这是下一章的重点。这不仅能让您管理系统上的进程,还能让您比其他人更有优势,从而让您更接近认证。希望能在那里见到您。

问题

  1. 哪个命令打印在新终端中启动的进程?

A. pkill

B. chmod

C. ps

D. chage

  1. ps命令的哪个选项可以用于打印系统中运行的所有进程?

A. -B

B. -b

C. -e

D. -x

  1. ps命令的哪个选项可以用于以分层布局打印输出?

A. -forest

B. --forest

C. --tree

D. -tree

  1. ps命令的哪个选项用于指定用户进程?

A. -x

B. -a

C. -u

D. -d

  1. kill命令的哪个选项用于显示各种 SIG 术语?

A. -

B. -l

C. -i

D. -d

  1. 使用kill命令时,哪个数字等同于SIGKILL

A. 8

B. 10

C. 7

D. 9

  1. top命令的哪个选项可以指定用户?

A. -u

B. -p

C. -v

D. -a

  1. top实用程序中用哪个字母设置刷新结果的频率?

A. -a

B. b

C. d

D. e

  1. 哪个选项可以用于使用service命令重新读取进程配置?

A. reboot

B. stop

C. status

D. reload

  1. 在由systemctl命令管理的系统中,单位/processes位于哪个目录?

A. /var/lib/systemd

B. /usr/lib/systemd/system

C. /usr/systemd/system

D. /usr/system/systemd

进一步阅读

  • 有关进程的更多信息,请参阅:www.tutorialspoint.com.

  • 这个网站为您提供了许多有关进程的有用提示:www.linux.com.

  • 这个最后的链接为您提供了与各种命令相关的一般信息。您可以在那里发布您的问题,其他社区成员将会回答:www.linuxquestions.org.

第十章:修改进程执行

在上一章中,我们揭示了暴露当前在 shell 中运行的进程的各种方法。此外,我们还看到了如何获取内存和 CPU 信息,以及如何使用ps命令结合kill命令终止进程。接下来,我们接触了pstree命令。接着,我们接触了pgrep命令;也称为进程 Grep。之后,我们接触了pkill命令;顾名思义,它用于终止进程。之后,我们使用了top命令。接下来,我们使用了service命令。最后,我们使用了systemctl命令。

与前几章相比,本章内容较少,但在资源管理方面具有重要意义。首先,进一步讨论了进程管理,这次重点是进程在进程调度器中的重要性(有时您可能会听到内核调度器这个术语;它们是指同一件事)。通常,我们面临着与资源限制相关的挑战。这将以多种方式加以解决。考虑到这一点,我们将探讨在 Linux 发行版的范围内尝试更改进程优先级时应遵循的各种准则。第一部分关注nice命令。接下来是renice命令。最后,重点将放在前台进程与后台进程上。

我们将在本章中涵盖以下主题:

  • nice命令

  • renice命令

  • 前台进程与后台进程

nice 命令

简而言之,nice命令用于调整进程的 niceness,以便与 CPU 资源的可用性相关。当我们说“niceness”时,这是指对特定进程在 CPU 资源方面给予的关注或优先级。我们可以增加或减少给定进程的优先级。每当 CPU 被一系列进程拖垮时,这就变得相关起来,每个进程都在争夺自己的关注。通过改变特定进程的 niceness,我们影响了进程的调度。

我们可以使用ps命令查看进程的当前nice值;我们会传递al选项:

root@ubuntu:/home/philip# ps -al
F S UID PID  PPID C PRI  NI ADDR SZ WCHAN TTY  TIME CMD
4 S  0  2423 2271 0 80   0 - 13698 poll_s pts/17   00:00:00 sudo
4 S  0   2437 2423 0 80  0 - 13594 wait   pts/17   00:00:00 su
4 S  0   2438 2437 0 80  0 - 5304 wait   pts/17   00:00:00 bash
0 R  0   3063 2438 0 80  0 - 7229 -      pts/17   00:00:00 ps
root@ubuntu:/home/philip#

出于简洁起见,某些输出已被省略。根据前面的输出,NI列代表进程的当前 niceness。您会注意到大多数进程的 niceness 值都设置为0。我们还可以过滤ps命令的输出;我们可以使用grep命令:

root@ubuntu:/home/philip# ps -eo pid,ppid,ni,comm | grep update
 2402   1841   0 update-notifier
 2421   1611  10 update-manager
root@ubuntu:/home/philip#

干得漂亮!基于此,我们可以看到有一些进程的 niceness 值默认不是0。有趣的是,我们还可以利用另一个命令来查看进程的当前 niceness;我们可以使用top命令:

root@ubuntu:/home/philip# top
PID USER   PR  NI    VIRT   RES  SHR S %CPU %MEM   TIME+   COMMAND                                           3020 root  20   0   41800  3880  3176 R  6.7  0.4   0:00.01 top 
1 root     20   0  185164  4532  3100 S  0.0  0.5   0:01.92 systemd 
2 root     20   0     0   0     0 S  0.0  0.0   0:00.00   kthreadd                                         3 root    20    0     0   0     0 S  0.0  0.0   0:00.16  ksoftirqd/0 
9 root    rt   0     0    0     0 S  0.0  0.0   0:00.00  migration/0 
10 root   rt   0     0    0     0 S  0.0  0.0   0:00.00  watchdog/0 
15 root   0   -20    0    0     0 S  0.0  0.0   0:00.00  writeback 
16 root   25   5     0    0     0 S  0.0  0.0   0:00.00  ksmd 
17 root   39  19     0    0     0 S  0.0  0.0   0:00.00  khugepaged 

第四列NI代表每个进程的 niceness。另一个关键列是第三列PR;这代表 Linux 内核所看到的实际优先级。PRI列不可由用户配置。此外,PRI列下的rt表示这些进程的优先级是由实时调度处理的。

我们不能改变PRI列下的值。

我们可以通过传递--help选项来查看nice命令的语法:

root@ubuntu:/home/philip# nice --help
Usage: nice [OPTION] [COMMAND [ARG]...]
Run COMMAND with an adjusted niceness, which affects process scheduling.
With no COMMAND, print the current niceness.  Niceness values range from
-20 (most favorable to the process) to 19 (least favorable to the process).
Mandatory arguments to long options are mandatory for short options too.
 -n, --adjustment=N   add integer N to the niceness (default 10)
 --help     display this help and exit
 --version  output version information and exit

您的 shell 可能有自己的nice版本,通常会取代此处描述的版本。有关其支持的选项的详细信息,请参阅您的 shell 文档。

GNU coreutils 在线帮助可以在以下网址找到:www.gnu.org/software/coreutils

完整的文档可以在以下网址找到:www.gnu.org/software/coreutils/nice

或者在本地通过以下方式查看:info '(coreutils) nice invocation'

root@ubuntu:/home/philip#

根据前述语法,我们可以设置的范围是从-19(最高优先级)到 20(最低优先级)。让我们运行不带任何选项的nice命令:

root@ubuntu:/home/philip# nice
0
root@ubuntu:/home/philip#

很好!值0表示启动 shell 的优先级。请记住,普通用户无法更改其他用户的进程的优先级;只有 root 用户才能更改任何用户的优先级。默认情况下,如果我们运行nice命令而没有指定优先级值,那么优先级将设置为10。让我们验证一下:

root@ubuntu:/home/philip# ps -alx | grep cron
1  0  3419  1611  30 10  29008  2540 hrtime SNs  ?   0:00 cron
0  0  3435 2438 20 0 14224 952 pipe_w S+ pts/17 0:00 grep --color=auto cron
root@ubuntu:/home/philip# nice cron
cron: can't lock /var/run/crond.pid, otherpid may be 3419: Resource temporarily unavailable
root@ubuntu:/home/philip#

根据前面的输出,NI值没有改变。这是因为进程已经启动。nice命令无法改变当前正在运行的进程的优先级。我们可以通过停止进程来解决这个问题:

root@ubuntu:/home/philip# systemctl stop cron
root@ubuntu:/home/philip#

现在,让我们尝试使用nice命令启动cron进程:

root@ubuntu:/home/philip# ps -alx | grep cron
0     0   3463   2438  20   0  14224   900 pipe_w S+   pts/17     0:00 grep --color=auto cron
root@ubuntu:/home/philip# nice cron
root@ubuntu:/home/philip# ps -alx | grep cron
1 0 3467 1611 30 10 29008  2732 hrtime SNs  ? 0:00 cron
0 0 3469 2438 20 0 14224 940 pipe_w S+ pts/17 0:00 grep --color=auto cron
root@ubuntu:/home/philip#

太棒了!我们可以清楚地看到NI值已更改为10,即使我们没有指定优先级值。如果我们想指定一个值,那么我们通过在数字前面放置一个-来传递它。让我们再次使用cron进程:

root@ubuntu:/home/philip# systemctl stop cron
root@ubuntu:/home/philip# systemctl status cron
cron.service - Regular background program processing daemon
 Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
 Active: failed (Result: exit-code) since Thu 2018-08-16 11:30:00 PDT; 8min ago
 Docs: man:cron(8)
 Process: 3430 ExecStart=/usr/sbin/cron -f $EXTRA_OPTS (code=exited, status=1/FAILURE)
 Main PID: 3430 (code=exited, status=1/FAILURE)
root@ubuntu:/home/philip# pgrep cron
3467
root@ubuntu:/home/philip#

有时,停止进程时可能会遇到类似的错误。您可以使用systemctl命令或service命令,但进程仍将继续运行。我们可以通过使用前一章学到的知识轻松解决这个问题;我们可以调用kill命令:

root@ubuntu:/home/philip# kill -9 3467
root@ubuntu:/home/philip# pgrep cron
root@ubuntu:/home/philip#

干得好!现在让我们尝试使用一个优先级值启动cron进程:

root@ubuntu:/home/philip# nice -15 cron
root@ubuntu:/home/philip# pgrep cron
3636
root@ubuntu:/home/philip# ps -alx | grep cron
1 0 3636 1611  35 15 29008 2616 hrtime SNs  ?  0:00 cron
0 0 3658 2438  20 0 14224 920 pipe_w S+ pts/17 0:00 grep --color=auto cron
root@ubuntu:/home/philip#

但是有一个问题。如果我们运行system1命令来检查状态,我们将看到以下内容:

root@ubuntu:/home/philip# systemctl status cron
cron.service - Regular background program processing daemon
 Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
 Active: failed (Result: exit-code) since Thu 2018-08-16 11:30:00 PDT; 21min ago
 Docs: man:cron(8)
 Process: 3430 ExecStart=/usr/sbin/cron -f $EXTRA_OPTS (code=exited, status=1/FAILURE)
 Main PID: 3430 (code=exited, status=1/FAILURE)
Aug 16 11:30:00 ubuntu systemd[1]: cron.service: Unit entered failed state.
Aug 16 11:30:00 ubuntu systemd[1]: cron.service: Failed with result 'exit-code'.
root@ubuntu:/home/philip#

我们收到此错误的原因是,当我们使用使用systemd的 Linux 发行版时,我们需要编辑/lib/systemd/system/中的服务文件。在我们的情况下,它将是/lib/systemd/system/cron.service。这是/lib/systemd/system/cron.service配置文件:

root@ubuntu:/home/philip# cat /lib/systemd/system/cron.service
[Unit]
Description=Regular background program processing daemon
Documentation=man:cron(8)
[Service]
EnvironmentFile=-/etc/default/cron
ExecStart=/usr/sbin/cron -f $EXTRA_OPTS
IgnoreSIGPIPE=false
KillMode=process
[Install]
WantedBy=multi-user.target
root@ubuntu:/home/philip#

[Service]部分是我们放置Nice=value的地方。这是我们将存储cron进程的优先级并消除systemctl正在生成的错误的方法:

root@ubuntu:/home/philip# cat /lib/systemd/system/cron.service
[Unit]
Description=Regular background program processing daemon
Documentation=man:cron(8)
[Service]
Nice=15
EnvironmentFile=-/etc/default/cron
ExecStart=/usr/sbin/cron -f $EXTRA_OPTS
IgnoreSIGPIPE=false
KillMode=process
[Install]
WantedBy=multi-user.target
root@ubuntu:/home/philip#

现在,一旦我们对systemd服务进行了任何更改,我们需要运行这个命令:

root@ubuntu:/home/philip# systemctl daemon-reload
root@ubuntu:/home/philip#

太棒了!此外,您希望在ExecStart之前放置Nice=,因为如果您将其放在之后,它将不会对进程产生影响。我们现在将停止现有的cron进程并使用systemctl启动cron;错误将消失,systemctl将很高兴:

root@ubuntu:/home/philip# systemctl stop cron
root@ubuntu:/home/philip# ps -alx | grep cro
0   0 3904  2438 20  0  14224  1016 pipe_w S+ pts/17  0:00 grep --color=auto cro
root@ubuntu:/home/philip# systemctl start cron
root@ubuntu:/home/philip# ps -alx | grep cro
4  0 3907  1  35  15  29008  2988 hrtime SNs  ?  0:00 /usr/sbin/cron -f
0  0 3911  2438  20  0 14224  1024 pipe_w S+   pts/17     0:00 grep --color=auto cro
root@ubuntu:/home/philip#

干得好!现在我们可以看到cron进程的NI设置为15。这仅适用于cron等系统服务。另一种方法是传递--adjustment=选项;我们将在等号(=)后指定一个优先级值:

root@ubuntu:/home/philip# systemctl stop cron
root@ubuntu:/home/philip# nice --adjustment=13 cron
root@ubuntu:/home/philip# ps -alx | grep cro
1  0 3941   1611  33  13  29008  2576 hrtime SNs  ?   0:00 cron
0  0 3943   2438  20   0  14224  1008 pipe_w S+  pts/17 0:00 grep --color=auto cro
root@ubuntu:/home/philip#

当然,systemctl会抱怨:

root@ubuntu:/home/philip# systemctl status cron
cron.service - Regular background program processing daemon
 Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
 Active: inactive (dead) since Thu 2018-08-16 12:13:32 PDT; 1min 3s ago
 Docs: man:cron(8)
 Process: 3907 ExecStart=/usr/sbin/cron -f $EXTRA_OPTS (code=killed, signal=TERM)
 Main PID: 3907 (code=killed, signal=TERM)
root@ubuntu:/home/philip#

但是我们可以很容易地通过使用我们刚学到的技术来解决这个问题;通过在/lib/systemd/system/cron.service中指定声明:

root@ubuntu:/home/philip# cat /lib/systemd/system/cron.service
[Unit]
Description=Regular background program processing daemon
Documentation=man:cron(8)
[Service]
Nice=13
EnvironmentFile=-/etc/default/cron
ExecStart=/usr/sbin/cron -f $EXTRA_OPTS
IgnoreSIGPIPE=false
KillMode=process
[Install]
WantedBy=multi-user.target
root@ubuntu:/home/philip#
root@ubuntu:/home/philip# systemctl daemon-reload
root@ubuntu:/home/philip# systemctl start cron
root@ubuntu:/home/philip# ps -alx | grep cro
4  0  4084   1  33  13  29008  2956 hrtime SNs ? 0:00 /usr/sbin/cron -f
0  0  4088   2438  20   0  14224  1076 pipe_w S+   pts/17  0:00 grep --color=auto cro
root@ubuntu:/home/philip#

太棒了!

在修改系统进程时要非常谨慎,就像在这些演示中看到的那样。

renice 命令

当我们使用nice命令时,很明显它无法更改正在运行的进程的调度优先级;正如我们刚才看到的,我们需要停止然后启动进程。这就是renice命令的优势所在。我们可以利用renice命令在进程运行时更改优先级。要查看语法,我们将传递--help选项:

root@ubuntu:/home/philip# renice --help
Usage:
 renice [-n] <priority> [-p|--pid] <pid>...
renice [-n] <priority>  -g|--pgrp <pgid>...
 renice [-n] <priority>  -u|--user <user>...
Alter the priority of running processes.
Options:
 -n, --priority <num>   specify the nice increment value
 -p, --pid <id>         interpret argument as process ID (default)
 -g, --pgrp <id>        interpret argument as process group ID
 -u, --user <name>|<id> interpret argument as username or user ID
 -h, --help     display this help and exit
 -V, --version  output version information and exit
For more details see renice(1).
root@ubuntu:/home/philip#

首先,让我们使用ps命令查看进程的优先级,然后更改其优先级:

root@ubuntu:/home/philip# ps -alx | grep ssh
4     0   3375      1  20   0   9996  4900 poll_s Ss   ?          0:00 /usr/sbin/sshd -D
0    0   4196   2438  20   0  14224   936 pipe_w S+   pts/17     0:00 grep --color=auto ssh
root@ubuntu:/home/philip#
root@ubuntu:/home/philip# renice -2 3375
3375 (process ID) old priority 0, new priority -2
root@ubuntu:/home/philip# ps -alx | grep ssh
4  0  3375  1  18  -2   9996  4900 poll_s S<s  ? 0:00 /usr/sbin/sshd -D
0  0   4209   2438  20  0  14224  1080 pipe_w S+ pts/17 0:00 grep --color=auto ssh
root@ubuntu:/home/philip#

根据前面的输出,renice命令期望进程的 PID。此外,当我们指定一个-后跟一个数字时,它会将其解释为负-号并分配一个负值。此外,systemctl命令不会抱怨,因为使用renice命令时不需要停止和启动进程以应用更改:

root@ubuntu:/home/philip# systemctl status sshd
ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2018-08-16 11:25:39 PDT; 1h 20min ago
 Main PID: 3375 (sshd)
CGroup: /system.slice/ssh.service
└─3375 /usr/sbin/sshd -D
root@ubuntu:/home/philip#

干得好!我们还可以为特定用户更改优先级;我们将传递-u选项。让我们为所有属于某个用户的进程更改优先级:

root@ubuntu:/home/philip# ps -alu philip
F S UID  PID PPID C  PRI  NI ADDR SZ WCHAN  TTY  TIME CMD
4 S  1000 1507 1  0  80  0 - 11319 ep_pol   ?  00:00:00 systemd
5 S  1000  1508 1507 0 80 0 - 36293 sigtim  ?   00:00:00 (sd-pam)
1 S  1000  1599  1  0  80  0 - 51303 poll_s ? 00:00:00 gnome-keyring-d
4 S  1000  1611 1349  0  80 0 - 11621 poll_s ?  00:00:00 upstart
1 S  1000  1696 1611  0  80  0 - 10932 ep_pol ? 00:00:00 dbus-daemon
0 S  1000   1708  1611 0 80 0 - 21586 poll_s ? 00:00:00 window-stack-br
1 S  1000   1721 1611  0  80 0 - 8215 poll_s ? 00:00:00 upstart-udev-br
1 S  1000   1735   1611 0 80 0 - 8198 poll_s ? 00:00:00 upstart-dbus-br
1 S  1000 1737 1611  0 80  0 -  8198 poll_s ? 00:00:00 upstart-dbus-br
1 S  1000 1743 1611  0 80 0 - 10321 poll_s ? 00:00:00 upstart-file-br
root@ubuntu:/home/philip# renice 3 -u philip
root@ubuntu:/home/philip # ps -alu philip
F S UID PID   PPID  C PRI  NI ADDR SZ WCHAN TTY TIME CMD
4 S  1000 1507  1   0  83 3 - 11319 ep_pol ? 00:00:00 systemd
5 S  1000 1508  1507 0 83  3 - 36293 sigtim ? 00:00:00 (sd-pam)
1 S  1000 1599  1   0  83  3 - 51303 poll_s ? 00:00:00 gnome-keyring-d
4 S  1000 1611  1349 0  83 3 - 11621 poll_s ? 00:00:00 upstart
1 S  1000 1696  1611 0  83 3 - 10932 ep_pol ? 00:00:00 dbus-daemon
0 S  1000 1708  1611 0 83  3 - 21586 poll_s ? 00:00:00 window-stack-br
1 S  1000 1721  1611 0 83  3 - 8215 poll_s ? 00:00:00 upstart-udev-br
1 S  1000 1735  1611 0 83  3 - 8198 poll_s ? 00:00:00 upstart-dbus-br
1 S  1000 1737  1611 0 83  3 - 8198 poll_s ? 00:00:00 upstart-dbus-br
1 S  1000 1743  1611 0  83 3 - 10321 poll_s ? 00:00:00 upstart-file-br

干得好!已经为指定用户拥有的每个进程更改了优先级。

前台进程与后台进程

在 shell 中工作时,实际上是在所谓的前台工作;除非我们停止当前进程,否则我们无法执行任何其他任务。有时候,您会想要将一些进程发送到后台进行处理;这将允许您在 shell 中继续工作,同时后台中的进程也在运行。要验证是否有任何后台运行的进程,我们可以使用jobs命令。让我们试一试:

root@ubuntu:/home/philip# jobs
root@ubuntu:/home/philip#

从前面的输出中,我们可以看到当前没有作业在后台运行。要了解进程如何影响您在 shell 中的工作,让我们看看yes实用程序;这可以在大多数 Linux 发行版中找到。yes实用程序将一直运行,直到我们暂停或停止它;当我们执行yes实用程序时,它将阻止我们执行任何命令:

root@ubuntu:/home/philip# yes
y
y
y

要停止此实用程序,我们将使用Ctrl + C的组合:

y
^C
root@ubuntu:/home/philip#

这将无意中停止yes实用程序。yes实用程序的语法如下:

  • yes <STRING>:如果我们省略字符串,它将像前面的代码中显示的那样输出一个y

  • yes <OPTIONS>:可用选项为 version 和 help

如果我们重新运行yes实用程序,并且决定不停止它,而是决定暂停它,我们将使用Ctrl + Z的组合。这将实际上将yes实用程序放在后台:

root@ubuntu:/home/philip# yes
y
y
y
^Z
[1]+  Stopped                 yes
root@ubuntu:/home/philip#

这次,当我们运行jobs命令时,我们会看到有一个作业被列出:

root@ubuntu:/home/philip# jobs
[1]+  Stopped                 yes
root@ubuntu:/home/philip#

这已经暂停了yes实用程序并将其放在后台,使我们能够继续在命令提示符下工作。另一个例子来说明前台进程阻止 shell,从而阻止我们执行任何其他命令的概念,是我们启动了一个实用程序,例如vim或任何 GUI 程序。

让我们选择一个 GUI 来演示;这将更加突出这一点。我们将从 shell 启动gedit实用程序:

根据前面的输出,shell 正在阻止我们输入任何其他命令,直到我们暂停或关闭gedit实用程序。让我们暂停gedit实用程序:

从前面的输出中,您会注意到gedit实用程序已经冻结,这意味着我们无法从gedit实用程序内执行任何操作。现在让我们再次运行jobs命令:

root@ubuntu:/home/philip# jobs
[1]-  Stopped                 yes
[2]+  Stopped                 gedit
root@ubuntu:/home/philip#

干得好!现在有两个作业被列出。如果我们决定要恢复其中一个作业,我们可以使用另一个强大的命令:fg命令。fg命令的语法如下:

fg %<job id>

要看到这一点,让我们从其停止状态恢复gedit实用程序:

太棒了!现在我们可以在从命令提示符启动的gedit实用程序中工作。但是,有一个问题。当我们按下Ctrl + Z时,程序会停止。在实际环境中,我们希望将发送到后台的进程继续运行。这将加快我们的生产力,使我们能够执行同时进行的工作。请放心,事实上,通过另一种技术是可能的,我们可以在 shell 中执行命令时使用。&用于启动进程并将其发送到后台。让我们关闭gedityes实用程序:

root@ubuntu:/home/philip# fg
y
y
^C
root@ubuntu:/home/philip# jobs
root@ubuntu:/home/philip#

现在,我们将使用&启动gedit实用程序并将其直接发送到后台:

干得好!现在我们可以在gedit实用程序中工作,或者我们可以继续在命令提示符下工作。此外,当我们运行jobs命令时,我们将看到gedit实用程序的状态为running

root@ubuntu:/home/philip# jobs
[1]+  Running                 gedit &
root@ubuntu:/home/philip#

太棒了!还有另一种方法可以恢复在后台停止的作业并指示它们在后台运行。这是通过利用另一个强大的命令实现的:bg命令。这是我们如果已经停止了gedit程序,我们将如何恢复gedit程序并指示它在后台运行:

干得好!bg命令做了两件事。首先,它恢复了gedit实用程序。然后在命令的末尾放置了&。正如我们之前看到的,&指示进程在后台运行。如果有多个作业,我们将指定作业 ID 或作业名称:

root@ubuntu:/home/philip# gnome-calculator
** (gnome-calculator:9649): WARNING **: currency.vala:407: Currency ZAR is not provided by IMF or ECB
^Z
[2]+  Stopped                 gnome-calculator
root@ubuntu:/home/philip# jobs
[1]-  Running                 gedit &
[2]+  Stopped                 gnome-calculator
root@ubuntu:/home/philip#
root@ubuntu:/home/philip# bg 2
[2]+ gnome-calculator &
root@ubuntu:/home/philip# jobs
[1]-  Running                 gedit &
[2]+  Running                 gnome-calculator &
root@ubuntu:/home/philip#

太棒了!我们可以看到这两个实用程序都是打开的,并且可以与命令提示符同时使用。

摘要

在本章中,我们已经介绍了处理进程的各种方法。首先,我们专注于使用nice命令调度进程。每当 CPU 上的工作负载上升时,各种进程都在争夺 CPU 的资源。使用各种命令暴露了每个进程的 niceness,例如:pstop。接下来,我们进行了一些演示,演示了如何设置进程的 niceness。这使我们进入了运行systemd的系统;我们看到了在systemd系统上更改进程的 niceness 的问题。这导致我们修改了进程的配置文件,以便在启动进程时systemd能够识别 niceness。之后,我们转向了renice命令,特别是处理当前正在运行的进程以及更改正在运行的进程的 niceness 的方法。这通过更改 niceness 来说明,不仅适用于给定的进程,而且我们还能够更改由用户拥有的所有进程的 niceness。systemd识别了正在运行的进程的更改,而无需我们修改任何特定的配置。但是,如果进程停止并启动或重新启动,那么我们设置的 niceness 将被删除。要解决这个问题并使 niceness 持续存在,意味着编辑给定进程的配置文件。最后,我们在前台和后台的背景下处理了进程。前台进程的概念影响我们在命令提示符上工作,直到前台进程被挂起或关闭。当我们被要求执行多个操作时,这大大降低了生产力。解决方法是让进程在后台运行,从而使您能够有效地在命令提示符下执行功能。

在下一章中,我们将把注意力转向显示管理器的世界。通常,大多数用户都习惯于在 GUI 环境中工作。因此,重点将涵盖今天 Linux 发行版中普遍存在的常见显示管理器,以及当前 Linux+考试目标中的显示管理器。首先,我们将涉及X 显示管理器XDM)。接下来,将讨论 KDE 显示管理器。然后将讨论Gnome 显示管理器GDM)。最后,本章将涵盖Light 显示管理器LDM)。这一章对于您的考试准备至关重要,就像以前的所有章节一样。这将使您能够使用今天 Linux 环境中常见的各种显示管理器。

问题

  1. 使用ps命令的哪个选项打印每个进程的 niceness?

A. n

B. l

C. a

D. x

  1. 使用ps命令表示每个进程的 niceness 的哪一列?

A. NI

B. ni

C. N1

D. nice

  1. 使用top命令表示每个进程的 niceness 的哪一列?

A. ni

B. PNI

C. pnic

D. NI

  1. 在使用nice命令时,哪个值不是有效值?

A. -20

B. -19

C. 20

D. 19

  1. 哪个 niceness 值具有最高优先级?

A. -21

B. -32

C. -19

D. -20

  1. 使用systemd存储进程配置文件的目录是哪个?

A. /usr/lib/systemd/system

B. /lib/systemd/system

C. /lib/systemd/system/service

D. /lib/systemd/service

  1. 在使用systemd编辑服务文件后需要运行哪个命令?

A. systemctl daemon-reload

B. systemctl --daemon-reload

C. systemctl daemon --reload

D. systemctl daemonreload

  1. 在使用renice命令时,指定 niceness 值后会发生什么?

A. 进程名称

B. PID

C. 进程名称 + PID

D. 以上都不是

  1. 哪个命令可以从后台恢复一个进程,并阻止你执行其他命令,直到当前进程结束为止?

A. fg

B. bg

C. jobs

D. job

  1. 哪个命令可以从后台恢复一个进程,但将其放在后台,允许你在命令提示符下执行其他命令?

A. fg

B. jobs

C. bg

D. CTRL+C

进一步阅读

  • 你可以通过查看www.tecmint.com来获取有关管理进程的更多信息。

  • 这个网站提供了很多有用的关于处理进程的技巧和最佳实践:www.digitalocean.com

  • 这个链接提供了一般性的信息,涉及适用于 CentOS 和 Ubuntu 的各种命令。你可以在那里发布你的问题,其他社区成员将能够回答:www.linuxquestions.org

第十一章:显示管理器

在上一章中,我们介绍了处理进程的各种方法。首先,我们专注于使用nice命令调度进程。每当 CPU 的工作负载增加时,各种进程都在争夺 CPU 的资源;使用各种命令(如pstop)暴露了每个进程的 niceness。之后,我们转向renice命令,特别是处理当前正在运行的进程,以及更改正在运行的进程的 niceness 的方法。最后,我们在前台与后台的进程上工作。

在本章中,将介绍显示管理器。通常,大多数用户习惯在 GUI 环境中工作。我们将看看当今 Linux 发行版中普遍存在的显示管理器。显示管理器有时会与桌面混淆;显示管理器管理 GUI 登录提示,该提示在用户启动时呈现。桌面是用户用来执行各种任务的 X Windows 集合。一些桌面的例子包括 XFCE KDE,GNOME 和 Unity 等。此外,还将介绍当前 Linux+考试目标中的显示管理器。首先,我们将介绍X 显示管理器XDM)。接下来,将讨论KDE 显示管理器KDM)。然后是GNOME 显示管理器GDM)。最后,本章将介绍轻量级显示管理器Lightdm)。

本章将涵盖以下主题:

  • 使用 XDM

  • 使用 KDM

  • 使用 GDM

  • 使用 Lightdm

使用 XDM

XDM 管理一组 X 服务器。这可以是系统上的本地 X 服务器,也可以是网络上另一个 X 服务器上的远程 X 服务器。XDM 实用程序在某种程度上类似于较旧的 SysVinit,因此您可能会对 X 服务器的概念感到困惑。X 服务器是 X Window 系统中的一个程序;它在本地机器上运行。它通常管理对图形卡、显示器以及本地机器上的键盘和鼠标的访问。那么 X Window 系统是什么?嗯,X Window 系统,通常称为 X,是一个由跨平台、免费的客户端-服务器基础设施组成的整套系统,用于管理单个或一系列计算机上的图形用户界面GUI),就像在网络环境中一样。在 X 的上下文中,客户端/服务器的工作方式有点奇怪;每台本地机器上都运行一个 X 服务器。然后,X 服务器访问 X 客户端;X 客户端是 GUI 应用程序。另一个有趣的地方是 X 客户端可以在本地运行,也可以在网络上远程运行。X 服务器充当中间人,实际的 X 客户端与 X 服务器进行交互;然后 X 服务器与实际的显示设备进行交互。X 服务器使用X 显示管理器控制协议XDMCP)。XDM 旨在成为命令行登录提示的图形替代品。用户提供其登录凭据后,XDM 启动其 X 会话。

使用 XDM 的第一步是安装它。我们将使用 CentOS 6.5 系统。我们将搜索xdm

[root@localhost Desktop]# yum search xdm
Loaded plugins: fastestmirror, refresh-packagekit, security
=========================================== N/S Matched: xdm ===========================================
libXdmcp-devel.i686 : Development files for libXdmcp
libXdmcp-devel.x86_64 : Development files for libXdmcp
xorg-x11-xdm.x86_64 : X.Org X11 xdm - X Display Manager
libXdmcp.i686 : X Display Manager Control Protocol library
libXdmcp.x86_64 : X Display Manager Control Protocol library
xorg-x11-server-Xdmx.x86_64 : Distributed Multihead X Server and utilities
 Name and summary matches only, use "search all" for everything.
[root@localhost Desktop]#

太棒了!默认情况下,CentOS 6.5 使用 GDM;我们将安装 XDM 进行演示:

[root@localhost Desktop]# yum install xorg-x11-xdm.x86_64
Loaded plugins: fastestmirror, refresh-packagekit, security
Loading mirror speeds from cached hostfile
 * updates: centos.mirror.iweb.ca
Setting up Install Process
Resolving Dependencies
--> Processing Dependency: libXaw.so.7()(64bit) for package: 1:xorg-x11-xdm-1.1.6-14.1.el6.x86_64
Installed:
 xorg-x11-xdm.x86_64 1:1.1.6-14.1.el6 
Dependency Installed:
 libXaw.x86_64 0:1.0.11-2.el6                       libXpm.x86_64 0:3.5.10-2.el6 
Complete!
[root@localhost Desktop]#

出于简洁起见,某些输出已被省略。接下来,我们将看看配置目录;这在/etc/X11内:

[root@localhost Desktop]# ls /etc/X11
applnk  fontpath.d  prefdm  xdm  xinit  Xmodmap  xorg.conf.d  Xresources
[root@localhost Desktop]#
[root@localhost xdm]# ll
total 40
-rwxr-xr-x. 1 root root  510 Aug 19  2010 GiveConsole
-rwxr-xr-x. 1 root root  244 Aug 19  2010 TakeConsole
-rw-r--r--. 1 root root 3597 Aug 19  2010 Xaccess
-rw-r--r--. 1 root root 1394 Aug 19  2010 xdm-config
-rwxr-xr-x. 1 root root  183 Aug 19  2010 Xreset
-rw-r--r--. 1 root root 2381 Aug 19  2010 Xresources
-rw-r--r--. 1 root root  484 Aug 19  2010 Xservers
lrwxrwxrwx. 1 root root   17 Aug 24 07:55 Xsession -> ../xinit/Xsession
-rwxr-xr-x. 1 root root  938 Aug 19  2010 Xsetup_0
-rwxr-xr-x. 1 root root  181 Aug 19  2010 Xstartup
-rwxr-xr-x. 1 root root  303 Aug 19  2010 Xwilling
[root@localhost xdm]#

这些是使 XDM 发光的必要文件。默认情况下,CentOS 6.5 不会使用 XDM;这可以通过编辑/etc/X11/preferdm轻松解决:

[root@localhost xdm]# cat /etc/X11/prefdm
#!/bin/sh
PATH=/sbin:/usr/sbin:/bin:/usr/bin
# We need to source this so that the login screens get translated
[ -f /etc/sysconfig/i18n ] && . /etc/sysconfig/i18n
# Run preferred X Display Manager
quit_arg=
preferred=
exit 1
[root@localhost xdm]#

出于简洁起见,某些输出已被省略。我们应该在preferred=行中指定显示管理器。我们还可以编辑/etc/sysconfig/desktop来采取另一种方法:

[root@localhost xdm]# ls /etc/sysconfig | grep desktop
[root@localhost xdm]#

根据前面的输出,我们需要创建/etc/sysconfig/桌面文件。让我们试试看:

[root@localhost xdm]# which xdm
/usr/bin/xdm
[root@localhost xdm]# vim /etc/sysconfig/desktop
[root@localhost philip]# cat /etc/sysconfig/desktop
preferred=/usr/bin/xdm
[root@localhost philip]#

根据前面的示例,我们已经创建了一个文件并存储了 XDM 的位置,这是使用which命令得出的。which命令可用于查找可执行文件的位置。

现在,让我们重新启动系统以使这些更改生效:

干得漂亮!现在我们看到了 XDM 登录界面。XDM 的配置文件存储在/etc/X11/xdm中:

[root@localhost philip]# ll /etc/X11/xdm
total 40
-rwxr-xr-x. 1 root root 510 Aug 19 2010 GiveConsole
-rwxr-xr-x. 1 root root 244 Aug 19 2010 TakeConsole
-rw-r--r--. 1 root root 3597 Aug 19 2010 Xaccess
-rw-r--r--. 1 root root 1394 Aug 19 2010 xdm-config
-rwxr-xr-x. 1 root root 183 Aug 19 2010 Xreset
-rw-r--r--. 1 root root 2381 Aug 19 2010 Xresources
-rw-r--r--. 1 root root 484 Aug 19 2010 Xservers
lrwxrwxrwx. 1 root root 17 Aug 24 07:55 Xsession -> ../xinit/Xsession
-rwxr-xr-x. 1 root root 938 Aug 19 2010 Xsetup_0
-rwxr-xr-x. 1 root root 181 Aug 19 2010 Xstartup
-rwxr-xr-x. 1 root root 303 Aug 19 2010 Xwilling
[root@localhost philip]#

现在我们可以专注于/etc/X11/xdm/Xaccess

# To control which addresses xdm listens for requests on:
#  LISTEN     address [list of multicast groups ... ]
# The first form tells xdm which displays to respond to itself.
#  LISTEN     * ff02:0:0:0:0:0:0:12b
# This example shows listening for multicast on all scopes up
# to site-local
# LISTEN      * ff01:0:0:0:0:0:0:12b ff02:0:0:0:0:0:0:12b ff03:0:0:0:0:0:0:12b ff04:0:0:0:0:0:0:12b ff05:0:0:0:0:0:0:12b
[root@localhost philip]#

出于简洁起见,某些输出已被省略。前面的文件控制 XDM 将监听哪些地址以进行传入请求。另一个重要文件,在远程使用 XDM 时,是/etc/X11/xdm/xdm-config

[root@localhost philip]# cat /etc/X11/xdm/xdm-config
! The following three resources set up display :0 as the console.
DisplayManager._0.setup:            /etc/X11/xdm/Xsetup_0
DisplayManager._0.startup:          /etc/X11/xdm/GiveConsole
DisplayManager._0.reset:            /etc/X11/xdm/TakeConsole
DisplayManager*loginmoveInterval:      10
! SECURITY: do not listen for XDMCP or Chooser requests
! Comment out this line if you want to manage X terminals with xdm
DisplayManager.requestPort:    0
[root@localhost philip]#

出于简洁起见,某些输出已被省略。最后一行DisplayManager.requestPort: 0需要被注释掉,以便我们可以使用 XDM 管理远程会话。

使用 KDM

KDM 是当今 Linux 发行版中更受欢迎的显示管理器之一。KDM 基于 X 显示管理器的源代码开发,由 KDE 开发。多年来,它一直是 KDE 框架的显示管理器,但最近发生了变化。为了看到 KDM,我们将使用dnf命令在我们的 Fedora 28 系统上。Fedora 28 使用 GDM。

我们将使用groupinstall选项为演示安装 KDE 桌面;这将安装 KDE 桌面所需的所有必要软件包:

[root@localhost philip]# dnf groupinstall KDE
Install  412 Packages
Upgrade    3 Packages
Total download size: 425 M
Is this ok [y/N]: y
 xorg-x11-apps.x86_64 7.7-20.fc28 
 xorg-x11-fonts-misc.noarch 7.5-19.fc28 
 xorg-x11-xbitmaps.noarch 1.1.1-13.fc28 
Upgraded:
 firewalld.noarch 0.5.3-2.fc28        firewalld-filesystem.noarch 0.5.3-2.fc28
 python3-firewall.noarch 0.5.3-2.fc28
Complete!
[root@localhost philip]#

接下来,我们将使用dnf命令安装kdm实用程序和其他组件:

[root@localhost philip]# dnf install kdm kde-settings-kdm
Last metadata expiration check: 0:12:52 ago on Mon 27 Aug 2018 11:16:03 AM EDT.
Dependencies resolved.
====================================================================
Package           Arch         Version        Repository  Size
====================================================================
Installing:
 kdm              x86_64  1:4.11.22-22.fc28    fedora     740 k
 kdm-settings     noarch  1:4.11.22-22.fc28    fedora     186 k
====================================================================
Install  5 Packages
Total download size: 1.2 M
Installed size: 2.3 M
Is this ok [y/N]: y
Installed:
 kdm.x86_64 1:4.11.22-22.fc28 
 kdm-settings.noarch 1:4.11.22-22.fc28 
 kgreeter-plugins.x86_64 1:4.11.22-22.fc28 
 libkworkspace.x86_64 1:4.11.22-22.fc28 
 qimageblitz.x86_64 0.0.6-15.fc28 
Complete!
[root@localhost philip]#

太棒了!出于简洁起见,某些输出已被省略。kdm实用程序已被安装。最后,我们将安装系统切换器;这将允许我们从 GDM 切换到 KDM:

[root@localhost philip]# dnf install system-switch-displaymanager.noarch
Last metadata expiration check: 0:16:52 ago on Mon 27 Aug 2018 11:16:03 AM EDT.
Dependencies resolved.
====================================================================
Package                       Arch   Version     Repository  Size
Installing:
system-switch-displaymanager noarch 1.5.1-3.fc28 fedora 17 k
Transaction Summary
Installed:
 system-switch-displaymanager.noarch 1.5.1-3.fc28 
Complete!
[root@localhost philip]#

干得漂亮!现在我们可以调用system-switch实用程序来从 GDM3 切换到 KDM:

[root@localhost philip]# system-switch-displaymanager KDM
Created symlink /etc/systemd/system/display-manager.service → /usr/lib/systemd/system/kdm.service.
Your default graphical display manager has successfully been switched.
[root@localhost philip]#

太棒了!现在,让我们重新启动我们的 Fedora 28 系统以使更改生效:

根据前面的输出,我们现在可以看到 Fedora 28 系统正在使用kdm实用程序作为显示管理器,而不是gdm。我们还可以在会话类型下看到各种桌面。Plasma 是我们安装的 KDE 风格桌面。让我们登录到 Plasma 桌面并确认我们确实正在使用kdm实用程序:

太棒了!所以我们成功地将我们的桌面更改为了 KDE 风格的 Plasma,现在我们可以查看/etc/systemd/system/display-manager.service以验证正在使用哪个显示管理器:

[root@localhost philip]# ls -l /etc/systemd/system/display-manager.service
lrwxrwxrwx. 1 root root 35 Aug 27 11:34 /etc/systemd/system/display-manager.service -> /usr/lib/systemd/system/kdm.service
[root@localhost philip]#

干得漂亮!我们清楚地看到我们确实已经将我们的显示管理器更改为了 KDM。我们还可以使用systemctl命令检查 KDM 的状态:

[root@localhost philip]# systemctl status kdm.service
kdm.service - The KDE login manager
 Loaded: loaded (/usr/lib/systemd/system/kdm.service; enabled; vendor preset: disabled)
 Active: active (running) since Mon 2018-08-27 11:36:40 EDT; 14min ago
 Main PID: 821 (kdm)
 Tasks: 3 (limit: 2331)
 Memory: 121.6M
 CGroup: /system.slice/kdm.service
 ├─821 /usr/bin/kdm vt1
 └─894 /usr/libexec/Xorg -br -novtswitch -quiet :0 vt1 -background none -nolisten tcp -auth /var/run/kdm/A:0-fPUysb
Aug 27 11:36:40 localhost.localdomain systemd[1]: Started The KDE login manager.
Aug 27 11:36:40 localhost.localdomain kdm[821]: plymouth is running
[root@localhost philip]#

根据前面的输出,我们可以看到kdm.service确实是活动的并正在运行。为了进一步验证,我们还可以检查 GDM 的状态:

[root@localhost philip]# systemctl status gdm.service
gdm.service - GNOME Display Manager
 Loaded: loaded (/usr/lib/systemd/system/gdm.service; disabled; vendor preset: disabled)
 Active: inactive (dead)
[root@localhost philip]#

干得漂亮!根据前面的输出,我们可以看到gdm实用程序目前处于非活动状态。KDM 的各种配置文件可以在/etc/kde/kdm中找到:

[root@localhost philip]# ls -l /etc/kde/kdm
-rw-r--r--. 1 root root 22985 Jun 12  2016 kdmrc
-rw-r--r--. 1 root root  3607 Apr 26  2010 Xaccess
-rw-r--r--. 1 root root  2381 Apr 26  2010 Xresources
-rwxr-xr-x. 1 root root   207 Jul  8  2008 Xsession
-rwxr-xr-x. 1 root root   938 Apr 26  2010 Xsetup
-rwxr-xr-x. 1 root root   303 Apr 26  2010 Xwilling
[root@localhost philip]#

根据前面的示例,我们可以看到这些文件的名称与本章前面介绍的 XDM 文件类似。

使用 GDM

GDM 是当今 Linux 环境中另一个流行的显示管理器。特别是在 CentOS 和 Fedora 等 Red Hat 发行版中,您会发现 GDM。它提供了一个 GUI 登录提示,用户有机会提供他们的登录凭据。此外,如果我们安装了多个桌面,我们还可以选择登录后加载哪个桌面。正如我们之前看到的,我们可以确定我们更喜欢使用哪个显示管理器。让我们为这个演示选择我们的 Ubuntu 系统。首先,让我们检查我们的 Ubuntu 16 系统上是否安装了 GDM(Ubuntu 中的 GDM3):

root@ubuntu:/etc# ls /etc/ | grep gdm3
root@ubuntu:/etc# ls /etc/X11/
app-defaults  default-display-manager  openbox  xdm    xkb                 Xreset    Xresources  Xsession.d        xsm
cursors       fonts                    rgb.txt  xinit  xorg.conf.failsafe  Xreset.d  Xsession    Xsession.options
root@ubuntu:/etc#

根据前面的输出,GDM3 目前尚未安装。让我们也添加一个桌面,以便我们可以看到选择桌面的选项在哪里。我们将在我们的 Ubuntu 系统中安装 GNOME 桌面。我们将使用apt-get命令,特别是ubuntu-gnome-desktop软件包:

root@ubuntu:/etc# apt-get install ubuntu-gnome-desktop
Reading package lists... Done
Building dependency tree 
Reading state information... Done
The following additional packages will be installed:
python-boto python-cffi-backend python-chardet python-cloudfiles python-cryptography python-enum34 python-idna python-ipaddress
 python-libxml2 python-lockfile python-ndg-httpsclient python-openssl python-pkg-resources python-pyasn1 python-requests python-six
 python-urllib3 rhythmbox-plugin-magnatune seahorse-daemon ssh-askpass-gnome telepathy-gabble telepathy-haze telepathy-idle
 telepathy-logger telepathy-salut tracker tracker-extract tracker-miner-fs ubuntu-gnome-default-settings ubuntu-gnome-wallpapers
 ubuntu-gnome-wallpapers-xenial unoconv wodim xserver-xorg-legacy xsltproc yelp-tools zsync
Suggested packages:
 argyll-doc gir1.2-colordgtk-1.0 db5.3-util vcdimager libdvdcss2 dvdauthor readom python-paramiko python-oauthlib ncftp lftp
After this operation, 447 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
Processing triggers for initramfs-tools (0.122ubuntu8.11) ...
update-initramfs: Generating /boot/initrd.img-4.4.0-134-generic
root@ubuntu:/etc#

出于简洁起见,某些输出已被省略。接下来,让我们安装gdm实用程序。请注意,在 Ubuntu 中它的名称是gdm3,而在 Fedora 中它的名称是gdm,两者是相同的,只是命名约定不同。

在处理 Debian 发行版时,请考虑gdm3,在处理 Red Hat 发行版时,请考虑gdm

当我们安装ubuntu-gnome-desktop时,实际上为我们安装了gdm3,为我们节省了一些时间。我们可以通过查看/etc来验证这一点:

root@ubuntu:/etc# ls -l /etc | grep gdm
drwxr-xr-x  8 root root    4096 Aug 27 11:43 gdm3
root@ubuntu:/etc#

太棒了!根据之前的代码,我们可以看到gdm3实际上已经安装。目前,这不会更改显示管理器,因为我们尚未指定要使用gdm3。要解决这个问题,我们只需运行dpkg-reconfigure命令并传递gdm3

root@ubuntu:/etc# dpkg-reconfigure gdm3

根据前面的输出,Lightdm 被设置为默认的显示管理器。我们可以使用键盘上下滚动并选择要设置为默认的显示管理器。我们将选择 gdm3:

root@ubuntu:/etc# dpkg-reconfigure gdm3
root@ubuntu:/etc#

干得好!现在,我们可以检查/etc/X11/来验证当前设置的显示管理器:

root@ubuntu:/etc# cat /etc/X11/default-display-manager
/usr/sbin/gdm3
root@ubuntu:/etc#

根据以前的代码,我们可以看到gdm3已经设置。我们可以使用systemctl命令来采用另一种技术:

root@ubuntu:/etc# systemctl status lightdm
lightdm.service - Light Display Manager
 Loaded: loaded (/lib/systemd/system/lightdm.service; static; vendor preset: enabled)
 Drop-In: /lib/systemd/system/display-manager.service.d
 └─xdiagnose.conf
 Active: active (running) since Fri 2018-08-24 12:46:32 PDT; 2 days ago
 Docs: man:lightdm(1)
 Main PID: 1011 (lightdm)
 CGroup: /system.slice/lightdm.service
 ├─1011 /usr/sbin/lightdm
 └─1038 /usr/lib/xorg/Xorg -core :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.
root@ubuntu:/etc#

根据前面的代码,我们可以看到当前的 Lightdm 仍然处于活动状态。现在,让我们检查gdm3

root@ubuntu:/etc# systemctl status gdm3
gdm.service - GNOME Display Manager
 Loaded: loaded (/lib/systemd/system/gdm.service; static; vendor preset: enabled)
 Active: inactive (dead)
root@ubuntu:/etc#

根据那个输出,我们可能会认为我们有问题,但事实是只有当我们重新启动系统时,更改才会生效:

太棒了!根据之前的截图,我们可以看到系统已经启动了 GDM3。此外,我们可以选择要加载的桌面。让我们选择 GNOME。现在,让我们重新运行systemctl命令来验证我们确实正在运行 GDM3:

root@ubuntu:/home/philip# systemctl status lightdm
lightdm.service - Light Display Manager
 Loaded: loaded (/lib/systemd/system/lightdm.service; static; vendor preset: e
 Active: inactive (dead)
 Docs: man:lightdm(1)
root@ubuntu:/home/philip#

看起来不错!现在让我们检查一下 GDM3:

root@ubuntu:/home/philip# systemctl status gdm
gdm.service - GNOME Display Manager
 Loaded: loaded (/lib/systemd/system/gdm.service; static; vendor preset: enabl
 Drop-In: /lib/systemd/system/display-manager.service.d
 └─xdiagnose.conf
 Active: active (running) since Mon 2018-08-27 12:33:26 PDT; 3min 22s ago
 Process: 990 ExecStartPre=/usr/share/gdm/generate-config (code=exited, status=
 Process: 983 ExecStartPre=/bin/sh -c [ "$(cat /etc/X11/default-display-manager
 Main PID: 1006 (gdm3)
 CGroup: /system.slice/gdm.service
 └─1006 /usr/sbin/gdm3
root@ubuntu:/home/philip#

太棒了!根据我们在前面的输出中看到的,毫无疑问,我们正在运行 GDM3。

使用 Lightdm

轻型显示管理器,即Lightdmlightdm(在命令行上),一直在 Linux 世界中引起轰动。Lightdm 曾取代 KDM,并且是 Ubuntu 16 之前的首选显示管理器。在后来的 Ubuntu 版本中,它被 GDM 取代。它提供了一个 GUI 来管理用户登录。Lightdm 是跨平台的,这意味着它支持各种桌面。让我们在我们的 Fedora 28 系统中安装 Lightdm。以前我们有 KDM。让我们使用dnf命令:

[root@localhost philip]# dnf install lightdm lightdm-gtk
ast metadata expiration check: 4:55:54 ago on Mon 27 Aug 2018 11:16:03 AM EDT.
Dependencies resolved.
==============================================================
Package           Arch      Version       Repository     Size
==============================================================
Installing:
lightdm          x86_64   1.26.0-1.fc28     updates      222 k
lightdm-gtk      x86_64   2.0.5-1.fc28      fedora       139 k
Installing dependencies:
lightdm-gobject  x86_64   1.26.0-1.fc28     updates       72 k
Transaction Summary
==============================================================
Install  3 Packages
Total download size: 433 k
Installed size: 1.2 M
Is this ok [y/N]: y
Installed:
 lightdm.x86_64 1.26.0-1.fc28   lightdm-gtk.x86_64 2.0.5-1.fc28           lightdm-gobject.x86_64 1.26.0-1.fc28 
Complete!
[root@localhost philip]#

太棒了!现在我们将使用system-switch-displaymanger命令切换到lightdm

[root@localhost philip]# system-switch-displaymanager lightdm
Created symlink /etc/systemd/system/display-manager.service → /usr/lib/systemd/system/lightdm.service.
Your default graphical display manager has successfully been switched.
[root@localhost philip]#

为了验证,我们可以使用ls命令查看systemd中的服务:

[root@localhost philip]# ls -l /etc/systemd/system/display-manager.service
lrwxrwxrwx. 1 root root 39 Aug 27 16:17 /etc/systemd/system/display-manager.service -> /usr/lib/systemd/system/lightdm.service
[root@localhost philip]#

太棒了!我们还可以使用systemctl命令来检查显示管理器的状态:

[root@localhost philip]# systemctl status kdm
kdm.service - The KDE login manager
 Loaded: loaded (/usr/lib/systemd/system/kdm.service; disabled; vendor preset: disabled)
 Active: active (running) since Mon 2018-08-27 11:36:40 EDT; 4h 42min ago
 Main PID: 821 (kdm)
 Tasks: 3 (limit: 2331)
 Memory: 101.0M
[root@localhost philip]#

根据以前的代码,我们可以看到 KDM 仍然处于活动状态。让我们检查一下lightdm

[root@localhost philip]# systemctl status lightdm
lightdm.service - Light Display Manager
 Loaded: loaded (/usr/lib/systemd/system/lightdm.service; enabled; vendor preset: disabled)
 Active: inactive (dead)
 Docs: man:lightdm(1)
[root@localhost philip]#

要使更改生效,请重新启动系统:

太棒了!根据前面的代码,我们现在在我们的 Fedora 28 系统中运行 Lightdm。此外,我们可以选择在屏幕右上角加载哪个桌面。登录后,我们可以进行验证。我们将使用systemctl命令:

[root@localhost philip]# systemctl status kdm
kdm.service - The KDE login manager
 Loaded: loaded (/usr/lib/systemd/system/kdm.service; disabled; vendor preset: disabled)
 Active: inactive (dead)
[root@localhost philip]#

这就是我们希望看到的。同样,当我们检查lightdm时,我们看到以下内容:

[root@localhost philip]# systemctl status lightdm
lightdm.service - Light Display Manager
 Loaded: loaded (/usr/lib/systemd/system/lightdm.service; enabled; vendor preset: disabled)
 Active: active (running) since Mon 2018-08-27 16:23:18 EDT; 4min 0s ago
 Docs: man:lightdm(1)
 Main PID: 840 (lightdm)
 Tasks: 8 (limit: 2331)
 Memory: 84.3M
[root@localhost philip]#

干得好!根据那个,我们可以确认我们在我们的 Fedora 28 系统中运行 Lightdm。

总结

在本章中,我们的重点是显示管理器,特别是 XDM、KDM、GDM 和 Lightdm。还确定了显示管理器和桌面之间的区别。我们首先在 CentOS 系统中使用 XDM 进行工作。我们关注了 XDM 存储的目录。除此之外,我们还关注了 XDM 的访问控制。接下来,我们将注意力转移到 KDM;KDM 在 Ubuntu 发行版中占主导地位,直到后来被替换。我们概述了安装和配置系统以使用 KDM 的方法。接下来,我们转向了 GDM。我们看到 GDM 在大多数 Linux 发行版中实际上是如何使用的。在 Ubuntu 和 Fedora 发行版中工作时,突出了名称的不同。我们演示了安装 GDM 的步骤。此外,我们还涵盖了在混合环境中安装一些桌面;这被证明是相当简单的。然后,还演示了选择桌面的过程。最后,我们介绍了 Lightdm。Lightdm 也很受欢迎,因为它在 Ubuntu 中取代了 KDM,并最终被 GDM 取代。我们使用 Fedora 28 发行版重点介绍了运行 Lightdm 的技术。本章的重点是安装显示管理器和在显示管理器之间切换的过程。

在下一章中,重点将放在用户和组帐户上。到目前为止,我们一直在处理 Linux 环境中的各个方面。首先,将重点放在管理用户帐户的过程上(例如用户创建和删除,目录修改,设置密码,权限和所有权)。接下来,将关注组。我们将深入探讨用于管理组的技术,创建和删除组的过程,将用户分配到组和权限等。我鼓励您再次加入我,以便在即将到来的章节中更好地为管理用户和组做好准备。

问题

  1. XDM 代表什么?

A. X 显示管理器

B. XD 管理器

C. X 桌面管理器

D. 以上都不是

  1. XDM 配置文件存储在哪个目录中?

A. /etc/XDM/xdm

B. /etc/X11/xdm

C. /etc/X1/xdm

D. /etc/XM/xdm

  1. 哪个配置文件控制 XDM 的资源?

A. Xaccess

B. Xresources

C. Xsession

D. Xdisplay

  1. CentOS 6.5 中哪个配置文件指定要使用哪个显示管理器?

A. /etc/desktop

B. /etc/X11/xdm

C. /etc/sysconfig/desktop

D. /etc/desktop

  1. dnf命令中的哪个选项可以用来安装 KDE 桌面作为一个完整的包?

A. --install

B. groupinstall

C. --group

D. --install-group

  1. 在 Fedora 28 中用于更改显示管理器的软件包是什么?

A. displaymanager-switcher

B. system-displaymanager

C. system-switch-displaymanager

D. switch-displaymanager

  1. KDM 登录提示中的哪个选项允许用户指定要加载哪个桌面?

A. 会话类型

B. 桌面类型

C. 登录桌面类型

D. 会话桌面

  1. 哪个命令用于在 Ubuntu 16 中在显示管理器之间切换?

A. chage

B. apt-cache

C. system-switcher

D. dpkg-reconfigure

  1. Ubuntu 16 中的哪个配置文件显示默认的显示管理器?

A. /etc/desktop

B. /etc/preferdm

C. /etc/X11/default-display-manager

D. /default-display-manager

  1. 哪个命令可以将 Fedora 28 中当前的显示管理器识别为一个服务?

A. ls -l /etc/systemd/system/display.manager.service

B. ls -l /etc/systemd/system/display-manager.service

C. ls -l /etc/systemd/system/dm.service

D. ls -l /etc/systemd/system/display.service

进一步阅读

  • 这个网站提供了关于 GDM 的有用信息:wiki.gnome.org

  • 这个网站提供了关于 KDM 的有用信息:forum.kde.org

  • 这个网站提供了关于各种显示管理器的有用信息:superuser.com

第十二章:管理用户和组帐户

在上一章中,我们介绍了显示管理器。我们涉及了 XDM、KDM、GDM 和 Lightdm。我们确定了显示管理器和桌面之间的区别。我们首先在 CentOS 系统中使用 XDM。接下来,我们将注意力转移到 KDM。在此之后,GDM 成为我们议程的下一个内容。此外,我们还介绍了在其中安装一些桌面。最后,我们介绍了 Lightdm。使用 Fedora 28 发行版,重点介绍了使 Lightdm 运行起来的技术。上一章的重点是安装各种显示管理器和在它们之间切换的过程。

在本章中,主题将是用户和组帐户。到目前为止,我们已经涵盖了 Linux 环境中的许多关键领域。我们的重点从管理用户帐户的过程开始;诸如用户创建和删除、目录修改、设置密码、权限和所有权等内容将是重点。在此之后,我们将进入分组的范围;我们将深入探讨用于管理组的技术。将涵盖创建和删除组、将用户分配给组、权限等内容。我鼓励您再次加入我,以便更好地管理用户和组。

我们将在本章中涵盖以下主题:

  • 创建新用户时使用的目录

  • 管理用户帐户

  • 管理组

创建新用户时使用的目录

每次我们在系统中使用useradd命令创建新用户时,都会发生一系列事件。首先,存在一种结构,用于生成新用户的目录。该结构存储在骨架目录中;这位于/etc/skel目录中。/etc/skel目录包含文件和文件夹,这些文件和文件夹将被复制到新用户的主目录中。我们可以使用我们的 Ubuntu 系统查看骨架目录:

root@ubuntu:/home/philip# ls -a /etc/skel/
.  ..  .bash_logout  .bashrc  examples.desktop  .profile
root@ubuntu:/home/philip#

每个新用户都从这里拉取其结构。点(.)表示隐藏文件。文件如/etc/skel/.logout/etc/.skel/.bashrc/etc/skel/.profile

The .bash_logout

请注意,.bash_history是存储注销期间执行的命令的地方。它只是清除屏幕以确保注销时的隐私。这可以在以下命令中看到:

root@ubuntu:/home/philip# cat /home/philip/.bash_logout
# ~/.bash_logout: executed by bash(1) when login shell exits.
# when leaving the console clear the screen to increase privacy
if [ "$SHLVL" = 1 ]; then
 [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q
fi
root@ubuntu:/home/philip#

The .bashrc

/etc/skel/.bashrc通常用于存储各种别名。通过查看/etc/skel/.bashrc可以看到这一点:

root@ubuntu:/home/philip# cat /etc/skel/.bashrc
# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
root@ubuntu:/home/philip#

为了简洁起见,一些输出已被省略。根据前面的输出,我们已经为我们定义了一些别名;其中一个例子是alias ll='ls -af'

The .profile

让我们将/etc/skel/.profile视为它执行了许多任务的文件;其中之一是检查$Home/.bashrc的存在。通过查看/etc/skel/.profile可以看到这一点:

root@ubuntu:/home/philip# cat /etc/skel/.profile
#umask 022
# if running bash
if [ -n "$BASH_VERSION" ]; then
 # include .bashrc if it exists
 if [ -f "$HOME/.bashrc" ]; then
 . "$HOME/.bashrc"
 fi
fi
# set PATH so it includes user's private bin directories
PATH="$HOME/bin:$HOME/.local/bin:$PATH"
root@ubuntu:/home/philip#

为了简洁起见,一些输出已被省略。根据前面的输出,我们可以看到#if running bash部分。另一种看到这些目录确实被复制过来的方法是查看现有用户。我们将使用ls命令结合egrep命令:

root@ubuntu:/home/philip# ls -a ~ | egrep '.bash|.profile'
.bash_history
.bashrc
.profile
root@ubuntu:/home/philip#

干得好!根据前面的输出,我们可以看到.bash_history.bashrc.profile

The .bash_history

在命令提示符下执行的每个命令都存储在.bash_history中。此外,.bash_history只有在我们开始在命令提示符下运行命令后才会创建。以下是对/home/philip/.bash_history的简要查看:

root@ubuntu:/home/philip# cat /home/philip/.bash_history
ls /etc/grub.d/
cat /var/log/Xorg.0.log | less
startx
sudo su
Xorg -configure
rm /tmp/.X0-lock
sudo su
su
sudo su
root@ubuntu:/home/philip#

为了简洁起见,一些输出已被省略。

此外,我们可以检查另一个用户是否存在各种.bash文件:

root@ubuntu:/home/philip# ls -a /home/philip | egrep '.bash|.profile'
.bash_history
.bash_logout
.bashrc
.profile
root@ubuntu:/home/philip#

干得好!我们可以看到.bash_history.bash_logout.bashrc.profile

另一种识别在使用useradd命令创建新用户时是否使用/etc/skel目录的方法是调用useradd命令并传递-D选项:

root@ubuntu:/home/philip# useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/sh
SKEL=/etc/skel
CREATE_MAIL_SPOOL=no
root@ubuntu:/home/philip#

根据前面的输出,我们得到了大量信息。特别是,SKEL=/etc/skel指示创建新用户时要使用的目录。

管理用户帐户

到目前为止,在前面的章节中,我们使用了两个用户帐户;一个是标准用户,另一个是 root 用户。在 Linux 中,我们可以通过 GUI 实用程序或命令行创建用户帐户。在 shell 中,我们使用useradd命令来创建新用户帐户。在较新的发行版中,还有adduser命令。在某些发行版中,如 CentOS,adduser是一个符号链接。可以在这里看到:

[root@localhost philip]# ll /usr/sbin/adduser
lrwxrwxrwx. 1 root root 7 Jun 20 09:19 /usr/sbin/adduser -> useradd
[root@localhost philip]#

在 Ubuntu 上,adduser命令与useradd命令是分开的:

root@ubuntu:/home/philip# ll /usr/sbin/adduser
-rwxr-xr-x 1 root root 37276 Jul  2  2015 /usr/sbin/adduser*
root@ubuntu:/home/philip#

使用useradd命令的基本语法是useradd <option> username。默认情况下,标准用户无法创建用户帐户。可以在这里看到:

philip@ubuntu:~$ useradd tom
useradd: Permission denied.
useradd: cannot lock /etc/passwd; try again later.
philip@ubuntu:~$

根据前面的输出,我们收到了Permission denied的消息。

默认情况下,标准用户无法创建用户帐户。

创建新用户时,我们将继续使用 root 用户。我们将在第十七章 执行安全管理任务中介绍使用sudoers文件管理权限。这里是使用 root 用户:

root@ubuntu:/home/philip# useradd tom
root@ubuntu:/home/philip#

根据前面的输出,我们没有得到任何指示来验证新用户是否已创建。请放心,我们可以通过查看/home目录来确认:

root@ubuntu:/home/philip# cat /etc/passwd
rtkit:x:118:126:RealtimeKit,,,:/proc:/bin/false
saned:x:119:127::/var/lib/saned:/bin/false
usbmux:x:120:46:usbmux daemon,,,:/var/lib/usbmux:/bin/false
philip:x:1000:1000:philip,,,:/home/philip:/bin/bash
gdm:x:121:129:Gnome Display Manager:/var/lib/gdm3:/bin/false
geoclue:x:122:130::/var/lib/geoclue:/bin/false
tom:x:1001:1001::/home/tom:
root@ubuntu:/home/philip#

为了简洁起见,已省略了一些输出。最后一个条目显示了新用户的信息。我们读取这些信息的方式如下:

tom=user
x=password placeholder
1001=UID
1001=GID
/home/tome=home directory for Tom

但是,如果我们比较另一个用户的条目,我们会得到这个:

 philip:x:1000:1000:philip,,,:/home/philip:/bin/bash

根据前面的输出,最后的:/bin/bash部分定义了用户的 shell。我们创建的用户没有分配 shell。此外,我们需要为用户设置密码。为了设置密码,我们将使用passwd命令:

root@ubuntu:/home/philip# passwd tom
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
root@ubuntu:/home/philip#

干得漂亮!现在,让我们注销并尝试使用tom账户登录:

干得漂亮!我们可以看到新用户出现了,但当我们尝试登录时,系统会将我们弹出,因为我们已为用户定义了一个 shell。让我们通过删除用户并再次添加用户来解决这个问题。我们将使用userdel命令删除用户:

root@ubuntu:/home/philip# userdel -r tom
userdel: tom mail spool (/var/mail/tom) not found
userdel: tom home directory (/home/tom) not found
root@ubuntu:/home/philip#
root@ubuntu:/home/philip# cat /etc/passwd
philip:x:1000:1000:philip,,,:/home/philip:/bin/bash
gdm:x:121:129:Gnome Display Manager:/var/lib/gdm3:/bin/false
geoclue:x:122:130::/var/lib/geoclue:/bin/false
root@ubuntu:/home/philip#

太棒了!现在,让我们创建用户并传递-s选项。这将为用户定义一个 shell,以便与useradd命令一起使用:

root@ubuntu:/home/philip# useradd -s /bin/bash tom
root@ubuntu:/home/philip# cat /etc/passwd:
philip:x:1000:1000:philip,,,:/home/philip:/bin/bash
gdm:x:121:129:Gnome Display Manager:/var/lib/gdm3:/bin/false
geoclue:x:122:130::/var/lib/geoclue:/bin/false
tom:x:1001:1001::/home/tom:/bin/bash
root@ubuntu:/home/philip#

干得漂亮!现在我们可以看到在最后一个条目中,用户tom已被分配了/bin/bash shell。/etc/passwd的另一个有趣部分是每个帐户中的x

我们说它代表密码,但我们并没有将x设置为密码,那么x是什么意思呢?嗯,x只是表示密码已加密;它实际上存储在一个单独的位置。/etc/shadow目录存储密码。我们可以查看/etc/shadow目录以供参考:

root@ubuntu:/home/philip# passwd tom
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
root@ubuntu:/home/philip#
root@ubuntu:/home/philip# cat /etc/shadow
messagebus:*:16911:0:99999:7:::
uuidd:*:16911:0:99999:7:::
lightdm:*:16911:0:99999:7:::
whoopsie:*:16911:0:99999:7:::
avahi-autoipd:*:16911:0:99999:7:::
avahi:*:16911:0:99999:7:::
dnsmasq:*:16911:0:99999:7:::
colord:*:16911:0:99999:7:::
gdm:*:17770:0:99999:7:::
geoclue:*:17770:0:99999:7:::
tom:!:17778:0:99999:7:::
root@ubuntu:/home/philip#

为了简洁起见,已省略了一些输出。根据前面的输出,我们可以看到每个帐户的实际加密密码。

chage 命令

关于用户帐户的另一个有趣方面涉及密码的过期时间;密码的过期时间。我们可以使用chage命令查看给定用户的过期时间。让我们为用户tom创建一个密码,然后检查新用户的密码过期设置:

更改密码过期参数需要 root 权限。

root@ubuntu:/home/philip# passwd tom
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
root@ubuntu:/home/philip#

太棒了!根据前面的输出,我们使用了-l选项来显示过期设置;我们可以看到一些有价值的信息,特别是上次密码更改密码过期帐户过期。我们可以通过传递各种选项来更改这些值。例如,让我们更改帐户过期。我们使用-E选项:

root@ubuntu:/home/philip# chage -E 2018-09-04 tom
root@ubuntu:/home/philip# chage -l tom
Last password change                                                                : Sep 04, 2018
Password expires                                                                    : never
Password inactive                                                                   : never
Account expires                                                                     : Sep 04, 2018
Minimum number of days between password change                                       : 0
Maximum number of days between password change                                      : 99999
Number of days of warning before password expires                                   : 7
root@ubuntu:/home/philip#

干得漂亮!根据前面的输出,我们已将帐户设置为在此演示的当前时间到期。现在,为了查看此更改的效果,我们将打开另一个终端并尝试以用户tom的身份登录:

干得好!根据前面的输出,我们看到了尝试以用户tom的身份登录时返回的消息。要删除用户tom的此过期时间,我们将使用-1作为值:

root@ubuntu:/home/philip# chage -E -1 tom
root@ubuntu:/home/philip# chage -l tom
Last password change                                                                : Sep 04, 2018
Password expires                                                                    : never
Password inactive                                                                   : never
Account  expires                                                                    : never
Minimum number of days between password change                                      : 0
Maximum number of days between password change                                      : 99999
Number of days of warning before password expires                                   : 7
root@ubuntu:/home/philip#

现在,我们将能够以用户tom的身份登录:

太棒了!根据前面的内容,我们可以看到使用chage命令的有效性。要查看可以与chage命令一起传递的可用选项,我们可以执行:

root@ubuntu:/home/philip# chage

usermod 命令

我们之前看到,要进行任何更改,我们必须使用useradd命令删除用户。每次我们决定更改时,这可能会很麻烦;相反,我们可以利用另一个强大的命令:usermod命令。usermod命令的基本语法如下:

usermod <option> username

使用我们的测试用户tom,我们可以使用usermod命令更改许多参数。例如,我们可以锁定用户tom的帐户,这将阻止用户tom登录系统。要锁定帐户,我们将使用-L选项:

root@ubuntu:/home/philip# cat /etc/passwd
philip:x:1000:1000:philip,,,:/home/philip:/bin/bash
gdm:x:121:129:Gnome Display Manager:/var/lib/gdm3:/bin/false
geoclue:x:122:130::/var/lib/geoclue:/bin/false
tom:x:1001:1001::/home/tom:
root@ubuntu:/home/philip# usermod -L tom
root@ubuntu:/home/philip#

干得好!根据前面的输出,用户tom无法登录。值得注意的是,在/etc/shadow中用户tom的条目显示在第二个字段的密码前面有!,这表示密码:

root@ubuntu:/home/philip# cat /etc/shadow | grep tom
tom:!$6$uJ52BA2n$SWGisIpNTTOSygIX6swWdkS/gLPGZacEzCz2Ht6qfUHIr7ZIxkJyUjEyqN9ncb1yIFIXYnePz4HVzrwqJA1DZ0:17778:0:99999:7:::
root@ubuntu:
 root@ubuntu:/home/philip# cat /etc/shadow | grep philip
philip:$1$8gQrKziP$v6Uv6
root@ubuntu:/home/philip#

根据前面的内容,用户philip的密码前面没有!。验证帐户是否已锁定的另一种方法是使用passwd命令。我们传递--status选项:

root@ubuntu:/home/philip# passwd --status tom
tom L 09/04/2018 0 99999 7 -1
root@ubuntu:/home/philip#

干得好!请注意,L表示用户帐户当前已锁定。我们可以使用usermod命令并传递-U选项来解锁用户帐户:

root@ubuntu:/home/philip# usermod -U tom
root@ubuntu:/home/philip# passwd --status tom
tom P 09/04/2018 0 99999 7 -1
root@ubuntu:/home/philip#

干得好!根据前面的输出,P表示用户tom有一个可用的密码;这意味着帐户是解锁的:

太棒了!现在,当我们再次查看etc/shadow时,我们将不再看到哈希密码前面的!

root@ubuntu:/home/philip# cat /etc/shadow | grep tom
tom:$6$uJ52BA2n$SWGisIpNTTOSygIX6swWdkS/gLPGZacEzCz2Ht6qfUHIr7ZIxkJyUjEyqN9ncb1yIFIXYnePz4HVzrwqJA1DZ0:17778:0:99999:7:::
root@ubuntu:/home/philip#

太棒了!如果我们添加用户而没有指定 shell,我们还可以为用户定义一个 shell;我们使用usermod命令传递-s选项:

root@ubuntu:/home/philip# cat /etc/passwd
gdm:x:121:129:Gnome Display Manager:/var/lib/gdm3:/bin/false
geoclue:x:122:130::/var/lib/geoclue:/bin/false
tom:x:1001:1001::/home/tom:
root@ubuntu:/home/philip# usermod -s /bin/bash tom
root@ubuntu:/home/philip# cat /etc/passwd
gdm:x:121:129:Gnome Display Manager:/var/lib/gdm3:/bin/false
geoclue:x:122:130::/var/lib/geoclue:/bin/false
tom:x:1001:1001::/home/tom:/bin/bash
root@ubuntu:/home/philip#

干得好!锁定帐户的另一种方法是使用passwd命令;我们传递-l选项。让我们锁定用户tom

root@ubuntu:/home/philip# passwd -l tom
passwd: password expiry information changed.
root@ubuntu:/home/philip# passwd --status tom
tom L 09/04/2018 0 99999 7 -1
root@ubuntu:/home/philip#

再次,当我们尝试以用户tom的身份登录时,我们将看到这个:

干得好!此外,我们还可以使用passwd命令解锁帐户;我们将传递-u选项:

root@ubuntu:/home/philip# passwd -u tom
passwd: password expiry information changed.
root@ubuntu:/home/philip# passwd --status tom
tom P 09/04/2018 0 99999 7 -1
root@ubuntu:/home/philip#

太棒了!请注意,root 用户仍然可以使用tom用户登录,是的!我们可以通过再次锁定用户tom来说明这一点:

root@ubuntu:/home/philip# passwd -l tom
passwd: password expiry information changed.
root@ubuntu:/home/philip# passwd --status tom
tom L 09/04/2018 0 99999 7 -1
root@ubuntu:/home/philip# cat /etc/shadow | grep tom
tom:!$6$uJ52BA2n$SWGisIpNTTOSygIX6swWdkS/gLPGZacEzCz2Ht6qfUHIr7ZIxkJyUjEyqN9ncb1yIFIXYnePz4HVzrwqJA1DZ0:17778:0:99999:7:::
root@ubuntu:/home/philip#

根据前面的输出,从所有迹象来看,用户tom的帐户似乎已被禁用,但是看看这个:

太棒了!当有人尝试以用户tom的身份登录时,他们将被阻止,除非他们首先成为 root 用户,因为锁定不会阻止 root 用户访问已锁定的帐户。

root 用户可以访问任何帐户。

当我们管理用户帐户时,其中一些基本信息来自一个特殊的配置文件:/etc/login.def文件。我们可以查看/etc/login.def

root@ubuntu:/home/philip# cat /etc/login.defs
# /etc/login.defs - Configuration control definitions for the login package.
# Three items must be defined:  MAIL_DIR, ENV_SUPATH, and ENV_PATH.
# If unspecified, some arbitrary (and possibly incorrect) value will
SU_NAME                           su
PASS_MAX_DAYS            99999
PASS_MIN_DAYS             0
PASS_WARN_AGE          7
root@ubuntu:/home/philip#

出于简洁起见,某些输出已被省略。根据前面的输出,我们可以看到suchage命令的设置。

w 命令

w命令显示系统中当前登录的用户。我们可以查看w命令:

root@ubuntu:/home/philip# w
 08:00:03 up 22:14,  4 users,  load average: 0.04, 0.01, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
philip   tty2     :1               Mon13    7days  1:35   0.29s /sbin/upstart --user
root@ubuntu:/home/philip#

根据前面的输出,我们从左到右有从用户开始的字段。一些有趣的字段是FROM字段,因为它显示用户登录的位置(如果是通过网络,它将显示 IP 地址),以及LOGIN@字段,因为它显示用户登录的日期。我们可以通过传递--help选项来查看可用的选项:

root@ubuntu:/home/philip# w --help
Usage:
 w [options]
Options:
 -h, --no-header     do not print header
 -u, --no-current    ignore current process username
 -s, --short         short format
 -f, --from          show remote hostname field
 -o, --old-style     old style output
 -i, --ip-addr       display IP address instead of hostname (if possible)
 --help     display this help and exit
 -V, --version  output version information and exit
For more details see w(1).
root@ubuntu:/home/philip#

who 命令

who命令是另一个用于显示当前登录用户的流行命令。我们只需使用who而不带任何选项:

root@ubuntu:/home/philip# who
philip   tty2         2018-09-03 13:29 (:1)
root@ubuntu:/home/philip#

太棒了!但等等,我们实际上可以确定系统启动的日期和时间,是的!我们传递-a选项:

root@ubuntu:/home/philip# who -a
 system boot  2018-08-27 12:33
LOGIN      tty1         2018-09-03 13:29             13792 id=tty1
 run-level 5  2018-08-27 12:33           tty2         2018-08-30 06:34              1434 id=      term=0 exit=0
 tty2         2018-08-30 06:35              9661 id=      term=0 exit=0
 tty2         2018-09-03 13:17             10231 id=      term=0 exit=0
philip   + tty2         2018-09-03 13:29  old        13815 (:1)
root@ubuntu:/home/philip#
Excellent! The first entry “system boot”, displays the date and time the system booted up. We can see the available options by passing the “--help” option:
root@ubuntu:/home/philip# who --help
Usage: who [OPTION]... [ FILE | ARG1 ARG2 ]
Print information about users who are currently logged in.
 -a, --all         same as -b -d --login -p -r -t -T -u  -b, --boot        time of last system boot
 -d, --dead        print dead processes
 -H, --heading     print line of column headings
 --ips         print ips instead of hostnames. with --lookup,
 canonicalizes based on stored IP, if available,                    rather than stored hostname
 -l, --login       print system login processes
 --lookup      attempt to canonicalize hostnames via DNS  -m                only hostname and user associated with stdin
 -p, --process     print active processes spawned by init
 -q, --count       all login names and number of users logged on  -r, --runlevel    print current runlevel
 -s, --short       print only name, line, and time (default)  -t, --time        print last system clock change
 -T, -w, --mesg    add user's message status as +, - or ?
 -u, --users       list users logged in
 --message     same as -T
 --writable    same as -T
 --help     display this help and exit
 --version  output version information and exit
root@ubuntu:/home/philip#

last 命令

另一个用于显示最近登录用户的流行命令是last命令。我们只需输入last

root@ubuntu:/home/philip# last
tom   pts/18   172.16.175.129   Tue Sep  4 08:31   still logged in
wtmp begins Tue Sep  4 08:31:36 2018
root@ubuntu:/home/philip#

根据前面的输出,用户tom已经通过网络登录。我们可以通过传递--help选项来查看可用的选项:

root@ubuntu:/home/philip# last --help
Usage:
 last [options] [<username>...] [<tty>...]
Show a listing of last logged in users.
Options:
 -<number>            how many lines to show
 -a, --hostlast       display hostnames in the last column
 -d, --dns            translate the IP number back into a hostname
 -f, --file <file>    use a specific file instead of /var/log/wtmp
 -F, --fulltimes      print full login and logout times and dates
 -i, --ip             display IP numbers in numbers-and-dots notation
 -n, --limit <number> how many lines to show
 -R, --nohostname     don't display the hostname field
 -s, --since <time>   display the lines since the specified time
 -t, --until <time>   display the lines until the specified time
 -p, --present <time> display who were present at the specified time
 -w, --fullnames      display full user and domain names
 -x, --system         display system shutdown entries and run level changes
 --time-format <format>  show timestamps in the specified <format>:
 notime|short|full|iso
 -h, --help     display this help and exit
 -V, --version  output version information and exit
root@ubuntu:/home/philip#

干得好!

whoami 命令

我们可以使用whoami命令快速查看当前用户的信息。whoami命令显示当前登录会话的所有者:

root@ubuntu:/home/philip# whoami
root
root@ubuntu:/home/philip#

干得好!我们可以通过传递--help选项来查看whoami命令的可用选项:

root@ubuntu:/home/philip# whoami --help
Usage: whoami [OPTION]...
Print the user name associated with the current effective user ID.
Same as id -un.
 --help     display this help and exit
 --version  output version information and exit
GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
Full documentation at: <http://www.gnu.org/software/coreutils/whoami>
or available locally via: info '(coreutils) whoami invocation'
root@ubuntu:/home/philip#

管理组

到目前为止,我们一直在系统中创建用户帐户;那么组帐户呢?当我们使用useradd命令创建帐户时,事实上我们也间接地创建了一个与用户同名的组帐户。为了证明这一点,让我们看一下/etc/login.def文件:

root@ubuntu:/home/philip# cat /etc/login.defs | grep GRO
#             TTYGROUP          Login tty will be assigned this group ownership.
# which owns the terminals, define TTYGROUP to the group number and
# TTYPERM to 0620\.  Otherwise leave TTYGROUP commented out and assign
TTYGROUP          tty
# If USERGROUPS_ENAB is set to "yes", that will modify this UMASK default value
USERGROUPS_ENAB yes
#CONSOLE_GROUPS                      floppy:audio:cdrom
root@ubuntu:/home/philip#

根据前面的输出,USERGROUPS_ENAB yes变量允许使用与用户名相同的名称创建一个组。我们还可以通过查看/etc/group来查看可用的组:

root@ubuntu:/home/philip# cat /etc/group
pulse-access:x:125:
rtkit:x:126:
saned:x:127:
philip:x:1000:
sambashare:x:128:philip
gdm:x:129:
geoclue:x:130:
tom:x:1001:
root@ubuntu:/home/philip#

为了简洁起见,已省略了一些输出。根据前面的输出,当我们创建用户名tom时,也创建了一个名为tom的组。但是,我们也可以使用另一个强大的命令groupadd来创建一个组:

root@ubuntu:/home/philip# groupadd Hacki
root@ubuntu:/home/philip# cat /etc/group
philip:x:1000:
sambashare:x:128:philip
gdm:x:129:
geoclue:x:130:
tom:x:1001:
Hacki:x:1002:
root@ubuntu:/home/philip#

太棒了!现在我们看到我们新创建的Hacki组正在显示。同样,我们可以使用groupdel命令删除一个组:

root@ubuntu:/home/philip# groupdel Hacki
root@ubuntu:/home/philip# cat /etc/group
philip:x:1000:
sambashare:x:128:philip
gdm:x:129:
geoclue:x:130:
tom:x:1001:
root@ubuntu:/home/philip#

太棒了!现在,让我们重新创建一个Hacki组:

root@ubuntu:/home/philip# groupadd Hacki
root@ubuntu:/home/philip# cat /etc/group
tom:x:1001:
Hacki:x:1002:
root@ubuntu:/home/philip#

可以使用usermod命令将用户添加到另一个组。让我们使用tom用户:

root@ubuntu:/home/philip# usermod -G Hacki,tom tom
root@ubuntu:/home/philip# cat /etc/group
tom:x:1001:tom
Hacki:x:1002:tom
root@ubuntu:/home/philip#

现在,我们可以看到用户tomtomHacki组的一部分。另一种为用户分组的方法是使用id命令:

root@ubuntu:/home/philip# id tom
uid=1001(tom) gid=1001(tom) groups=1001(tom),1002(Hacki)
root@ubuntu:/home/philip#

干得好!此外,我们可以通过在usermod命令中使用-g来将组作为用户的主组:

root@ubuntu:/home/philip# usermod -g Hacki tom
root@ubuntu:/home/philip# id tom
uid=1001(tom) gid=1002(Hacki) groups=1002(Hacki) ,1001(tom)
root@ubuntu:/home/philip# cat /etc/group | grep tom
tom:x:1001:
Hacki:x:1002:tom
root@ubuntu:/home/philip#

太棒了!根据前面的输出,用户tom属于的唯一组是Hacki组。也可以给组添加密码;我们使用gpasswd命令。请注意,/etc/gshadow存储每个组的密码。我们可以看一下:

root@ubuntu:/home/philip# cat /etc/gshadow
philip:!::
sambashare:!::philip
gdm:!::
geoclue:!::
tom:!::tom
Hacki:!::
root@ubuntu:/home/philip#

为了简洁起见,已省略了一些输出。感叹号表示相应组没有设置密码。让我们为Hacki组设置密码:

root@ubuntu:/home/philip# gpasswd Hacki
Changing the password for group Hacki
New Password:
Re-enter new password:
root@ubuntu:/home/philip# cat /etc/gshadow
geoclue:!::
tom:!::tom
Hacki:$6$eOvgO//4tAi/0C$v/FxkZyQLE0BLJ9jfrQ3sElm3kyNbhThl8DFXokZmAWzK1AKQFztSLOBpNsvOESOsWIz6DXKt4Erg.J7ElZut1::tom
root@ubuntu:/home/philip#

太棒了!现在我们可以看到密码的哈希版本已经取代了感叹号。

还有另一个命令可以用来创建或更改组的密码:groupmod命令。让我们使用groupmod命令为tom组分配一个密码:

root@ubuntu:/home/philip# groupmod -p password tom
root@ubuntu:/home/philip# cat /etc/gshadow
gdm:!::
geoclue:!::
tom:password::tom
Hacki:$6$eOvgO//4tAi/0C$v/FxkZyQLE0BLJ9jfrQ3sElm3kyNbhThl8DFXokZmAWzK1AKQFztSLOBpNsvOESOsWIz6DXKt4Erg.J7ElZut1::tom
root@ubuntu:/home/philip#

干得好!根据前面的输出,与gpasswd命令相反,当我们使用groupmod命令时,它期望一个加密密码。我们指定了一个明文密码;因此,我们看到密码被暴露了。

总结

在本章中,我们涵盖了一系列管理用户和组帐户的技术。首先,我们调查了新用户的主目录所在的各个目录。接下来,我们处理了用户帐户的创建。我们看到了如何添加或删除用户帐户。此外,我们还看到了如何为用户帐户设置密码。此外,我们还研究了保存用户密码的各种配置文件,特别是关注了/etc/passwd/etc/shadow文件。在此之后,我们处理了修改用户帐户的属性。

我们提到了锁定和解锁用户帐户。此外,我们使用chage命令处理了密码过期设置。最后,我们关注了组。我们涵盖了创建组以及添加和删除组的步骤。此外,我们还看到了如何将组分配给用户;同样,我们还看到了如何分配主组。最后,我们看了一下为组设置密码的方法。

在下一章中,我们的重点将是自动化任务。我们将介绍常用于执行任务的实用程序。此外,我们将介绍在 Linux 系统中执行任务的权限。我希望您加入我下一章,因为它包含了有关任务自动化的重要信息。

问题

  1. 哪个配置文件通常在 /etc/skel 目录中存储别名?

A. /etc/skel/bash

B. /etc/skel/bash_rc

C. /etc/skel/.bash_rc

D. /etc/skel/.bashrc

  1. 哪个配置文件在用户退出系统时清除屏幕?

A. /etc.skel/.bash_logout

B. /etc/skel/bash_logout

C. /etc/skel/.logout

D. /etc/skel/.bashlogout

  1. 哪个配置文件存储执行的命令?

A. /etc/skel/.bash_history

B. ~/.bash_history

C. /etc/skel/bash_history

D. ~/.history

  1. 哪个选项打印 useradd 命令的默认值?

A. -d

B. -b

C. -D

D. --defaults

  1. 哪个选项允许在使用 useradd 时指定 shell?

A. -c

B. -d

C. -S

D. -s

  1. adduser 命令在 Fedora 28 中是指向哪个命令的符号链接?

A. adduser

B. add-user

C. user-mod

D. user-add

  1. 哪个选项与 chage 命令一起将打印出帐户到期设置?

A. -a

B. -l

C. -c

D. -d

  1. passwd --status 命令中的哪个代码表示帐户已锁定?

A. P

B. A

C. L

D. N

  1. 哪个选项与 groupmod 命令一起指定用户的主要组?

A. -g

B. -G

C. -A

D. -b

  1. 用于更改组密码的命令是哪个?

A. adduser

B. groupedit

C. groupmod

D. grouppasswd

进一步阅读

第十三章:自动化任务

在上一章中,我们涵盖了管理用户和组帐户的各种技术。首先,我们调查了新用户的主目录来自哪些目录。接下来,我们处理了用户帐户的创建。此外,我们查看了用户密码保存的各种配置文件。最后,我们关注了组。我们介绍了创建组的步骤,以及添加、删除和为组分配密码。

在本章中,我们的重点转向自动化,特别是自动化任务。我们将涵盖使用各种方法进行任务调度。我们经常在日常工作中处理各种任务,而不是手动和重复地在一段时间内运行任务;实施某种额外的自动化是一个好的实践,我们将关注任务执行权限。

在本章中,我们将涵盖以下主题:

  • atatqarm命令

  • crontab文件和anacron命令

  • 使用配置文件进行任务权限

使用atatqatrm命令管理自动化

在本节中,我们将介绍在 Linux 系统中自动化各种类型任务的常见方法。首先,我们将介绍at命令。接下来,我们将使用atq命令处理队列。最后,我们将以使用atrm命令删除作业的技术结束本节。

at 命令

at命令安排一个任务在固定时间运行;它只运行一次。您可以安排一个简单的任务,比如将一些输出附加到文件,或者像备份数据库这样复杂的任务。启动at实用程序的基本语法如下:

at <time>

我们可以看到at命令在我们的 Fedora 28 系统上的运行情况;我们只需输入at而不指定任何选项:

[root@localhost philip]# at
Garbled time
[root@localhost philip]#

根据前面的命令,如果不指定时间,at实用程序将返回Garbled time。这是我们如何指定时间的方法:

[root@localhost philip]# at 18:10
warning: commands will be executed using /bin/sh
at>

根据前面的输出,一旦输入日期(在这种情况下,我们输入了格式为 HH:MM 的时间),它就会启动at实用程序,并出现warning: commands will be executed using /bin/sh的警告;这告诉我们at实用程序在执行时将使用哪个 shell。从这里,我们可以输入任何我们想在指定时间运行的命令。例如:

[root@localhost philip]# at 18:10
warning: commands will be executed using /bin/sh
at> ls -l > /home/philip/Documents/schedule
at>

看起来似乎没有什么改变;要保存更改,我们必须告诉at实用程序我们已经完成输入命令。这是使用Ctrl + D组合完成的:

[root@localhost philip]# at 18:10
warning: commands will be executed using /bin/sh
at> ls -l > /home/philip/Documents/schedule
at> <EOT>
job 1 at Tue Sep  4 18:10:00 2018
[root@localhost philip]#

根据前面的输出,at实用程序已经安排了一个任务在当前时间的18:10运行。使用at实用程序安排任务的另一种方法是以 12 小时制指定时间。这是我们如何做到的:

[root@localhost philip]# at 9:00 PM
warning: commands will be executed using /bin/sh
at> date > /home/philip/Documents/date_schedule
at> <EOT>
job 2 at Tue Sep  4 21:00:00 2018
[root@localhost philip]#

太棒了!根据前面的输出,我们已经使用 12 小时制指定了时间,通过添加PM。这告诉at实用程序在当前时间从9:00 PM执行作业。此外,我们还可以使用关键词指定时间。例如,我们可以说tomorrownoon tomorrownext weeknext Mondayfri等等。这是它的样子:

[root@localhost philip]# at next monday
warning: commands will be executed using /bin/sh
at> ls -l /etc > /home/philip/Documents/ls_schedule
at> <EOT>
job 4 at Mon Sep 10 09:11:00 2018
[root@localhost philip]#

很棒!根据前面的输出,at实用程序已经使用当前日期来计算何时执行。此外,<EOT>是按下Ctrl + D的结果。指定运行at实用程序的另一种方法是使用关键词的组合。例如,我们可以指定now + 4 weeksnow + 6 yearsnow + 25 minutes等等。这是它的样子:

[root@localhost philip]# at now + 15 minutes
warning: commands will be executed using /bin/sh
at> ls -a /var/log > /home/philip/Documents/lsa_schedule
at> <EOT>
job 5 at Thu Sep  6 09:32:00 2018
[root@localhost philip]# date
Thu Sep  6 09:19:25 EDT 2018
[root@localhost philip]#

太棒了!根据前面的输出,我们可以看到at实用程序使用当前日期和时间进行计算。此外,我们还可以指定年份来查看其计算:

[root@localhost philip]# at now + 25 years
warning: commands will be executed using /bin/sh
at> systemctl status sshd.service > /home/philip/Documents/ssh_25yrs_schedule
at> <EOT>
job 7 at Sun Sep  6 09:25:00 2043
[root@localhost philip]#

很棒!根据前面的输出,at实用程序将在当前时间的 25 年后运行此任务。我们可以看到一些可以与at实用程序一起传递的常见选项列表,我们传递-help选项:

[root@localhost philip]# at -help
Usage: at [-V] [-q x] [-f file] [-mMlbv] timespec ...
 at [-V] [-q x] [-f file] [-mMlbv] -t time
 at -c job ...
 atq [-V] [-q x]
 at [ -rd ] job ...
 atrm [-V] job ...
 batch
[root@localhost philip]#
Awesome job!

atq 命令

到目前为止,我们一直在使用at实用程序创建一些要执行的任务。跟踪使用at命令安排运行的任务将是很好的;atq命令正是这样做的。要了解其工作原理,我们可以运行atq命令:

[root@localhost philip]# atq
4              Mon Sep 10 09:11:00 2018 a root
7              Sun Sep  6 09:25:00 2043 a root
[root@localhost philip]#

根据前面的输出,我们列出了两个要由at实用程序运行的作业。当我们以 root 用户身份运行atq命令时,所有作业都将由at命令列出;当我们以标准用户身份运行at命令时,只有用户作业将被列出。这是它的外观:

[root@localhost philip]# exit
exit
[philip@localhost ~]$ atq
[philip@localhost ~]$

根据前面的输出,用户不知道根用户使用at命令安排的作业。此外,我们可以使用at命令查看队列;我们传递-l选项:

[root@localhost philip]# at -l
4              Mon Sep 10 09:11:00 2018 a root
7              Sun Sep  6 09:25:00 2043 a root
[root@localhost philip]#

很棒!根据前面的命令,我们可以看到输出与atq命令的输出相同。这是因为at命令与atq命令一起使用的-l选项只是atq命令的别名。

atrm 命令

使用at实用程序安排运行作业是很好的。但是,我们需要对安排的作业有一定的控制。如果我们决定取消作业,可以使用atrm命令。atrm命令用于取消at实用程序执行之前的作业。例如,我们使用at实用程序安排了一次重启:

[root@localhost philip]# at now + 5 minutes
warning: commands will be executed using /bin/sh
at> reboot
at> <EOT>
job 8 at Thu Sep  6 10:06:00 2018
[root@localhost philip]# date
Thu Sep  6 10:01:21 EDT 2018
[root@localhost philip]#

根据前面的命令,我们已经指定使用at命令在五分钟内重新启动系统。现在,如果出于某种原因我们想要取消此作业,我们可以使用atrm命令。我们会这样做:

 [root@localhost philip]# atq
4              Mon Sep 10 09:11:00 2018 a root
8              Thu Sep  6 10:06:00 2018 a root
7              Sun Sep  6 09:25:00 2043 a root
[root@localhost philip]# atrm 8
[root@localhost philip]# atq
4              Mon Sep 10 09:11:00 2018 a root
7              Sun Sep  6 09:25:00 2043 a root
[root@localhost philip]#

很好!根据前面的命令,我们使用atq命令列出了计划的作业;然后我们使用atrm命令并指定作业 ID 来删除它。此外,我们可以使用at实用程序删除作业;为此,我们传递-r-d选项:

[root@localhost philip]# atq
4              Mon Sep 10 09:11:00 2018 a root
7              Sun Sep  6 09:25:00 2043 a root
[root@localhost philip]# at -r 4
[root@localhost philip]# atq
7              Sun Sep  6 09:25:00 2043 a root
[root@localhost philip]#

很好!根据前面的输出,我们可以看到使用at命令的-r选项删除了 ID 为4的作业。at命令的-d选项的工作方式相同:

[root@localhost philip]# atq
7              Sun Sep  6 09:25:00 2043 a root
[root@localhost philip]#
[root@localhost philip]# at -d 7
[root@localhost philip]# atq
[root@localhost philip]#
Excellent!

使用 cron、crontab 和 anacron 进行自动化管理

在本节中,我们将介绍一些管理任务的技术,这些任务通常需要运行多次。首先,我们将从各种cron目录开始。接下来,我们将使用crontab。最后,我们将介绍anacron。重点是它们不是彼此的替代品,而是在 Linux 系统中管理任务中扮演关键角色。

Cron

正如我们之前看到的,at实用程序只运行一次任务。有时我们需要多次运行任务。每次要执行给定的作业时,必须亲自输入at实用程序的任务,这很麻烦。例如,备份,这是大多数 Linux 管理员负责执行的最常见任务之一。

鉴于这些情况,我们可以使用cron实用程序,更具体地说是/etc/cron.*目录;我们放置我们想要运行的任务。作业可以每小时,每天或每月运行。Cron 使用crond守护程序。在 Ubuntu 中,cron守护程序称为croncron.service,而在 Fedora 28 中,cron守护程序称为crondcrond.service。我们可以按以下方式在 Ubuntu 上检查cron守护程序的状态:

root@philip-virtual-machine:/home/philip# systemctl status crond
Unit crond.service could not be found.
root@philip-virtual-machine:/home/philip# systemctl status cron
cron.service - Regular background program processing daemon
 Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
 Active: active (running) since Thu 2018-09-06 10:58:35 EDT; 10min ago
 Docs: man:cron(8)
 Main PID: 608 (cron)
 Tasks: 1 (limit: 4636)
 CGroup: /system.slice/cron.service
 └─608 /usr/sbin/cron -f
root@philip-virtual-machine:/home/philip#

根据前面的输出,cron守护程序称为cron.service。让我们在 Fedora 28 中检查cron守护程序:

[root@localhost philip]# systemctl status cron
Unit cron.service could not be found.
[root@localhost philip]# systemctl status crond
crond.service - Command Scheduler
 Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
 Active: active (running) since Tue 2018-09-04 08:56:09 EDT; 2 days ago
 Main PID: 867 (crond)
 Tasks: 1 (limit: 2331)
 Memory: 3.3M
 CGroup: /system.slice/crond.service
 └─867 /usr/sbin/crond -n
 [root@localhost philip]#

很好!如在 Fedora 28 中所示,cron 服务称为crond.service。接下来,让我们看看cron目录:

root@philip-virtual-machine:/home/philip# ls -l /etc/cron.hourly/
total 0
root@philip-virtual-machine:/home/philip#

根据前面的输出,没有计划每小时运行的任务。但是,我们将在/etc/cron.daily目录中放置一些任务:

root@philip-virtual-machine:/home/philip# ls -l /etc/cron.daily/
total 52
-rwxr-xr-x 1 root root  311 May 29  2017 0anacron
-rwxr-xr-x 1 root root  376 Nov 20  2017 apport
-rwxr-xr-x 1 root root 1478 Apr 20 06:08 apt-compat
-rwxr-xr-x 1 root root  355 Dec 29  2017 bsdmainutils
-rwxr-xr-x 1 root root  384 Dec 12  2012 cracklib-runtime
-rwxr-xr-x 1 root root 1176 Nov  2  2017 dpkg
-rwxr-xr-x 1 root root  372 Aug 21  2017 logrotate
-rwxr-xr-x 1 root root 1065 Apr  7 06:39 man-db
-rwxr-xr-x 1 root root  538 Mar  1  2018 mlocate
-rwxr-xr-x 1 root root  249 Jan 25  2018 passwd
-rwxr-xr-x 1 root root 3477 Feb 20  2018 popularity-contest
-rwxr-xr-x 1 root root  246 Mar 21 13:20 ubuntu-advantage-tools
-rwxr-xr-x 1 root root  214 Jul 12  2013 update-notifier-common
root@philip-virtual-machine:/home/philip#

根据前面的输出,有许多任务,如passwddpkgmlocate等,每天都有安排运行。同样,我们可以查看/etc/cron.monthly内部:

root@philip-virtual-machine:/home/philip# ls -al /etc/cron.monthly/
total 24
drwxr-xr-x   2 root root  4096 Apr 26 14:23 .
drwxr-xr-x 124 root root 12288 Sep  6 10:58 ..
-rwxr-xr-x   1 root root   313 May 29  2017 0anacron
-rw-r--r--   1 root root   102 Nov 16  2017 .placeholder
root@philip-virtual-machine:/home/philip#

太棒了!我们可以更深入地查看一个已安排的任务。让我们看看/etc/cron.daily/passwd任务:

root@philip-virtual-machine:/home/philip# cat /etc/cron.daily/passwd
#!/bin/sh
cd /var/backups || exit 0
for FILE in passwd group shadow gshadow; do
 test -f /etc/$FILE              || continue
 cmp -s $FILE.bak /etc/$FILE     && continue
 cp -p /etc/$FILE $FILE.bak && chmod 600 $FILE.bak
done
root@philip-virtual-machine:/home/philip#

根据前面的输出,我们可以看到任务被写成脚本。

Crontab

正如我们刚才看到的,我们可以将任务放在各自的/etc/cron.*目录中。然后每小时、每天或每月执行一次。但是,我们可以获得更灵活性;我们可以将脚本放在/etc/cron.*目录中,而不是将脚本放在crontab本身中。我们可以查看/etc/crontab文件:

root@philip-virtual-machine:/home/philip# cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user            command
17 *        * * *      root    cd / && run-parts --report /etc/cron.hourly
25 6        * * *      root       test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6        * * 7      root       test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6        1 * *      root       test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
root@philip-virtual-machine:/home/philip#

太棒了!我们可以看到前面的输出中,我们涵盖的脚本在最后部分;它们由crontab执行。我们可以在crontab中添加我们自己的条目。我们使用-e选项与crontab一起,这意味着进入编辑模式:

root@philip-virtual-machine:/home/philip# crontab -e
Select an editor.  To change later, run 'select-editor'.
/bin/nano    <---- easiest
/usr/bin/vim.tiny
/bin/ed
Choose 1-3 [1]:

现在,我们需要指定使用哪个编辑器;我们将接受默认值:

太棒了!根据前面的截图,我们有一些关于如何定义条目的指导方针。让我们定义自己的条目:

根据前面的截图,我们已经定义了我们的条目,每半分钟运行一次,每天运行一次;ls命令将针对/boot目录运行,并将其输出追加保存到/home/philip/Documents/ls_crontab。定义时间的语法如下:

0/30         minute
*             hour
*             day of month
*             month
*             hour

完成条目创建后,我们需要写入更改;我们使用 nano 编辑器,所以按下Ctrl + O来写入更改:

现在,crontab文件将为用户生成,如下所示:

crontab: installing new crontab
root@philip-virtual-machine:/home/philip#
Awesome! Now, we can pass the “-l” option with the crontab command :
root@philip-virtual-machine:/home/philip# crontab -l
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# For more information see the manual pages of crontab(5) and cron(8)
# m h  dom mon dow   command
*/30 * * * * ls -l /boot >> /home/philip/Documents/ls_crontab
root@philip-virtual-machine:/home/philip#

根据前面的输出,我们可以看到我们的条目在底部。30 分钟后,我们的文件将生成,我们可以看到输出:

root@philip-virtual-machine:/home/philip# cat Documents/ls_crontab
total 66752
-rw-r--r-- 1 root root  1536934 Apr 24 00:56 abi-4.15.0-20-generic
-rw-r--r-- 1 root root   216807 Apr 24 00:56 config-4.15.0-20-generic
drwxr-xr-x 5 root root     4096 Sep  6 10:30 grub
-rw-r--r-- 1 root root 53739884 Sep  6 10:45 initrd.img-4.15.0-20-generic
-rw-r--r-- 1 root root   182704 Jan 28  2016 memtest86+.bin
-rw-r--r-- 1 root root   184380 Jan 28  2016 memtest86+.elf
-rw-r--r-- 1 root root   184840 Jan 28  2016 memtest86+_multiboot.bin
-rw-r--r-- 1 root root        0 Apr 24 00:56 retpoline-4.15.0-20-generic
-rw------- 1 root root  4038188 Apr 24 00:56 System.map-4.15.0-20-generic
-rw-r--r-- 1 root root  8249080 Apr 26 14:40 vmlinuz-4.15.0-20-generic
root@philip-virtual-machine:/home/philip#
root@philip-virtual-machine:/home/philip# date
Thu Sep  6 12:00:05 EDT 2018
root@philip-virtual-machine:/home/philip#

太棒了,我们将再等待 30 分钟,然后查看追加的输出:

root@philip-virtual-machine:/home/philip# date
Thu Sep  6 12:30:18 EDT 2018
root@philip-virtual-machine:/home/philip# cat Documents/ls_crontab
total 66752
-rw-r--r-- 1 root root  1536934 Apr 24 00:56 abi-4.15.0-20-generic
-rw-r--r-- 1 root root   216807 Apr 24 00:56 config-4.15.0-20-generic
drwxr-xr-x 5 root root     4096 Sep  6 10:30 grub
-rw-r--r-- 1 root root 53739884 Sep  6 10:45 initrd.img-4.15.0-20-generic
-rw-r--r-- 1 root root   182704 Jan 28  2016 memtest86+.bin
-rw-r--r-- 1 root root   184380 Jan 28  2016 memtest86+.elf
-rw-r--r-- 1 root root   184840 Jan 28  2016 memtest86+_multiboot.bin
-rw-r--r-- 1 root root        0 Apr 24 00:56 retpoline-4.15.0-20-generic
-rw------- 1 root root  4038188 Apr 24 00:56 System.map-4.15.0-20-generic
-rw-r--r-- 1 root root  8249080 Apr 26 14:40 vmlinuz-4.15.0-20-generic
total 66752
-rw-r--r-- 1 root root  1536934 Apr 24 00:56 abi-4.15.0-20-generic
-rw-r--r-- 1 root root   216807 Apr 24 00:56 config-4.15.0-20-generic
drwxr-xr-x 5 root root     4096 Sep  6 10:30 grub
-rw-r--r-- 1 root root 53739884 Sep  6 10:45 initrd.img-4.15.0-20-generic
-rw-r--r-- 1 root root   182704 Jan 28  2016 memtest86+.bin
-rw-r--r-- 1 root root   184380 Jan 28  2016 memtest86+.elf
-rw-r--r-- 1 root root   184840 Jan 28  2016 memtest86+_multiboot.bin
-rw-r--r-- 1 root root        0 Apr 24 00:56 retpoline-4.15.0-20-generic
-rw------- 1 root root  4038188 Apr 24 00:56 System.map-4.15.0-20-generic
-rw-r--r-- 1 root root  8249080 Apr 26 14:40 vmlinuz-4.15.0-20-generic
root@philip-virtual-machine:/home/philip#

太棒了!请注意,标准用户看不到 root 用户的crontab作业:

philip@philip-virtual-machine:~$ crontab -l
no crontab for philip
philip@philip-virtual-machine:~$

但是,root 用户可以通过使用-u选项查看任何用户的条目:

root@philip-virtual-machine:/home/philip# crontab -u philip -l
no crontab for philip
root@philip-virtual-machine:/home/philip#

太棒了!

Anacron

有趣的是,Anacron 并不是作为cron的替代品,而是用于系统有时关闭的情况。此外,Anacron 并不期望系统一直开启。例如,笔记本电脑会不时关闭。Anacron 的另一个显著特点是持续时间以天或月为单位,而不是以小时或分钟为单位。如果有一个工作需要在特定时间执行,而系统关闭了,放心,当系统启动时,Anacron 会执行该工作。我们可以查看anacrontab文件:

root@philip-virtual-machine:/home/philip# cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron
# See anacron(8) and anacrontab(5) for details.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
HOME=/root
LOGNAME=root
# These replace cron's entries
1              5              cron.daily            run-parts --report /etc/cron.daily
7              10           cron.weekly       run-parts --report /etc/cron.weekly
@monthly           15           cron.monthly     run-parts --report /etc/cron.monthly
root@philip-virtual-machine:/home/philip# 

根据前面的输出,我们可以看到anacrontab文件中有一些cron条目。我们可以看到anacroncron的补充,而不是替代cron。我们读取anacrontab文件中的条目的方式如下:

1                                                                            =Daily, other                                                                                      possible values are                                                                              7 = weekly,
                                                                             @daily, @monthly
5         
=Delay in minutes
cron.daily                                                                   = Job ID
run-parts --report /etc/cron.daily                                           = Command

我们可以在/var/spool/anacron目录中获取有关作业的信息:

root@philip-virtual-machine:/home/philip# ls -l /var/spool/anacron/
total 12
-rw------- 1 root root 9 Sep  6 10:44 cron.daily
-rw------- 1 root root 9 Sep  6 10:53 cron.monthly
-rw------- 1 root root 9 Sep  6 10:48 cron.weekly
root@philip-virtual-machine:/home/philip#

太棒了!我们可以查看其中一个文件,看到作业上次运行的时间:

root@philip-virtual-machine:/home/philip# cat /var/spool/anacron/cron.daily
20180906
root@philip-virtual-machine:/home/philip#

太好了!根据前面的输出,我们可以看到作业执行的时间戳。要查看anacron在前台处理的作业,我们可以使用anacron-d选项:

root@philip-virtual-machine:/home/philip# anacron -d
Anacron 2.3 started on 2018-09-06
Normal exit (0 jobs run)
root@philip-virtual-machine:/home/philip#

根据前面的输出,当前没有正在执行的作业。我们可以通过编辑/etc/anacrontab文件创建一个条目:

root@philip-virtual-machine:/home/philip# cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron
# See anacron(8) and anacrontab(5) for details.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
HOME=/root
LOGNAME=root
# These replace cron's entries
1              5              cron.daily            run-parts --report /etc/cron.daily
7              10           cron.weekly       run-parts --report /etc/cron.weekly
@monthly           15           cron.monthly     run-parts --report /etc/cron.monthly
1              10           test                        /bin/ls -l /boot > /home/philip/Documents/ls_anacron
root@philip-virtual-machine:/home/philip#
Excellent! Now, can check the /var/spool/anacrontab:
root@philip-virtual-machine:/home/philip# ls -l /var/spool/anacron/
total 12
-rw------- 1 root root 9 Sep  6 10:44 cron.daily
-rw------- 1 root root 9 Sep  6 10:53 cron.monthly
-rw------- 1 root root 9 Sep  6 10:48 cron.weekly
-rw------- 1 root root 0 Sep  6 13:47 test
root@philip-virtual-machine:/home/philip#

根据前面的输出,我们现在看到了我们自定义条目的新条目。我们可以查看文件内部:

root@philip-virtual-machine:/home/philip# cat /var/spool/anacron/test
root@philip-virtual-machine:/home/philip#

根据前面的输出,文件是空的,因为作业尚未运行。我们可以通过使用anacron-T选项在anacrontab文件中检查语法错误:

root@philip-virtual-machine:/home/philip# anacron -T
root@philip-virtual-machine:/home/philip#

根据前面的输出,没有发现语法错误。我们可以使用-u选项更新作业的时间戳,而不运行作业:

root@philip-virtual-machine:/home/philip# anacron -u
root@philip-virtual-machine:/home/philip#

我们没有看到任何输出,因为时间戳是在后台更新的。我们可以添加-d选项,然后我们将看到前台发生的情况:

root@philip-virtual-machine:/home/philip# anacron -d -u
Updated timestamp for job `cron.daily' to 2018-09-06
Updated timestamp for job `cron.weekly' to 2018-09-06
Updated timestamp for job `test' to 2018-09-06
Updated timestamp for job `cron.monthly' to 2018-09-06
root@philip-virtual-machine:/home/philip#

太棒了!我们可以通过使用anacron-f选项立即执行作业:

root@philip-virtual-machine:/home/philip# anacron -d -f
Anacron 2.3 started on 2018-09-06
Will run job `cron.daily' in 5 min.
Will run job `cron.weekly' in 10 min.
Will run job `test' in 10 min.
Will run job `cron.monthly' in 15 min.
^C
root@philip-virtual-machine:/home/philip#

根据前面的输出,anacron 正在尝试执行作业;但是它必须等待每个作业的延迟时间。这就是-n的威力所在;它会忽略设置的延迟:

root@philip-virtual-machine:/home/philip# anacron -d -f -n
Anacron 2.3 started on 2018-09-06
Will run job `cron.daily'
Will run job `cron.weekly'
Will run job `test'
Will run job `cron.monthly'
Jobs will be executed sequentially
Job `cron.daily' started
Job `cron.daily' terminated
Job `cron.weekly' started
Job `cron.weekly' terminated (mailing output)
anacron: Can't find sendmail at /usr/sbin/sendmail, not mailing output
Job `test' started
Job `test' terminated (exit status: 1) (mailing output)
anacron: Can't find sendmail at /usr/sbin/sendmail, not mailing output
Job `cron.monthly' started
Job `cron.monthly' terminated
Normal exit (4 jobs run)
root@philip-virtual-machine:/home/philip#

太好了!现在,我们可以检查/home/philip/Documents中的ls_anacron文件:

root@philip-virtual-machine:/home/philip# ls -l /home/philip/Documents/
total 4
-rw-r--r-- 1 root root    0 Sep  6 14:11 ls_anacron
-rw-r--r-- 1 root root 3405 Sep  6 14:00 ls_crontab
root@philip-virtual-machine:/home/philip#

太好了!我们可以查看ls_anacron文件的内容:

root@philip-virtual-machine:/home/philip# cat /home/philip/Documents/ls_anacron
abi-4.15.0-20-generic
config-4.15.0-20-generic
grub
initrd.img-4.15.0-20-generic
memtest86+.bin
memtest86+.elf
memtest86+_multiboot.bin
retpoline-4.15.0-20-generic
System.map-4.15.0-20-generic
vmlinuz-4.15.0-20-generic
root@philip-virtual-machine:/home/philip#

完美!

使用配置文件的任务权限

我们可以使用/etc/at.allow/etc/at.deny/etc/cron.allow/etc/cron.deny来限制对atcron实用程序的访问。如果这些文件不存在,我们可以创建它们;/etc/at.allow/etc/cron.allow文件就足够了。对于/etc/at.allow文件,我们执行以下操作:

root@philip-virtual-machine:/home/philip# cat /etc/at.allow
cat: /etc/at.alow: No such file or directory
root@philip-virtual-machine:/home/philip# cat /etc/cron.allow
cat: /etc/cron.allow: No such file or directory
We can use an editor and create the file and store the usernames, one username per line:
root@philip-virtual-machine:/home/philip# cat /etc/at.allow
philip
harry
teddy
root@philip-virtual-machine:/home/philip#
root@philip-virtual-machine:/home/philip# cat /etc/cron.allow
philip
harry
teddy
root@philip-virtual-machine:/home/philip#

太棒了!现在,只有这些用户可以使用atcron来执行作业。

总结

在本章中,我们讨论了命令行上的自动化。我们涉及了at实用程序,重点是创建一个只运行一次的作业。接下来,我们关注了atq实用程序以及它如何显示at实用程序将运行的所有预定作业。此外,我们还看到了如何利用at实用程序的一个选项来使我们能够查看作业队列。接着,我们看了atrm实用程序,主要关注了删除预定作业的能力。除此之外,我们还看到了使用at命令和传递选项来停止作业的可能性。然后我们讨论了cron,重点是各种cron目录;每个目录在自动化任务方面都发挥着重要作用。接下来,我们使用了crontab;我们看到了语法的细节,然后在crontab中创建了一个自定义条目。在此之后,我们使用了anacron。我们看到了anacron的用例以及它如何补充cron。然后我们创建了我们自己的自定义条目,并执行了作业,以便更好地理解anacron。最后,我们看了自动化方面的限制;主要是限制对atcron实用程序的访问。

在下一章中,我们的重点将放在时间管理上,特别是维护系统时间和执行日志记录,包括本地和远程。下一章对于任何在网络环境中工作并且每天都需要进行监视的人来说都是非常重要的。我邀请你来加入我,一起来体验另一个激动人心的章节。

问题

  1. 如果在at命令中没有传递选项,将会输出什么?

A. 无效的语法

B. 混乱的时间

C. 没有输出

D. 以上都不是

  1. 哪个是有效的at命令?

A. 在下下个早上 9:00

B. 在今晚 9:00

C. 在下周一的早上 9:00

D. 以上都不是

  1. at实用程序中,<EOT>是什么意思?

A. 时间结束

B. 按下了CTRL+ D

C. 按下了CTRL + X

D. 以上都不是

  1. 哪个选项使用at命令打印队列?

A. -a

B. -c

C. -d

D. -l

  1. 哪个选项使用at命令删除作业?

A. -a

B. -c

C. -a

D. -r

  1. 使用at命令可以打印创建的作业队列的哪个其他命令?

A. atrm

B. atc

C. atq

D. atr

  1. 哪个选项可以使用crontab每分钟运行一个作业?

A. 1/30 * * * *

B. */20 * * * *

C. *****

D. ****1

  1. 哪个选项用于打开crontab并开始进行更改?

A. -a

B. -e

C. -b

D. -c

  1. 哪个单词可以代表 anacron 中的 7?

A. @daily

B. @monthly

C. @weekly

D. @sunday

  1. 哪个选项强制anacron在其计划之前运行作业?

A. -f

B. -e

C. -c

D. -a

进一步阅读

第十四章:维护系统时间和日志记录

在上一章中,我们处理了命令行上的自动化。我们涉及了atatqatrm命令。在此之后,我们使用了各种cron目录,然后介绍了crontab实用程序。此外,我们还介绍了anacron。最后,我们讨论了自动化的限制。

在本章中,我们的重点是维护系统时间和执行日志记录。首先,我们将介绍系统时间的配置,通过网络同步时间。然后,我们将关注各种日志文件。最后,我们将在不同的 Linux 系统之间执行远程日志记录。

在本章中,我们将涵盖以下主题:

  • 日期配置

  • 设置本地系统日志

  • 配置远程日志记录

日期配置

在大多数 Linux 环境中,将系统与正确的时间同步是至关重要的。我们可以使用date命令来显示当前日期。我们可以通过简单运行以下命令来查看系统日期和时间:

root@philip-virtual-machine:/home/philip# date
Thu Sep  6 16:25:56 EDT 2018
root@philip-virtual-machine:/home/philip#

根据前面的输出,我们可以看到当前日期。还可以使用date命令设置日期和时间。为了能够以字符串格式指定日期,我们传递-s选项:

philip@philip-virtual-machine:~$ date -s "19 Dec 2020 12:00:00"
date: cannot set date: Operation not permitted
Sat Dec 19 12:00:00 EST 2020
philip@philip-virtual-machine:~$

根据前面的输出,我们遇到了一个障碍;这是因为我们需要 root 权限才能更改日期。让我们再试一次,这次作为 root 用户:

root@philip-virtual-machine:/home/philip# date -s "19 Dec 2020 12:00:00"
Sat Dec 19 12:00:00 EST 2020
root@philip-virtual-machine:/home/philip# date
Fri Sep  7 09:51:24 EDT 2018
root@philip-virtual-machine:/home/philip#

哇!发生了什么?嗯,事情是这样的:系统配置为自动同步时间。这可以通过使用另一个强大的命令来验证:timedatectl命令。我们可以运行timedatectl命令来查看当前的同步设置:

root@philip-virtual-machine:/home/philip# timedatectl
 Local time: Fri 2018-09-07 09:57:49 EDT
 Universal time: Fri 2018-09-07 13:57:49 UTC
 RTC time: Fri 2018-09-07 13:57:49
 Time zone: America/New_York (EDT, -0400)
 System clock synchronized: yes
systemd-timesyncd.service active: yes
 RTC in local TZ: no
root@philip-virtual-machine:/home/philip#

太棒了!根据前面的输出,systemd-timesyncd.service active: yes部分表明系统确实已设置为同步。此外,我们可以传递status选项,这将返回类似的结果:

root@philip-virtual-machine:/home/philip# timedatectl status
 Local time: Fri 2018-09-07 10:02:38 EDT
 Universal time: Fri 2018-09-07 14:02:38 UTC
 RTC time: Fri 2018-09-07 14:02:38
 Time zone: America/New_York (EDT, -0400)
 System clock synchronized: yes
systemd-timesyncd.service active: yes
 RTC in local TZ: no
root@philip-virtual-machine:/home/philip#

太棒了!我们可以手动设置时间,但首先需要通过使用timedatectl命令传递set-ntp选项来禁用自动同步:

root@philip-virtual-machine:/home/philip# timedatectl set-ntp false
root@philip-virtual-machine:/home/philip#
root@philip-virtual-machine:/home/philip# timedatectl status
 Local time: Fri 2018-09-07 10:04:27 EDT
 Universal time: Fri 2018-09-07 14:04:27 UTC
 RTC time: Fri 2018-09-07 14:04:27
 Time zone: America/New_York (EDT, -0400)
 System clock synchronized: yes
systemd-timesyncd.service active: no
 RTC in local TZ: no
root@philip-virtual-machine:/home/philip#

干得好!根据前面的命令,我们现在可以看到systemd-timesyncd.service active: no部分已更改为no。我们现在可以尝试再次使用date命令更改日期:

root@philip-virtual-machine:/home/philip# date
Fri Sep  7 10:06:28 EDT 2018
root@philip-virtual-machine:/home/philip# date -s "19 Dec 2020 12:00:00"
Sat Dec 19 12:00:00 EST 2020
root@philip-virtual-machine:/home/philip# date
Sat Dec 19 12:00:01 EST 2020
root@philip-virtual-machine:/home/philip#

太棒了!命令已成功执行并更改了当前日期。我们还可以使用数字值来表示月份,如下所示:

root@philip-virtual-machine:/home/philip# date -s "20240101 13:00:00"
Mon Jan  1 13:00:00 EST 2024
root@philip-virtual-machine:/home/philip# date
Mon Jan  1 13:00:08 EST 2024
root@philip-virtual-machine:/home/philip#

根据前面的输出,我们可以看到日期和时间已更改以反映新的设置。除此之外,还可以使用连字符分隔日期,如下所示:

root@philip-virtual-machine:/home/philip# date -s "2000-10-05 07:00:00"
Thu Oct  5 07:00:00 EDT 2000
root@philip-virtual-machine:/home/philip# date
Thu Oct  5 07:00:02 EDT 2000
root@philip-virtual-machine:/home/philip#

太棒了!我们还可以使用正则表达式来设置时间。我们可以使用+%T来设置时间:

root@philip-virtual-machine:/home/philip# date
Thu Oct  5 03:06:43 EDT 2000
root@philip-virtual-machine:/home/philip#
root@philip-virtual-machine:/home/philip# date +%T -s "20:00:00"
20:00:00
root@philip-virtual-machine:/home/philip# date
Thu Oct  5 20:00:03 EDT 2000
root@philip-virtual-machine:/home/philip#

太棒了!还可以使用date命令仅更改小时;我们传递+%H选项:

root@philip-virtual-machine:/home/philip# date +%H -s "4"
04
root@philip-virtual-machine:/home/philip# date
Thu Oct  5 04:00:03 EDT 2000
root@philip-virtual-machine:/home/philip#

太棒了!还可以使用timedatectl命令更改日期和时间。我们可以通过传递set-time选项来更改日期:

root@philip-virtual-machine:/home/philip# timedatectl set-time 10:00:00
root@philip-virtual-machine:/home/philip# date
Thu Oct  5 10:00:02 EDT 2000
root@philip-virtual-machine:/home/philip# timedatectl
 Local time: Thu 2000-10-05 10:00:06 EDT
 Universal time: Thu 2000-10-05 14:00:06 UTC
 RTC time: Thu 2000-10-05 14:00:06
 Time zone: America/New_York (EDT, -0400)
 System clock synchronized: no systemd-timesyncd.service active: no
 RTC in local TZ: no
root@philip-virtual-machine:/home/philip#

太棒了!还可以通过传递set-time选项来仅设置日期:

root@philip-virtual-machine:/home/philip# timedatectl set-time 2019-03-01
root@philip-virtual-machine:/home/philip# date
Fri Mar  1 00:00:02 EST 2019
root@philip-virtual-machine:/home/philip#

根据前面的输出,日期已更改,但请注意时间也已更改。我们可以通过合并日期和时间来解决这个问题:

root@philip-virtual-machine:/home/philip# timedatectl set-time '2019-03-01 10:00:00'
root@philip-virtual-machine:/home/philip# date
Fri Mar  1 10:00:01 EST 2019
root@philip-virtual-machine:/home/philip#

太棒了!我们还可以使用timedatectl命令更改时区;我们可以通过传递list-timezones选项来查看可用的时区:

root@philip-virtual-machine:/home/philip# timedatectl list-timezones
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
Africa/Asmara
Africa/Bamako
Africa/Bangui
America/Guayaquil
America/Guyana
root@philip-virtual-machine:/home/philip#

出于简洁起见,某些输出已被省略。我们通过传递set-timezone选项来更改时区:

root@philip-virtual-machine:/home/philip# timedatectl
 Local time: Fri 2019-03-01 10:15:43 EST
 Universal time: Fri 2019-03-01 15:15:43 UTC
 RTC time: Fri 2019-03-01 15:15:43
 Time zone: America/New_York (EST, -0500)
 System clock synchronized: no
systemd-timesyncd.service active: no
 RTC in local TZ: no
root@philip-virtual-machine:/home/philip# timedatectl set-timezone America/Guyana
root@philip-virtual-machine:/home/philip# timedatectl
 Local time: Fri 2019-03-01 11:15:59 -04
 Universal time: Fri 2019-03-01 15:15:59 UTC
 RTC time: Fri 2019-03-01 15:16:00
 Time zone: America/Guyana (-04, -0400)
 System clock synchronized: no
systemd-timesyncd.service active: no
 RTC in local TZ: no
root@philip-virtual-machine:/home/philip#

太棒了!我们已成功更改了时区。时区信息存储在/etc/timezone/etc/localtime文件中。它是指向/usr/share/zoneinfo/<timezone>的符号链接;<timezone>是我们指定的任何内容:

root@philip-virtual-machine:/home/philip# ls -l /etc/localtime
lrwxrwxrwx 1 root root 36 Mar  1 11:15 /etc/localtime -> ../usr/share/zoneinfo/America/Guyana
root@philip-virtual-machine:/home/philip#
root@philip-virtual-machine:/home/philip# cat /etc/timezone
America/Guyana
root@philip-virtual-machine:/home/philip#

太棒了!根据前面的输出,我们可以看到/etc/timezone/etc/localtime已更新为指定的时区。

tzselect 命令

tzselect命令可用于更改系统的时区。当我们启动tzselect命令时,它将以交互模式询问一系列问题。可以通过以下方式说明这一点:

root@philip-virtual-machine:/home/philip# tzselect
Please identify a location so that time zone rules can be set correctly.
Please select a continent, ocean, "coord", or "TZ".
 1) Africa
 2) Americas
 3) Antarctica
 4) Asia
 5) Atlantic Ocean
 6) Australia
 7) Europe]
 8) Indian Ocean
 9) Pacific Ocean
10) coord - I want to use geographical coordinates.
11) TZ - I want to specify the time zone using the Posix TZ format.
#?

根据前面的输出,我们需要输入代表大陆的数字:

#? 2
Please select a country whose clocks agree with yours.
 1) Anguilla          19) Dominican Republic   37) Peru
 2) Antigua & Barbuda 20) Ecuador              38) Puerto Rico
 3) Argentina         21) El Salvador          39) St Barthelemy
 4) Aruba             22) French Guiana        40) St Kitts & Nevis
 5) Bahamas           23) Greenland            41) St Lucia
 6) Barbados          24) Grenada              42) St Maarten (Dutch)
 7) Belize            25) Guadeloupe           43) St Martin (French)
 8) Bolivia           26) Guatemala            44) St Pierre & Miquelon
 9) Brazil            27) Guyana               45) St Vincent
#?

出于简洁起见,一些输出已被省略。然后我们必须指定国家:

The following information has been given:
 Guyana
Therefore TZ='America/Guyana' will be used.
Selected time is now:     Fri Mar  1 11:27:49 -04 2019.
Universal Time is now:   Fri Mar  1 15:27:49 UTC 2019.
Is the above information OK?
1) Yes
2) No
#?

根据前面的输出,我们需要确认信息:

#? 1
You can make this change permanent for yourself by appending the line
 TZ='America/Guyana'; export TZ
to the file '.profile' in your home directory; then log out and log in again.
Here is that TZ value again, this time on standard output so that you
can use the /usr/bin/tzselect command in shell scripts:
America/Guyana
root@philip-virtual-machine:/home/philip#

我们需要在当前用户的主目录的.profile中添加TZ='America/Guyana'; export TZ行;然后用户需要注销并重新登录以使更改永久生效。当然,我们已经通过使用前面的命令:timedatectl命令使我们的更改永久生效。

tzconfig 命令

tzconfig命令是更改系统时区的旧方法。实际上已经不可用了;取而代之的是 Ubuntu 中的tzdata命令。

这可以通过运行tzconfig命令来说明:

root@philip-virtual-machine:/home/philip# tzconfig
WARNING: the tzconfig command is deprecated, please use:
 dpkg-reconfigure tzdata
root@philip-virtual-machine:/home/philip#

根据前面的命令,我们需要运行dpkg-reconfigure tzdata命令;这将启动一个交互式对话框:

现在我们需要使用键盘滚动;然后按Enter键选择所需的大陆。然后会出现这个:

根据前面的输出,然后滚动到所需的国家并按Enter键;这将使用你突出显示的国家的时区:

root@philip-virtual-machine:/home/philip# dpkg-reconfigure tzdata
Current default time zone: 'America/Guyana'
Local time is now: Fri Mar 1 11:40:31 -04 2019.
Universal Time is now: Fri Mar 1 15:40:31 UTC 2019.
root@philip-virtual-machine:/home/philip#

太棒了!改变时区的另一种方法是手动删除/etc/localtime并创建一个符号链接,指向/usr/share/zoneinfo内所需的时区。这是它的样子:

root@philip-virtual-machine:/etc# unlink localtime
root@philip-virtual-machine:/etc# ln -s /usr/share/zoneinfo/America/Paramaribo localtime
root@philip-virtual-machine:/etc# ll /etc/localtime
lrwxrwxrwx 1 root root 38 Mar  1 13:01 /etc/localtime -> /usr/share/zoneinfo/America/Paramaribo
root@philip-virtual-machine:/etc#
root@philip-virtual-machine:/etc# timedatectl
 Local time: Fri 2019-03-01 13:03:57 -03
Universal time: Fri 2019-03-01 16:03:57 UTC
 RTC time: Fri 2019-03-01 16:03:57
 Time zone: America/Paramaribo (-03, -0300)
 System clock synchronized: no
systemd-timesyncd.service active: no
 RTC in local TZ: no
root@philip-virtual-machine:/etc#
root@philip-virtual-machine:/etc# cat /etc/timezone
America/Guyana
root@philip-virtual-machine:/etc#

从前面的输出中,我们可以看到时区信息在timedatectl命令中已更新。但是在/etc/timezone中没有更新。为了更新/etc/timezone,我们需要运行dpkg-reconfigure tzdata命令:

root@philip-virtual-machine:/etc# dpkg-reconfigure tzdata
Current default time zone: 'America/Paramaribo'
Local time is now:      Fri Mar  1 13:07:43 -03 2019.
Universal Time is now:  Fri Mar  1 16:07:43 UTC 2019.
root@philip-virtual-machine:/etc# cat /etc/timezone
America/Paramaribo
root@philip-virtual-machine:/etc#         

太棒了!

hwclock 命令

还有另一个时钟;即使系统关机时也在运行的时钟;这是硬件时钟。我们可以查看硬件时钟的时间如下:

root@philip-virtual-machine:/etc# date
Fri Mar  1 13:11:49 -03 2019
root@philip-virtual-machine:/etc# hwclock
2019-03-01 13:11:51.634343-0300
root@philip-virtual-machine:/etc#

从前面的输出中,我们可以看到日期和时间是相对接近的。我们可以将硬件时钟设置为与系统时间同步,如下所示:

root@philip-virtual-machine:/etc# hwclock --systohc
root@philip-virtual-machine:/etc# date
Fri Mar  1 12:17:04 -04 2019
root@philip-virtual-machine:/etc# hwclock
2019-03-01 12:17:06.556082-0400
root@philip-virtual-machine:/etc#

还可以配置系统时间与硬件时钟同步。我们可以这样做:

root@philip-virtual-machine:/etc# hwclock --hctosys
root@philip-virtual-machine:/etc# date
Fri Mar  1 12:18:52 -04 2019
root@philip-virtual-machine:/etc# hwclock
2019-03-01 12:18:54.571552-0400
root@philip-virtual-machine:/etc#

硬件时钟从/etc/adjtime中获取设置,如下所示:

root@philip-virtual-machine:/etc# cat /etc/adjtime
0.000000 1551457021 0.000000
1551457021
UTC
root@philip-virtual-machine:/etc#

还有硬件时钟;我们可以使用hwclock命令查看硬件时钟。如果我们使用 UTC 时间,我们可以在hwclock命令中使用--utc选项:

root@philip-virtual-machine:/home/philip# hwclock -r --utc
2018-09-06 16:30:27.493714-0400
root@philip-virtual-machine:/home/philip#

如前面的命令所示,硬件时钟的日期以 UTU 形式呈现。除此之外,我们还可以使用--show选项来显示类似的结果:

root@philip-virtual-machine:/home/philip# hwclock --show --utc
2018-09-06 16:31:43.025628-0400
root@philip-virtual-machine:/home/philip#

太棒了!

设置本地系统日志记录

在 Linux 环境中,具有可用于识别系统潜在瓶颈的日志非常重要。幸运的是,默认情况下我们已经打开了日志记录。有不同类型的日志文件可供检查;主要是/var/log目录包含了系统不同方面的各种日志文件。我们可以查看/var/log目录:

root@philip-virtual-machine:/etc# cd /var

从前面的输出中,首先是/var/log/syslog文件。这包含了有关系统运行情况的相关信息。我们可以查看/var/log/syslog文件:

root@philip-virtual-machine:/var# ll /var/log/syslog
-rw-r----- 1 syslog adm 48664 Mar 1 15:38 /var/log/syslog
root@philip-virtual-machine:/var# tail -f /var/log/syslog
Mar  1 14:31:52 philip-virtual-machine snapd[725]: 2019/03/01 14:31:52.052401 autorefresh.go:327: Cannot prepare auto-refresh change: cannot refresh snap-declaration for "core": Get https://api.snapcraft.io/api/v1/snaps/assertions/snap-declaration/16/99T7MUlRhtI3U0QFgl5mXXESAiSwt776?max-format=2: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
Mar  1 14:31:52 philip-virtual-machine snapd[725]: 2019/03/01 14:31:52.053013 stateengine.go:101: state ensure error: cannot refresh snap-declaration for "core": Get https://api.snapcraft.io/api/v1/snaps/assertions/snap-declaration/16/99T7MUlRhtI3U0QFgl5mXXESAiSwt776?max-format=2: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
Mar  1 14:38:03 philip-virtual-machine gnome-shell[1576]: Object Gdm.UserVerifierProxy (0x560080fc4cd0), has been already deallocated - impossible to access to it. This might be caused by the fact that the object has been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs
^C
root@philip-virtual-machine:/var#

出于简洁起见,一些输出已被省略。我们使用tail命令和-f选项;这将打印出最近生成的日志,存储在/var/log/syslog文件中。另一个有用的日志文件是/var/log/auth.log。这显示了各种认证消息。我们可以查看/var/log/auth.log文件:

root@philip-virtual-machine:/var# tail -f /var/log/auth.log
Mar  1 13:17:01 philip-virtual-machine CRON[7162]: pam_unix(cron:session): session closed for user root
Mar  1 13:30:01 philip-virtual-machine CRON[7167]: pam_unix(cron:session): session opened for user root by (uid=0)
Mar  1 13:30:01 philip-virtual-machine CRON[7167]: pam_unix(cron:session): session closed for user rootMar  1 14:00:01 philip-virtual-machine CRON[7178]: pam_unix(cron:session): session opened for user root by (uid=0)
Mar  1 14:00:01 philip-virtual-machine CRON[7178]: pam_unix(cron:session): session closed for user root
Mar  1 14:17:01 philip-virtual-machine CRON[7184]: pam_unix(cron:session): session opened for user
 ^C
root@philip-virtual-machine:/var#

太棒了!在前面的输出中,我们可以看到与 root 用户有关的各种日志。此外,如果有人试图侵入系统,这些登录尝试也会出现在这里:

root@philip-virtual-machine:/var/log# tail -f /var/log/auth.log
Mar  4 10:39:04 philip-virtual-machine sshd[26259]: Failed password for invalid user tom from 172.16.175.129 port 39010 ssh2
Mar  4 10:39:04 philip-virtual-machine sshd[26259]: Connection closed by invalid user tom 172.16.175.129 port 39010 [preauth]
Mar  4 10:39:04 philip-virtual-machine sshd[26259]: PAM 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruser= rhost=172.16.175.129
Mar  4 10:39:09 philip-virtual-machine sshd[26261]: Invalid user harry from 172.16.175.129 port 39012
Mar  4 10:39:10 philip-virtual-machine sshd[26261]: pam_unix(sshd:auth): check pass; user unknown
Mar  4 10:39:10 philip-virtual-machine sshd[26261]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=172.16.175.129
Mar  4 10:39:12 philip-virtual-machine sshd[26261]: Failed password for invalid user harry from 172.16.175.129 port 39012 ssh2
Mar  4 10:39:13 philip-virtual-machine sshd[26261]: pam_unix(sshd:auth): check pass; user unknown
Mar  4 10:39:15 philip-virtual-machine sshd[26261]: Failed password for invalid user harry from 172.16.175.129 port 39012 ssh2
Mar  4 10:39:16 philip-virtual-machine sshd[26261]: pam_unix(sshd:auth): check pass; user unknown
Mar  4 10:39:18 philip-virtual-machine sshd[26261]: Failed password for invalid user harry from 172.16.175.129 port 39012 ssh2
Mar  4 10:39:18 philip-virtual-machine sshd[26261]: Connection closed by invalid user harry 172.16.175.129 port 39012 [preauth]
Mar  4 10:39:18 philip-virtual-machine sshd[26261]: PAM 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruser= rhost=172.16.175.129

太棒了!我们可以看到有关用户尝试登录系统的认证消息。另一个有用的日志文件是/var/log/kern.log。此文件包含与启动期间内核相关的各种消息。我们可以查看这个文件:

root@philip-virtual-machine:/var/log# tail -f /var/log/kern.log
Mar 1 15:40:32 philip-virtual-machine kernel: [106182.510455] hrtimer: interrupt took 7528791 ns
Mar 2 04:58:37 philip-virtual-machine kernel: [154065.757609] sched: RT throttling activated
Mar 4 10:07:45 philip-virtual-machine kernel: [345414.648164] IPv6: ADDRCONF(NETDEV_UP): ens33: link is not ready
Mar 4 10:07:45 philip-virtual-machine kernel: [345414.653620] IPv6: ADDRCONF(NETDEV_UP): ens33: link is not ready
Mar 4 10:07:45 philip-virtual-machine kernel: [345414.655942] e1000: ens33 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
Mar 4 10:07:45 philip-virtual-machine kernel: [345414.656712] IPv6: ADDRCONF(NETDEV_CHANGE): ens33: link becomes ready
^C
root@philip-virtual-machine:/var/log#

在前面的文件中,我们可以看到与中断和网络有关的日志。在 Fedora 28 系统上,当我们检查/var/log文件时,我们会注意到没有/var/log/syslog文件:

[root@localhost philip]# ls /var/log
anaconda         dnf.log               hawkey.log           pluto            vmware-network.7.log
audit            dnf.log-20180805      hawkey.log-20180805  ppp    vmware-network.8.log
blivet-gui       dnf.log-20180812      hawkey.log-20180812  README vmware-network.9.log
boot.log         dnf.log-20180827      hawkey.log-20180827  samba  vmware-network.log
btmp             dnf.log-20180904      hawkey.log-20180904  speech-dispatcher     vmware-vgauthsvc.log.0
btmp-20180904     dnf.rpm.log           httpd                sssd             vmware-vmsvc.log
chrony           dnf.rpm.log-20180805  journal              tallylog         wtmp
cups             dnf.rpm.log-20180812  kdm.log              vmware-network.1.log  Xorg.0.log
dnf.librepo.log  dnf.rpm.log-20180827  kdm.log-20180904     vmware-network.2.log  Xorg.0.log.old
dnf.librepo.log-20180805  dnf.rpm.log-20180904  lastlog              vmware-network.3.log
dnf.librepo.log-20180812  firewalld             libvirt              vmware-network.4.log
dnf.librepo.log-20180827  gdm                   lightdm              vmware-network.5.log
dnf.librepo.log-20180904  glusterfs             mariadb              vmware-network.6.log
[root@localhost philip]#

根据前面的输出,Fedora 28 正在使用systemd。这已经用journal替换了/var/log/messages/var/log/syslog。这反过来又是在journald守护程序内实现的。我们可以使用journalctl命令查看日志。要查看所有日志文件,我们可以简单地输入journalctl而不带任何选项:

root@localhost philip]# journalctl
-- Logs begin at Tue 2018-07-31 10:57:23 EDT, end at Fri 2018-09-07 15:51:56 EDT. --
Jul 31 10:57:23 localhost.localdomain kernel: Linux version 4.16.3-301.fc28.x86_64 (mockbuild@bkernel02.phx2.fedoraprojec>
Jul 31 10:57:23 localhost.localdomain kernel: Command line: BOOT_IMAGE=/vmlinuz-4.16.3-301.fc28.x86_64 root=/dev/mapper/f>
Jul 31 10:57:23 localhost.localdomain kernel: Disabled fast string operations
Jul 31 10:57:23 localhost.localdomain kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
Jul 31 10:57:23 localhost.localdomain kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
Jul 31 10:57:23 localhost.localdomain kernel: x86/fpu: Enabled xstate features 0x3, context size is 576 bytes, using 'sta>
Jul 31 10:57:23 localhost.localdomain kernel: e820: BIOS-provided physical RAM map:
Jul 31 10:57:23 localhost.localdomain kernel: BIOS-e820: [mem 0x0000000000000000-0x000000000009ebff] usable
Jul 31 10:57:23 localhost.localdomain kernel: BIOS-e820: [mem 0x000000000009ec00-0x000000000009ffff] reserved
Jul 31 10:57:23 localhost.localdomain kernel: BIOS-e820: [mem 0x00000000000dc000-0x00000000000fffff] reserved
 [root@localhost philip]#

为了简洁起见,已省略了一些输出。有许多日志消息。我们可以过滤我们想要显示的内容。例如,要查看自最近系统引导以来的日志,我们可以传递-b选项:

[root@localhost philip]# journalctl -b
-- Logs begin at Tue 2018-07-31 10:57:23 EDT, end at Fri 2018-09-07 15:52:26 EDT. --
Sep 04 08:55:38 localhost.localdomain kernel: Linux version 4.16.3-301.fc28.x86_64 (mockbuild@bkernel02.phx2.fedoraprojec>
Sep 04 08:55:38 localhost.localdomain kernel: Command line: BOOT_IMAGE=/vmlinuz-4.16.3-301.fc28.x86_64 root=/dev/mapper/f>
Sep 04 08:55:38 localhost.localdomain kernel: Disabled fast string operations
Sep 04 08:55:38 localhost.localdomain kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
Sep 04 08:55:38 localhost.localdomain kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
Sep 04 08:55:38 localhost.localdomain kernel: x86/fpu: Enabled xstate features 0x3, context size is 576 bytes, using 'sta>
Sep 04 08:55:38 localhost.localdomain kernel: e820: BIOS-provided physical RAM map:
Sep 04 08:55:38 localhost.localdomain kernel: BIOS-e820: [mem 0x0000000000000000-0x000000000009ebff] usable
[root@localhost philip]#

在前面的输出中,我们看到了相当多的消息。我们甚至可以通过传递--utc选项显示带有 UTC 时间戳的日志:

[root@localhost philip]# journalctl -b --utc
-- Logs begin at Tue 2018-07-31 14:57:23 UTC, end at Fri 2018-09-07 19:52:26 UTC. --
Sep 04 12:55:38 localhost.localdomain kernel: Linux version 4.16.3-301.fc28.x86_64 (mockbuild@bkernel02.phx2.fedoraprojec>
Sep 04 12:55:38 localhost.localdomain kernel: Command line: BOOT_IMAGE=/vmlinuz-4.16.3-301.fc28.x86_64 root=/dev/mapper/f>
Sep 04 12:55:38 localhost.localdomain kernel: Disabled fast string operations
Sep 04 12:55:38 localhost.localdomain kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
[root@localhost philip]#

太棒了!根据前面的输出,第一行-- Logs begin at Tue 2018-07-31 14:57:23 UTC, end at Fri 2018-09-07 19:52:26 UTC. --表示时间戳是 UTC 时间。journalctl文件还将信息存储在/var/log/journal中,如下所示:

[root@localhost philip]# ls /var/log/journal/
30012ff3b6d648a09e33e4927d140504
[root@localhost philip]#

我们甚至可以深入了解并查看/var/journal/30012ff3b6d648a09e33e4927d140504下的更多日志文件,如下所示:

[root@localhost philip]# ls /var/log/journal/30012ff3b6d648a09e33e4927d140504/
system@000572748a062ca4-7a3da8346cf70fb7.journal~
system@0005746b23e241ef-7ed07e858f3a6f48.journal~
system@0005746c7d7bed2f-80a58e1cfa65a3dd.journal~
system@0005750b2d37139f-3ddba79811cf1357.journal~
system@123e7dba3db2484697ae1cc5bfff550d-0000000000000001-0005750b2cb5f7d4.journal
system.journal
user-1000@000572749f063152-ae4ff154ee396e12.journal~
user-1000@4e535b252cc04ea69811c152632aafcd-0000000000000907-000572749f062b74.journal
user-1000.journal
[root@localhost philip]#

太棒了!我们可以使用journalctl来公开这些信息。例如,我们可以查看与先前引导有关的日志;这可以通过传递--list-boots选项来查看:

[root@localhost philip]# journalctl --utc --list-boots
-6 6d6ff5ab30284bbe8da4c97e54298944 Tue 2018-07-31 14:57:23 UTC—Tue 2018-07-31 20:17:06 UTC
-5 a7a23120abff44c8bca6807f1711c1c2 Thu 2018-08-02 14:22:09 UTC—Sun 2018-08-12 14:18:21 UTC
-4 905ba9f3c37d46b69920466e9a93a67d Mon 2018-08-27 13:59:47 UTC—Mon 2018-08-27 15:06:04 UTC
-3 e4d2ad4c25df41a2b905fdcb8cfae312 Mon 2018-08-27 15:06:18 UTC—Mon 2018-08-27 15:37:50 UTC
-2 ae1c87d6ea6842da91eb4a1cba331ead Mon 2018-08-27 15:38:18 UTC—Mon 2018-08-27 20:22:15 UTC
-1 7cfc215cb74149748fe717b688630bd3 Mon 2018-08-27 20:22:33 UTC—Wed 2018-08-29 12:50:59 UTC
 0 d3cb4fafa63a41f99bd3cc4da0b74d1d Tue 2018-09-04 12:55:38 UTC—Fri 2018-09-07 19:59:02 UTC
[root@localhost philip]#

根据前面的输出,我们可以看到包含引导信息的七个文件;我们可以通过传递文件的偏移量来查看这些文件中的任何一个。每个文件的偏移量是第一列中的值。让我们看一下-6偏移量:

[root@localhost philip]# journalctl -b -6 --utc
-- Logs begin at Tue 2018-07-31 14:57:23 UTC, end at Fri 2018-09-07 20:01:02 UTC. --
Jul 31 14:57:23 localhost.localdomain kernel: Linux version 4.16.3-301.fc28.x86_64 (mockbuild@bkernel02.phx2.fedoraprojec>
Jul 31 14:57:23 localhost.localdomain kernel: Command line: BOOT_IMAGE=/vmlinuz-4.16.3-301.fc28.x86_64 root=/dev/mapper/f>
Jul 31 14:57:23 localhost.localdomain kernel: Disabled fast string operations
Jul 31 14:57:23 localhost.localdomain kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
Jul 31 14:57:23 localhost.localdomain kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
Jul 31 14:57:23 localhost.localdomain kernel: x86/fpu: Enabled xstate features 0x3, context size is 576 bytes, using 'sta>
Jul 31 14:57:23 localhost.localdomain kernel: e820: BIOS-provided physical RAM map:
 [root@localhost philip]#

为了简洁起见,已省略了一些输出。我们可以查看/etc/systemd/journald.conf

[root@localhost philip]# cat /etc/systemd/journald.conf
[Journal]
#Storage=auto
#Compress=yes
#Seal=yes
#SplitMode=uid
#SyncIntervalSec=5m
#RateLimitIntervalSec=30s
#RateLimitBurst=1000
#SystemMaxUse=
#SystemKeepFree=
#SystemMaxFileSize=
#SystemMaxFiles=100
#RuntimeMaxUse=
#RuntimeKeepFree=
#RuntimeMaxFileSize=
#RuntimeMaxFiles=100
#MaxRetentionSec=
#MaxFileSec=1month
#ForwardToSyslog=no
#ForwardToKMsg=no
#ForwardToConsole=no
#ForwardToWall=yes
#TTYPath=/dev/console
#MaxLevelStore=debug
#MaxLevelSyslog=debug
#MaxLevelKMsg=notice
#MaxLevelConsole=info
#MaxLevelWall=emerg
#LineMax=48K
[root@localhost philip]#

为了简洁起见,已省略了一些输出。根据前面的输出,所有设置都是默认的;表示注释。我们可以通过传递--since选项来指定我们想要查看日志信息的日期:

root@localhost philip]# journalctl --since today --utc
-- Logs begin at Tue 2018-07-31 14:57:23 UTC, end at Fri 2018-09-07 20:01:02 UTC. --
Sep 07 04:00:58 localhost.localdomain systemd[1]: Started Update a database for mlocate.
Sep 07 04:00:58 localhost.localdomain audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:sy>
Sep 07 04:00:58 localhost.localdomain systemd[1]: Starting update of the root trust anchor for DNSSEC validation in unbou>
Sep 07 04:00:59 localhost.localdomain systemd[1]: Started update of the root trust anchor for DNSSEC validation in unboun>
Sep 07 04:00:59 localhost.localdomain audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:sy>
Sep 07 04:00:59 localhost.localdomain audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:sys>
Sep 07 04:01:01 localhost.localdomain CROND[13532]: (root) CMD (run-parts /etc/cron.hourly)
Sep 07 04:01:01 localhost.localdomain run-parts[13535]: (/etc/cron.hourly) starting 0anacron
Sep 07 04:01:01 localhost.localdomain run-parts[13543]: (/etc/cron.hourly) finished 0anacron
Sep 07 04:01:01 localhost.localdomain anacron[13541]: Anacron started on 2018-09-07
Sep 07 04:01:01 localhost.localdomain anacron[13541]: Normal exit (0 jobs run)
Sep 07 04:01:19 localhost.localdomain audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:sys>
Sep 07 04:05:16 localhost.localdomain dhclient[1011]: DHCPREQUEST on ens33 to 172.16.175.254 port 67 (xid=0x1269bc29)
[root@localhost philip]#

太棒了!为了简洁起见,已省略了一些输出。我们还可以用数字指定日期:

[root@localhost philip]# journalctl --since "2018-09-07 15:00:00"
-- Logs begin at Tue 2018-07-31 10:57:23 EDT, end at Fri 2018-09-07 16:11:54 EDT. --
Sep 07 15:01:01 localhost.localdomain CROND[16031]: (root) CMD (run-parts /etc/cron.hourly)
Sep 07 15:01:01 localhost.localdomain run-parts[16034]: (/etc/cron.hourly) starting 0anacron
Sep 07 15:01:01 localhost.localdomain run-parts[16040]: (/etc/cron.hourly) finished 0anacron
Sep 07 15:09:56 localhost.localdomain dhclient[1011]: DHCPREQUEST on ens33 to 172.16.175.254 port 67 (xid=0x1269bc29)
Sep 07 15:09:56 localhost.localdomain dhclient[1011]: DHCPACK from 172.16.175.254 (xid=0x1269bc29)
Sep 07 15:09:56 localhost.localdomain NetworkManager[833]: <info>  [1536347396.3834] dhcp4 (ens33):   address 172.16.175.>
Sep 07 15:09:56 localhost.localdomain NetworkManager[833]: <info>  [1536347396.3842] dhcp4 (ens33):   plen 24 (255.255.25>
Sep 07 15:09:56 localhost.localdomain NetworkManager[833]: <info>  [1536347396.3845] dhcp4 (ens33):   gateway 172.16.175.2
[root@localhost philip]#

为了简洁起见,已省略了一些输出。但是,我们可以看到与网络有关的信息。同样,我们可以在/var/log/audit/audit.log中查看认证信息。以下是此文件的摘录:

干得好!从摘录中,我们可以看到登录尝试进入 Fedora 系统。此外,我们可以利用journalctl命令显示认证信息。我们可以传递-u选项并指定要查找的服务:

[root@localhost philip]# journalctl -u sshd.service
-- Logs begin at Tue 2018-07-31 10:57:23 EDT, end at Mon 2018-09-10 12:06:49 EDT. --
Sep 10 12:05:28 localhost.localdomain sshd[27585]: Invalid user ted from 172.16.175.132 port 37406
Sep 10 12:05:29 localhost.localdomain sshd[27585]: pam_unix(sshd:auth): check pass; user unknown
Sep 10 12:05:29 localhost.localdomain sshd[27585]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty>
Sep 10 12:05:31 localhost.localdomain sshd[27585]: Failed password for invalid user ted from 172.16.175.132 port 37406 ss>
Sep 10 12:05:32 localhost.localdomain sshd[27585]: pam_unix(sshd:auth): check pass; user unknown
Sep 10 12:05:34 localhost.localdomain sshd[27585]: Failed password for invalid user ted from 172.16.175.132 port 37406 ss>
Sep 10 12:05:54 localhost.localdomain sshd[27585]: pam_unix(sshd:auth): check pass; user unknown
Sep 10 12:05:56 localhost.localdomain sshd[27585]: Failed password for invalid user ted from 172.16.175.132 port 37406 ss>
Sep 10 12:05:56 localhost.localdomain sshd[27585]: Connection closed by invalid user ted 172.16.175.132 port 37406 [preau>
Sep 10 12:05:56 localhost.localdomain sshd[27585]: PAM 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruse>
[root@localhost philip]#

从中,我们可以看到journalctl实用程序的有效性。

配置远程日志记录

查看本地系统的日志文件总是很好,但是如何管理远程日志呢?好吧,可以配置 Linux 系统执行远程日志记录。我们必须安装(如果尚未安装)日志记录软件。在本演示中,我们将使用 Fedora 28 作为日志记录客户端,Ubuntu 18 系统作为日志记录服务器。此外,我们将使用rsyslog作为日志记录软件。默认情况下,它已经安装在 Ubuntu 18 系统中。但是,在 Fedora 28 上,我们将不得不安装rsyslog软件。首先,让我们在 Fedora 28 中安装rsyslog软件。我们使用dnf命令,如下所示:

[root@localhost philip]# dnf search rsyslog
Last metadata expiration check: 1:38:20 ago on Mon 10 Sep 2018 10:41:18 AM EDT.
============================================= Name Exactly Matched: rsyslog ==============================================
rsyslog.x86_64 : Enhanced system logging and kernel message trapping daemon
============================================ Summary & Name Matched: rsyslog =============================================
rsyslog-mysql.x86_64 : MySQL support for rsyslog
rsyslog-hiredis.x86_64 : Redis support for rsyslog
rsyslog-doc.noarch : HTML documentation for rsyslog
[root@localhost philip]#

为了简洁起见,已省略了一些输出。我们找到了rsyslog软件包。接下来,我们将传递install选项以安装rsyslog软件包:

[root@localhost philip]# dnf install rsyslog.x86_64
Last metadata expiration check: 2:42:37 ago on Mon 10 Sep 2018 10:41:18 AM EDT.
Dependencies resolved.
==========================================================================================================================
 Package                       Arch                     Version                           Repository                 Size
==========================================================================================================================
Installing:
 rsyslog                       x86_64                   8.37.0-1.fc28                     updates                   697 k
Installing dependencies:
 libestr                       x86_64                   0.1.9-10.fc28                     fedora                     26 k
 libfastjson                   x86_64                   0.99.8-2.fc28                     fedora                     36 k
Transaction Summary
==========================================================================================================================
Install  3 Packages
Total download size: 759 k
Installed size: 2.2 M
Is this ok [y/N]: y
Installed:
 rsyslog.x86_64 8.37.0-1.fc28           libestr.x86_64 0.1.9-10.fc28           libfastjson.x86_64 0.99.8-2.fc28 
Complete!
[root@localhost philip]#

同样,出于简洁起见,某些输出已被省略。我们已成功安装了rsyslog软件包。现在,我们需要在文本编辑器(如 vi 或 nano)中编辑/etc/rsyslog.conf,并指定远程日志服务器的 IP 地址。我们是这样做的:

[root@localhost philip]# cat /etc/rsyslog.conf
# rsyslog configuration file
# For more information see /usr/share/doc/rsyslog-*/rsyslog_conf.html
# or latest version online at http://www.rsyslog.com/doc/rsyslog_conf.html
# If you experience problems, see http://www.rsyslog.com/doc/troubleshoot.html
#queue.maxdiskspace="1g"         # 1gb space limit (use as much as possible)
#queue.saveonshutdown="on"       # save messages to disk on shutdown
#queue.type="LinkedList"         # run asynchronously
#action.resumeRetryCount="-1"    # infinite retries if host is down
# # Remote Logging (we use TCP for reliable delivery)
# # remote_host is: name/ip, e.g. 192.168.0.1, port optional e.g. 10514
#Target="remote_host" Port="XXX" Protocol="tcp")
*.*         @172.16.175.132:514
[root@localhost philip]#

太棒了!出于简洁起见,某些输出已被省略。在前面的输出中,我们添加了最后一个条目*.* @172.16.175.132:514。这是通知本地系统将所有日志设施的*.消息以及所有.*严重性发送到172.16.175.132远程系统,使用UDP协议和514端口号。我们也可以更具体;例如,我们可以通过指定emerg关键字仅从每个设施发送紧急消息:

[root@localhost philip]# cat /etc/rsyslog.conf
# rsyslog configuration file
#queue.maxdiskspace="1g"         # 1gb space limit (use as much as possible)
#queue.saveonshutdown="on"       # save messages to disk on shutdown
#queue.type="LinkedList"         # run asynchronously
#action.resumeRetryCount="-1"    # infinite retries if host is down
# # Remote Logging (we use TCP for reliable delivery)
# # remote_host is: name/ip, e.g. 192.168.0.1, port optional e.g. 10514
#Target="remote_host" Port="XXX" Protocol="tcp")
*.emerg               @172.16.175.132:514
[root@localhost philip]#

每个具有紧急消息的设施都将通过 UDP 发送到远程服务器。到目前为止,我们一直在使用 UDP 发送日志,但也可以使用 TCP 发送日志。为了使用 TCP 作为传输方式,我们需要在第一个@前面再添加一个@。我们将把消息类型从emerg更改为info,并使用 TCP 作为传输协议,如下所示:

[root@localhost philip]# cat /etc/rsyslog.conf
# rsyslog configuration file
 #queue.saveonshutdown="on"       # save messages to disk on shutdown
#queue.type="LinkedList"         # run asynchronously
#action.resumeRetryCount="-1"    # infinite retries if host is down
# # Remote Logging (we use TCP for reliable delivery)
# # remote_host is: name/ip, e.g. 192.168.0.1, port optional e.g. 10514
#Target="remote_host" Port="XXX" Protocol="tcp")
*.info    @@172.16.175.132:514
[root@localhost philip]#

太棒了!出于简洁起见,某些输出已被省略。现在,最后一步是重新启动rsyslog守护进程,以使新更改生效。我们使用systemctl命令,如下所示,重新启动rsyslog守护进程:

现在我们可以看到rsyslog守护进程正在运行。请注意在systemctl状态的底部,有一些关于连接到172/16.175.132的日志。这是因为我们尚未配置远程服务器以接受来自 Fedora 系统的日志。现在我们将前往 Ubuntu 系统并编辑/etc/rsyslog.conf并添加以下内容:

root@philip-virtual-machine:/var/log# cat /etc/rsyslog.conf
# provides UDP syslog reception
#module(load="imudp")
#input(type="imudp" port="514")
# provides TCP syslog reception
module(load="imtcp")
input(type="imtcp" port="514")
root@philip-virtual-machine:/var/log#

太棒了!出于简洁起见,某些输出已被省略。我们已经去掉了TCP部分的注释。最后一步是重新启动rsyslog守护进程;可以使用systemctl命令,如下面的屏幕截图所示:

我们可以看到rsyslog守护进程正常运行。现在,为了测试,我们将检查/var/log/syslog以查看来自 Fedora 日志客户端的日志。我们可以使用另一个强大的命令来生成测试日志:logger命令。以下是我们如何使用logger命令。

在 Fedora 28 rsyslog客户端上,我们发出以下命令:

[root@localhost philip]# logger This is the Fedora Logging client 172.16.175.129
[root@localhost philip]# logger This is another Logging test from the Fedora client 172.16.175.129
[root@localhost philip]#

在 Ubuntu 18 rsyslog服务器上,我们将看到以下内容:

root@philip-virtual-machine:/home/philip# tail -f /var/log/syslog
Sep 10 14:20:46 localhost dbus-daemon[720]: [system] Successfully activated service 'net.reactivated.Fprint'
Sep 10 14:20:46 localhost systemd[1]: Started Fingerprint Authentication Daemon.
Sep 10 14:20:50 localhost kscreenlocker_greet[58309]: QObject::disconnect: No such signal QObject::screenChanged(QScreen*)
Sep 10 14:22:25 localhost philip[58396]: This is the Fedora Logging client 172.16.175.129
Sep 10 14:23:04 localhost philip[58403]: This is another Logging test from the Fedora client 172.16.175.129
^C
root@philip-virtual-machine:/home/philip#

太棒了!我们可以看到rsyslog客户端确实将日志通过网络发送到 Ubuntu 18 rsyslog服务器。

摘要

在本章中,主要关注系统时间和日志的维护。特别是,我们看了一下如何操纵系统时间;我们广泛使用了datetimedatectl命令。此外,我们还涉及了用于更改日期的正则表达式。此外,我们还处理了硬件时钟;我们看到了如何同步系统时钟和硬件时钟。接下来,我们处理了日志记录;我们探索了常见的日志文件。在 Ubuntu 环境中,我们探索了/var/log/syslog文件,而在 Fedora 28 中,我们广泛使用了journalctl命令来查看日志。最后,我们处理了远程日志记录;我们在 Fedora 28 中安装了rsyslog软件包,并将其配置为rsyslog客户端。然后,我们转到 Ubuntu 18 并配置了其/etc/rsyslog.conf文件以接受远程日志并使用 TCP 作为传输协议。然后,我们在 Fedora 系统上生成了测试日志,并验证了我们在 Ubuntu rsyslog服务器上收到了日志。

在下一章中,我们将深入探讨互联网协议的世界。我们将涉及各种 IPv4 地址和 IPv6 地址。此外,我们将介绍对 IPv4 地址进行子网划分以及缩短冗长的 IPv6 地址的方法。最后,我们将介绍一些著名的协议。

问题

  1. 使用date命令设置日期的选项是什么?

A. -s

B. -S

C. -t

D. -u

  1. timedatectl命令中,哪个选项用于关闭同步?

A. --set-ntp

B. --set-sync

C. set-ntp

D. set-sync

  1. 使用哪个正则表达式只设置date命令的时间?

A. -$%t

B. +$T

C. -$t

D. +%T

  1. 使用timedatectl命令设置时间的选项是什么?

A. set-time

B. set-clock

C. set-sync

D. --set-zone

  1. /usr/share/zoneinfo/<zone>生成哪个文件?

A. /etc/synczone

B. /etc/timedate

C. /etc/clock

D. /etc/localtime

  1. 在新的 Ubuntu 发行版中,哪个命令替代了tzconfig命令?

A. tztime

B. tzdata

C. tzzone

D. tzclock

  1. 用于设置时区的命令是什么?

A. tzsync

B. tzselect

C. tzdate

D. tztime

  1. journalctl命令的哪个选项列出特定守护进程的日志?

  2. -a

  3. -e

  4. -b

  5. -u

  6. 当我们在/etc/rsyslog.conf中有*.* @@1.2.3.4时,使用了哪种协议?

  7. ICMP

  8. UDP

  9. ECHO

  10. TCP

  11. 哪个命令可以用于发送测试消息,作为验证rsyslog客户端与rsyslog服务器通信的一部分?

  12. send-message

  13. nc

  14. logger

  15. logrotate

更多阅读

第十五章:互联网协议基础知识

在上一章中,重点是维护系统的时间和日志记录。特别是,我们触及了可以操纵系统的方法。接下来,我们处理了日志记录并探讨了常见的日志文件。最后,我们使用远程。然后我们在我们的 Fedora 系统上生成了测试日志,并验证我们在 Ubuntu 的rsyslog服务器上收到了日志。

本章的重点是Internet ProtocolIP)。我们从 IPv4 开始,查看地址结构和今天环境中常用的各种 IPv4 地址。然后我们转向对 IPv4 地址进行子网划分,确定 IPv4 地址的网络和主机部分。然后是 IPv6。我们看一下 IPv6 地址的结构和一些知名的 IPv6 地址。然后我们关注如何缩短冗长的 IPv6 地址。最后,我们的重点是协议。我们将介绍一些知名的协议及其相应的端口号。

我们将涵盖以下主题:

  • IPv4 寻址

  • IPv6 寻址

  • 知名协议

IPv4 寻址

IP 版本 4 是 IP 的第四个版本。它在我们所知的互联网中扮演着至关重要的角色。到目前为止,IPv4 是在网络和互联网中为各种设备寻址最常用的协议。关于 IP 的另一个有趣的事实是,它不像 TCP 那样是面向连接的;相反,IP 是无连接的。

IPv4 地址由 32 位或 4 字节组成。我们使用 2 进制计算地址;这给我们 2³²,相当于 4,294,967,296 个地址。看起来 IPv4 地址很多;然而,现实并非如此。事实上,目前存在 IPv4 短缺。IPv4 地址以点分十进制格式表示。IPv4 地址的一个示例如下:

192.168.1.1

在这里,我们可以看到 IPv4 地址确实是以点分十进制格式表示的。点.充当地址之间的分隔符。数字可以在 0 到 255 之间的任何位置,包括 0 和 255。IPv4 地址的每部分称为一个八位组;因此,这四个数字组成了四个八位组。在今天的环境中有各种类型的 IPv4 地址;特别是在局域网LAN)中,您可能会看到以下之一:

  • 10.0.0.0/8

  • 172.16.0.0/12

  • 192.16.0.0/16

这些地址可能看起来很熟悉。这三个地址可以通过 RFC 1918 进一步解释;这个规范了一些应在私人网络中使用的地址,比如 LAN。

我们有五类地址空间;前四类地址在各种环境中常用。这些是地址类:

Class A 0-127
Class B 128-191
Class C 192-223
Class D 224-239
Class E 240-255

在这里,数字范围代表第一个八位组中的占位符。我们可以分解 IPv4 地址以便更好地理解。我们将使用第一个八位组作为参考。首先,我们将建立一个表。IPv4 地址的每个八位组代表 1 个字节;1 个字节 = 8 位。然后我们可以使用这些信息来形成我们的表:

7 6 5 4 3 2 1 0 = 8 位位置
128 64 32 16 18 4 2 1 = 255

太棒了!基于这一点,我们从 7 数到 0 的原因是因为在计算 IPv4 地址中的一个八位组的值时,我们总是从 0 开始,并且在添加时从右向左移动。现在,我们得到值的方式是通过乘以 2^x,其中 x = 最右边的字符。因此,它将如下所示:

7 6 5 4 3 2 1 0 = 8 位位置
1 1 1 1 1 1 1 1 = 1 表示该位被打开
2^ 2^ 2^ 2^ 2^ 2^ 2^ 2^ = 2 进制
128 6 32 16 8 4 2 1 = 每个位位置的 2 进制结果

使用 8 位中的所有值,我们得到128+64+32+16+8+4+2+1 = 255

基于这一点,我们现在看到表是如何使用二进制进行计算的。因此,在任何给定时间,只有 0-255 之间的值,包括 0 和 255,才是合法值。

A 类

A 类地址空间 0-127,只看第一个八位字节中的领先位(因为我们从 0 到 7 进行计数);这被称为最重要的位位置。127 地址空间被保留;这被称为环回地址空间。因此,我们只使用值 0-126。此外,0 实际上是保留用于网络使用(稍后在我们讨论子网划分时会详细介绍)。现在,我们计算 A 类地址的第一个值的方式如下:

7 6 5 4 3 2 1 0 = 8 位位置
128 64 32 16 8 4 2 1 =255
0 0 0 0 0 0 0 0 = 0-127

基于这一点,我们在第一个八位字节中关闭了所有八位。因此,这给了我们类 A 地址空间,即第一个八位字节在 0-126 之间,0 被保留,127 被保留为环回空间。因此,第一个八位字节中真正可用的 IPv4 地址是 1-126。然后,接下来的三个八位字节都是零。因此,类 A 地址空间将如下所示:

  • A 类0-126.0.0.0/8,其中第 8 位位置为 0

  • A 类保留地址空间127.0.0.0/8

  • A 类自动私有 IP 地址(APIPA)169.0.0.0/8保留

基于这一点,我们可以定义最多 126 个网络。A 类地址的剩余三个八位字节0.0.0组成了主机部分;每个八位字节由八位组成。主机是可以分配 IPv4 地址的任何设备。A 类地址允许的最大主机数量是每个网络的 1677216-2 = 16,777,214 个主机。主机部分是 2³ 个八位字节的结果(每个八位字节 8 位 x 3 = 24 位)- 2 = 1677216-2 =每个 A 类网络的 16,777,214 个主机。

B 类

B 类地址空间 128-191,查看领先位位置 7 和 6(记住我们从 0 开始计数,从左到右移动)。最重要的位,位置 7,在二进制中被打开。这被设置为 1,第二最重要的位,位置 6,被设置为 0。这可以通过我们之前创建的表来看到:

7 6 5 4 3 2 1 0 = 8 位位置
128 64 32 16 8 4 2 1 =255
1 0 0 0 0 0 0 0 = 128

基于这一点,最重要的位被打开,第二最重要的位被关闭。这给了我们地址空间为 128-191,其中 128 被保留用于网络使用,191 被保留为广播地址。我们将在本章后面讨论广播地址时讨论。在 B 类地址空间中,前 16 位被保留用于网络使用;然而,有两位被保留。这将给我们每个 B 类地址的 16384 个网络。这可以如下所示:

7 6 5 4 3 2 1 0 = 8 位位置
128 64 32 16 8 4 2 1 = 255
1 0 0 0 0 0 0 0 = 128

我们必须跳过前两位,位置 7 和 6;这样我们就得到了 2¹⁴ = 163864 个网络

基于这一点,我们看到了可用网络的最大数量,但我们没有看到最大主机数量。我们计算 B 类地址的主机的方式是使用最后两个八位字节作为主机;我们将进行 2² 个八位字节(每个八位字节 8 位 x 2 = 16 位)-两位用于网络和广播= 65,536-2 =每个 B 类网络的 65,534 个主机。

C 类

类 C 地址空间,192-223,考虑了前三位最重要的位;即,位置 7、6 和 5。前两位最重要的位被打开;它们在二进制中设置为 1。第三位,二进制中的位置 5,被关闭;这被设置为 0。前 24 位被保留用于类 C 地址空间中的网络使用。然后我们可以使用这些信息构建我们的表。表格如下:

7 6 5 4 3 2 1 0 = 8 位位置
128 64 32 16 8 4 2 1 =255
1 1 0 0 0 0 0 0 = 128+64=>192

基于此,我们可以看到类 C 地址空间从 192 开始,到 223 结束。192 保留为网络,223 保留为广播。然后我们可以通过使用 2²¹ = 2,097,152 个网络来计算网络的数量。这可以用以下表格表示:

7 6 5 4 3 2 1 0 = 8 位位置
128 64 32 16 8 4 2 1 =255
1 1 0 0 0 0 0 0 = 前 3 位总共 192

24 位被保留用于类 C,24 位—三个最重要的位= 21,然后 2²¹ 位= 2,097,152 个网络。

最后一个八位.0保留用于主机地址。这意味着每个 C 类地址有 2¹ 个八位(8 位)- 2 位用于网络和广播= 256 - 2 = 254 个主机。

类 D

类 D,224-239,地址空间保留用于多播。前三位最重要的位被打开;它们被设置为 1。第四位最重要的位设置为 0。类 D 地址空间不用于 IP 寻址,就像前几个地址空间一样。相反,类 D 地址空间用于为多播组分配 IP 地址。然后主机是多播组的一部分,反过来共享一个组地址。以下表格说明了用于类 D 地址空间的位:

7 6 5 4 3 2 1 0 = 8 位位置
128 64 32 16 8 4 2 1 = 255
1 1 1 0 0 0 0 0 = 总共 224

基于此,类 D 地址空间从224.0.0.0开始,到239.255.255.255结束。

类 E

类 E,240-255,地址空间保留用于将来使用。因此,它不像以前的地址空间那样被实现。前四位最重要的位被打开;它们被设置为 1。在类 E 中唯一使用的地址是255.255.255.255;这就是所谓的所有广播地址。以下表格说明了用于类 E 地址空间的位:

7 6 5 4 3 2 1 0 = 8 位位置
128 64 32 16 8 4 2 1 = 255
1 1 1 1 0 0 0 0 = 总共 240

基于此,类 E 地址空间从240.0.0.0开始,到255.255.255.255结束,其中255.255.255.255保留为所有广播地址。

子网掩码

我们刚刚介绍了 IPv4 地址空间的各种类别,但在某些情况下,使用这些地址空间的类别可能不合适。事实上,如果我们使用这些 IP 地址类别的默认子网掩码,那么 A 类、B 类和 C 类都是有类别的地址空间。例如,A 类使用子网掩码255.0.0.0。但是,等等,什么是子网掩码?首先,子网掩码标识给定 IP 地址的网络部分和主机部分。这包括 IPv4 和 IPv6。子网掩码使我们能够轻松地找出给定 IP 地址的网络地址。子网掩码通常以点分十进制格式编写。但是,也可以用斜杠表示法来表示子网掩码;即 CIDR 表示法。CIDR(无类别域间路由)简称,通过在 IP 地址后附加网络位数的斜杠格式来表示子网掩码。对于 A 类地址,子网掩码如下:

255.0.0.0

基于此,值255.0.0.0表示前八位组中的所有位都被打开;它们被设置为 1。我们可以用之前创建的表来表示这一点:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^ 位位置
1 1 1 1 1 1 1 1 = 打开的位数

128+64+32+16+8+4+2+1 = 255 位

基于此,255 的值来源于所有八位都被打开的总和。除此之外,子网掩码也可以用二进制格式表示。使用 A 类地址,子网掩码可以写成如下形式:

  • 十进制格式的 A 类子网掩码255.0.0.0

  • 二进制格式的 A 类子网掩码11111111.00000000.00000000.00000000

太棒了!现在我们可以看到子网掩码可以用 0-255 之间的值以十进制格式表示,也可以用 0 或 1 的值以二进制格式表示。此外,还可以用 CIDR 表示子网掩码。我们可以用以下格式表示 CIDR 格式的 A 类地址:

  • 十进制格式的 A 类子网掩码255.0.0.0

  • 二进制格式的 A 类子网掩码11111111.00000000.00000000.00000000

  • CIDR 格式的 A 类子网掩码/8

基于此,/8表示地址的网络部分有八位被打开。

使用 B 类地址,我们可以用点分十进制格式表示 B 类地址如下:

255.255.0.0

基于此,值255.255.0.0表示前两个八位组中的所有位都被打开;它们被设置为 1。我们可以用之前创建的表来表示这一点:

第一个八位组:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^ 位位置
1 1 1 1 1 1 1 1 = 打开的位数

128+64+32+16+8+4+2+1 = 255 位

第二个八位组:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^ 位位置
1 1 1 1 1 1 1 1 = 打开的位数

128+64+32+16+8+4+2+1 = 255 位

基于此,值255.255.0.0来源于所有 16 位都被打开的总和。除此之外,子网掩码也可以用二进制格式表示。使用 B 类地址,子网掩码可以写成如下形式:

  • 十进制格式的 B 类子网掩码255.255.0.0

  • 二进制格式的 B 类子网掩码11111111.11111111.00000000.00000000

太棒了!现在我们可以看到子网掩码可以用 0-255 之间的值以十进制格式表示,也可以用 0 或 1 的值以二进制格式表示。此外,还可以用 CIDR 表示子网掩码。我们可以用以下格式表示 CIDR 格式的 B 类地址:

  • 十进制格式的 B 类子网掩码255.255.0.0

  • 二进制格式的 B 类子网掩码11111111.11111111.00000000.00000000

  • CIDR 格式的 B 类子网掩码/16

基于此,/16表示地址的网络部分有十六位被打开。

使用 C 类地址,我们可以用点分十进制格式表示 C 类地址如下:

255.255.255.0

基于此,值255.255.255.0表示前两个八位组中的所有位都被打开;它们被设置为 1。我们可以用之前创建的表来表示这一点:

第一个八位组:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^ 位位置
1 1 1 1 1 1 1 1 = 打开的位数

128+64+32+16+8+4+2+1 = 255 位

第二个八位组:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^ 位位置
1 1 1 1 1 1 1 1 = 打开的位数

128+64+32+16+8+4+2+1 = 255 位

第三个八位组:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^ 位位置
1 1 1 1 1 1 1 1 = 打开的位数

128+64+32+16+8+4+2+1 = 255 位

基于此,255.255.255.0的值是由所有 24 位打开的总和得出的。此外,子网掩码也可以用二进制格式表示。使用 C 类地址,子网掩码可以写成以下形式:

  • 十进制中的 C 类子网掩码255.255.255.0

  • 二进制中的 C 类子网掩码11111111.11111111.11111111.00000000

太棒了!现在,我们可以看到子网掩码可以用 0-255 之间的值以十进制格式表示,也可以用 0 或 1 的值以二进制格式表示。此外,可以用 CIDR 表示子网掩码。我们可以用以下方式用 CIDR 格式表示 C 类地址:

  • 十进制中的 C 类子网掩码255.255.255.0

  • 二进制中的 C 类子网掩码11111111.11111111.11111111.00000000

  • CIDR 中的 C 类子网掩码/24

基于这一点,/24表示地址的网络部分有 24 位打开。

子网划分

正如我们刚刚看到的 A、B 和 C 类,它们的子网掩码分别使用 CIDR 表示为/81624。在今天的大多数环境中,这些默认子网掩码被称为类别,这意味着如果我们使用这些子网掩码,我们将无法执行任何形式的流量工程。当我们想要控制广播域时,这就成了一个问题。我们应该尽量减少广播到特定的房间、办公室或部门。这确保在任何类型的网络广播事件发生时,整个网络不会开始出现延迟。我们可以利用子网划分来克服类别网络的限制。例如,让我们选择一个 C 类 IP 地址:

192.168.0.0/24

基于此,每个网络地址最多可以有 254 个主机。我们可能会遇到这样的情况,我们只有八个系统需要 IP 连接。这意味着我们正在失去那些剩余的 IP 地址,因为我们使用了默认的 C 类子网。在这种情况下的要求是有八个 IP 地址,而不是浪费剩下的 IP 地址。我们可以通过子网划分来实现这个要求。子网划分是通过从主机部分借用位来实现的。让我们写出给定 IP 地址的子网掩码:

192.168.0.0/24 Network
  • 十进制中的子网掩码255.255.255.0 

  • 二进制中的子网掩码11111111.11111111.11111111.00000000 

基于此,前 24 位被打开。我们可以对这个地址进行子网划分,以便更好地控制我们的 IP 地址空间。我们想要八个 IP 地址。我们借用位的方式是从主机位中取位。我们可以使用我们的表格来帮助:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 =2^ 位位置
1 1 1 1 0 0 0 0 =借用了 4 位
  • 2⁴ 位 = 可以创建 16 个网络

  • 2⁴ -2 =每个网络 14 个主机

基于此,我们从网络的主机部分借用了四位;这使我们能够创建四个更小的子网/网络。然后,每个创建的网络将有 14 个主机。这使我们能够节省 IP 地址的数量,而不是使用标准的 C 类/24网络。因此,我们从网络部分借用了四位。我们如何用十进制和 CIDR 表示这一点呢?嗯,我们表示新创建的子网的方式是通过添加网络位。这可以在以下表格中说明:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 =2^ 位位置
1 1 1 1 0 0 0 0 =4 位

128+64+32+16 = 240

  • 旧的十进制子网 = 255.255.255.0

  • 老子网在 CIDR = /24

  • 新的十进制子网 = 255.255.255.240

  • 新的 CIDR 子网 = /28

  • 网络地址 = 192.168.0.0/28

基于此,我们可以看到新的子网掩码的十进制和 CIDR 表示。下一步是使用这个新的子网掩码来识别可用的子网/网络。我们可以使用以下表格来计算可用的子网:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^位位置
1 1 1 1 0 0 0 0 = 4 位

网络按位位置的 2 进制值递增:

  • 第一个网络192.168.0.0/28

  • 第二个网络192.168.0.16/28

  • 第三个网络192.168.0.32/28

  • 第四个网络192.168.0.48/28

  • 直到第十六个网络192.168.0.240/28

基于这一点,我们可以看到第四个八位组是增量发生的地方。特别是对于/28,子网增量为 16;这是因为计算得到的 2⁴ 位位置=16。最后一步是确定可以分配给网络内主机的可用 IP。我们将使用以下作为分解:

  • 第一个子网/网络192.168.0.0/28

  • 第一个可用 IP 地址192.168.0.1/28

  • 最后一个可用 IP 地址192.168.0.14/28

  • 广播 IP 地址192.168.0.15/28

  • 第二个子网/网络192.168.0.16/28

基于这一点,我们可以看到有两个 IP 是不可用的。这些是我们在计算主机 IP 时考虑的因素。同样,我们可以通过以下分解来获得第二个子网192.168.0.16/28的可用 IP:

  • 第二个子网/网络192.168.0.16/28

  • 第一个可用 IP 地址192.168.0.17/28

  • 最后一个可用 IP 地址192.168.0.30/28

  • 广播 IP 地址192.168.0.31/28

  • 第三个子网/网络192.168.0.32/28

太棒了!基于这一点,我们可以看到一个模式;我们总是最终得到 14 个可用的 IP 地址。此外,我们可以对 B 类地址进行子网划分,并利用主机位来更好地管理我们的网络。让我们使用以下 B 类地址:

172.16.0.0/16
Subnet mask:255.255.0.0

基于这一点,每个网络有超过 65,000 个主机 IP;这在大多数环境中都不理想。例如,我们想要对这个 IP 进行子网划分,以获得 500 个主机 IP。这可以通过从地址的主机部分借用一些主机位来实现。我们可以使用以下分解来帮助我们:

255.255.0.0
11111111.11111111.00000000.00000000 =/16 bits being used

我们计算主机的方法是从右到左移动。

第四个八位组:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^位位置
1 1 1 1 1 1 1 1 = 8 位总共 255

2⁸ = 255-2 = 每个网络 254 个主机。

第三个八位组:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^位位置
0 0 0 0 0 0 0 1 = 9 位打开

2⁹ = 512 -2 = 每个网络 510 个主机。

太棒了!基于这一点,为了满足要求,需要九位。这意味着我们将不得不从第三个八位组借用八位来满足要求。我们可以通过以下方式进行分解:

255.255.0.0
11111111.11111111.11111110.00000000 =/23 bits being used.
7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^位位置
1 1 1 1 1 1 1 0 = 7 位打开
Eight bits in first octet + eight bits in second octet + seven bits in third octet =23 bits
The sum of the bits turned on in the third octet 128+64+32+16+8+4+2 =254
The new subnet mask in decimal = 255.255.254.0

基于这些计算,新网络将被写成如下:

172.16.0.0/23
The total number of subnets = 2 ^ 7 = 128 subnets created
The total number of hosts per subnet/network =2⁹ - 2 = 512 -2 = 510 hosts per subnet/network
Subnets = 172.16.0.0/23 , 172.16.2.0/23, 172.16.4.0/23, 172.16.6.0/23 - 172.16.254.0/23

基于这一点,我们有每个子网的总子网和主机。现在,我们需要计算每个子网的可用 IP 地址。这可以通过以下分解来完成:

  • 第一个子网/网络172.16.0.0/23

  • 第一个可用 IP172.16.0.1/23

  • 最后一个可用 IP172.16.2.254/23

  • 广播 IP172.16.2.255

  • 第二个子网/网络172.16.2.0/23

基于这一点,我们可以看到可用的 IP 地址;172.16.2.255是使用/23子网的有效 IP。同样,172.16.1.0/23也是有效的 IP 地址。在一些操作系统中,比如 Windows,如果你尝试分配这两个 IP 中的任何一个,可能会遇到错误。然而,在 Linux 中,一切都是公平的。我们通过增量子网 2 来增量,因为这是最后一个网络位的位置。

我们甚至可以对 A 类地址进行子网划分。例如,假设我们想要从单个 A 类地址创建 100 个子网。我们将使用以下:

10.0.0.0/8
255.0.0.0

我们可以使用之前创建的表来做到这一点。

第二个八位组:

7 6 5 4 3 2 1 0 = 位位置
128 64 32 16 8 4 2 1 = 2^位位置
1 1 1 1 1 1 1 0 = 7 位打开

太棒了!基于此,我们可以快速推导出我们需要从第二个八位组借用七位来创建 100 个子网。实际上,我们将有 128 个子网。这是因为我们正在计算第二个八位组中的 2⁷ 位。然后我们可以按以下格式写出我们的子网:

11111111.11111110.00000000.00000000
Subnet 255.254.0.0 /15
Subnets 10.0.0.0/15, 10.2.0.0/15, 10.4.0.0/15, 10.6.0.0/15 - 10.254.0.0/15

太棒了!这么容易就对 A 类进行子网划分。现在我们需要计算每个子网的主机总数。我们可以使用以下方法:

Subnet in binary
11111111.11111110.00000000.00000000
Network bits are represented by n
Host bits are represented by h
nnnnnnnn.nnnnnnnh.hhhhhhhh.hhhhhhhh
2¹⁷ -2 = 131072 - 2 = 131070 hosts per subnet/network

基于此,我们可以看到使用/15每个子网获得了相当多的主机。我们可以使用以下方法来推导每个子网的可用 IP:

  • 第一个子网/网络:10.0.0.0/15

  • 第一个可用 IP:10.0.0.1/15

  • 最后一个可用 IP:10.2.255.254/15

  • 广播 IP:10.2.255.255

  • 第二个子网/网络:10.2.0.0/15

太棒了!计算任何一个子网的最简单方法是始终将网络位乘以 2。要计算总主机数,始终将主机位乘以 2,然后减去 2 得到网络和广播地址。

IPv6 寻址

互联网协议第 6 版(IPv6),由互联网工程任务组(IETF)开发。IPv6 地址旨在解决 IPv4 地址短缺问题。IPv4 已经完全耗尽,公司现在愿意以巨额资金交换他们的 IPv4 地址块。IPv6 地址长度为 128 位或 16 字节。这给了我们 2¹²⁸ 个 IPv6 地址。IPv6 地址以十六进制格式表示。有三种类型的 IPv6 地址。

单播

单播地址指定设备上单个接口的标识符,类似于 IPv4 地址。使用 IPv6,很可能所有 IPv6 流量大多是基于单播的。

多播

IPv6 多播地址的概念类似于 IPv4 地址。数据包被发送到 IPv6 多播地址,属于多播组的接收者将接收多播数据包。

单播

这种地址类型是在 IPv6 中引入的。任播的概念是通过将多个设备分配相同的任播 IPv6 地址来工作。当发送者向任播 IPv6 地址发送数据包时,任播数据包通过路由协议路由到距离发送者最近的主机。

以下是 IPv6 地址的示例:

2001:0db8:0000:0000:0000:ff00:0042:8329

基于此,我们可以看到 IPv6 地址由八组 16 位或 2 字节值组成,用冒号分隔。这就是我们得到 128 位或 16 字节长度的方法。写 IPv6 地址可能看起来很长,但我们可以使用一些方法使 IPv6 地址变得更小。

删除前导零

我们可以删除 IPv6 地址中的前导零,从而使其更易读:

2001:0db8:0000:0000:0000:ff00:0042:8329
2001:db8:0:0:0:ff00:42:8329

太棒了!基于此,我们使 IPv6 地址更加易于呈现。但是,请等一下,我们还可以通过使用下面描述的技术使其更小。

删除连续的零

我们可以删除 IPv6 地址中连续的零,并用双冒号替换这些零。这只能做一次:

2001:db8::ff0:42:8329

太棒了!正如我们所看到的,IPv6 地址现在更易读。此外,在浏览器中输入 IPv6 地址时,我们会执行以下操作:

http://[ 2001:db8::ff0:42:8329]/

基于此,我们会用方括号括起 IPv6 地址。有一些特殊类型的单播 IPv6 地址值得一提:

  • 全局单播地址:这些地址以2000::/3开头,如 RFC 4291 中所述。它们是类似于公共 IPv4 地址的可公开路由地址。

  • 链路本地地址:这些地址以fe80::/10开头;它们仅在本地物理链路上有效。

  • 站点本地地址:这些地址以fec::/10开头;它们仅在单个站点内有效。它们已被 RFC 机构弃用。

  • 唯一本地地址:这些地址以fc00::/7开头;它们旨在在一组合作站点内进行路由。它们旨在取代站点本地地址。唯一本地地址的一个有趣特点是它们减少了地址冲突的风险。

有一些类似于 IPv4 的特殊 IPv6 地址。以下是一些保留的 IPv6 地址:

2000::/3 全局单播
::/128 未指定地址
::/0 默认路由
::1/128 回环地址
FF00::/8 多播地址

太棒了!在识别子网方面,我们需要解析 IPv6 地址。我们可以使用以下方法进行分解:

2001:db8:0000:0000:0000:ff0:42:8329
全局路由前缀 子网 主机 ID
2001:db8:0000: 0000: 0000:ff0:42:8329
48 位或 3 字节 16 位或 2 字节 64 位或 8 字节

基于此,全局路由前缀由 48 位组成。子网由接下来的 16 位组成。主机标识符由最后的 64 位组成。

知名协议

我们在环境中使用许多我们需要了解的知名协议。首先,当我们浏览互联网时,实际上是使用 HTTP 协议来查看网页。此外,当我们从服务器复制文件并提供身份验证时;在后台,我们使用某种 FTP 协议。同样,当我们输入 URL 时,实际上是使用 DNS 进行名称解析。正如我们所看到的,我们在我们的环境中使用了许多协议。接下来描述了一些知名协议及其相应的端口号。

TCP

传输控制协议TCP)是一种面向连接的协议,提供了许多服务,包括错误检查和排序等。它在 OSI 模型的第 4 层,即传输层上运行。

HTTP

超文本传输协议HTTP)按需提供网页;这是互联网上通过 URL 进行数据通信的协议。它使用端口80进行通信。此外,它建立在 TCP 之上。

HTTPS

超文本传输安全协议HTTPS)为互联网上的 URL 提供安全通信。它使用端口443进行通信。此外,它的通信使用传输层安全TLS)。它建立在 TCP 之上。

FTP

文件传输协议FTP)用于在客户端和服务器之间传输文件。这可以在局域网内或通过互联网进行。FTP 支持身份验证,但所有传输都是明文发送的;没有内置安全性。FTP 使用 TCP 端口20进行数据传输和端口21进行命令传输。

UDP

用户数据报协议UDP)是一种无连接协议,提供速度但不进行任何错误检查。它在 OSI 模型的第 4 层,即传输层上运行。

DNS

域名系统DNS)提供了将 IP 地址转换为用户友好的名称的手段,用户可以与之相关联。它通常使用 UDP 端口53,但每当请求或响应大于一个数据包时,也使用 TCP 端口53

TFTP

简单文件传输协议TFTP)用于以快速速率传输数据。不支持任何身份验证方法;也没有错误检查。TFTP 使用 UDP 端口69

ICMP

互联网控制消息协议ICMP)是网络环境中使用的另一种协议。通常用于通过局域网或互联网在各种网络设备之间发送消息进行故障排除。还有 ICMPv6,用于 IPv6。ICMP 使用 IP 协议1,而 ICMPv6 使用 IP 协议58

总结

在本章中,我们深入研究了 IPv4 和 IPv6 的世界。除此之外,我们还涵盖了子网掩码和识别子网掩码的方法。接下来,我们介绍了子网划分。我们通过了一些示例,并说明了推导所需主机数量和所需子网数量的技术。最后,我们使用了一些知名的协议。我们涵盖了一些最广泛使用的协议及其端口号。

在下一章中,我们将继续进行网络配置和故障排除。我们将在 Linux 系统上工作,分配 IPv4 地址和 IPv6 地址,并查看各种网络连接故障排除的方法。

问题

  1. 哪个地址是 A 类地址?

A. 192.0.0.1

B. 172.0.0.1

C. 10.0.0.1

D. 以上都不是

  1. 哪个地址是 C 类地址?

A. 128.0.0.1

B. 100.0.0.2

C. 192.168.0.1

D. 以上都不是

  1. 哪个地址被称为 IPv4 环回地址?

A. 127.0.0.1

B. 169.0.0.1

C. 172.16.0.1

D. 192.1.1.1

  1. 哪个地址是 APIPA 地址?

A. 169.0.0.1

B. 172.16.0.1

C. 10.1.1.1

D. 192.168.1.1

  1. 哪个地址是 B 类地址?

A. 128.0.0.1

B. 10.11.1.1

C. 127.0.0.1

D. 223.0.0.1

  1. IPv6 组播地址以什么开头?

A. fc0e::/8

B. fce::/7

C. ff00::/8

D. fd0:/9

  1. 哪个地址是 IPv6 默认路由?

A. ::1/0

B. ::/0

C. 01A:00000000:00000000:00000000:00000000::9

D. ::1/128

  1. 哪个地址是 IPv6 环回地址?

A. ::0/1

B. ::0/0

C. ::1/128

D. ::128/128

  1. 链路本地地址以什么开头?

A.ff00::/8 B.fc00::/10 C.fcd00::128 D.fe80::/10

  1. HTTP 使用哪个端口?

A.TCP 10 B.UDP 80 C.TCP 80 D.UDP 69

进一步阅读

  • 这个网站提供了有关 IP 的有用信息:tools.ietf.org

  • 这个网站提供了有关子网划分的有用信息:www.quora.com

  • 这个网站提供了有关 IPv6 的有用信息:www.ipv6.com

第十六章:网络配置和故障排除

在上一章中,我们深入研究了 IPv4 或 IPv4 和 IPv6 或(IPv6)的世界。除此之外,我们还涵盖了子网掩码。之后,我们涵盖了子网划分。最后,我们使用了一些知名协议。我们涵盖了一些最常用的协议及其端口号。

在本章中,我们的重点转向了 IPv4 和 IPv6 的配置。首先,我们将研究配置 IPv4 地址及其子网掩码的方法。接下来,我们将查看 Linux 系统中的路由表;特别是配置静态路由,最后是默认路由配置。然后是在 Linux 系统中配置 IPv6 地址;然后是 IPv6 的路由表。然后是配置 IPv6 路由;最后是配置 IPv6 的默认路由。之后,我们的重点转向 DNS 的配置;特别是在 Linux 环境中配置指向 DNS 服务器的 DNS IP 地址。最后,本章结束于网络故障排除;我们将研究各种命令行工具,以帮助我们解决潜在的连接问题。

在本章中,我们将涵盖以下主题:

  • IPv4 配置

  • IPv6 配置

  • 客户端 DNS

  • 网络故障排除

IPv4 配置

在 Linux 系统中,有各种配置 IPv4 地址的方法。首先,我们可以使用 GUI 实用程序执行 IPv4 配置。让我们看看我们的 Ubuntu 18 系统。

我们可以选择网络图标,然后选择下拉箭头,选择有线设置,如下截图所示:

太棒了!根据我们在上一个例子中所看到的,当我们选择有线设置时,它会打开设置对话框;之后,我们应该选择齿轮图标。然后会打开网络设置。为了配置 IPv4 设置,我们会选择 IPv4 选项卡,如下截图所示:

根据前面的例子,我们可以看到 IPv4 寻址的默认方法是自动(DHCP);这意味着系统将通过网络上配置为动态分配 IPv4 寻址信息的服务器获取其 IPv4 寻址信息。为了演示目的,我们希望使用手动方法分配 IPv4 地址。在我们选择手动后,将出现一个地址字段,允许我们输入 IPv4 寻址信息,如下截图所示:

很棒!根据之前的截图,我们可以看到我们有机会输入 IPv4 信息。我们已经输入了一个 IPv4 地址;此外,我们会看到一个名为 Netmask 的文本框,这是子网掩码的另一个名称。一旦我们完成了输入 IPv4 地址信息,我们就会选择应用按钮。需要记住的一件重要事情是,我们可以在接口上配置多个 IPv4 地址。是的!我们可以简单地点击第二行的文本框并输入我们选择的 IPv4 地址,如下截图所示:

根据我们在上一个例子中所看到的,当我们输入第二个 IPv4 地址时,第三行会出现另一个文本框;如果我们在第三行输入 IPv4 地址,这种情况会再次发生。一旦我们对配置满意,我们应该选择应用按钮以保存更改。管理 IPv4 寻址的另一种方法是通过 shell;我们可以使用命令提示符处的各种命令添加和删除 IPv4 地址。

ifconfig 命令

ifconfig命令可以用于在命令行管理 IPv4 地址信息。我们可以运行ifconfig命令而不带任何选项,它将只显示活动接口,如下面的命令所示:

root@philip-virtual-machine:/home/philip# ifconfig
Command 'ifconfig' not found, but can be installed with:
apt install net-tools
root@philip-virtual-machine:/home/philip#

根据我们在前面的命令中找到的信息,我们看到ifconfig实用程序在 Ubuntu 18 中默认没有安装;这可以通过运行aptapt-get命令轻松解决,如下面的示例所示:

root@philip-virtual-machine:/home/philip# apt install net-tools
Reading package lists... Done
Building dependency tree 
Reading state information... Done
The following NEW packages will be installed:
 net-tools
Setting up net-tools (1.60+git20161116.90da8a0-1ubuntu1) ...
root@philip-virtual-machine:/home/philip#

为了简洁起见,一些输出已被省略。现在我们可以再次运行ifconfig命令,如下所示:

root@philip-virtual-machine:/home/philip# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.16.175.132  netmask 255.255.255.0  broadcast 172.16.175.255
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
 RX packets 75738  bytes 57194615 (57.1 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 35446  bytes 3084763 (3.0 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
 inet 127.0.0.1  netmask 255.0.0.0
 inet6 ::1  prefixlen 128  scopeid 0x10<host>
 loop  txqueuelen 1000  (Local Loopback)
 RX packets 17102  bytes 1274792 (1.2 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 17102  bytes 1274792 (1.2 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@philip-virtual-machine:/home/philip#

太棒了!根据我们在前面的代码中找到的信息,我们可以看到我们获得了大量信息;特别是 IPv4 地址位于inet部分。我们可以通过筛选来显示只有 IPv4 地址信息,如下所示的代码:

root@philip-virtual-machine:/home/philip# ifconfig | grep inet
 inet 172.16.175.132  netmask 255.255.255.0  broadcast 172.16.175.255
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 inet 127.0.0.1  netmask 255.0.0.0
 inet6 ::1  prefixlen 128  scopeid 0x10<host>
root@philip-virtual-machine:/home/philip#

根据前面的代码,我们可以看到 IPv4 地址信息以及一些 IPv6。我们之前配置了另外两个 IPv4 地址;然而,它们没有显示出来,因为默认情况下只会显示主要的 IPv4 地址。我们将在下一个命令中看到如何轻松查看这些额外的 IPv4 地址。除了查看活动接口,我们还可以查看非活动接口;我们将传递-a选项,如下面的代码所示:

root@philip-virtual-machine:/home/philip# ifconfig -a
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.16.175.132  netmask 255.255.255.0  broadcast 172.16.175.255
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
 RX packets 75817  bytes 57204880 (57.2 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 35485  bytes 3087793 (3.0 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
 inet 127.0.0.1  netmask 255.0.0.0
 inet6 ::1  prefixlen 128  scopeid 0x10<host>
 loop  txqueuelen 1000  (Local Loopback)
 RX packets 17110  bytes 1275456 (1.2 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 17110  bytes 1275456 (1.2 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@philip-virtual-machine:/home/philip#

根据我们在前面的示例中所看到的,这个系统上只有一个物理接口,所以输出与运行不带任何选项的ifconfig命令的输出相同。此外,我们可以选择要显示的接口,使用ifconfig命令;我们将指定接口,如下面的代码所示:

root@philip-virtual-machine:/home/philip# ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.16.175.132  netmask 255.255.255.0  broadcast 172.16.175.255
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
 RX packets 75825  bytes 57205574 (57.2 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 35493  bytes 3088408 (3.0 MB)
 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
root@philip-virtual-machine:/home/philip#

太棒了!这在系统可能有很多接口并且你只对特定接口感兴趣的情况下非常有用。我们可以使用ifconfig命令分配 IPv4 地址;我们只需传递接口和 IPv4 地址,如下面的代码所示:

root@philip-virtual-machine:/home/philip# ifconfig ens33 172.10.1.1
root@philip-virtual-machine:/home/philip# ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.10.1.1  netmask 255.255.0.0  broadcast 172.10.255.255
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
 RX packets 76407  bytes 57564515 (57.5 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 35550  bytes 3099266 (3.0 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@philip-virtual-machine:/home/philip#

根据我们在前面的代码中找到的信息,我们可以看到主要的 IPv4 地址已经更改为我们指定的 IPv4 地址。那么如果我们不想删除先前的 IPv4 地址呢?我们可以通过创建一个别名接口来满足这个要求;它只是一个逻辑接口。然后我们将第二个 IPv4 地址分配到别名接口上。这是我们将如何完成这个任务的方式:

root@philip-virtual-machine:/home/philip# ifconfig ens33 172.16.175.132/24
root@philip-virtual-machine:/home/philip# ifconfig ens33:0 172.10.1.1
root@philip-virtual-machine:/home/philip# ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.16.175.132  netmask 255.255.255.0  broadcast 172.16.175.255
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
 RX packets 76902  bytes 57781395 (57.7 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 35579  bytes 3104505 (3.1 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@philip-virtual-machine:/home/philip# ifconfig ens33:0
ens33:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.10.1.1  netmask 255.255.0.0  broadcast 172.10.255.255
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
root@philip-virtual-machine:/home/philip#

太棒了!基于此,我们现在可以看到我们在物理接口上有原始的 IPv4 地址,另外还创建了一个具有次要 IPv4 地址的别名接口。需要注意的是,当我们为别名接口指定 IPv4 地址时,我们没有指定任何子网掩码。系统根据第一个八位自动检测了子网掩码;子网掩码设置为255.255.0.0/16的 B 类子网掩码。我们可以通过删除 IPv4 地址然后以 CIDR 表示法添加带有子网掩码的 IPv4 地址来解决这个问题,如下面的代码所示:

root@philip-virtual-machine:/home/philip# ifconfig ens33:0 down
root@philip-virtual-machine:/home/philip# ifconfig ens33:0
ens33:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
root@philip-virtual-machine:/home/philip# ifconfig ens33:0 172.10.1.1/23
root@philip-virtual-machine:/home/philip# ifconfig ens33:0
ens33:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.10.1.1  netmask 255.255.254.0  broadcast 172.10.1.255
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
root@philip-virtual-machine:/home/philip#

干得好!根据我们在前面的代码中找到的信息,为了删除 IPv4 地址,我们可以通过输入down来禁用接口。然后我们应该以 CIDR 表示法添加带有子网掩码的 IPv4 地址。除此之外,广播地址已经为我们设置好了,系统根据子网掩码计算了广播地址。然而,我们可以使用ifconfig命令设置广播,因此我们将传递broadcast选项,如下面的示例所示:

root@philip-virtual-machine:/home/philip# ifconfig ens33:0 broadcast 172.10.20.255
root@philip-virtual-machine:/home/philip# ifconfig ens33:0
ens33:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.10.0.1  netmask 255.255.254.0  broadcast 172.10.20.255
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
root@philip-virtual-machine:/home/philip#

根据我们在前面的代码中找到的信息,我们可以看到广播地址已经被我们提供的地址改变了。让我们通过将其改回正确的广播地址来修复这个问题,如下面的示例所示:

root@philip-virtual-machine:/home/philip# ifconfig ens33:0 broadcast 172.10.1.255
root@philip-virtual-machine:/home/philip# ifconfig ens33:0
ens33:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.10.0.1  netmask 255.255.254.0  broadcast 172.10.1.255
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
root@philip-virtual-machine:/home/philip#

删除 IPv4 地址的另一种方法是使用ifconfig命令传递del选项,如下面的示例所示:

root@philip-virtual-machine:/home/philip# ifconfig ens33:0 del 172.10.0.1
root@philip-virtual-machine:/home/philip# ifconfig ens33:0
ens33:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
root@philip-virtual-machine:/home/philip#

太棒了!在前面的例子中,我们看到 IPv4 地址已成功删除。当我们完成与别名的工作时,可以通过传递down选项来删除其配置,如下面的代码所示:

root@philip-virtual-machine:/home/philip# ifconfig ens33:0 down
root@philip-virtual-machine:/home/philip# ifconfig -a
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.16.175.132  netmask 255.255.255.0  broadcast 172.16.175.255
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
 RX packets 77475  bytes 57962754 (57.9 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 35781  bytes 3140240 (3.1 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
 inet 127.0.0.1  netmask 255.0.0.0
 inet6 ::1  prefixlen 128  scopeid 0x10<host>
 loop  txqueuelen 1000  (Local Loopback)
 RX packets 17311  bytes 1289908 (1.2 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 17311  bytes 1289908 (1.2 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@philip-virtual-machine:/home/philip#

太棒了!从前面的例子中可以看出,接口在ifconfig命令中不再被识别。

ifup 命令

ifup命令用于启动或启用接口。然后,接口就能够发送和接收数据包。

然而,只有列在/etc/network/interfaces中的接口才会被ifup命令识别。让我们关闭ens33接口,并使用ifup命令重新启动ens33接口。这是我们将如何做到这一点:

root@philip-virtual-machine:/home/philip# ifconfig ens33 down
root@philip-virtual-machine:/home/philip# ifup ens33
Unknown interface ens33
root@philip-virtual-machine:/home/philip# cat /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
root@philip-virtual-machine:/home/philip#

根据我们在前面的例子中看到的,ifup不会识别ens33接口。这是因为ens33接口没有列在/etc/network/interfaces中。我们可以添加这个条目,然后它将与ifup命令一起工作。这可以在下面的例子中看到:

root@philip-virtual-machine:/home/philip# cat /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
auto ens33
iface ens33 inet manual
root@philip-virtual-machine:/home/philip# ifup ens33
root@philip-virtual-machine:/home/philip# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.16.170.1  netmask 255.255.255.0  broadcast 172.16.170.255
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
 RX packets 77776  bytes 58152478 (58.1 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 35893  bytes 3155908 (3.1 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
 inet 127.0.0.1  netmask 255.0.0.0
 inet6 ::1  prefixlen 128  scopeid 0x10<host>
 loop  txqueuelen 1000  (Local Loopback)
 RX packets 17323  bytes 1290784 (1.2 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 17323  bytes 1290784 (1.2 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@philip-virtual-machine:/home/philip# 

太棒了!根据我们在前面的例子中看到的,ifup命令成功地启动了ens33接口。此外,分配的 IPv4 地址是我们通过 GUI 网络设置配置的 IPv4 地址。在 Ubuntu 18 中,默认情况下所有的网络设置都由 network-manager 服务处理;每当我们通过命令提示符进行更改,如果系统重新启动或者 network-manager 服务重新启动,那么通过命令提示符进行的所有更改都会丢失,只有network-manager.service中的更改才会被使用。为了解决这个问题,我们需要停止network-manger.service,然后禁用 network-manager 服务。请注意,如果您没有在 Ubuntu 18 系统的/etc/network/interfaces中保存网络设置的更改(包括 IP、子网掩码默认网关、DNS 和 IP),这样做可能会导致系统失去连接。

除非您确定已经将网络配置保存在/etc/network/interfaces文件中,否则不要停止network-manager.service

ifdown 命令

ifdown命令可用于关闭或禁用接口;同样,只有列在/etc/network/interfaces中的接口才会被识别。让我们使用ifdown命令关闭ens33接口,如下面的代码中所示:

root@philip-virtual-machine:/home/philip# ifdown ens33
root@philip-virtual-machine:/home/philip# ifconfig
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
 inet 127.0.0.1  netmask 255.0.0.0
 inet6 ::1  prefixlen 128  scopeid 0x10<host>
 loop  txqueuelen 1000  (Local Loopback)
 RX packets 17323  bytes 1290784 (1.2 MB)
 RX errors 0  dropped 0  overruns 0  frame 0
 TX packets 17323  bytes 1290784 (1.2 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@philip-virtual-machine:/home/philip#  

太棒了!在前面的例子中,ifdown命令成功地关闭了ens33接口,因为我们将ens33接口添加到了/etc/network/interfaces文件中。

ip 命令

ip命令比ifconfig命令更具可扩展性。例如,我们可以使用 ip 命令查看在每个接口上配置的所有次要 IPv4 地址。没有任何选项,ip命令将显示可以使用的选项;这可以在下面的例子中看到:

root@philip-virtual-machine:/home/philip# ip
Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }
 ip [ -force ] -batch filename
where  OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |
tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |
netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |
vrf | sr }
OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |
-h[uman-readable] | -iec |
-f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |
-4 | -6 | -I | -D | -B | -0 |
-l[oops] { maximum-addr-flush-attempts } | -br[ief] |
-o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |
-rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}
root@philip-virtual-machine:/home/philip#

根据前面的例子,我们可以看到可以传递一些选项;其中一个选项是a选项。这会显示所有的寻址信息,就像下面的代码中所示:

root@philip-virtual-machine:/home/philip# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
 inet 127.0.0.1/8 scope host lo
 valid_lft forever preferred_lft forever
 inet6 ::1/128 scope host
 valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 link/ether 00:0c:29:32:fc:d5 brd ff:ff:ff:ff:ff:ff
 inet 172.16.170.1/24 brd 172.16.170.255 scope global noprefixroute ens33
 valid_lft forever preferred_lft forever
 inet 172.16.30.1/24 brd 172.16.30.255 scope global noprefixroute ens33
 valid_lft forever preferred_lft forever
root@philip-virtual-machine:/home/philip#

太棒了!从前面的例子中可以立即看到ens33接口有多个 IPv4 地址。我们可以使用ip命令添加 IPv4 地址;我们将传递add选项,如下面的代码中所示:

root@philip-virtual-machine:/home/philip# ip a add 172.16.20.2/24 dev ens33
root@philip-virtual-machine:/home/philip# ip a | grep ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 inet 172.16.170.1/24 brd 172.16.170.255 scope global noprefixroute ens33
 inet 172.16.30.1/24 brd 172.16.30.255 scope global noprefixroute ens33
 inet 172.16.20.2/24 scope global ens33
root@philip-virtual-machine:/home/philip#

太棒了!现在我们可以看到 IPv4 地址已经添加了。同样,我们也可以删除 IPv4 地址;我们会传递del选项,就像下面的代码中所示:

root@philip-virtual-machine:/home/philip# ip a del 172.16.20.2/24 dev ens33
root@philip-virtual-machine:/home/philip# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 link/ether 00:0c:29:32:fc:d5 brd ff:ff:ff:ff:ff:ff
 inet 172.16.170.1/24 brd 172.16.170.255 scope global noprefixroute ens33
 valid_lft forever preferred_lft forever
 inet 172.16.30.1/24 brd 172.16.30.255 scope global noprefixroute ens33
 valid_lft forever preferred_lft forever
root@philip-virtual-machine:/home/philip#

基于此,我们可以看到我们使用del选项指定的 IPv4 地址已被删除。此外,我们使用了show选项,这使我们能够指定我们感兴趣的接口。类似于ifconfig命令,也可以指定广播地址。为此,我们将传递brdbroadcast选项,如下例所示:

root@philip-virtual-machine:/home/philip# ip a add 172.16.20.2/22 brd 255.255.252.0 dev ens33
root@philip-virtual-machine:/home/philip# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 link/ether 00:0c:29:32:fc:d5 brd ff:ff:ff:ff:ff:ff
 inet 172.16.170.1/24 brd 172.16.170.255 scope global noprefixroute ens33
 valid_lft forever preferred_lft forever
 inet 172.16.30.1/24 brd 172.16.30.255 scope global noprefixroute ens33
 valid_lft forever preferred_lft forever
 inet 172.16.20.2/22 brd 255.255.252.0 scope global ens33
 valid_lft forever preferred_lft forever
root@philip-virtual-machine:/home/philip#

太棒了!根据先前的例子,我们可以看到为 IPv4 地址分配了广播地址。此外,可以使用ip命令关闭或启用接口。为此,我们将使用ip命令的link选项,如下代码所示:

root@philip-virtual-machine:/home/philip# ip link set dev ens33 down
root@philip-virtual-machine:/home/philip# ip a show ens33 | grep DOWN
2: ens33: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
root@philip-virtual-machine:/home/philip#

通过查看先前的例子,我们可以看到链接已经断开。同样,我们可以通过传递up选项来启动接口,如下代码所示:

root@philip-virtual-machine:/home/philip# ip link set dev ens33 up
root@philip-virtual-machine:/home/philip# ip a show ens33 | grep UP
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
root@philip-virtual-machine:/home/philip#

太棒了!根据先前的例子,我们可以看到接口已经重新启动。我们也可以使用 IP 命令来处理别名;我们将通过ip命令传递aadd选项。这可以在下面的代码中看到:

root@philip-virtual-machine:/home/philip# ip a a 172.50.5.1/24 brd + dev ens33 label ens33:1
root@philip-virtual-machine:/home/philip# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 link/ether 00:0c:29:32:fc:d5 brd ff:ff:ff:ff:ff:ff
 inet 172.16.170.1/24 brd 172.16.170.255 scope global noprefixroute ens33
 valid_lft forever preferred_lft forever
 inet 172.16.30.1/24 brd 172.16.30.255 scope global noprefixroute ens33
 valid_lft forever preferred_lft forever
 inet 172.50.5.1/24 brd 172.50.5.255 scope global ens33:1
 valid_lft forever preferred_lft forever
 inet6 fe80::d5a6:db57:33f4:7285/64 scope link noprefixroute
 valid_lft forever preferred_lft forever
root@philip-virtual-machine:/home/philip#
root@philip-virtual-machine:/home/philip# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.16.170.1  netmask 255.255.255.0  broadcast 172.16.170.255
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
 RX packets 79421  bytes 58846078 (58.8 MB)
 RX errors 0  dropped 1  overruns 0  frame 0
 TX packets 36124  bytes 3191485 (3.1 MB)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
ens33:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.50.5.1  netmask 255.255.255.0  broadcast 172.50.5.255
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
 TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@philip-virtual-machine:/home/philip#

太棒了!根据先前的例子,我们可以看到别名在ens33下使用ip命令列出。然而,当我们使用ifconfig命令时,我们会看到ens33:1被列为一个单独的逻辑接口。一旦我们完成使用别名,可以通过在ip命令中传递del选项来删除别名,如下例所示:

root@philip-virtual-machine:/home/philip# ip a del 172.50.5.1/24 brd + dev ens33 label ens33:1
root@philip-virtual-machine:/home/philip# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 link/ether 00:0c:29:32:fc:d5 brd ff:ff:ff:ff:ff:ff
 inet 172.16.170.1/24 brd 172.16.170.255 scope global noprefixroute ens33
 valid_lft forever preferred_lft forever
 inet 172.16.30.1/24 brd 172.16.30.255 scope global noprefixroute ens33
 valid_lft forever preferred_lft forever
 inet6 fe80::d5a6:db57:33f4:7285/64 scope link noprefixroute
 valid_lft forever preferred_lft forever
root@philip-virtual-machine:/home/philip# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet 172.16.170.1  netmask 255.255.255.0  broadcast 172.16.170.255
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 ether 00:0c:29:32:fc:d5  txqueuelen 1000  (Ethernet)
root@philip-virtual-machine:/home/philip#

出于简洁起见,一些输出已被省略。根据先前的例子,我们可以看到别名接口已被删除。在网络使用 VLAN 或虚拟局域网的环境中,可以创建映射到 VLAN 的子接口,从而使 Linux 系统能够处理标记的 VLAN 流量。您需要配置网络交换机以标记流量,然后将流量发送到 Linux 系统中的 VLAN。Linux 系统和交换机之间的链接被视为trunk端口,因为它可以通过其物理链接发送多个 VLAN,并且 Linux 系统可以处理流量,因为它知道我们创建的 VLAN。我们将使用ip linkadd选项。以下是我们如何创建一个子接口并将其映射到 VLAN:

root@philip-virtual-machine:/home/philip# ip link add link ens33 name ens33.100 type vlan id 100
root@philip-virtual-machine:/home/philip# ip a | grep ens
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 inet 172.16.170.1/24 brd 172.16.170.255 scope global noprefixroute ens33
 inet 172.16.30.1/24 brd 172.16.30.255 scope global noprefixroute ens33
3: ens33.100@ens33: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
root@philip-virtual-machine:/home/philip#

太棒了!根据我们在先前的例子中看到的,接口已经创建,并且被视为一个独立的接口。为了检查这一点,我们可以像为物理接口一样分配 IPv4 地址,如下例所示:

root@philip-virtual-machine:/home/philip# ip a a 172.16.5.5/24 dev ens33.100
root@philip-virtual-machine:/home/philip# ip a | grep ens
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 inet 172.16.170.1/24 brd 172.16.170.255 scope global noprefixroute ens33
 inet 172.16.30.1/24 brd 172.16.30.255 scope global noprefixroute ens33
3: ens33.100@ens33: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
 inet 172.16.5.5/24 scope global ens33.100
root@philip-virtual-machine:/home/philip#

太棒了!最后一步是启动接口。为此,我们将通过ip link命令传递up选项,如下代码所示:

root@philip-virtual-machine:/home/philip# ip link set dev ens33.100 up
root@philip-virtual-machine:/home/philip# ip a | grep ens
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 inet 172.16.170.1/24 brd 172.16.170.255 scope global noprefixroute ens33
 inet 172.16.30.1/24 brd 172.16.30.255 scope global noprefixroute ens33
3: ens33.100@ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
 inet 172.16.5.5/24 scope global ens33.100
root@philip-virtual-machine:/home/philip#

基于先前的例子,我们可以看到映射到 VLAN 100 的子接口现在已经启动。我们可以添加和删除 IP 地址信息,类似于物理接口。当我们完成对子接口的操作后,可以通过在ip link命令中传递del选项来删除它,如下例所示:

root@philip-virtual-machine:/home/philip# ip link del ens33.100
root@philip-virtual-machine:/home/philip# ip a | grep ens
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 inet 172.16.170.1/24 brd 172.16.170.255 scope global noprefixroute ens33
 inet 172.16.30.1/24 brd 172.16.30.255 scope global noprefixroute ens33
root@philip-virtual-machine:/home/philip#

太棒了!通过查看该示例,我们可以看到子接口不再存在。ip命令的另一个有用用途是查看接口的统计信息。我们将通过ip link命令传递-sls选项,如下代码所示:

root@philip-virtual-machine:/home/philip# ip -s link ls ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
 link/ether 00:0c:29:32:fc:d5 brd ff:ff:ff:ff:ff:ff
 RX: bytes  packets  errors  dropped overrun mcast 
 58851742   79482    0       1       0       0 
 TX: bytes  packets  errors  dropped carrier collsns
 3199078    36174    0       0       0       0 
root@philip-virtual-machine:/home/philip#

根据先前的例子,我们可以看到关于接收和发送的数据包统计;通过向当前命令添加另一个-s选项,我们甚至可以看到帧、丢失和 CRC 错误,如下代码所示:

root@philip-virtual-machine:/home/philip# ip -s -s link ls ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
 link/ether 00:0c:29:32:fc:d5 brd ff:ff:ff:ff:ff:ff
 RX: bytes  packets  errors  dropped overrun mcast 
 58852018   79485    0       1       0       0 
 RX errors: length   crc     frame   fifo    missed
 0        0       0       0       0 
 TX: bytes  packets  errors  dropped carrier collsns
 3199078    36174    0       0       0       0 
 TX errors: aborted  fifo   window heartbeat transns
 0        0       0       0       20 
root@philip-virtual-machine:/home/philip#

太棒了!根据先前的例子,我们可以看到与 CRC、帧等相关的计数器。

配置 IPv4 路由

到目前为止,我们一直在分配 IPv4 地址信息,但没有指定任何类型的路由信息。我们可以使用多个命令查看当前的路由表。例如,我们可以使用route命令显示路由表,如下例所示:

root@philip-virtual-machine:/home/philip# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
link-local      0.0.0.0         255.255.0.0     U     1000   0        0 ens33
172.16.30.0     0.0.0.0         255.255.255.0   U     100    0        0 ens33
172.16.170.0    0.0.0.0         255.255.255.0   U     100    0        0 ens33
root@philip-virtual-machine:/home/philip#

根据我们在先前的例子中看到的,只显示与配置的 IPv4 地址相对应的连接路由。还可以使用ip命令显示路由表;我们将传递route选项,如下命令所示:

root@philip-virtual-machine:/home/philip# ip route
169.254.0.0/16 dev ens33 scope link metric 1000
172.16.30.0/24 dev ens33 proto kernel scope link src 172.16.30.1 metric 100
172.16.170.0/24 dev ens33 proto kernel scope link src 172.16.170.1 metric 100
root@philip-virtual-machine:/home/philip#

根据前面的例子,我们可以看到与 route 命令类似的信息。另一个可以用来打印路由表的命令是netstat命令;为了做到这一点,我们会传递-r选项,就像下面的例子中所示的那样。

root@philip-virtual-machine:/home/philip# netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
link-local      0.0.0.0         255.255.0.0     U         0 0          0 ens33
172.16.30.0     0.0.0.0         255.255.255.0   U         0 0          0 ens33
172.16.170.0    0.0.0.0         255.255.255.0   U         0 0          0 ens33
root@philip-virtual-machine:/home/philip#

干得好!在前面的例子中,路由表再次被打印出来。我们还没有配置默认路由;默认路由用于到达不在同一子网上的主机,或者在 LAN 外部的主机。我们将使用ip route命令并传递adddefault选项来定义一个默认路由。下面的例子展示了这是什么样子:

root@philip-virtual-machine:/home/philip# ip route add default via 172.16.175.1
root@philip-virtual-machine:/home/philip# ip route | grep def
default via 172.16.175.1 dev ens33
root@philip-virtual-machine:/home/philip#
root@philip-virtual-machine:/home/philip# route  | grep UG
default         _gateway        0.0.0.0         UG    0      0        0 ens33
root@philip-virtual-machine:/home/philip#

太棒了!根据前面的例子,我们可以看到已经添加了一个默认路由。当我们运行route命令时,我们看到了_gateway这个词,而不是 IPv4 地址;我们可以传递-n选项来查看默认网关的数值。下面的例子演示了这一点:

root@philip-virtual-machine:/home/philip# route -n | grep UG
0.0.0.0         172.16.175.1    0.0.0.0         UG    0      0        0 ens33
root@philip-virtual-machine:/home/philip#

太棒了!我们还可以通过指定我们要到达的子网来创建一个静态路由。下面是我们如何做到这一点的:

root@philip-virtual-machine:/home/philip# ip route add 10.20.0.0/24 via 172.16.30.1
root@philip-virtual-machine:/home/philip# ip route | grep via
default via 172.16.175.1 dev ens33
10.20.0.0/24 via 172.16.30.1 dev ens33
root@philip-virtual-machine:/home/philip#
root@philip-virtual-machine:/home/philip# route -n | grep UG
0.0.0.0         172.16.175.1    0.0.0.0         UG    0      0        0 ens33
10.20.0.0       172.16.30.1     255.255.255.0   UG    0      0        0 ens33
root@philip-virtual-machine:/home/philip#

太棒了!根据前面的例子,我们现在可以看到为10.20.0.0/24子网添加的静态路由,通过172.16.30.1。当我们不再需要一个路由时,我们可以使用ip route命令并传递del选项来删除它,就像下面的命令中所示的那样。

root@philip-virtual-machine:/home/philip# ip route del 10.20.0.0/24 via 172.16.30.1
root@philip-virtual-machine:/home/philip# ip route | grep via
default via 172.16.175.1 dev ens33
root@philip-virtual-machine:/home/philip# route -n | grep UG
0.0.0.0         172.16.175.1    0.0.0.0         UG    0      0        0 ens33
root@philip-virtual-machine:/home/philip#

正如我们在前面的例子中所看到的,10.20.0.0/24的静态路由不再存在于我们的路由表中。

IPv6 配置

我们可以以与 IPv4 相似的方式配置 IPv6 寻址信息。为了只查看 IPv6 地址,我们可以使用ip命令并传递-6选项,就像下面的命令中所示的那样。

root@philip-virtual-machine:/home/philip# ip -6 a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
 inet6 ::1/128 scope host
 valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
 inet6 fe80::d5a6:db57:33f4:7285/64 scope link noprefixroute
 valid_lft forever preferred_lft forever
root@philip-virtual-machine:/home/philip#

根据前面的例子,我们只能看到 IPv6 信息,特别是以fe80开头的链路本地地址。我们可以使用ip命令添加一个 IPv6 地址。我们将以以下方式添加 IPv6 地址:

root@philip-virtual-machine:/home/philip# ip -6 a a 2001:0db8:0:f101::1/64 dev ens33
root@philip-virtual-machine:/home/philip# ip -6 a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
 inet6 2001:db8:0:f101::1/64 scope global
 valid_lft forever preferred_lft forever
 inet6 fe80::d5a6:db57:33f4:7285/64 scope link noprefixroute
 valid_lft forever preferred_lft forever
root@philip-virtual-machine:/home/philip#

太棒了!在前面的例子中,我们可以看到 IPv6 地址被分配给了ens33接口。此外,我们可以使用ifconfig命令来显示 IPv6 寻址信息,就像下面的例子中所示的那样:

root@philip-virtual-machine:/home/philip# ifconfig | egrep 'ens|inet6'
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
 inet6 2001:db8:0:f101::1  prefixlen 64  scopeid 0x0<global>
 inet6 fe80::d5a6:db57:33f4:7285  prefixlen 64  scopeid 0x20<link>
 inet6 ::1  prefixlen 128  scopeid 0x10<host>
root@philip-virtual-machine:/home/philip#

从前面的例子中可以看到,在inet6部分中有 IPv6 信息。也可以配置多个 IPv6 地址;我们只需使用带有-6ip命令,就像下面的命令中所示的那样。

root@philip-virtual-machine:/home/philip# ip -6 a a 2001:0db8:0:f102::2/64 dev ens33
root@philip-virtual-machine:/home/philip# ip -6 a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
 inet6 2001:db8:0:f102::2/64 scope global
 valid_lft forever preferred_lft forever
 inet6 2001:db8:0:f101::1/64 scope global
 valid_lft forever preferred_lft forever
 inet6 fe80::d5a6:db57:33f4:7285/64 scope link noprefixroute
 valid_lft forever preferred_lft forever
root@philip-virtual-machine:/home/philip#

根据那个例子,我们可以看到第二个 IPv6 地址已经被添加。当我们不再需要一个 IPv6 地址时,我们可以使用ip命令并传递del选项,就像下面的例子中所示的那样。

root@philip-virtual-machine:/home/philip# ip -6 a del 2001:0db8:0:f102::2/64 dev ens33
root@philip-virtual-machine:/home/philip# ip -6 a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
 inet6 2001:db8:0:f101::1/64 scope global
 valid_lft forever preferred_lft forever
 inet6 fe80::d5a6:db57:33f4:7285/64 scope link noprefixroute
 valid_lft forever preferred_lft forever
root@philip-virtual-machine:/home/philip#

太棒了!在前面的例子中,我们删除了 IPv6 地址,这是我们用del选项指定的。

配置 IPv6 路由

我们已经查看了 IPv4 路由表,但也有一个 IPv6 路由表。我们可以使用相同的ip route命令和-6选项,就像下面的例子中所示的那样。

root@philip-virtual-machine:/home/philip# ip -6 route
2001:db8:0:f101::/64 dev ens33 proto kernel metric 256 pref medium
fe80::/64 dev ens33 proto kernel metric 100 pref medium
fe80::/64 dev ens33 proto kernel metric 256 pref medium
root@philip-virtual-machine:/home/philip#

在前面的例子中,我们只显示了 IPv6 路由信息。目前在这个系统中没有配置 IPv6 的默认网关。我们可以使用ip route命令并传递-6add选项来修复这个问题,就像下面的例子中所示的那样。

root@philip-virtual-machine:/home/philip# ip -6 route add ::/0 via 2001:db8:0:f101::2
root@philip-virtual-machine:/home/philip# ip -6 route
2001:db8:0:f101::/64 dev ens33 proto kernel metric 256 pref medium
fe80::/64 dev ens33 proto kernel metric 100 pref medium
fe80::/64 dev ens33 proto kernel metric 256 pref medium
default via 2001:db8:0:f101::2 dev ens33 metric 1024 pref medium
root@philip-virtual-machine:/home/philip#

太棒了!在前面的例子中,我们可以看到为 IPv6 添加了一个默认路由。我们还可以使用 route 命令查看 IPv6 路由信息;我们会传递-6选项,就像下一个例子中所示的那样。

root@philip-virtual-machine:/home/philip# route -6 | grep UG
[::]/0                         _gateway                   UG   1024 1     0 ens33
root@philip-virtual-machine:/home/philip#
root@philip-virtual-machine:/home/philip# route -6 -n | grep UG
::/0                           2001:db8:0:f101::2         UG   1024 1     0 ens33
root@philip-virtual-machine:/home/philip#

太棒了!根据前面的例子,我们可以看到默认网关的 IPv6 地址。我们也可以为一个不同的 IPv6 子网或 LAN 外的 IPv6 子网配置静态路由。下面是我们如何为一个 IPv6 子网添加静态路由的:

root@philip-virtual-machine:/home/philip# ip -6 route add 2001:db8:2222:1::/64 via 2001:db8:0:f101::2
root@philip-virtual-machine:/home/philip# ip -6 route | grep via
2001:db8:2222:1::/64 via 2001:db8:0:f101::2 dev ens33 metric 1024 pref medium
default via 2001:db8:0:f101::2 dev ens33 metric 1024 pref medium
root@philip-virtual-machine:/home/philip# route -6 | grep UG
2001:db8:2222:1::/64           _gateway                   UG   1024 1     0 ens33
[::]/0                         _gateway                   UG   1024 1     0 ens33
root@philip-virtual-machine:/home/philip# route -6 -n | grep UG
2001:db8:2222:1::/64           2001:db8:0:f101::2         UG   1024 1     0 ens33
::/0                           2001:db8:0:f101::2         UG   1024 1     0 ens33
root@philip-virtual-machine:/home/philip#

干得好!在前面的例子中,你可以看到我们为一个 IPv6 子网添加了一个静态路由。同样,我们可以通过在ip route命令中传递del选项来删除一个 IPv6 子网的静态路由,就像下面的例子中所示的那样。

root@philip-virtual-machine:/home/philip# ip -6 route del 2001:db8:2222:1::/64 via 2001:db8:0:f101::2
root@philip-virtual-machine:/home/philip# route -6 -n | grep UG
::/0                           2001:db8:0:f101::2         UG   1024 1     0 ens33
root@philip-virtual-machine:/home/philip#

太棒了!

客户端 DNS

到目前为止,我们已经在系统中为网络连接分配了寻址信息(IPv4 和 IPv6)。然而,为了能够浏览互联网,我们需要在系统中配置 DNS;特别是,我们需要告诉 Linux 系统在尝试连接到互联网时使用哪个 DNS 服务器。正如我们在本章前面看到的,我们可以使用各种文本框来填写 IPv4、IPv6、网关和 DNS 信息,使用 GUI 实用程序。在这里,我们将看看如何在命令提示符下配置 DNS 信息;特别是/etc/resolv.conf文件。以下是/etc/resolv.conf文件的内容:

root@philip-virtual-machine:/home/philip# cat /etc/resolv.conf
# This file is managed by man:systemd-resolved(8). Do not edit.
nameserver 127.0.0.53
root@philip-virtual-machine:/home/philip#

出于简洁起见,一些输出已被省略。正如在前面的示例中所看到的,Ubuntu 18 中定义 DNS 服务器的格式如下:

nameserver <DNS IP>

根据这段代码,我们可以在此文件中指定我们的 DNS 服务器 IP。让我们看看是否可以浏览互联网,如下面的屏幕截图所示:

根据我们在前面的示例中看到的,我们无法连接到互联网。让我们使用 vi 或 nano 等编辑器在/etc/resolv.conf中放入 DNS 服务器的 IP 地址;以下条目是我们要放入的:

root@philip-virtual-machine:/home/philip# cat /etc/resolv.conf | grep name
nameserver 8.8.8.8
root@philip-virtual-machine:/home/philip#

正如我们在前面的示例中看到的,我们已经添加了一个 DNS 条目。现在,当我们刷新页面时,我们将看到内容开始填充页面,如下面的屏幕截图所示:

太棒了!我们还可以在/etc/hosts文件中为本地名称解析创建本地 DNS 条目。以下是/etc/hosts文件的内容:

root@philip-virtual-machine:/home/philip# cat /etc/hosts
127.0.0.1              localhost
127.0.1.1              philip-virtual-machine
# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
root@philip-virtual-machine:/home/philip#

我们可以编辑此文件,并使用 vi 或 nano 等文本编辑器为 Fedora 28 系统添加条目。以下是我们添加的示例条目:

root@philip-virtual-machine:/home/philip# cat /etc/hosts | grep Fed
172.16.175.129  Fedora28
root@philip-virtual-machine:/home/philip#

太棒了!现在我们可以通过 IP 地址或名称访问 Fedora 28 系统,如下例所示:

root@philip-virtual-machine:/home/philip# ssh philip@Fedora28
The authenticity of host 'fedora28 (172.16.175.129)' can't be established.
ECDSA key fingerprint is SHA256:DqRh+J43GfuMKC0i+QHkMU+V2MpephHZqSYANA362hg.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'fedora28' (ECDSA) to the list of known hosts.
philip@fedora28's password:
root@philip-virtual-machine:/home/philip#

太棒了!

网络故障排除

我们可以使用多种工具来帮助我们解决网络连接问题,从 GUI 实用程序到命令行工具。我们的重点将是使用可用的命令行工具进行故障排除。

ping 命令

ping实用程序使用 ICMP 协议发送请求并接收回复。我们可以使用ping实用程序测试系统之间的基本可达性,无论是本地还是互联网上。ping实用程序的基本语法如下:

ping  <DNS name or IPv4>

根据我们在前面的示例中看到的,现在我们可以尝试使用ping实用程序,如下例所示:

root@philip-virtual-machine:/home/philip# ping Fedora28
PING Fedora28 (172.16.175.129) 56(84) bytes of data.
64 bytes from Fedora28 (172.16.175.129): icmp_seq=1 ttl=64 time=0.299 ms
64 bytes from Fedora28 (172.16.175.129): icmp_seq=2 ttl=64 time=0.341 ms
64 bytes from Fedora28 (172.16.175.129): icmp_seq=3 ttl=64 time=0.733 ms
64 bytes from Fedora28 (172.16.175.129): icmp_seq=4 ttl=64 time=0.957 ms
64 bytes from Fedora28 (172.16.175.129): icmp_seq=5 ttl=64 time=0.224 ms
^C
--- Fedora28 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5064ms
rtt min/avg/max/mdev = 0.224/0.564/0.957/0.287 ms
root@philip-virtual-machine:/home/philip#

正如我们在前面的示例中看到的,ping实用程序将一直运行,直到用户使用CTRL + C停止;这在 Windows 环境中是不同的,那里只能看到四个 ICMP 回显请求/回复。

ping6 命令

也可以测试 IPv6 的潜在连接问题。我们将使用ping6命令;ping6命令的语法如下:

ping6  <DNS name or IPv6>

根据我们在前面的示例中看到的,我们只需要指定目标系统的 DNS 名称或 IPv6 地址。以下是如何使用ping6命令:

root@philip-virtual-machine:/home/philip# ping6 2001:db8:0:f101::3
PING 2001:db8:0:f101::3(2001:db8:0:f101::3) 56 data bytes
64 bytes from 2001:db8:0:f101::3: icmp_seq=1 ttl=64 time=0.355 ms
64 bytes from 2001:db8:0:f101::3: icmp_seq=2 ttl=64 time=0.289 ms
64 bytes from 2001:db8:0:f101::3: icmp_seq=3 ttl=64 time=0.222 ms
64 bytes from 2001:db8:0:f101::3: icmp_seq=4 ttl=64 time=0.596 ms
^C
--- 2001:db8:0:f101::3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3052ms
rtt min/avg/max/mdev = 0.222/0.365/0.596/0.142 ms
root@philip-virtual-machine:/home/philip#

太棒了!

traceroute 命令

我们可以使用traceroute命令来测试潜在的连接问题。traceroute命令显示了通往目标系统的每个设备;每个设备被视为一个“跳跃”。traceroute的基本语法如下:

traceroute <DNS name or IPv4>

您可以看到,我们只需要指定目标系统的 DNS 名称或 IPv4 地址。如下例所示:

root@philip-virtual-machine:/home/philip# traceroute Fedora28
Command 'traceroute' not found, but can be installed with:
apt install inetutils-traceroute
apt install traceroute 
root@philip-virtual-machine:/home/philip# apt install inetutils-traceroute
update-alternatives: using /usr/bin/inetutils-traceroute to provide /usr/bin/traceroute (traceroute) in auto mode
Processing triggers for man-db (2.8.3-2) ...
root@philip-virtual-machine:/home/philip#

正如我们在前面的示例中看到的,traceroute实用程序在 Ubuntu 18 中默认未安装;我们通过安装inetutils-traceroute软件包迅速解决了这个问题。现在让我们再次尝试运行traceroute命令,如下例所示:

root@philip-virtual-machine:/home/philip# traceroute Fedora28
traceroute to Fedora28 (172.16.175.129), 64 hops max
 1 172.16.175.129 0.199ms 0.199ms 0.251ms
root@philip-virtual-machine:/home/philip#

太棒了!根据前面的示例,我们可以看到设备距离 Ubuntu 系统只有一跳。

traceroute6 命令

也可以使用traceroute6命令来测试 IPv6 系统之间的潜在瓶颈。traceroute6命令的基本语法如下:

traceroute6  <DNS name or IPv6>

根据我们在前面的示例中看到的,我们只需指定目标系统的 DNS 名称或 IPv6 地址。以下示例显示了如何使用traceroute6命令:

root@philip-virtual-machine:/home/philip# traceroute6 2001:db8:0:f101::2
traceroute to 2001:db8:0:f101::2 (2001:db8:0:f101::2) from 2001:db8:0:f101::1, 30 hops max, 24 byte packets
sendto: Invalid argument
 1 traceroute: wrote 2001:db8:0:f101::2 24 chars, ret=-1
^C
root@philip-virtual-machine:/home/philip#

因此,我们可以看到traceroute6命令的工作方式与traceroute命令类似。

netstat 命令

我们可以使用netstat命令来排除许多不同的问题。在本章的前面部分,当我们讨论路由时,我们需要传递-r选项来查看路由表。我们还可以使用netstat命令来查看活动连接。这在服务器环境中特别有用,当我们运行利用各种端口的各种程序时;这些端口可以是 TCP 端口或 UDP 端口。我们可以传递-n选项,显示数字地址;-t选项,显示 TCP 连接;-l选项,显示正在监听的套接字;-p选项,显示程序 ID 和程序名称。在尝试缩小 TCP 端口范围时,这些选项可以很好地配合使用。以下是 TCP 的示例:

太棒了!从前面的示例中可以看出,有许多程序在运行,包括dnssshdryslogd等。同样,我们可以查看 UDP 连接;我们将传递nulp选项。-u表示 UDP,如以下示例所示:

太棒了!从前面的示例中可以看出,有很多服务在等待连接,其中systemd-resolve(端口53)就是其中之一。

tracepath 命令

tracepath命令是测试系统之间潜在瓶颈的另一种方法。它的工作方式类似于traceroute命令。tracepath命令的基本语法如下:

tracepath <DNS name or IPv4>

根据我们在前面的示例中看到的,我们只需指定目标系统的 DNS 名称或 IPv4 地址,即可使用tracepath命令。以下命令显示了这一点:

root@philip-virtual-machine:/home/philip# tracepath Fedora28
 1?: [LOCALHOST]          pmtu 1500
 1:  Fedora28             0.309ms reached
 1:  Fedora28             0.201ms reached
 Resume: pmtu 1500 hops 1 back 1
root@philip-virtual-machine:/home/philip#

在前面的示例中,除了到目标设备的跳数之外,还显示了pmtuPath MTU

tracepath -6 命令

tracepath命令类似,带有-6选项的tracepath是使用 IPv6 地址测试系统之间潜在瓶颈的另一种方法。tracepath带有-6选项的基本语法如下:

tracepath -6 <DNS name or IPv6>

根据我们在前面的示例中看到的,我们只需指定目标系统的 DNS 名称或 IPv6 地址,即可使用带有-6选项的tracepath。以下示例显示了这一点:

root@philip-virtual-machine:/home/philip# tracepath -6 2001:db8:0:f101::3
 1?: [LOCALHOST]                        0.012ms pmtu 1500
 1:  2001:db8:0:f101::3                                    0.384ms reached
 1:  2001:db8:0:f101::3                                    0.352ms reached
 Resume: pmtu 1500 hops 1 back 1
root@philip-virtual-machine:/home/philip#

太棒了!根据我们在前面的示例中看到的,我们可以看到带有-6选项的tracepath命令与 IPv4 的tracepath命令的工作方式类似。

nmap 命令

网络映射器(nmap)也可以使用nmap命令来排除潜在的连接问题;此命令扫描给定系统并显示为nmap命令指定的系统开放的服务及其相应的端口号。

nmap命令的基本语法如下:

nmap <option>  <IP of destination>

根据我们在前面的示例中看到的,我们会在以下示例中指定选项和目标系统的 IP,这是我们正在进行故障排除的目标系统:

root@Linuxplus:/home/philip# nmap -A -T4 172.16.175.129
Nmap scan report for Fedora28 (172.16.175.129)
Host is up (0.00066s latency).
Not shown: 845 closed ports, 154 filtered ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.7 (protocol 2.0)
| ssh-hostkey:
|   2048 b8:02:f8:79:f4:d8:77:b4:26:de:70:93:e8:66:94:69 (RSA)
|   256 9b:e0:d1:33:3b:08:02:bf:fd:c6:48:c1:47:7d:9c:9e (ECDSA)
|_  256 cd:f8:47:d1:75:95:e3:59:f3:b6:c0:12:a0:8b:d1:0e (EdDSA)
MAC Address: 00:0C:29:04:35:BD (VMware)
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.10 - 4.8
Network Distance: 1 hop
TRACEROUTE
HOP RTT     ADDRESS
1   0.66 ms Fedora28 (172.16.175.129)
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 49.30 seconds
root@Linuxplus:/home/philip#

太棒了!根据前面的示例,我们可以看到目标系统上正在运行的服务及其相应的端口号。-A选项用于显示 OS 和版本检测;-T4选项用于加快执行速度。在运行nmap命令之前,您应该征得目标系统或网络的所有者或管理员的许可;尤其是在有规定使用给定网络的公司环境中。

在网络中执行任何类型的端口扫描之前,始终寻求许可。

dig 命令

到目前为止,我们已经看过了解决连接问题的方法,但 DNS 问题也可能带来风险。我们可以使用dig实用程序来执行给定域的 DNS 查找。dig命令的基本语法如下:

dig <domain>

如您所见,我们只需指定要执行查找的域。

以下是我们执行简单查找的方法:

root@philip-virtual-machine:/home/philip# dig www.packtpub.com
; <<>> DiG 9.11.3-1ubuntu1-Ubuntu <<>> www.packtpub.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39472
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;www.packtpub.com.                    IN           A
;; ANSWER SECTION:
www.packtpub.com.     14037    IN           CNAME                varnish.packtpub.com.
varnish.packtpub.com.  14049    IN           A             83.166.169.231
;; Query time: 77 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Wed Mar 06 16:21:23 -04 2019
;; MSG SIZE  rcvd: 83
root@philip-virtual-machine:/home/philip#

太棒了!根据前面的示例,我们可以看到给定域的 DNS 记录;特别是我们可以看到A记录。回答我们查询的服务器是8.8.8.8,我们在/etc/resolv.conf中配置了该服务器。但是,我们可以通过在dig命令中传递@来使用不同的 DNS 服务器,如下例所示:

root@philip-virtual-machine:/home/philip# dig @8.8.4.4 packtpub.com
; <<>> DiG 9.11.3-1ubuntu1-Ubuntu <<>> @8.8.4.4 packtpub.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16754
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;packtpub.com.                                                IN          A
;; ANSWER SECTION:
packtpub.com.                  21599    IN           A             83.166.169.231
;; Query time: 116 msec
;; SERVER: 8.8.4.4#53(8.8.4.4)
;; WHEN: Wed Mar 06 16:25:29 -04 2019
;; MSG SIZE  rcvd: 57
root@philip-virtual-machine:/home/philip#

正如我们从前面的示例中看到的,我们已经指定了不同的 DNS 服务器来回答我们的查询。除此之外,我们还可以通过在dig命令中传递NS来查找特定的 DNS 信息,例如名称服务器或 NS,如下例所示:

root@philip-virtual-machine:/home/philip# dig @8.8.4.4 packtpub.com NS
; <<>> DiG 9.11.3-1ubuntu1-Ubuntu <<>> @8.8.4.4 packtpub.com NS
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40936
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;packtpub.com.                                                IN           NS
;; ANSWER SECTION:
packtpub.com.                  21599    IN           NS          dns2.easydns.net.
packtpub.com.                  21599    IN           NS          dns3.easydns.org.
packtpub.com.                  21599    IN           NS          dns4.easydns.info.
packtpub.com.                  21599    IN           NS          dns1.easydns.com.
;; Query time: 105 msec
;; SERVER: 8.8.4.4#53(8.8.4.4)
;; WHEN: Wed Mar 06 16:26:06 -04 2019
;; MSG SIZE  rcvd: 159
root@philip-virtual-machine:/home/philip#

太棒了!在前面的示例中,我们可以看到给定域的名称服务器。

whois 命令

还可以使用whois命令获取域的信息。whois命令的基本语法如下:

whois <domain>

因此,我们可以简单地通过whois命令传递一个域名,并获取给定域的有价值信息,如下例所示:

root@Linuxplus:/home/philip# whois packtpub.com
 Domain Name: PACKTPUB.COM
 Registry Domain ID: 97706392_DOMAIN_COM-VRSN
 Registrar WHOIS Server: whois.easydns.com
 Registrar URL: http://www.easydns.com
 Updated Date: 2015-08-10T20:01:35Z
 Creation Date: 2003-05-09T14:34:02Z
 Registry Expiry Date: 2024-05-09T14:34:02Z
 Registrar: easyDNS Technologies, Inc.
 Registrar IANA ID: 469
 Registrar Abuse Contact Email:
 Registrar Abuse Contact Phone:
 Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited
 Domain Status: clientUpdateProhibited https://icann.org/epp#clientUpdateProhibited
 Name Server: DNS1.EASYDNS.COM
 Name Server: DNS2.EASYDNS.NET
 Name Server: DNS3.EASYDNS.ORG
 Name Server: DNS4.EASYDNS.INFO
You have 20 lookups left today
root@Linuxplus:/home/philip#

太棒了!为了简洁起见,某些输出已被省略。前面的示例显示了我们为给定域提供了丰富的信息。

hostname 命令

此命令仅用于设置或返回系统的 DNS 名称和系统的 IP 地址。基本语法如下:

hostname <options> <new hostname>

该示例显示,如果我们只输入hostname命令,将产生以下代码:

root@philip-virtual-machine:/home/philip# hostname
philip-virtual-machine
root@philip-virtual-machine:/home/philip#

因此,我们可以看到系统的 DNS 名称。我们还可以传递-i选项来查看与hostname关联的 IP,如下例所示:

root@philip-virtual-machine:/home/philip# hostname -i
127.0.1.1
root@philip-virtual-machine:/home/philip#

太棒了!根据前面的示例,我们可以看到来自127.0.0.0/8回环范围的 IP。我们可以通过传递新的hostname值来更改hostname,如下面的代码所示:

root@philip-virtual-machine:/home/philip# hostname Linuxplus
root@philip-virtual-machine:/home/philip# hostname
Linuxplus
root@philip-virtual-machine:/home/philip#

使用前面的示例,我们可以看到hostname命令指示hostname已更改,但未更新提示符。我们可以退出 root 并重新登录,然后我们将看到以下更改:

root@philip-virtual-machine:/home/philip# exit
exit
philip@philip-virtual-machine:~$ sudo su
[sudo] password for philip:
root@Linuxplus:/home/philip#

太棒了!现在我们可以看到主机名已更改以反映我们指定的名称。但是,当我们重新启动系统时,主机名将被设置回/etc/hostname文件中指定的值,如下例所示:

root@Linuxplus:/home/philip# cat /etc/hostname
philip-virtual-machine
root@Linuxplus:/home/philip#reboot
root@philip-virtual-machine:/home/philip# cat /etc/hostname
philip-virtual-machine
root@philip-virtual-machine:/home/philip# hostname Linuxplus

我们可以通过使用文本编辑器(如 vi 或 nano)编辑/etc/hostname文件并将值放置如下代码所示来解决这个问题:

root@philip-virtual-machine:/home/philip#cat /etc/hostname
Linuxplus
root@philip-virtual-machine:/home/philip# reboot
root@Linuxplus:/home/philip#

太棒了!

总结

在本章中,我们配置了 IPv4、IPv6 配置、客户端 DNS 和网络故障排除。首先,我们使用 IPv4,并且我们看了各种管理 IPv4 地址的方法。接下来,我们涵盖了 IPv4 路由;我们看到了如何添加默认路由以及添加静态路由以连接的子网。然后我们进行了 IPv6 配置;我们看到了如何使用命令行中可用的各种工具来管理我们的 IPv6 基础设施。接着,我们看了如何配置 IPv6 的路由,特别是关注默认路由和静态路由以连接的子网。接下来,我们涵盖了客户端 DNS。我们看了配置 DNS 服务器 IP 地址的方法。然后我们通过浏览互联网来测试我们的 DNS 配置。最后,我们涵盖了网络故障排除;我们涵盖了一些可用于命令行的工具,以帮助我们解决潜在的网络连接问题。

在下一章中,我们将专注于安全性;特别是主机安全性,SSH 和加密。下一章非常关键,因为当今环境中存在许多安全风险。希望在下一章中见到您。

问题

  1. ifconfig命令的哪个选项显示所有活动和非活动的接口?

A. -s

B. -d

C. -A

D. -a

  1. 在创建默认网关时,ip路由命令使用哪个关键字?

A. default

B. 0.0.0.0

C. 网关

D. 以上都不是

  1. ping使用哪种协议在源和目的地之间发送和接收消息?

A. FTP

B. TFTP

C. ICMP

D. SSH.1.1

  1. 哪个文件保存系统的hostname值?

A. /etc/hosts

B. /etc/hostname

C. /etc/hostname/hosts

D. /var/log/hosts

  1. 哪个命令执行跟踪并输出跳数以及pmtu值?

A. traceroute

B. trace

C. tracepath

D. tracert

  1. 哪个命令执行给定域的 DNS 查询?

A. ping

B. traceroute

C. dnsq

D. dig

  1. 哪个命令为 IPv6 添加默认路由?

A. ip -6 route add default via 2001:db8:0:f101::2

B. iproute add default via 2001:db8:0:f101::2

C. ip-6 route add default via 2001:db8:0:f101::2

D. ip -6 add default via 2001:db8:0:f101::2

  1. 哪个选项与 netstat 命令一起显示打开的 UDP 连接的 IP 地址和端口号,程序 ID 和程序名称?

A. -t

B. -u

C. -udp

D. -ulp

  1. 哪个命令用于扫描系统以公开正在使用的服务及其相应的端口号?

A. traceroute

B. dig

C. nmap

D. ip

  1. 哪个命令显示给定域的注册表信息?

A. who

B. whois

C. whoami

D. w

进一步阅读

第十七章:执行管理安全任务

在上一章中,我们涵盖了 IPv4、IPv6、客户端 DNS 和网络故障排除。我们使用 IPv4 并讨论了 IPv4 路由,然后我们对 IPv6 做了同样的事情。这导致了客户端 DNS 和网络故障排除;我们涵盖了一些命令行工具,这些工具有助于排除潜在的网络连接问题。

在本章中,我们将专注于安全:主机安全、SSH 和加密。首先,我们将介绍主机安全;/etc/sudoers/etc/hosts.allow/etc/.hosts.deny文件将是我们的主要关注点。接下来,我们将使用 SSH。我们将专注于设置 SSH 所涉及的步骤,以及生成密钥的步骤。我们还将研究使用 SSH 登录到远程系统的步骤。此外,我们将使用各种可用的 SSH 文件。加密将是我们接下来的重点;我们将探讨加密和解密文件的方法。这将是一个重要的章节,涉及到保护 Linux 系统的安全。

本章我们将涵盖以下主题:

  • 主机安全

  • SSH

  • 加密

主机安全

在 Linux 中,我们可以执行一系列安全任务来保护我们的系统。到目前为止,我们一直以 root 用户的身份执行大部分管理任务。我们能否以普通用户的身份执行其中一些任务呢?我们可以使用普通用户帐户并赋予其某些 root 权限,而无需实际以 root 用户身份登录。这是通过/etc/sudoers文件实现的。在本演示中,我们将使用 Fedora 28 系统。如果我们尝试查看/boot/grub2/中的引导文件,将会看到以下内容:

[philip@localhost ~]$ ls /boot/grub2/
ls: cannot open directory '/boot/grub2/': Permission denied
[philip@localhost ~]$

根据前面的信息,用户没有足够的权限查看/boot/grub2的内容;我们收到了Permission denied的消息。此外,如果我们尝试进行更改(例如添加 IP 地址),将会看到以下内容:

[philip@localhost ~]$ ip a s ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
 link/ether 00:0c:29:04:35:bd brd ff:ff:ff:ff:ff:ff
 inet 172.16.175.129/24 brd 172.16.175.255 scope global dynamic noprefixroute ens33
 valid_lft 1700sec preferred_lft 1700sec
 inet 172.16.11.0/23 scope global ens33
 valid_lft forever preferred_lft forever
 inet6 2001:db8:0:f101::3/64 scope global
 valid_lft forever preferred_lft forever
 inet6 fe80::413:ea63:2e8a:5f2b/64 scope link noprefixroute
 valid_lft forever preferred_lft forever
[philip@localhost ~]$ ip a a 10.20.1.1/24 dev ens33
RTNETLINK answers: Operation not permitted
[philip@localhost ~]$

根据前面的信息,我们将执行第一个命令——IP命令,使用as选项(a表示地址,s表示显示),但是当我们尝试添加 IP 地址时,会收到Operation not permitted的消息。消息会有所不同,具体取决于您尝试查看的内容,就像ls命令的情况一样,而不是在后面的演示中进行更改。

su 命令

解决标准用户权限问题的一种技术是使用su命令;su表示substitute usersu命令的基本语法如下:

su <option>

根据前面的命令,我们还可以使用su命令而不使用任何选项,如下所示:

[philip@localhost ~]$ su
Password:
[root@localhost philip]#

太棒了!当我们使用su命令而不使用任何选项时,它会提示我们输入 root 密码,然后以 root 用户身份登录。但是,由于安全问题,这可能不是理想的做法。更好的方法是执行命令,但不要以 root 用户身份登录;这可以通过传递-l选项来实现,该选项需要用户帐户的名称,以及-c选项,该选项需要命令。以下命令显示了我们如何使用su命令有效地显示/boot/grub2/目录的内容,并同时以标准用户身份登录:

[philip@localhost ~]$ su -l root -c 'ls /boot/grub2/'
Password:
device.map  fonts  grub.cfg  grubenv  i386-pc  locale  themes
[philip@localhost ~]$

太棒了!/boot/grub2/目录的内容现在将被显示。但是,内容将以白色(除了白色)显示;我们可以传递--color选项来指示ls命令显示颜色,就像我们以 root 用户身份登录一样。如下所示:

太棒了!我们可以看到当省略--color选项时,与在 ls 命令中包括它相比的区别。此外,当命令之间有空格时,我们必须用单引号(')括起整个命令。另一个有用的选项是-s选项;这告诉 su 命令使用用户提供的指定 shell,如下面的截图所示:

太棒了!当我们使用-s选项并指定了 shell(在我们的案例中是/usr/sbin/sh)时,我们不需要在 ls 命令中指定--color选项。

使用 su 命令的另一种方法是传递-选项,这意味着 root 用户,如下所示:

[philip@localhost ~]$ su - -c 'ls /boot/grub2/' -s /usr/bin/sh
Password:
device.map  fonts  grub.cfg  grubenv  i386-pc  locale  themes
[philip@localhost ~]$

完美!内容被显示出来,我们没有指定登录root。我们可以通过查看/etc/shells 文件来看到可用的 shell 列表,如下所示:

[philip@localhost ~]$ cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/usr/bin/tmux
/bin/tmux
[philip@localhost ~]$

太棒了!我们可以看到可以与 su 命令的-s选项一起使用的各种 shell。到目前为止,我们只查看了 su 命令的内容,但我们也可以对其进行更改。以下命令显示了我们如何使用 su 命令进行更改:

[philip@localhost ~]$ su - -c 'ip a a 172.20.1.1/24 dev ens33'
Password:
[philip@localhost ~]$ ip a s ens33 | grep inet
 inet 172.16.175.129/24 brd 172.16.175.255 scope global dynamic noprefixroute ens33
 inet 172.16.11.0/23 scope global ens33
 inet 172.20.1.1/24 scope global ens33
 inet6 2001:db8:0:f101::3/64 scope global
 inet6 fe80::413:ea63:2e8a:5f2b/64 scope link noprefixroute
[philip@localhost ~]$

太棒了!IP 地址已成功添加。

使用 su 命令的一个主要缺点是,每个用户都必须知道 root 密码才能执行它。

sudo 命令

sudo 命令解决了普通用户需要 root 密码的困境,只要用户帐户位于/etc/sudoers 配置文件中。sudo 命令的基本语法如下:

sudo <command>

除了前面的命令,我们只需指定要执行的命令,这通常需要 root 权限。让我们尝试 sudo 命令,如下所示:

[philip@localhost ~]$ sudo ls /boot/grub2/
[sudo] password for philip:
device.map  fonts  grub.cfg  grubenv  i386-pc  locale  themes
[philip@localhost ~]$

太棒了!当我们执行 sudo 命令并传递需要 root 权限的命令时,我们会提示输入标准用户的密码,而不是 root 用户的密码。之后,我们可以传递另一个带有 sudo 命令的命令,我们不会被提示输入密码,如下面的代码片段所示:

[philip@localhost ~]$ sudo ip a a 192.168.5.5/24 dev ens33
[philip@localhost ~]$ ip a | grep inet
 inet 127.0.0.1/8 scope host lo
 inet6 ::1/128 scope host
 inet 172.16.175.129/24 brd 172.16.175.255 scope global dynamic noprefixroute ens33
 inet 172.16.11.0/23 scope global ens33
 inet 172.20.1.1/24 scope global ens33
 inet 192.168.5.5/24 scope global ens33
 inet6 2001:db8:0:f101::3/64 scope global
 inet6 fe80::413:ea63:2e8a:5f2b/64 scope link noprefixroute
[philip@localhost ~]$

太棒了!命令成功执行,而不需要用户的密码。这是可能的,因为有一个超时设置,保存了用户的密码;超时后,我们将被提示再次输入用户的密码。然而,在用户打开另一个终端的情况下,情况并非如此,如下面的截图所示:

太棒了!我们可以看到超时值不会影响新的终端,因为用户被提示输入他们的密码。

有时我们可能希望增加超时值,特别是当我们要长时间工作时。放心,我们可以通过在/etc/sudoers 文件中搜索 env_reset 并在其旁边附加 timestamp_timeout 选项来增加超时值。/etc/sudoers 文件的内容如下:

## Sudoers allows particular users to run various commands as
## the root user, without needing the root password.
## This file must be edited with the 'visudo' command.
## Host Aliases
## Groups of machines. You may prefer to use hostnames (perhaps using
## wildcards for entire domains) or IP addresses instead.
# Host_Alias     FILESERVERS = fs1, fs2
# Host_Alias     MAILSERVERS = smtp, smtp2
## User Aliases
## These aren't often necessary, as you can use regular groups
## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname
## rather than USERALIAS
# User_Alias ADMINS = jsmith, mikem
## Command Aliases
## These are groups of related commands...
## Networking
# Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool
## Installation and management of software
Defaults    env_reset
Defaults    env_keep =  "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
## Allow root to run any commands anywhere
root       ALL=(ALL)            ALL
## Allows people in group wheel to run all commands
%wheel                ALL=(ALL)            ALL
## Same thing without a password
# %wheel            ALL=(ALL)            NOPASSWD: ALL
#includedir /etc/sudoers.d
[philip@localhost ~]$

在前面的代码中,为了简洁起见,省略了一些输出。我们可以更改许多选项。例如,要增加超时值,我们可以使用 visudo 编辑/etc/sudoers;强烈建议不要使用 visudo 之外的任何编辑器,如下所示:

[philip@localhost ~]$ sudo cat /etc/sudoers | grep env_reset
Defaults    env_reset,timestamp_timeout=60
[philip@localhost ~]$

太棒了!我们添加了timestamp_timeout=60;这告诉 sudo 保存用户的密码 60 分钟。另一个有用的选项是在用户输入密码时显示输出;可以显示用户输入的每个按键的星号(*)。这是通过在 env_reset 选项旁边附加 pwfeedback 选项来实现的,如下所示:

[philip@localhost ~]$ sudo cat /etc/sudoers | grep env_reset
Defaults    env_reset,timestamp_timeout=60,pwfeedback
[philip@localhost ~]$

根据前面的命令,当用户首次尝试使用 sudo 命令时,密码将用星号表示,如下所示:

[philip@localhost ~]$ sudo ls /boot/grub2/
[sudo] password for philip: *******
device.map  fonts  grub.cfg  grubenv  i386-pc  locale  themes
[philip@localhost ~]$

太棒了!我们现在可以看到代表输入密码的星号。

当我们添加新用户时,新用户不会自动添加到/etc/sudoers 文件中。我们必须手动添加用户,如下所示:

[philip@localhost ~]$ sudo useradd teddy
[philip@localhost ~]$ sudo passwd teddy
Changing password for user teddy.
New password:
BAD PASSWORD: The password fails the dictionary check - it is based on a dictionary word
Retype new password:
passwd: all authentication tokens updated successfully.
[philip@localhost ~]$

现在,我们可以切换用户,要么通过在计算机上注销并重新登录,要么使用su命令,如下所示:

[philip@localhost ~]$ su teddy
Password:
[teddy@localhost philip]$

我们已经成功以新用户登录;现在,当我们尝试发出sudo命令时,结果将如下所示:

[teddy@localhost philip]$ sudo ls /boot/grub2/
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
 #1) Respect the privacy of others.
 #2) Think before you type.
 #3) With great power comes great responsibility.
[sudo] password for teddy:
teddy is not in the sudoers file.  This incident will be reported.
[teddy@localhost philip]$

我们收到了一条通知消息,但当我们输入新用户的密码时,我们收到了可怕的teddy 不在 sudoers 文件中消息,以及此事件将被报告。这基本上告诉我们,我们必须将新用户添加到/etc/sudoer文件中。有多种方法可以做到这一点;其中一种可能是最简单的方法是将新用户添加到wheel组。wheel组可以执行所有命令,如在/etc/sudoer文件中所示:

[philip@localhost ~]$ sudo cat /etc/sudoers | grep wheel
## Allows people in group wheel to run all commands
%wheel                ALL=(ALL)            ALL
# %wheel            ALL=(ALL)            NOPASSWD: ALL
[philip@localhost ~]$

如您所见,wheel组存在,并具有完全访问权限;我们可以使用usermod命令并传递-a-G选项(a表示追加,G表示组),如下所示:

[philip@localhost ~]$ usermod -aG wheel teddy
usermod: Permission denied.
usermod: cannot lock /etc/passwd; try again later.
[philip@localhost ~]$

我们需要 root 权限来修改另一个用户的属性;我们可以使用sudo命令,如下所示:

[philip@localhost ~]$ sudo usermod -aG wheel teddy
[philip@localhost ~]$ su teddy
Password:
 [teddy@localhost philip]$ sudo ls /boot/grub2/
[sudo] password for teddy: 
device.map  fonts  grub.cfg  grubenv  i386-pc  locale  themes
[teddy@localhost philip]$

太棒了!新用户现在可以使用sudo命令。让我们来看看在/etc/sudoer中添加条目的语法,如下所示:

[teddy@localhost philip]$ sudo cat /etc/sudoers | grep %
%wheel                ALL=(ALL)           ALL
[teddy@localhost philip]$
Based on the above, the syntax for an entry is as follows:
<user/group> <system/ALL> = <effective user/ALL> <command(s)>

我们可以为特定用户或组定义一个条目(在组名前面必须加上%);然后我们可以指定要为哪个系统添加条目,要允许哪个用户执行命令,最后是实际的命令。让我们试试;我们将从新用户中删除wheel组,并为新用户创建一个条目,如下所示:

[philip@localhost ~]$ sudo usermod -G "" teddy
[philip@localhost ~]$ groups teddy
teddy : teddy
[philip@localhost ~]$ sudo cat /etc/sudoers | grep teddy
teddy ALL=(ALL) /usr/sbin/ls
[philip@localhost ~]$

太棒了!我们已经限制了新用户只能执行lscat命令;可以通过以下方式证明:

[philip@localhost ~]$ su teddy
Password:
[teddy@localhost philip]$ sudo ls /boot/grub2/
device.map  fonts  grub.cfg  grubenv  i386-pc  locale  themes
[teddy@localhost philip]$ sudo cat /etc/resolv.conf
Sorry, user teddy is not allowed to execute '/usr/bin/cat /etc/resolv.conf' as root on localhost.localdomain.
[teddy@localhost philip]$

太棒了!新用户只能以 root 权限使用ls命令,并且无法使用sudo命令进行任何其他更改。此外,我们可以授予新用户执行我们指定的尽可能多的命令的能力,如下所示:

[philip@localhost ~]$ sudo cat /etc/sudoers | grep teddy
teddy    ALL=(ALL)            /usr/bin/ls,         /usr/bin/cat
[philip@localhost ~]$
[teddy@localhost philip]$ sudo ls /boot/grub2/
device.map  fonts  grub.cfg  grubenv  i386-pc  locale  themes
[teddy@localhost philip]$ sudo cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 8.8.8.8
[teddy@localhost philip]$
[teddy@localhost philip]$ sudo ip a a 172.16.20.1/24 dev ens33
Sorry, user teddy is not allowed to execute '/usr/sbin/ip a a 172.16.20.1/24 dev ens33' as root on localhost.localdomain.
[teddy@localhost philip]$

太棒了!我们为新用户添加了cat命令,使新用户能够以 root 权限执行cat命令。要记住的一件事是,当将多个命令放在一起时,必须在命令之间按Tab键放置制表符。我们可以与sudo命令一起使用的另一个选项是-l选项;这将列出当前用户的权限,如下所示:

[philip@localhost ~]$ sudo -l
Matching Defaults entries for philip on localhost:
 !visiblepw, env_reset, timestamp_timeout=60, pwfeedback, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2
 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME
 LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User philip may run the following commands on localhost:
 (ALL) ALL
[philip@localhost ~]$

如您所见,用户philip可以使用sudo命令运行所有命令。但是,如果我们对其他用户teddy运行带有-lsudo命令,我们将看到用户的访问权限,如下所示:

[teddy@localhost philip]$ sudo -l
[sudo] password for teddy: 
Matching Defaults entries for teddy on localhost:
 !visiblepw, env_reset, timestamp_timeout=60, pwfeedback, env_keep="COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS", env_keep+="MAIL PS1 PS2
 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY LC_NAME
 LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY",
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User teddy may run the following commands on localhost:
 (ALL) /usr/bin/ls, /usr/bin/cat
[teddy@localhost philip]$

太棒了!我们只能看到teddy可以以 root 权限执行两个命令。还可以使用-u选项传递用户名,并指定要使用sudo执行的命令,如下所示:

[philip@localhost ~]$ sudo -u teddy cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 8.8.8.8
[philip@localhost ~]$ sudo -u teddy ip a a 10.10.10.10/24 dev ens33
RTNETLINK answers: Operation not permitted
[philip@localhost ~]$

太棒了!另一个有用的选项是-v,它将重置用户的身份验证超时,如下所示:

[philip@localhost ~]$ sudo -v
[philip@localhost ~]$

类似地,可以通过使用sudo传递-k选项立即终止身份验证会话,如下所示:

[philip@localhost ~]$ sudo -k
[philip@localhost ~]$ sudo ls /boot/grub2/
[sudo] password for philip: 
device.map  fonts  grub.cfg  grubenv  i386-pc  locale  themes
[philip@localhost ~]$

太棒了!在前面的代码中,用户在尝试使用-k选项执行sudo命令时必须提供他们的密码。

到目前为止,我们在第一次执行sudo时一直提供用户的密码;可以在不输入密码的情况下运行sudo。我们在为新用户添加的条目中添加NOPASSWD选项,如下所示:

[philip@localhost ~]$ sudo cat /etc/sudoers | grep teddy
teddy    ALL=(ALL)            NOPASSWD:/usr/bin/ls,               /usr/bin/cat
[philip@localhost ~]$
[philip@localhost ~]$ su teddy
Password:
[teddy@localhost philip]$ sudo cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 8.8.8.8
[teddy@localhost philip]$ sudo ls /boot/grub2/
device.map  fonts  grub.cfg  grubenv  i386-pc  locale  themes
[teddy@localhost philip]$

太棒了!每当用户teddy尝试执行sudo命令时,他们将不再被提示输入密码。

TCP 包装

我们可以通过使用 TCP 包装在 Linux 系统中添加另一层安全性。TCP 包装在流入系统时过滤流量。 TCP 包装检查流量与两个文件:/etc/hosts.allow/etc/hosts.deny。规则采用自上而下的方式应用,这意味着始终先应用第一条规则。我们可以查看/etc/hosts.allow的内容,如下所示:

[philip@localhost ~]$ cat /etc/hosts.allow
#
# hosts.allow  This file contains access rules which are used to
# allow or deny connections to network services that
# either use the tcp_wrappers library or that have been
# started through a tcp_wrappers-enabled xinetd.
# See 'man 5 hosts_options' and 'man 5 hosts_access'
# for information on rule syntax.
# See 'man tcpd' for information on tcp_wrappers
#
[philip@localhost ~]$

该文件只包含以#开头的注释。创建规则的基本语法如下:

<daemon>:        <client list> [:<option>: <option>:…]      

我们可以使用文本编辑器(如 vi 或 nano)添加规则,如下所示:

[philip@localhost ~]$ sudo cat /etc/hosts.allow
#
vsftpd:                  172.16.175.
[philip@localhost ~]$

在上述命令中,我们为vsftpd添加了一个规则;这是 FTP 的安全版本。然后我们指定了客户端列表——子网172.16.175..表示该子网中的任何 IP 地址都可以访问vsftpd。定义规则的另一种方法是指定域,如下所示:

[philip@localhost ~]$ sudo cat /etc/hosts.allow
#
vsftpd:                  .packtpub.com
[philip@localhost ~]$

太棒了!.packtpub.com内的任何人都可以访问本地系统上的vsftpd。此外,我们可以在规则中使用关键字ALL;这匹配一切,并且可以放在守护程序或客户端列表部分,如下所示:

[philip@localhost ~]$ sudo cat /etc/hosts.allow
vsftpd:                  .packtpub.com
in.telnetd:           ALL
[philip@localhost ~]$

太棒了!每个人都可以访问本地系统上的 Telnet 服务。还可以通过传递spawn选项来执行另一个命令。当我们想要记录谁正在尝试访问本地系统上的特定服务时,这是有用的。我们使用spawn选项如下:

[philip@localhost ~]$ sudo cat /etc/hosts.allow
vsftpd:                  .packtpub.com: spawn /bin/echo `/bin/date` from %h>>/var/log/vsftp.log : allow
in.telnetd:           ALL
[philip@localhost ~]$

太棒了!spawn选项创建一个包含当前日期(/bin/date)的消息,然后将其附加到尝试访问vsftpd的系统的主机名(%h)中;然后将其附加到/var/log/vsftp.log中。然后我们可以查看/etc/hosts.deny文件,如下所示:

[philip@localhost ~]$ sudo cat /etc/hosts.deny
# hosts.deny   This file contains access rules which are used to
#              deny connections to network services that either use
#              the tcp_wrappers library or that have been
#              The rules in this file can also be set up in
#              /etc/hosts.allow with a 'deny' option instead.
#              See 'man 5 hosts_options' and 'man 5 hosts_access'
#              for information on rule syntax.
#              See 'man tcpd' for information on tcp_wrappers
 [philip@localhost ~]$

在上述命令中,/etc/hosts.deny只包含注释(#)。建议在此文件中拒绝一切,如下所示:

[philip@localhost ~]$ sudo cat /etc/hosts.deny
ALL:ALL
[philip@localhost ~]$

太棒了!我们指定了ALL:ALL:,以拒绝除/etc/hosts.allow中列出的规则之外的所有内容。

SSH

我们主要使用 SSH 来安全登录到远程系统。大多数 Linux 发行版默认安装了 SSH 软件包。为了验证 SSH 是否正在运行,我们使用systemctl命令;我们传递status选项,如下所示:

SSH 守护程序ssh.service目前正在运行(特别是安全外壳服务器)。我们可以使用的另一种验证 SSH 服务是否正在运行的方法是netstat命令;我们传递ntlp选项(n用于显示端口号,t用于 TCP 协议,l用于当前监听,p用于程序 ID/程序名称),如下所示:

root@Linuxplus:/home/philip# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State       PID/Program name 
tcp  0   0  0.0.0.0:514     0.0.0.0:*  LISTEN  519/rsyslogd 
tcp  0   0  127.0.0.53:53   0.0.0.0:*  LISTEN  431/systemd-resolve
tcp  0   0  0.0.0.0:22      0.0.0.0:*  LISTEN  1152/sshd 
tcp  0   0  127.0.0.1:631   0.0.0.0:*  LISTEN  2638/cupsd 
tcp6 0   0  :::514          :::*       LISTEN  519/rsyslogd 
tcp6 0   0  :::22           :::*       LISTEN  1152/sshd 
tcp6 0   0  ::1:631         :::*       LISTEN  2638/cupsd 
root@Linuxplus:/home/philip#

正如您所看到的,SSH 服务器守护程序目前正在 TCP 端口22上运行。建立与远程系统的连接的基本语法如下:

ssh <remote system>

我们只需运行ssh命令并仅传递远程系统;我们将从 Fedora 28 系统使用ssh命令并尝试连接到 Ubuntu 18 系统,如下所示:

 [philip@localhost ~]$ ssh 172.16.175.130
The authenticity of host '172.16.175.130 (172.16.175.130)' can't be established.
ECDSA key fingerprint is SHA256:SfI3vfS3yRRWSGN2jgAG7K5aQc65c/zVt/lz+D8mQBQ.
ECDSA key fingerprint is MD5:a2:03:c5:38:b3:83:88:fa:85:b5:5f:e6:91:eb:87:c1.
Are you sure you want to continue connecting (yes/no)?yes
Warning: Permanently added '172.16.175.130' (ECDSA) to the list of known hosts.
philip@172.16.175.130's password:
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-20-generic x86_64)
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
philip@Linuxplus:~$

在上述命令中,为简洁起见省略了一些输出。如果您指定不带任何选项的命令,SSH 程序将使用当前用户philip,并显示服务器的指纹。这将在 Fedora 28 系统中的~/.ssh/known_hosts中添加用户philip。我们可以查看文件,如下所示:

[philip@localhost ~]$ cat .ssh/known_hosts
172.16.175.130 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPhEHNo6YSOE+ZZ9vHVmQqBPFQd8WtAUFoGYAJe3VPQJlhjhc9bxy+vwsetQiEIKTyMgnfrOC7LNbhxxmJ4IX8w=
[philip@localhost ~]$

太棒了!我们在 Fedora 28 系统上的用户philip~/.ssh/known_hosts中有 Ubuntu 系统的信息。还可以使用ssh命令使用不同的用户名;我们指定-l选项,如下所示:

[philip@localhost ~]$ ssh -l hacker 172.16.175.130
hacker@172.16.175.130's password:
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-20-generic x86_64)
$ exit
Connection to 172.16.175.130 closed.
[philip@localhost ~]$

我们能够使用不同的用户通过 SSH 登录。还要注意,我们收到了之前识别服务器指纹的消息。这是因为信息先前存储在~/.ssh/known_hosts中。如果我们使用文本编辑器(如 vi 或 nano)删除内容,我们将再次收到身份验证消息,如下所示:

[philip@localhost ~]$ cat .ssh/known_hosts
[philip@localhost ~]$
[philip@localhost ~]$ ssh -l hacker 172.16.175.130
The authenticity of host '172.16.175.130 (172.16.175.130)' can't be established.
ECDSA key fingerprint is SHA256:SfI3vfS3yRRWSGN2jgAG7K5aQc65c/zVt/lz+D8mQBQ.
ECDSA key fingerprint is MD5:a2:03:c5:38:b3:83:88:fa:85:b5:5f:e6:91:eb:87:c1.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.16.175.130' (ECDSA) to the list of known hosts.
hacker@172.16.175.130's password:
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-20-generic x86_64)
[philip@localhost ~]$

太棒了!我们删除了内容,然后再次收到了身份验证消息。

到目前为止,每次我们尝试启动 SSH 会话时都会提示输入密码。但是,可以绕过密码提示并无阻碍地登录到系统。我们使用 SSH 密钥进行身份验证;这被称为基于密钥的身份验证。基于密钥的身份验证涉及创建一对密钥:私钥和公钥。私钥存储在客户端系统上,公钥存储在目标系统上。特别是,我们使用ssh-keygen命令在目标系统上生成 SSH 密钥。接下来,我们将客户端系统上的密钥复制过去;我们使用ssh-copy-id命令复制密钥。当您首次使用基于密钥的身份验证连接时,服务器会使用公钥向客户端系统传输一条消息,然后可以使用客户端系统上的私钥来解释这条消息。

让我们使用ssh-keygen命令在我们需要登录的客户端系统上生成 SSH 密钥;这将是 Fedora 28 系统,如下所示:

[philip@localhost ~]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/philip/.ssh/id_rsa):

默认情况下,算法是rsa,存储密钥对的位置在当前用户的主目录中(~/.ssh/id_rsa)。我们接受默认值并按Enter,如下所示:

[philip@localhost ~]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/philip/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:

我们必须指定一个passphrase;我们将使用一个超级秘密的passphrase,然后按Enter,如下所示:

[philip@localhost ~]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/philip/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/philip/.ssh/id_rsa.
Your public key has been saved in /home/philip/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:BwdFiHu2iEyvnnXhnY+1tNpZmlaZZdL1Zugwda9PJ7g philip@localhost.localdomain
The key's randomart image is:
+---[RSA 2048]----+
|       ..+o      |
|      . ..    . o|
|       .. .  . ++|
|    . . oo  o o O|
|   o o +S..  = X |
|    o o..+ .. B o|
|     .. o o oo.+.|
|    .o .   *EB  .|
|   .o     ooO    |
+----[SHA256]-----+
[philip@localhost ~]$

太棒了!密钥是使用 2,048 位密钥大小生成的。现在,我们可以在用户的主目录上运行ls命令,并查看~/.ssh目录中的内容,如下所示:

[philip@localhost ~]$ ls -a .ssh
.  ..  id_rsa  id_rsa.pub  known_hosts
[philip@localhost ~]$

太棒了!除了我们之前介绍的known_hosts文件之外,我们现在有两个额外的文件:id_rsa(这是私钥)和id_rsa.pub(这是公钥)。我们可以使用cat命令查看内容:

[philip@localhost ~]$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNvsCDZaUs6mralW+c1QnQ9cMeUqW0c/4IF8DThVK0Bi4CPnQApafJZrOyeQeJbLxORCJf+YLkE+DWREwJw0EU21PkiZeij0DEIlspqToo6BkKDPfXXCl35OQxSUXERlAhGQQpVSbEJLy0WZsbs6iAy4ohmKcCWeEdHLz/3p0VUyd3NHvXaLsyno/Qa2ZOBOOZgwUeHUA/p0zykUff7M4kIyGYatt1/vYKDH+UOC5fyB/nLtvrq7P1MrlfMGyEjtc7nFDEHz4VeAP1iUItKEzsyrqEH/KbAa3/ZeSoSfaFxoKvEtSKF5tnICyVp6uiUTNfi/cN74dmiDfG+vtcF0nt philip@localhost.localdomain
[philip@localhost ~]$

太棒了!下一步是使用ssh-copy-id命令将客户端系统的公钥复制到目标服务器,我们的情况下,服务器是 Ubuntu 系统。在运行ssh-copy-id命令之前,让我们检查一下 Ubuntu 系统上的~/.ssh目录,如下所示:

philip@Linuxplus:~$ ls -a ~/.ssh
.  ..
philip@Linuxplus:~$

如您所见,~/.ssh目前是空的。现在,让我们在客户端系统上执行ssh-copy-id命令,如下所示:

[philip@localhost ~]$ ssh-copy-id philip@172.16.175.130
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/philip/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
philip@172.16.175.130's password:
Number of key(s) added: 1
Now try logging into the machine, with:   "ssh 'philip@172.16.175.130'"
and check to make sure that only the key(s) you wanted were added.
[philip@localhost ~]$

太棒了!公钥~/.ssh/id_rsa.pub已安全传输到服务器系统。现在,让我们再次检查 Ubuntu 系统上的~/.ssh目录,如下所示:

philip@Linuxplus:~$ ls -a ~/.ssh
.  ..  authorized_keys
philip@Linuxplus:~$

太棒了!我们现在有一个authorized_keys文件,位于~/.ssh目录中。我们可以使用cat命令验证公钥是否与客户端系统上的公钥相同,如下所示:

philip@Linuxplus:~$ cat ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNvsCDZaUs6mralW+c1QnQ9cMeUqW0c/4IF8DThVK0Bi4CPnQApafJZrOyeQeJbLxORCJf+YLkE+DWREwJw0EU21PkiZeij0DEIlspqToo6BkKDPfXXCl35OQxSUXERlAhGQQpVSbEJLy0WZsbs6iAy4ohmKcCWeEdHLz/3p0VUyd3NHvXaLsyno/Qa2ZOBOOZgwUeHUA/p0zykUff7M4kIyGYatt1/vYKDH+UOC5fyB/nLtvrq7P1MrlfMGyEjtc7nFDEHz4VeAP1iUItKEzsyrqEH/KbAa3/ZeSoSfaFxoKvEtSKF5tnICyVp6uiUTNfi/cN74dmiDfG+vtcF0nt philip@localhost.localdomain
philip@Linuxplus:~$

太棒了!最后一步是在客户端系统(Fedora 28)上运行ssh命令,并验证我们能够登录到服务器(Ubuntu 18)而不使用密码,如下所示:

[philip@localhost ~]$ ssh 172.16.175.130
Enter passphrase for key '/home/philip/.ssh/id_rsa':
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-20-generic x86_64)
Last login: Thu Sep 13 16:47:50 2018 from 172.16.175.129
philip@Linuxplus:~$
ssh-add command:
[philip@localhost ~]$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-qLovqqH69q1D/agent.79449; export SSH_AUTH_SOCK;
SSH_AGENT_PID=79450; export SSH_AGENT_PID;
echo Agent pid 79450;
 [philip@localhost ~]$

太棒了!我们启动了ssh agent,它创建了必要的变量并启动了进程。接下来,我们将使用ssh-add命令和-l选项运行;这将列出ssh agent知道的所有身份,如下所示:

[philip@localhost ~]$ ssh-add -l
The agent has no identities.
[philip@localhost ~]$

如您在上述命令中所见,代理没有已知的身份;我们现在将使用ssh-add命令添加我们之前创建的身份,不带任何选项,如下所示:

[philip@localhost ~]$ ssh-add
Enter passphrase for /home/philip/.ssh/id_rsa:
Identity added: /home/philip/.ssh/id_rsa (/home/philip/.ssh/id_rsa)
[philip@localhost ~]$ ssh-add -l
2048 SHA256:BwdFiHu2iEyvnnXhnY+1tNpZmlaZZdL1Zugwda9PJ7g /home/philip/.ssh/id_rsa (RSA)
[philip@localhost ~]$

太棒了!您现在可以看到我们之前生成的私钥的身份。现在,我们将尝试启动 SSH 会话,如下所示:

[philip@localhost ~]$ ssh 172.16.175.130
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-20-generic x86_64)
Last login: Fri Sep 14 10:06:44 2018 from 172.16.175.129
philip@Linuxplus:~$ exit
[philip@localhost ~]$

太棒了!我们成功登录,而无需输入用户密码或passphrase。SSH 配置存储在/etc/ssh/ssh_config中:

philip@localhost ~]$ cat /etc/ssh/ssh_config
# $OpenBSD: ssh_config,v 1.33 2017/05/07 23:12:57 djm Exp $
# IdentityFile ~/.ssh/id_dsa
# IdentityFile ~/.ssh/id_ecdsa
# IdentityFile ~/.ssh/id_ed25519
# Port 22
# Protocol 2
#   Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc
#   MACs hmac-md5,hmac-sha1,umac-64@openssh.com
#   EscapeChar ~
#   Tunnel no
#   TunnelDevice any:any
# To modify the system-wide ssh configuration, create a  *.conf  file under
#  /etc/ssh/ssh_config.d/  which will be automatically included below
Include /etc/ssh/ssh_config.d/*.conf
[philip@localhost ~]$

在上述代码中,为了简洁起见,一些输出已被省略。所有设置都使用它们的默认值。

另一个保存known_hosts的位置是/etc/ssh/known_hosts;这允许管理员添加局域网内所有服务器的身份。这种方法可以防止每次新用户尝试启动 SSH 会话到服务器时出现身份验证消息。我们可以复制~./ssh/known_hosts的内容到/etc/ssh/known_hosts,如果我们尝试以另一个用户登录,我们将不会看到身份验证消息:

[philip@localhost ~]$ cat ~/.ssh/known_hosts
172.16.175.130 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPhEHNo6YSOE+ZZ9vHVmQqBPFQd8WtAUFoGYAJe3VPQJlhjhc9bxy+vwsetQiEIKTyMgnfrOC7LNbhxxmJ4IX8w=
[philip@localhost ~]$ cat /etc/ssh/ssh_known_hosts
172.16.175.130 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPhEHNo6YSOE+ZZ9vHVmQqBPFQd8WtAUFoGYAJe3VPQJlhjhc9bxy+vwsetQiEIKTyMgnfrOC7LNbhxxmJ4IX8w=
[philip@localhost ~]$
 [philip@localhost ~]$ ssh hacker@172.16.175.130
hacker@172.16.175.130's password:
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-20-generic x86_64)
$ exit
Connection to 172.16.175.130 closed.
[philip@localhost ~]$ ssh teddy@172.16.175.130
teddy@172.16.175.130's password:
[philip@localhost ~]$

很好。没有一个用户收到了身份验证消息。请注意,他们被提示输入各自的密码,因为我们只为philip用户设置了基于密钥的身份验证;我们必须为每个用户生成密钥。

加密

在当今的环境中,保护我们的数据至关重要。我们可以使用各种加密方法;在我们的环境中,我们将使用 GNU 隐私保护(GnuPG 或 GPG)来加密和解密我们的文件和文件夹。在进行加密和解密时,我们将使用 gpg 命令。

首先,我们将使用最基本的形式加密文件,即对称加密;这需要密码。以下命令显示了我们如何使用 gpg 命令执行对称加密,使用-c 或--symmetric 选项:

[philip@localhost ~]$ cd Documents/
[philip@localhost Documents]$ ls
date_schedule  lsa_schedule  ls.txt  schedule  ssh  STDERR.txt  STDIN_STDOUT  STDIN_STDOUT.txt  TestFile1  The_Tee_command.txt
[philip@localhost Documents]$ gpg -c The_Tee_command.txt
Enter passphrase:

我们必须输入密码/密码短语,然后重新输入,如下所示:

[philip@localhost Documents]$ gpg -c The_Tee_command.txt
Repeat passphrase:
[philip@localhost Documents]$
[philip@localhost Documents]$ ls -l | grep The
-rw-r--r--. 1 root   root   370 Aug  7 14:53 The_Tee_command.txt
-rw-rw-r--. 1 philip philip 307 Sep 14 11:01 The_Tee_command.txt.gpg
[philip@localhost Documents]$

太棒了!创建了一个带有.gpg 扩展名的新文件;这是加密文件。我们可以尝试使用 cat 命令查看内容:

[philip@localhost Documents]$ cat The_Tee_command.txt.gpg

内容已加密,我们现在可以删除原始内容,只留下加密内容,如下所示:

[philip@localhost Documents]$ rm The_Tee_command.txt
rm: remove write-protected regular file 'The_Tee_command.txt'? yes
[philip@localhost Documents]$ ls -l | grep The
-rw-rw-r--. 1 philip philip 307 Sep 14 11:01 The_Tee_command.txt.gpg
[philip@localhost Documents]$

现在,只剩下加密文件。我们可以通过传递-d 选项来解密此文件,如下所示:

[philip@localhost Documents]$ gpg -d The_Tee_command.txt.gpg
gpg: AES encrypted data
Enter passphrase:

我们必须提供密码来解密文件,如下所示:

[philip@localhost Documents]$ gpg -d The_Tee_command.txt.gpg
gpg: AES encrypted data
Enter passphrase:
gpg: AES encrypted data
gpg: encrypted with 1 passphrase
#
# hosts.allow This file contains access rules which are used to
#             allow or deny connections to network services that
#             either use the tcp_wrappers library or that have been
#             started through a tcp_wrappers-enabled xinetd.
#
#              See 'man 5 hosts_options' and 'man 5 hosts_access'
#              for information on rule syntax.
#              See 'man tcpd' for information on tcp_wrappers
#
[philip@localhost Documents]$ ls -l | grep The
-rw-rw-r--. 1 philip philip 307 Sep 14 11:01 The_Tee_command.txt.gpg
[philip@localhost Documents]$

太棒了!文件的内容被显示出来,但是,正如我们所看到的,当我们运行 ls 命令时,我们仍然只有加密文件,没有生成新文件。请放心;我们可以传递-o 选项将输出保存到文件中,如下所示:

[philip@localhost Documents]$ gpg -o The_Tee_command.txt -d The_Tee_command.txt.gpg
gpg: AES encrypted data
gpg: encrypted with 1 passphrase
[philip@localhost Documents]$ ls -l | grep The
-rw-rw-r--. 1 philip philip 370 Sep 14 11:10 The_Tee_command.txt
-rw-rw-r--. 1 philip philip 307 Sep 14 11:01 The_Tee_command.txt.gpg
[philip@localhost Documents]$

太棒了!现在,我们既有加密文件,也有未加密文件。

我们还可以使用私钥/公钥对进行加密和解密。首先,我们必须使用 gpg 命令和--gen-key 选项生成密钥对,如下所示:

[philip@localhost Documents]$ gpg --gen-key
gpg (GnuPG) 1.4.22; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
 (1) RSA and RSA (default)
 (2) DSA and Elgamal
 (3) DSA (sign only)
 (4) RSA (sign only)
Your selection?

我们必须选择密钥类型,“RSA 和 RSA”是默认值;我们将接受默认值,如下所示:

RSA keys may be between 1024 and 4096 bits long.

我们还必须指定密钥的大小,默认值为 2048;我们将选择 4096,因为更长的密钥更安全:

What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
 0 = key does not expire
 <n>  = key expires in n days
 <n>w = key expires in n weeks
 <n>m = key expires in n months
 <n>y = key expires in n years
Key is valid for? (0) 1y

我们还必须指定密钥何时过期,默认值为0,表示永不过期。我们将选择1y,表示一年后过期:

Key expires at Sat 14 Sep 2019 11:15:50 AM EDT
Is this correct? (y/N) y
You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
 "Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
Real name: Philip Inshanally

然后,我们必须确认过期日期并指定“真实姓名”;我们将按以下信息填写信息:

Email address: pinshanally@gmail.com
Comment: It's always good to help others
You selected this USER-ID:
 "Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?

现在我们必须通过输入O来确认,如下所示:

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.
Repeat passphrase:

我们还必须保护我们的秘密密钥,如下所示:

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
.+++++
...+++++
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
...............+++++
...+++++
gpg: key 73941CF4 marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2019-09-14
pub   4096R/73941CF4 2018-09-14 [expires: 2019-09-14]
 Key fingerprint = 3C24 9577 0081 C03B 4D88  2D34 60E4 B83C 7394 1CF4
uid                  Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>
sub   4096R/B29CE2BA 2018-09-14 [expires: 2019-09-14]
[philip@localhost Documents]$

太棒了!我们已成功生成了密钥对;我们可以通过使用 gpg 命令传递--list-keys 选项来验证这一点,如下所示:

[philip@localhost Documents]$ gpg --list-keys
/home/philip/.gnupg/pubring.gpg
-------------------------------
pub   4096R/73941CF4 2018-09-14 [expires: 2019-09-14]
uid                  Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>
sub   4096R/B29CE2BA 2018-09-14 [expires: 2019-09-14]
[philip@localhost Documents]$

太棒了!正如您所看到的,我们的公钥信息在/home/philip/.gnupg/pubring.gpg中:

[philip@localhost Documents]$ ls -a ~/.gnupg/
.  ..  gpg.conf  pubring.gpg  pubring.gpg~  random_seed  secring.gpg  trustdb.gpg
[philip@localhost Documents]$

我们现在可以看到我们的公钥信息。接下来,我们将检查我们的私钥信息;我们将使用 gpg 命令传递--list-secret-keys 选项,如下所示:

[philip@localhost Documents]$ gpg --list-secret-keys
/home/philip/.gnupg/secring.gpg
-------------------------------
sec   4096R/73941CF4 2018-09-14 [expires: 2019-09-14]
uid                  Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>
ssb   4096R/B29CE2BA 2018-09-14
[philip@localhost Documents]$

太棒了!我们可以看到有关私钥的信息;即私钥位于/home/philip/.gnupg/secring.gpg,如下所示:

[philip@localhost Documents]$ ls -a ~/.gnupg/
.  ..  gpg.conf  pubring.gpg  pubring.gpg~  random_seed  secring.gpg  trustdb.gpg
[philip@localhost Documents]$

太棒了!我们现在可以使用刚刚创建的公钥进行加密,通过 gpg 命令传递-r 选项,如下所示:

[philip@localhost Documents]$ gpg -e The_Tee_command.txt
You did not specify a user ID. (you may use "-r")
Current recipients:
Enter the user ID.  End with an empty line: pinshanally@gmail.com
Current recipients:
4096R/B29CE2BA 2018-09-14 "Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>"
Enter the user ID.  End with an empty line:
File `The_Tee_command.txt.gpg' exists. Overwrite? (y/N) y
[philip@localhost Documents]$ ls
date_schedule  ls.txt    ssh         STDIN_STDOUT      TestFile1            The_Tee_command.txt.gpg
lsa_schedule   schedule  STDERR.txt  STDIN_STDOUT.txt  The_Tee_command.txt
[philip@localhost Documents]$

我们没有使用命令指定用户 ID,因此我们被提示指定用户 ID;然后我们按Enter移动到第二行,输入用户 ID。以空行结束:"",我们只需按Enter生成一个空行。之后,我们必须确认是否要覆盖之前加密的文件,当我们执行对称加密时。我们还可以使用-r选项指定用户 ID。让我们试一试:

[philip@localhost Documents]$ rm The_Tee_command.txt.gpg
[philip@localhost Documents]$ gpg -e -r pinshanally@gmail.com The_Tee_command.txt
[philip@localhost Documents]$ ls -l | grep The
-rw-rw-r--. 1 philip philip 370 Sep 14 11:10 The_Tee_command.txt
-rw-rw-r--. 1 philip philip 827 Sep 14 11:34 The_Tee_command.txt.gpg
[philip@localhost Documents]$

太棒了!我们没有被提示输入用户 ID,因为我们使用了-r选项来指定它。为了解密文件,我们需要传递-d选项,如下所示:

[philip@localhost Documents]$ gpg -d The_Tee_command.txt.gpg
You need a passphrase to unlock the secret key for
user: "Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>"
4096-bit RSA key, ID B29CE2BA, created 2018-09-14 (main key ID 73941CF4)
Enter passphrase:
user: "Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>"
4096-bit RSA key, ID B29CE2BA, created 2018-09-14 (main key ID 73941CF4)
gpg: encrypted with 4096-bit RSA key, ID B29CE2BA, created 2018-09-14
 "Philip Inshanally (It's always good to help others)<pinshanally@gmail.com>"
# hosts.allow     This file contains access rules which are used to
#                 allow or deny connections to network services that
#                either use the tcp_wrappers library or that have been
#               started through a tcp_wrappers-enabled xinetd.
#
#            See 'man 5 hosts_options' and 'man 5 hosts_access'
#             for information on rule syntax.
#              See 'man tcpd' for information on tcp_wrappers
[philip@localhost Documents]$

在上述代码中,我们遇到了与对称解密时相同的问题;显示的内容没有被保存。我们可以通过传递-o选项来快速解决这个问题:

[philip@localhost Documents]$ ls -l | grep The
-rw-rw-r--. 1 philip philip 370 Sep 14 11:10 The_Tee_command.txt
-rw-rw-r--. 1 philip philip 827 Sep 14 11:34 The_Tee_command.txt.gpg
[philip@localhost Documents]$ rm The_Tee_command.txt
[philip@localhost Documents]$ gpg -o The_Tee_command.txt -d The_Tee_command.txt.gpg
You need a passphrase to unlock the secret key for
user: "Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>"
4096-bit RSA key, ID B29CE2BA, created 2018-09-14 (main key ID 73941CF4)
Enter passphrase:
gpg: encrypted with 4096-bit RSA key, ID B29CE2BA, created 2018-09-14
 "Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>"
[philip@localhost Documents]$ ls -l | grep The
-rw-rw-r--. 1 philip philip 370 Sep 14 11:39 The_Tee_command.txt
-rw-rw-r--. 1 philip philip 827 Sep 14 11:34 The_Tee_command.txt.gpg
[philip@localhost Documents]$

太棒了!文件成功解密了。

我们还可以编辑密钥;我们可以使用gpg命令传递--edit-key选项,如下所示:

[philip@localhost Documents]$ gpg --edit-key pinshanally@gmail.com
gpg (GnuPG) 1.4.22; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
pub  4096R/73941CF4  created: 2018-09-14  expires: 2019-09-14  usage: SC 
 trust: ultimate      validity: ultimate
sub  4096R/B29CE2BA  created: 2018-09-14  expires: 2019-09-14  usage: E 
[ultimate] (1). Philip Inshanally (It's always good to help others)<pinshanally@gmail.com>
gpg>

在上述命令中,我们可以进行多项更改。例如,如果我们想禁用密钥,我们可以输入disable,如下所示:

gpg> disable
gpg> list
pub  4096R/73941CF4  created: 2018-09-14  expires: 2019-09-14  usage: SC 
 trust: ultimate      validity: ultimate
*** This key has been disabled
sub  4096R/B29CE2BA  created: 2018-09-14  expires: 2019-09-14  usage: E 
[ultimate] (1). Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>
Please note that the shown key validity is not necessarily correct
unless you restart the program.
gpg>

在上述命令中,我们改变了密钥的状态为***此密钥已被禁用***;让我们保存并退出,看看这样做的效果:

gpg> save
Key not changed so no update needed.
[philip@localhost Documents]$ rm The_Tee_command.txt.gpg
[philip@localhost Documents]$
[philip@localhost Documents]$ gpg -e -r pinshanally@gmail.com The_Tee_command.txt
gpg: pinshanally@gmail.com: skipped: public key not found
gpg: The_Tee_command.txt: encryption failed: public key not found
[philip@localhost Documents]$

当我们尝试使用密钥加密文件时,出现了错误。我们可以通过在gpg控制台内将disable更改为enable来快速解决这个问题,如下所示:

philip@localhost Documents]$ gpg --edit-key pinshanally@gmail.com
gpg (GnuPG) 1.4.22; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
pub  4096R/73941CF4  created: 2018-09-14  expires: 2019-09-14  usage: SC 
 trust: ultimate      validity: ultimate
*** This key has been disabled
sub  4096R/B29CE2BA  created: 2018-09-14  expires: 2019-09-14  usage: E 
[ultimate] (1). Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>
gpg> enable
gpg> list
pub  4096R/73941CF4  created: 2018-09-14  expires: 2019-09-14  usage: SC 
 trust: ultimate      validity: ultimate
sub  4096R/B29CE2BA  created: 2018-09-14  expires: 2019-09-14  usage: E 
[ultimate] (1). Philip Inshanally (It's always good to help others) <pinshanally@gmail.com>
Please note that the shown key validity is not necessarily correct
unless you restart the program.
gpg> save
Key not changed so no update needed.
[philip@localhost Documents]$
[philip@localhost Documents]$ gpg -e -r pinshanally@gmail.com The_Tee_command.txt
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2019-09-14
[philip@localhost Documents]$ ls -l | grep The
-rw-rw-r--. 1 philip philip 370 Sep 14 11:54 The_Tee_command.txt
-rw-rw-r--. 1 philip philip 827 Sep 14 11:55 The_Tee_command.txt.gpg
[philip@localhost Documents]$

太棒了!

总结

在本章中,我们介绍了 Linux 环境中可用的各种安全功能。首先,我们介绍了以 root 权限访问命令;特别是,我们看了susudo命令。然后我们转向 TCP 包装器,重点介绍了/etc/hosts.allow/etc/hosts.deny文件。我们看了这两个文件如何通过允许/etc/hosts.allow文件中的访问和在/etc/hosts.deny文件中拒绝所有内容来互补。

接下来,我们介绍了 SSH;我们看了如何在客户端和服务器之间设置 SSH 访问,允许无需输入密码即可无缝登录,并介绍了如何使用密码短语。然后我们缓存了密码短语,这样用户在登录服务器时就不必输入密码短语了。最后,我们深入讨论了加密。我们专注于对称加密,其中涉及密码短语;然后我们通过使用密钥对来进一步加强了加密。最后,我们看了如何编辑密钥的属性。

在下一章(也是最后一章)中,我们将通过专注于 shell 脚本和 SQL 数据管理来完成本书。在 Linux 环境中工作时,理解一些 shell 脚本和 SQL 管理技能是至关重要的。

问题

  1. /etc/hosts.allow中每次激活规则时,以下哪个命令可以启动另一个命令?

A. 所有

B. 拒绝

C. 生成

D. 记录

  1. su代表什么?

A. 超级用户

B. 切换用户

C. 切换用户

D. 以上都不是

  1. 当我们在没有任何选项的情况下使用su命令时,会要求哪个用户的密码?

A. 根用户

B. 当前用户

C. SSH 密码短语

D. 以上都不是

  1. 以下哪个选项允许使用su命令在不登录的情况下执行命令?

A. -a

B. -c

C. -d

D. -l

  1. /etc/sudoers中声明组时,以下哪个符号必须在组前面?

A. -

B. ^

C. -$

D. %

  1. 以下哪个命令用于创建 SSH 密钥对?

A. ssh-keygen

B. ssh-key-gen

C. ssh-create-key

D. ssh-key

  1. 以下哪个命令用于向 SSH 代理添加身份?

A. ssh-add

B. ssh-agent

C. ssh.service

D. ssh-daemon

  1. 以下哪个命令可以安全地复制 SSH 公钥?

A. ssh-copy

B. ssh-copy-id

C. ssh-cp

D. ssh-id-copy

  1. 以下哪个选项用于使用gpg命令加密文件?

A. -d

B. -e

C. -r

D. -a

  1. 以下哪个选项用于在gpg命令中提供身份?

A. -f

B. -e

C. -r

D. -a

进一步阅读

第十八章:Shell 脚本和 SQL 数据管理

在上一章中,我们涵盖了 Linux 环境中可用的各种安全功能。首先,我们讨论了以 root 权限执行命令。然后,我们转向 TCP 包装,重点放在/etc/hosts.allow/etc/hosts.deny文件上。接下来,我们涵盖了 SSH;我们看了如何在客户端和服务器之间设置 SSH 访问。最后,我们深入讨论了加密。

在本章中,也是本书的最后一章,我们将涵盖 Shell 脚本和 SQL 管理的基础知识。首先,我们将看一下编写 shell 脚本的语法;然后是使用各种循环编写脚本,比如forwhile循环。接下来,我们将涵盖使用if语句编写 shell 脚本。最后,我们将通过涵盖 SQL 管理的基础知识来结束本章(和本书)。

我们将在本章中涵盖以下主题:

  • Shell 脚本

  • SQL 数据管理

Shell 脚本

在本节中,我们将涵盖 shell 脚本,从基础知识开始,然后转向使用循环和if语句编写脚本。

以下主题将在本节中涵盖:

  • Shell 脚本的基础知识

  • 使用for循环编写脚本

  • 使用while循环编写脚本

  • 使用if语句编写脚本

Shell 脚本的基础知识

在命令行上,我们经常需要定期执行一系列相同的命令。将这些命令捆绑在一起并简化这个过程,执行单个命令或脚本来完成一个需要重复输入单个命令的整体目标将是理想的。这就是 shell 脚本的优势所在。我们可以将我们的命令,无论有多长,放入一个单独的文件中;给它一个合适的名称;并根据需要执行脚本。以下代码显示了创建 shell 脚本的基本语法:

#! /bin/sh

上述命令是脚本中的第一行;它用于定义 shell 解释器。前面的字符#!通常被称为 shebang、sha-bang、hashbang、pound-bang 或 hash-pling。/bin/sh对象定义了应该使用哪个解释器来运行这个脚本;在这种情况下,它是 Shell 命令语言(sh)。另一个常见的解释器是:

#!/bin/bash

这与先前的声明类似,我们有#!,这表明我们将定义要使用的 shell 解释器;在这种情况下,我们使用的是 Bourne Again Shell,或者说是 Bash。这个 shell 提供了比常规的sh shell 更多的扩展;事实上,大多数较新的 Linux 发行版都默认使用 Bash 作为 shell。我们可以通过在终端中输入以下命令来轻松识别正在使用的 shell:

[philip@localhost Documents]$ echo $SHELL
/bin/bash
[philip@localhost Documents]$

太棒了!环境变量SHELL存储当前的 shell;返回的值表明我们正在运行 bash shell。另一种识别 shell 的方法如下:

[philip@localhost Documents]$ echo $0
bash
[philip@localhost Documents]$

太棒了!正在使用 bash shell。此外,我们可以使用ps命令来显示当前的 shell,如下所示:

[philip@localhost Documents]$ ps
 PID TTY          TIME CMD
 74972 pts/1    00:00:03 bash
 75678 pts/1    00:00:39 dnf
 92796 pts/1    00:00:00 ps
[philip@localhost Documents]$

太棒了!对于我们的目的,我们将使用#!/bin/bash来编写脚本。要开始编写你的第一个脚本,打开一个文本编辑器,比如 vi 或 nano,然后输入以下内容:

philip@localhost Documents]$ vi myFirstScript.sh

太棒了!我们在第一行中有我们的声明;我们定义了/bin/bash shell。接下来,我们有两行以#符号开头。除了顶部的第一行之外的任何行都被称为注释。也就是说,最后两行是注释。我们可以通过保存我们的脚本来证明这一点;我们可以使用:wq,这将保存并退出我们的脚本,如下所示:

[philip@localhost Documents]$ cat myFirstScript.sh
#!/bin/bash
#This is a comment
#echo 'This is also a comment'
[philip@localhost Documents]$
chmod command, as follows:

太棒了!我们使用了+x,它为用户、组和其他人打开了执行位;此外,脚本的名称已更改为绿色,表示该文件现在可执行。要运行此脚本,我们使用以下命令:

[philip@localhost Documents]$ ./myFirstScript.sh
[philip@localhost Documents]$

太棒了!脚本被执行了;但是内容没有显示。这是因为到目前为止我们只定义了注释;在脚本内部还没有定义其他内容。让我们让我们的脚本显示一条简短的消息。使用 vi 或 nano 打开脚本,输入以下内容:

[philip@localhost Documents]$ cat myFirstScript.sh
#!/bin/bash
#This is a comment
#echo 'This is also a comment'
echo 'Hello world'
[philip@localhost Documents]$

太棒了!我们已经添加了要执行的第一个命令:echo命令。这将简单地回复传递的内容,如下所示:

[philip@localhost Documents]$ ./myFirstScript.sh
Hello world
[philip@localhost Documents]$

太棒了!我们成功地编写了我们的第一个脚本。让我们添加另一个命令,以说明脚本的有效性;我们将添加date命令,每次执行脚本时都会提供日期,如下所示:

[philip@localhost Documents]$ cat myFirstScript.sh
#!/bin/bash
#This is a comment
#echo 'This is also a comment'
echo 'Hello world'
date
[philip@localhost Documents]$ ./myFirstScript.sh
Hello world
Mon Sep 17 10:04:48 EDT 2018
[philip@localhost Documents]$

太棒了!我们现在有两个命令,每次运行脚本时都会执行。除了将输出发送到显示器,我们还可以执行其他任务。例如,我们可以创建一个归档文件;让我们以创建/home/philip/Downloads目录的.tar文件为例,如下所示:

[philip@localhost Documents]$ cat myFirstScript.sh
#!/bin/bash
#This is a comment
#echo 'This is also a comment'
echo 'Hello world'
date
tar -cvf mytar.tar /home/philip/Downloads
[philip@localhost Documents]$

在上述代码中,我们使用tar命令创建了/home/philip/Downloads目录的归档。现在,我们可以运行脚本来查看结果,如下所示:

[philip@localhost Documents]$ ./myFirstScript.sh
Hello world
Mon Sep 17 10:35:37 EDT 2018
tar: Removing leading `/' from member names
/home/philip/Downloads/
/home/philip/Downloads/home/
/home/philip/Downloads/home/philip/
/home/philip/Downloads/home/philip/Downloads/
/home/philip/Downloads/home/philip/Downloads/song.mp3
[philip@localhost Documents]$ ls  | grep tar
mytar.tar
[philip@localhost Documents]$

太棒了!我们的脚本成功了,并且创建了一个扩展名为.tar的归档文件。此外,我们可以创建一个从用户那里获取输入的脚本,使用read命令。让我们创建另一个脚本,命名为input.sh,使用 vi 或 nano,如下所示:

[philip@localhost Documents]$ ls -l input.sh
-rw-rw-r--. 1 philip philip 75 Sep 17 10:42 input.sh
[philip@localhost Documents]$ cat input.sh
#!/bin/bash

echo 'Whats your name?'
read name
echo 'your name is $name'
[philip@localhost Documents]$ chmod +x input.sh
[philip@localhost Documents]$

太棒了!我们创建了一个input.sh脚本;我们使用read命令来存储用户的输入。存储在name中的值称为变量。通过在变量名前面加上$来显示它在最后一行中。脚本的结果如下所示:

提示会暂停,直到我们输入内容;我们将输入一个名字并查看结果,如下所示:

[philip@localhost Documents]$ ./input.sh
Whats your name?
Philip
your name is: Philip
[philip@localhost Documents]$

太棒了!我们输入的名字被添加到了最后一行。我们还可以通过以下语法来定义变量:

<variable name> = <value>

在上述代码中,我们给变量命名,然后指定一个值。

让我们创建一个名为myvar.sh的新脚本,使用 vi 或 nano。以下代码显示了如何使用新脚本定义变量:

[philip@localhost Documents]$ vi myvar.sh
[philip@localhost Documents]$ cat myvar.sh
#!/bin/bash

OUR_VAR="Philip Inshanally"

echo "The variable which we defined is $OUR_VAR"
[philip@localhost Documents]$ chmod +x myvar.sh
[philip@localhost Documents]$ ./myvar.sh
The variable which we defined is Philip Inshanally
[philip@localhost Documents]$

太棒了!我们定义了一个变量OUR_VAR,并给它赋值Philip Inshanally;然后在echo命令中调用它,通过在变量名前面放置$符号。正如你所看到的,有多种定义变量的方式。当单词之间有空格时,变量值需要用括号括起来。如果只有一个单词或数字,就不需要用括号括起来。

不要用括号括住单词或数字。

使用 for 循环编写脚本

有时,逐行在脚本中写出每个命令可能会很麻烦。我们可以通过使用循环来实现相同的目标,根据满足的表达式执行命令。for循环的基本语法如下:

for          <condition>
do
                <command1>
                <command2>
                …
                <commandN>
done

第一行定义了一个条件,一旦条件满足,我们就有一系列命令。为了看到这个过程,让我们创建一个脚本,名为myForLoop.sh,使用 vi 或 nano:

[philip@localhost Documents]$ vi myForLoop.sh
[philip@localhost Documents]$ chmod +x myForLoop.sh
[philip@localhost Documents]$ cat myForLoop.sh
#!/bin/bash
echo 'This script displays how a for loop works'
for o in {1..10}
do
 echo "The loop is running for the: $o time"
done
[philip@localhost Documents]$

太棒了!以for o in {1..10}开头的行定义了我们想要执行for循环的次数;它将被执行 10 次。do部分下的命令是将要执行的命令;$o是在for部分中定义的变量。结果如下:

[philip@localhost Documents]$ ./myForLoop.sh
This script displays how a for loop works
The loop is running for the: 1 time
The loop is running for the: 2 time
The loop is running for the: 3 time
The loop is running for the: 4 time
The loop is running for the: 5 time
The loop is running for the: 6 time
The loop is running for the: 7 time
The loop is running for the: 8 time
The loop is running for the: 9 time
The loop is running for the: 10 time
[philip@localhost Documents]$

太棒了!这个条件也可以用以下格式来写:

[philip@localhost Documents]$ cat myForLoop.sh
#!/bin/bash
echo 'This script displays how a for loop works'
#for o in {1..10}
for p in 1 2 3 4 5 6 7 8 9 10 11 12
do
 echo "The loop is running for the: $p time"
done
[philip@localhost Documents]$
 [philip@localhost Documents]$ ./myForLoop.sh
This script displays how a for loop works
The loop is running for the: 1 time
The loop is running for the: 2 time
The loop is running for the: 3 time
The loop is running for the: 4 time
The loop is running for the: 5 time
The loop is running for the: 6 time
The loop is running for the: 7 time
The loop is running for the: 8 time
The loop is running for the: 9 time
The loop is running for the: 10 time
The loop is running for the: 11 time
The loop is running for the: 12 time
[philip@localhost Documents]$

太棒了!我们写下了用空格分隔的值,脚本成功了。我们还可以像 C 编程语言一样,用三个部分指定条件,如下所示:

[philip@localhost Documents]$ cat myForLoop.sh
#!/bin/bash

echo 'This script displays how a for loop works'

#for o in {1..10}
#for p in 1 2 3 4 5 6 7 8 9 10 11 12
for ((p=1; p<=6; p++))
do
 echo "The loop is running for the: $p time"
done
[philip@localhost Documents]$
 [philip@localhost Documents]$ ./myForLoop.sh
This script displays how a for loop works
The loop is running for the: 1 time
The loop is running for the: 2 time
The loop is running for the: 3 time
The loop is running for the: 4 time
The loop is running for the: 5 time
The loop is running for the: 6 time
[philip@localhost Documents]$

太棒了!在上述代码中,for ((p=1; p<=6; p++))行定义了一个变量并为其赋值p=1;p<=6检查条件,p++表示只要条件满足就递增变量的值。

使用 while 循环编写脚本

另一个在脚本中可以使用的流行循环是while循环。while循环的基本语法如下:

while <condition>
do
                <command1>
                <command2>
                …
                <commandN>
done

在上述代码中,我们指定一个条件,只要条件满足,循环就会被执行。

使用 vi 或 nano 创建一个名为myWhile.sh的脚本,如下所示:

[philip@localhost Documents]$ vi myWhile.sh
[philip@localhost Documents]$ chmod +x myWhile.sh
[philip@localhost Documents]$ cat myWhile.sh
#!/bin/bash

d=1

while (( $d <= 8 ))
do
 echo "The number is $d times"
 d=$(( d+1 ))
done
[philip@localhost Documents]$

太棒了!首先,我们定义了一个变量,d=1,然后我们指定了一个条件,(( $d <= 8 )),它检查变量d是否小于或等于8;随后,我们使用echo命令根据条件提供文本。最后一部分,d=$(( d+1 )),将在满足每个条件后递增变量,如下所示:

[philip@localhost Documents]$ ./myWhile.sh
The number is 1 times
The number is 2 times
The number is 3 times
The number is 4 times
The number is 5 times
The number is 6 times
The number is 7 times
The number is 8 times
[philip@localhost Documents]$

太棒了!用于条件的另一种技术是在while语句之后使用::将始终为True;这意味着循环直到我们使用Ctrl + C结束脚本才会结束。让我们使用 vi 或 nano 创建另一个名为infinite.sh的脚本,如下所示:

[philip@localhost Documents]$ vi infinite.sh
[philip@localhost Documents]$ chmod +x infinite.sh
[philip@localhost Documents]$ cat infinite.sh
#!/bin/bash
while :
do
 echo "You can enter text and press Enter as many times (exit using CTRL+c)"
 read someText
 echo "You typed $someText"
done
[philip@localhost Documents]$

会出现提示,允许我们输入任何内容;一旦我们按下Enter键,将显示另一条消息,包括我们输入的任何内容。这将无限继续,直到我们使用Ctrl + C退出脚本,如下所示:

[philip@localhost Documents]$ ./infinite.sh
You can enter text and press Enter as many times (exit using CTRL+c)
Hi 
You typed Hi
You can enter text and press Enter as many times (exit using CTRL+c)
How are you?
You typed How are you?
You can enter text and press Enter as many times (exit using CTRL+c)
I can keep typing
You typed I can keep typing
You can enter text and press Enter as many times (exit using CTRL+c)
and typing 
You typed and typing
You can enter text and press Enter as many times (exit using CTRL+c)
I can exit by using the keystroke as shown in the message above
You typed I can exit by using the keystroke as shown in the message above
You can enter text and press Enter as many times (exit using CTRL+c)
^C
[philip@localhost Documents]$

太棒了!脚本直到我们使用Ctrl + C组合键才退出。展示while循环有效性的另一种方法是在脚本退出前查找一个字符串。使用 vi 或 nano 创建另一个名为whileString.sh的脚本,如下所示:

[philip@localhost Documents]$ vi whileString.sh
[philip@localhost Documents]$ chmod +x whileString.sh
[philip@localhost Documents]$ cat whileString.sh
#!/bin/bash
someString=begin
while [ "$someString" != "quit" ]
do
 echo "Enter some text (type quit to exit)"
 read someString
 echo "You entered: $someString"
done
[philip@localhost Documents]$

太棒了!我们声明了一个变量,someString=begin;这可以是您选择的任何值。接下来,我们检查了一个条件,[ "$someString" != "quit" ],它寻找quit字符串。只要字符串不是quit,脚本将无限运行,直到我们输入quit或按下Ctrl + C退出脚本,如下所示:

[philip@localhost Documents]$ ./whileString.sh
Enter some text (type quit to exit)
Hi
You entered: Hi
Enter some text (type quit to exit)
my name is Philip
You entered: my name is Philip
Enter some text (type quit to exit)
How are you
You entered: How are you
Enter some text (type quit to exit)
quit
You entered: quit
[philip@localhost Documents]$

太棒了!我们可以继续输入文本,脚本将继续运行,除非我们输入 quit 或按下Ctrl + C,这将退出脚本。

请注意,我们使用方括号([])括住文本;当测试字符串值时,脚本将无法使用常规括号(())。

使用 if 语句编写脚本

我们可以在脚本中使用if语句来测试条件。if语句的基本语法如下:

if [some condition]; then
                execute something
fi
or
if [[some condition]]; then
                execute something
fi

我们可以创建一个简单的if脚本,使用上述代码作为指导。有时,我们可能需要使用双方括号,它们比旧的单方括号样式提供了增强功能。让我们使用 vi 或 nano 创建一个名为myif.sh的脚本,如下所示:

[philip@localhost Documents]$ vi myif.sh
[philip@localhost Documents]$ cat myif.sh
#!/bin/bash

echo "Welcome to our if statement script"
if [[ $1 == 4 ]]; then
 echo "You're very smart"
fi
echo "See you soon!"
[philip@localhost Documents]$ chmod +x myif.sh
[philip@localhost Documents]$ ./myif.sh
Welcome to our if statement script
See you soon!
[philip@localhost Documents]$

我们使用echo命令显示欢迎消息;然后我们使用if [[ $1 == 4 ]]; then;此语句正在检查4。脚本被执行;但是我们没有看到if语句内的echo命令被执行。为了看到if语句内的消息,我们必须在运行脚本时输入一个值,如下所示:

[philip@localhost Documents]$ ./myif.sh 4
Welcome to our if statement script
You're very smart
See you soon!
[philip@localhost Documents]$

太棒了;if结构内的语句被执行,但是,如果我们传递的值不是4,我们将看到以下内容:

[philip@localhost Documents]$ ./myif.sh 3
Welcome to our if statement script
See you soon!
[philip@localhost Documents]$

由于我们传递的值不等于被检查的值,if语句内的命令没有被执行。我们可以在if语句中添加另一个部分来处理另一个响应;我们可以使用else子句。以下是注入到if语句中的else子句的语法:

if [[some condition]]; then
                execute something
else
                execute something else
fi

我们可以使用 vi 或 nano 编辑我们的my.sh脚本,并添加一个else子句来处理任何其他响应,如下所示:

[philip@localhost Documents]$ vi myif.sh
[philip@localhost Documents]$ cat myif.sh
#!/bin/bash
echo "Welcome to our if statement script"
if [[ $1 == 4 ]]; then
 echo "You're very smart"
else
 echo " Better luck next time"
fi
echo "See you soon!"
[philip@localhost Documents]$

太棒了!我们可以运行注入了else子句的脚本,结果如下:

[philip@localhost Documents]$ ./myif.sh 3
Welcome to our if statement script
Better luck next time
See you soon!
[philip@localhost Documents]$ ./myif.sh 2
Welcome to our if statement script
Better luck next time
See you soon!
[philip@localhost Documents]$ ./myif.sh 4
Welcome to our if statement script
You're very smart
See you soon!
[philip@localhost Documents]$

太棒了!当用户输入除4以外的值时,我们会看到不同的消息。此外,我们可以在另一个if语句中嵌套一个if语句。嵌套if语句的基本语法如下:

if [[first condition]]; then
execute something
elif [[second condition]]; then
                execute something else
 elif [[third condition]]; then
                execute something else
else
                execute_a_last_resort_command
fi

我们可以编辑我们的myif.sh脚本,使用 vi 或 nano,并添加第二个elif语句,如下所示:

[philip@localhost Documents]$ cat myif.sh
#!/bin/bash
echo "Welcome to our if statement script"
if [[ $1 == 4 ]]; then
 echo "You're very smart"
elif [[ $1 == 2 ]]; then
 echo "You've got your elseif value correct!"
else
 echo "Reach for the sky"
fi
echo "See you soon!"
[philip@localhost Documents]$

我们已经添加了elif [[ $1 == 2 ]]; then,它检查值2。一旦满足此条件,将显示一条消息,如下所示:

[philip@localhost Documents]$ ./myif.sh 2
Welcome to our if statement script
You've got your elseif value correct!
See you soon!
[philip@localhost Documents]$ ./myif.sh 3
Welcome to our if statement script
Reach for the sky
See you soon!
[philip@localhost Documents]$ ./myif.sh 4
Welcome to our if statement script
You're very smart
See you soon!
[philip@localhost Documents]$

太棒了!我们可以看到当我们输入与elif条件匹配的值时,elif条件下的命令将被执行。此外,当我们输入与ifelif条件都不匹配的值时,将显示一个全捕获消息。

还可以在单个if语句或elif语句上测试多个条件。让我们使用 vi 或 nano 编辑我们的myif.sh,如下所示:

[philip@localhost Documents]$ cat myif.sh
#!/bin/bash
echo "Welcome to our if statement script"
if [[ $1 == 4 ]] || [[ $1 == 3 ]] ; then
 echo "You're very smart"
elif [[ $1 == 2 ]]; then
 echo "You've got your elseif value correct!"
else
 echo "Reach for the sky"
fi
echo "See you soon!"
[philip@localhost Documents]$

在上述代码中,我们在if语句中添加了第二个条件;即if [[ $1 == 4 ]] || [[ $1 == 3 ]] ; then||表示。这是检查是否满足任一条件,并且命令将在if语句下执行,如下所示:

[philip@localhost Documents]$ ./myif.sh 4
Welcome to our if statement script
You're very smart
See you soon!
[philip@localhost Documents]$ ./myif.sh 3
Welcome to our if statement script
You're very smart
See you soon!
 [philip@localhost Documents]$

太棒了!一旦if子句中满足任一条件,命令就会在if子句下执行。此外,还有&&命令,用于比较条件;这意味着必须满足两个条件。我们可以快速编辑我们的myif.sh脚本,并添加&&,如下所示:

[philip@localhost Documents]$ cat myif.sh
#!/bin/bash
echo "Welcome to our if statement script"
if [[ $1 == 4 ]] || [[ $1 == 3 ]] ; then
 echo "You're very smart"
elif [[ $1 == 2 ]] && [[ $1 != 1 ]] ; then
 echo "You've got your elseif value correct!"
else
 echo "Reach for the sky"
fi
echo "See you soon!"
[philip@localhost Documents]$

当用户输入2时,将满足elif条件;这是因为两个条件都需要为真。如果用户输入除2以外的任何值,将执行全捕获else子句,如下所示:

[philip@localhost Documents]$ ./myif.sh 1
Welcome to our if statement script
Reach for the sky
See you soon!
[philip@localhost Documents]$ ./myif.sh 2
Welcome to our if statement script
You've got your elseif value correct!
See you soon!
[philip@localhost Documents]$

太棒了!elif子句中满足了两个条件,导致命令在elif子句下执行。

SQL 数据管理

结构化查询语言SQL)是用于数据库操作的一种广为人知的语言。有各种版本的 SQL。我们将使用 MySQL 的开放标准:mysql-community-server软件包。首先,我们需要在我们的 Fedora 28 系统中安装 MySQL YUM存储库;我们将使用dnf命令,如下所示:

[philip@localhost Documents]$ sudo dnf install https://dev.mysql.com/get/mysql80-community-release-fc28-1.noarch.rpm
==========================================================================================================================
 Package       Arch  Version    Repository                   Size
==========================================================================================================================
Installing:
mysql80-community-release    noarch  fc28-1       @commandline                 30 k

Transaction Summary
==========================================================================================================================
Install  1 Package
Total size: 30 k
Installed size: 29 k
Is this ok [y/N]: y
Installed:
mysql80-community-release.noarch fc28-1                                                                                
Complete!
[philip@localhost Documents]$

太棒了!存储库已成功安装。现在,我们将安装服务器,如下所示:

[philip@localhost Documents]$ sudo dnf install mysql-community-server
MySQL 8.0 Community Server                                                                302 kB/s | 215 kB     00:00 
MySQL Connectors Community                                                                 32 kB/s |  15 kB     00:00 
MySQL Tools Community                                                                      75 kB/s |  28 kB     00:00 

Total download size: 359 M
Installed size: 1.6 G
Is this ok [y/N]: y

在上述代码中,为了简洁起见,省略了一些输出。该软件包将占用超过 1GB 的空间;下载所需的时间将根据您的互联网连接而有所不同。进度将如下所示:

过一段时间,我们将看到以下内容:

Installed:
 mysql-community-server.x86_64 8.0.12-1.fc28                 mecab.x86_64 0.996-2.fc28 
 mysql-community-client.x86_64 8.0.12-1.fc28                 mysql-community-common.x86_64 8.0.12-1.fc28 
 mysql-community-libs.x86_64 8.0.12-1.fc28 
Complete!
[philip@localhost Documents]$

太棒了!下一步是启用mysqld服务;我们将使用systemctl命令,如下所示:

[philip@localhost Documents]$ sudo systemctl start mysqld
[philip@localhost Documents]$ sudo systemctl enable mysqld
[philip@localhost Documents]$ systemctl status mysqld

太棒了!mysqld.service已成功启动。在安装过程中,为mysql服务器生成了一个随机的root密码;我们必须查看/var/log/mysqld.log文件中的内容,如下所示:

[philip@localhost Documents]$ grep 'A temporary password is generated for root@localhost' /var/log/mysqld.log |tail -1
2018-09-17T19:25:35.229434Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: #a7RCyoyzwOF
[philip@localhost Documents]$

mysqlroot的随机密码是#a7RCyoyzwOF。最后,我们应该保护我们的mysql数据库;我们将使用mysql_secure_installation命令,如下所示:

[philip@localhost Documents]$ mysql_secure_installation
Securing the MySQL server deployment.
Enter password for user root:
The existing password for the user account root has expired. Please set a new password.
New password:

首先,我们必须输入随机密码;然后,我们必须设置一个新密码,如下所示:

New password:
Re-enter new password:
The 'validate_password' component is installed on the server.
The subsequent steps will run with the existing configuration
of the component.
Using existing password for root.
Estimated strength of the password: 100
Change the password for root ? ((Press y|Y for Yes, any other key for No) :

默认情况下,安装了validate_password插件;这设置了密码规范。我们必须输入一个密码,该密码由至少一个大写字符、一个小写字符、一个数字和一个特殊字符组成。总密码长度必须至少为八个字符,如下所示:

Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.
Remove anonymous users? (Press y|Y for Yes, any other key for No) : y

默认情况下,会生成一个匿名用户帐户;我们将选择y来删除它并继续:

Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.
Disallow root login remotely? (Press y|Y for Yes, any other key for No) :

我们将允许root用户远程登录,因此我们将按下一个键,这一步将被跳过,如下所示:

 ... skipping.
By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
 - Dropping test database...
Success.
 - Removing privileges on test database...
Success.
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.
All done!
[philip@localhost Documents]$

与默认安装相比,mysql现在更安全了。我们现在可以使用mysql命令登录mysql数据库,如下所示:

[philip@localhost Documents]$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 21
Server version: 8.0.12 MySQL Community Server - GPL
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>

太棒了!我们现在将创建我们的第一个数据库;我们将使用create database命令:

mysql> create database netaccess;
Query OK, 1 row affected (0.10 sec)
mysql>

太棒了!我们现在将创建一个可以访问我们数据库的用户;我们将使用create user命令:

mysql> create user 'philip'@'172.16.175.130' identified by 'password123';
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
mysql>

在上述代码中,密码要求再次未被满足;我们可以通过降低设置或删除validate_password组件来解决这个问题。我们将删除validate_password组件,如下所示:

mysql> uninstall plugin validate_password;
ERROR 1305 (42000): PLUGIN validate_password does not exist
mysql> exit
Bye
[philip@localhost Documents]$ mysql -h localhost -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 22
Server version: 8.0.12 MySQL Community Server - GPL
mysql> UNINSTALL COMPONENT 'file://component_validate_password';
Query OK, 0 rows affected (0.10 sec)
mysql> exit
Bye
[philip@localhost Documents]$

太棒了!我们使用UNINSTALL COMPONENT命令删除了component_validate_password。现在,我们可以像之前一样登录并继续:

mysql> grant all on netaccess.* to 'philip'@'172.16.175.130';
Query OK, 0 rows affected (0.06 sec)
mysql>

太棒了!最后一步是重新加载授权表;我们将使用flush命令,如下所示:

mysql> flush privileges
 -> ;
Query OK, 0 rows affected (0.00 sec)
mysql>

太棒了!当我们离开;时,命令没有被执行。我们总是需要以分号(;)结束。现在,我们可以从我们的 Ubuntu 系统通过网络进行测试。我们将不得不在 Ubuntu 18 系统上安装mysql-client,如下所示:

philip@Linuxplus:~$ mysql
Command 'mysql' not found, but can be installed with:
sudo apt install mysql-client-core-5.7 
sudo apt install mariadb-client-core-10.1
philip@Linuxplus:~$ sudo apt install mysql-client-core-5.7 
[sudo] password for philip:
Reading package lists... Done
Building dependency tree 
Setting up mysql-client-core-5.7 (5.7.23-0ubuntu0.18.04.1) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...
philip@Linuxplus:~$ mysql -h 172.16.175.129 -u philip -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 25
Server version: 8.0.12 MySQL Community Server - GPL
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>

太棒了!我们成功连接了托管在我们的 Fedora 28 系统上的mysql服务器,使用 Ubuntu 18 客户端通过网络。我们现在可以使用各种命令,比如show databases命令:

mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| netaccess |
+--------------------+
2 rows in set (0.06 sec)
mysql>

太棒了!我们可以看到两个数据库:我们之前创建的一个和一个内部数据库。但是,如果我们以 root 用户身份运行此命令,我们将看到所有可用的数据库,如下所示:

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| netaccess          |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
mysql>

太棒了!查看数据库的另一种方法是使用带有-e选项的mysql命令;这允许我们从 shell 执行命令。以下代码片段显示了我们如何列出数据库:

philip@Linuxplus:~$ mysql -h 172.16.175.129 -u philip -p -e "show databases"
Enter password:
+--------------------+
| Database           |
+--------------------+
| information_schema |
| netaccess          |
+--------------------+
philip@Linuxplus:~$

太棒了!接下来,我们可以使用use命令切换到指定的数据库。以下代码显示了我们如何指定要使用的数据库:

mysql> use netaccess;
Database changed
mysql>

我们现在在netaccess数据库中。要开始使用数据库,我们必须首先创建一个表;在创建表之前,我们需要知道要创建什么类型的表。例如,假设我们想创建一个关于公共场所的表;我们将希望有一个用于场所名称的字段。如果我们只创建一个带有场所名称的表,那将不太吸引人;我们将希望添加其他方面,比如提供的服务和位置等。正如您所看到的,表可以包含各种选项。首先,我们将使用我们示例中提到的字段;我们将使用create table命令,如下所示:

mysql> create table Public_Places (name VARCHAR(20), location VARCHAR(30), service_provided VARCHAR(30));
Query OK, 0 rows affected (9.44 sec)
mysql>

太棒了!我们成功创建了我们的第一个表。我们可以使用show tables命令查看表:

mysql> show tables;
+---------------------+
| Tables_in_netaccess |
+---------------------+
| Public_Places       |
+---------------------+
1 row in set (0.11 sec)
mysql>

我们可以看到我们的表已列出。我们可以使用describe命令查看我们创建的字段。以下代码显示了我们如何使用describe命令:

mysql> describe Public_Places;
+------------------+-------------+------+-----+---------+-------+
| Field            | Type        | Null | Key | Default | Extra |
+------------------+-------------+------+-----+---------+-------+
| name             | varchar(20) | YES  |     | NULL    |       |
| location         | varchar(30) | YES  |     | NULL    |       |
| service_provided | varchar(30) | YES  |     | NULL    |       |
+------------------+-------------+------+-----+---------+-------+
3 rows in set (0.23 sec)
mysql>

太棒了!我们可以看到字段及其类型;varchar类型的长度可以是 0 到 65,535 之间的值。目前,表是空的,所以我们必须填充它。

插入命令

我们可以使用insert命令填充表。基本语法如下:

insert into <table> <field(s)><value(s)>

我们可以向我们之前创建的表中添加一些信息,如下所示:

mysql> insert into Public_Places values('Police Station', 'Capital City', 'serve and protect');
Query OK, 1 row affected (0.17 sec)
mysql>

太棒了!我们指定了值并使用insert命令传递了这些值,将数据存储在表中。插入数据的另一种方法是只插入部分字段的数据;我们必须指定字段名称以进行选择性插入。以下代码显示了如何将数据插入到表的某些部分:

mysql> insert into Public_Places (name, location) values('Telephone Company', 'Georgetown');
Query OK, 1 row affected (0.16 sec)
mysql>

太棒了!我们只为两个字段(namelocation)插入了值。插入数据的另一种方法是使用带有-e选项的mysql命令,如下所示:

philip@Linuxplus:~$ mysql -h 172.16.175.129 -u philip -p -e "USE netaccess; INSERT INTO Public_Places values ('Hospital' , 'Georgetown', 'healthcare');"
Enter password:
philip@Linuxplus:~$

太棒了!数据已成功输入到表中。

选择命令

到目前为止,我们一直在向我们的表中添加内容。但是,我们还没有看到我们添加的值。我们可以使用select命令查看表的内容,如下所示:

mysql> select * from Public_Places;
+-------------------+--------------+-------------------+
| name              | location     | service_provided  |
+-------------------+--------------+-------------------+
| Police Station    | Capital City | serve and protect |
| Telephone Company | Georgetown   | NULL              |
| Hospital          | Georgetown   | healthcare        |
+-------------------+--------------+-------------------+
3 rows in set (0.00 sec)
mysql>

太棒了!我们可以看到我们迄今为止在我们的表中输入的所有值。此外,我们可以通过指定where子句执行选择性搜索,如下所示:

mysql> select * from Public_Places where name='Telephone Company';
+-------------------+------------+------------------+
| name              | location   | service_provided |
+-------------------+------------+------------------+
| Telephone Company | Georgetown | NULL             |
+-------------------+------------+------------------+
1 row in set (0.00 sec)
mysql>

太棒了!我们还可以使用以下方法进行搜索:

mysql> select name, service_provided from Public_Places;
+-------------------+-------------------+
| name              | service_provided  |
+-------------------+-------------------+
| Police Station    | serve and protect |
| Telephone Company | NULL              |
| Hospital          | healthcare        |
+-------------------+-------------------+
3 rows in set (0.00 sec)
mysql> select service_provided from Public_Places;
+-------------------+
| service_provided  |
+-------------------+
| serve and protect |
| NULL              |
| healthcare        |
+-------------------+
3 rows in set (0.00 sec)
mysql>

太棒了!

更新命令

我们可以使用update命令对表进行更改,如下所示:

mysql> update Public_Places set service_provided='Telephones' where name='Telephone Company';
Query OK, 1 row affected (0.05 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql>

太棒了!我们已经填写了Telephone Companyservice_provided字段的数据;可以使用select命令进行验证,如下所示:

mysql> select * from Public_Places;
+-------------------+--------------+-------------------+
| name              | location     | service_provided  |
+-------------------+--------------+-------------------+
| Police Station    | Capital City | serve and protect |
| Telephone Company | Georgetown   | Telephones        |
| Hospital          | Georgetown   | healthcare        |
+-------------------+--------------+-------------------+
3 rows in set (0.00 sec)
mysql>

太棒了!我们可以看到service_provided字段已经填充。此外,我们可以使用update命令更改数据,如下所示:

mysql> update Public_Places set location='Kaieteur Falls' where name='Hospital';
Query OK, 1 row affected (0.15 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> select * from Public_Places;
+-------------------+----------------+-------------------+
| name              | location       | service_provided  |
+-------------------+----------------+-------------------+
| Police Station    | Capital City   | serve and protect |
| Telephone Company | Georgetown     | Telephones        |
| Hospital          | Kaieteur Falls | healthcare        |
+-------------------+----------------+-------------------+
3 rows in set (0.00 sec)
mysql> update Public_Places set name='GPF' where name='Police Station';
Query OK, 1 row affected (0.16 sec)The dele
Rows matched: 1  Changed: 1  Warnings: 0
mysql> select * from Public_Places;
+-------------------+----------------+-------------------+
| name              | location       | service_provided  |
+-------------------+----------------+-------------------+
| GPF               | Capital City   | serve and protect |
| Telephone Company | Georgetown     | Telephones        |
| Hospital          | Kaieteur Falls | healthcare        |
+-------------------+----------------+-------------------+
3 rows in set (0.00 sec)
mysql>

太棒了!

删除命令

我们可以使用delete命令从表的字段中删除值,如下所示:

mysql> delete from Public_Places where name='Hospital';
Query OK, 1 row affected (0.18 sec)
mysql> select * from Public_Places;
+-------------------+--------------+-------------------+
| name              | location     | service_provided  |
+-------------------+--------------+-------------------+
| GPF               | Capital City | serve and protect |
| Telephone Company | Georgetown   | Telephones        |
+-------------------+--------------+-------------------+
2 rows in set (0.01 sec)
mysql>

太棒了!使用delete命令指定的字段已被删除。

from 选项

我们可以使用from选项来指定要使用的表;例如,如果我们指定一个不存在的表,我们将看到以下消息:

mysql> select * from myTable;
ERROR 1146 (42S02): Table 'netaccess.myTable' doesn't exist
mysql>

表不存在,因此在执行查询时,我们必须使用from选项输入正确的表。

where 条件

当我们想要执行一些选择性操作时,我们可以使用where条件。我们之前使用过selectupdatedelete命令的where条件。作为提醒,我们可以如下使用where条件:

mysql> select * from Public_Places where name='GPF';
+------+--------------+-------------------+
| name | location     | service_provided  |
+------+--------------+-------------------+
| GPF  | Capital City | serve and protect |
+------+--------------+-------------------+
1 row in set (0.00 sec)
mysql>

太棒了!只显示符合条件的结果。

group by 选项

我们可以使用group by选项根据我们指定的条件提供结果,如下所示:

mysql> select name from Public_Places group by name;
+-------------------+
| name              |
+-------------------+
| GPF               |
| Telephone Company |
+-------------------+
2 rows in set (0.02 sec)
mysql>

太棒了!结果根据指定的条件进行分组。当我们有包含数字的表时,这是非常有用的,例如客户 ID,员工 ID 和订单等。

order by 选项

我们可以使用order by选项按升序或降序对表中的数据进行排序。以下代码显示了如何使用order by选项:

mysql> select * from Public_Places order by service_provided;
+-------------------+--------------+-------------------+
| name              | location     | service_provided  |
+-------------------+--------------+-------------------+
| GPF               | Capital City | serve and protect |
| Telephone Company | Georgetown   | Telephones        |
+-------------------+--------------+-------------------+
2 rows in set (0.02 sec)
mysql>

根据默认设置,数据按升序排序;但是,我们可以通过传递DESC关键字以降序显示结果,如下所示:

mysql> select * from Public_Places order by service_provided DESC;
+-------------------+--------------+-------------------+
| name              | location     | service_provided  |
+-------------------+--------------+-------------------+
| Telephone Company | Georgetown   | Telephones        |
| GPF               | Capital City | serve and protect |
+-------------------+--------------+-------------------+
2 rows in set (0.00 sec)
mysql>

太棒了!结果以降序显示。

连接选项

我们可以通过传递join选项来使用简单的连接;这可以用于合并来自不同表的行,以查看表之间的共同因素。我创建了两个表,如下所示:

mysql> select * from Cust;
+--------+-------------------------+--------------------+
| custID | custName                | location           |
+--------+-------------------------+--------------------+
|      1 | Philip Inshanally       | Georgetown, Guyana |
|      2 | Matthew Zach Inshanally | Georgetown, Guyana |
+--------+-------------------------+--------------------+
2 rows in set (0.03 sec)
mysql> select * from Purchase;
+---------+------------+-----------+
| orderID | purchaseID | orderDate |
+---------+------------+-----------+
|       2 |   20150202 | 201800902 |
|       1 |   10031984 |  20180310 |
+---------+------------+-----------+
2 rows in set (0.00 sec)
mysql>

相同的列是每个表的第一列;Cust表将其称为custID,而Purchase表将其称为 ordered。基于此,我们可以创建一个选择查询,将两个表合并,如下所示:

mysql> SELECT Purchase.orderID, Cust.custName, Purchase.orderDate FROM Purchase INNER JOIN Cust ON Purchase.orderID=Cust.custID;
+---------+-------------------------+-----------+
| orderID | custName                | orderDate |
+---------+-------------------------+-----------+
|       1 | Philip Inshanally       |  20180310 |
|       2 | Matthew Zach Inshanally | 201800902 |
+---------+-------------------------+-----------+
2 rows in set (0.01 sec)
mysql>

太棒了!我们通过在Purchase.orderIDCust.custNamePurchase.orderDate前放置表的名称来引用字段;这定义了表的呈现方式。

接下来的部分,FROM Purchase INNER JOIN Cust ON Purchase.orderID=Cust.custID;,定义了内容将来自Purchase表,并且将使用Purchase.orderID=Cust.custID的共同列进行连接,从而产生包含来自两个表的数据的结果。

这被称为内部连接;它返回在两个表中具有匹配值的数据。

总结

在本章中,我们学习了 shell 脚本和 SQL 管理。首先,我们介绍了 shell 脚本的基础知识。接下来,我们通过使用for循环编写脚本。然后,我们使用了while循环。最后,我们在脚本中使用了if语句。

接下来,我们使用了 SQL 管理。首先,我们安装了 MySQL 存储库,然后安装了 MySQL 的社区服务器版本。然后,我们对我们的mysql服务器进行了安全设置。然后,我们开始创建数据库,然后创建表。然后,我们开始使用各种技术管理表中的数据;最后,我们创建了额外的表,以演示内部连接。

我很高兴编写了这本书中的每一章。我相信您在职业生涯中会从这本书中学到很多。感谢您选择这本书并将其收入您的收藏。下次再见,我是 Philip Inshanally,提醒您要时刻心存感激。很快再见!

问题

  1. 哪些字符标识了定义解释器的行的开头?

A. #$

B. #@

C. #!

D. #^

  1. 以下哪个环境变量存储当前的 shell?

A. SHELL

B. BASH

C. SH

D. TCSH

  1. 以下哪个关键字结束了for循环?

A. do

B. do 循环

C. 完成

D. fi

  1. 如果脚本位于当前目录中,需要在/前面放置哪个字符才能运行脚本?

A. .

B.

C. ;

D.

  1. 以下哪个命令可以创建一个变量来存储用户的输入?

A. 执行

B. 暂停

C. 写入

D. 读取

  1. 以下哪个字符可以用来测试两个条件,并在任一条件为真时返回TRUE

A. &&

B. ||

C. //

D. ==

  1. 在使用select命令执行mysql查询时,以下哪个字符用作通配符?

A. +

B. /

C. *

D. -

  1. 在使用select命令时,以下哪个选项用于检查条件?

A. 来自

B. if

C. where

D. 连接

  1. 以下哪个命令将使用 mysql 创建一个表?

A. 创建表

B. 创建表

C. 创建表

D. 创建表

  1. 以下哪个命令可以用于使用mysql更改值?

A. 插入

B. 删除

C. 更新

D. 连接

进一步阅读

第十九章:模拟考试 - 1

问题

  1. 以下列出的密码中哪个被认为是安全的?

A. password123

B. t%h@)_14!*!

C. 12345678

D. abcdefgh

  1. 哪个环境变量存储当前的 shell?

A. SHELL

B. BASH

C. SH

D. TCSH

  1. 哪个挂载点保存系统配置文件?

A. /boot

B. /home

C. /etc

D. /var

  1. 用于在 Ubuntu 中更新 GRUB2 的命令是什么?

A. update-grub2

B. make-grub

C. update-grub-gfxpayload

D. grub2-update

答案 A

  1. Ubuntu 18 中 GRUB 配置文件位于哪个目录?

A. /boot/grub2/

B. /var

C. /etct/grub2/grub/

D. /boot/grub/

  1. 哪些字符可以用于测试 2 个条件,并且如果两个条件都为真则返回 TRUE?

A. &&

B. ||

C. //

D. ==

  1. 在 if 子句中,哪个字符用于确保等号=前的条件不为真?

A. +

B. !

C. >

D. <

  1. 为了使脚本能够运行,必须打开哪个位?

A. 执行

B. 读取

C. 写

D. 读取和写入

  1. 哪个命令可以用于修改文件的读取、写入和执行权限?

A. chown

B. chmod

C. file

D. whois

  1. 哪个值代表文件的 RWX 权限?

A. 5

B. 4

C. 7

D. 1

  1. 哪个值代表文件的 RW 权限?

A. 6

B. 4

C.  7

D.1

  1. 哪个选项可以与mysql命令一起使用以使用户能够传递命令?

A. -a

B. -e

C. -c

D. -b

  1. 哪个选项可以用于使用timedatectl命令显示所有可用的时区?

A. --list-timezones

B. --list-time-zones

C. list-timezones

D. list-timezone

  1. 使用 date 命令设置小时时,需要在 H 的前面放置哪个字符?

A. #

B. @

C. $

D. %

  1. 哪个选项用于使用rpm命令查询给定软件包?

A. -a

B. -q

C. -e

D. r

  1. 哪个命令可以用于在 Ubuntu 系统中重新配置软件包?

A. dpkg--update

B. dpkg -r

C. dpkg -e

D. dpkg-reconfigure

  1. 哪个命令可以用于更改文件的所有权?

A. chmod

B. chown

C. chwn

D. chmd

  1. 在 mysql 中执行查询时,使用哪个关键字可以按降序排序?

A. 描述

B. DESC

C. 降序

D. 降序

  1. 以下哪个命令可以在当前时间 5 分钟后执行作业?

A. 在现在+5 分钟时

B. 在 5 分钟后

C. 在明天的 5 分钟

D. 在接下来的 5 分钟内

  1. 哪个选项可以用于在 at 命令中打印作业队列?

A. -q

B. -a

C. -l

D. -e

  1. Fedora 28 中cron服务的名称是什么?

A. crond.service

B. cron.service

C. cron-daemon.service

D. crond.daemon.service

  1. 如果我们希望每小时执行一次脚本,可以将脚本放在哪个目录?

A. /etc/crond.hourly

B. /etc/cron.hourly/

C. /etc/crond/hourly/jobs

D. /etc/cron/hourly/

  1. 编辑/etc/sudoers文件时应使用哪个命令?

A. visudo

B. visualdo

C. nano

D. vim.tiny

  1. 以下哪个定时器值可以使命令每 5 分钟执行一次?

A. 0/5 * * * *

B. * 5 * * *

C. * * 5 * *

D. * * * 5 *

  1. 哪个选项可以用于查看当前用户的crontab文件?

A. -a

B. -b

C. -d

D. -l

  1. 以下哪个定时器值可以使命令每天上午 5:00 执行一次?

A. 0/5 * * * *

B. * 5 * * *

C. * * 5 * *

D. * * * 5 *

  1. 以下哪个关于/proc/的陈述是正确的?

A. 对/proc/中的文件的更改不会以任何方式实施。

B. /proc/中的文件是用作注释的

C. /proc/中的任何更改都会实时实施。

D. /proc/中的文件无法编辑

  1. 在使用变量之前需要在前面放置哪个字符?

A. #

B. $

C. !

D. &

  1. 可以使用哪个选项从硬件时钟设置系统时间?

A. --hctosys

B. --systohc

C. --systohc

D. --hctohc

  1. 使用init命令重启系统时可以使用哪个数字?

A.1

B. 0

C. 6

D. 2

  1. 使用shutdown命令重新启动系统时可以使用哪个选项?

A. -a

B. -s

C. -c

D. -r

  1. 使用init命令进入救援模式的数字是多少?

A. 6

B. 1

C. 7

D. 2

  1. 在 CentOS 5 系统上使用 SysV init 系统时,默认运行级别是什么?

A. 2

B. 4

C. 5

D. 1

  1. 哪个命令可以用于显示在启动过程中生成的消息?

A. echo

B. anacron

C. message

D. dmesg

  1. BIOS 中常见的设置是什么?

A. Boot options

B. Kernel options

C. initram 选项

D. GRUB2 options

  1. 哪个命令可以用来显示给定命令的共享库信息?

A. ldconfig

B. ld

C. ldd

D. libconfig

  1. 以下哪个定义了 shell 脚本的开头处的/bin/sh

A. @!/bin/sh

B. #!/bin/sh

C. #%/bin/sh

D. @#/bin/sh

  1. 以下哪个用于比较一个条件是否等同于另一个条件?

A. ==

B. !=

C. =

D. =!

  1. 哪个关键字用于结束if语句?

A. if

B. endif

C. fi

D. elif

  1. 哪个选项用于使用rpm命令删除一个软件包?

A. -e

B. -a

C. -r

D. -d

  1. 哪个选项用于使用dpkg命令删除一个软件包及其配置文件?

A. -R

B. -r

C. -p

D. -P

  1. 哪个命令可以在 Debian 发行版中搜索软件包?

A. apt-cache

B. apt-get

C. dpkg

D. rpm

  1. apt 在安装新软件包时使用哪个目录作为源?

A. /etc/apt/sources.d/sources.list

B. /etc/apt/apt.sources.list

C. /etc/apt/sources.list

D. /etc/apt/list.sources

  1. 哪个选项可以用于使用apt-cache命令显示关于软件包的统计信息?

A. statistics

B. stats

C. stat

D. -s

  1. 哪个字符可以用于在后台启动一个程序?

A. #

B. !

C. %

D. &

  1. 哪个代表了默认的 IPv6 路由?

A. 0:1:1:1:1:1:1:1/128

B. ::/0

C. :0::/0

D. :1::/0

  1. FTP 用于命令流量的端口是哪个?

A. TCP 21

B. UDP 21

C. ICMP 21

D. HSRP 21

  1. 以下哪个代表了二进制中的/23

A. 11111111.11111000.11111111.00000000

B. 11111110.00000000.00000001.00000000

C. 11111111.11111110.00000000.00000001

D. 11111111.11111111.11111110.00000000

  1. 哪个代表了一个 Classful B 子网掩码?

A. 255.255.255.128

B. 255.255.0.0

C. 255.254.255.0

D. 255.253.255.0

  1. 哪个选项用于使用 ls 命令查看隐藏文件和目录?

A. -l

B. -s

C. -a

D. -r

  1. 哪个字符用于切换到当前用户的主目录?

A. ~

B. ```

C.

D. !

  1. 哪个选项可以用于使用find命令搜索权限?

A. --permissions

B. -perm

C. --perms

D. --view-permissions

  1. 哪个命令可以用于更新mlocate数据库?

A. update-locate

B. update-database

C. updatedb

D. updated

  1. 哪个选项可以用于在使用locate命令搜索时忽略大小写?

A. --ignore

B. -i

C. --no-case

D. -c

  1. 哪个选项用于使用wc命令显示总字数?

A. -c

B. -a

C. -w

D. -l

  1. 哪些字符可以用于向文件追加数据?

A. >

B. <

C. <<

D. >>

  1. 哪个命令可以用于显示输出并同时将输出发送到文件?

A. tee

B. cat

C. echo

D. pause

  1. 哪个命令可以用于更改运行中程序的 niceness 而无需停止和启动程序?

A. nice

B. touch

C. renice

D. updatedb

  1. 哪个命令可以用于恢复暂停的作业并将其放在后台运行?

A. bg

B. fg

C. gb

D. gf

  1. 通常用于存储别名的文件是哪个?

A. .bash_logout

B. .bash_history

C. .bashrc

D. .bash_login

答案

1. B 2. A 3. 4. C 5. A 6. D 7. A
8. A 9. B 10. C 11. A 12. B 13. C 14. D
15. B 16. D 17. B 18. B 19. A 20. B 21. A
22. B 23. A 24. A 25. D 26. B 27. C 28. B
29. A 30. C 31. D 32. B 33. C 34. D 35. A
36. C 37. B 38. A 39. C 40. C 41. A 42. D
43. A 44. C 45. B 46. D 47. B 48. A 49. D
50. B 51. C 52. A 53. B 54. C 55. B 56. C
57. D 58. A 59. C 60. A 61. C

第二十章:模拟考试 - 2

问题

  1. 哪个选项可用于与 netstat 命令一起使用以显示路由表?

A. -s

B. -a

C. -r

D. -d

  1. 使用 ifconfigip a 命令,IP 信息位于哪个地址族?

A. inet

B. inet6

C. int

D. int6

  1. 以下哪种是关闭接口的正确方法?

A. ifconfig down ens33

B. ifconfig ens33 down

C. ifconfig ens33 shutdown

D. ifconfig shutdown ens33

  1. ifup 命令在发出命令时检查哪个文件?

A. /etc/network/sysconfig

B. /etc/networking/interfaces

C. /etc/network/interfaces

D. /etc/sysconfig/network/interfaces

  1. 以下哪种是使用 ip 命令删除 IP 的正确方法?

A. ip a del 10.10.10.1/24 dev ens33

B. ip a 10.10.10.1/24 del dev ens33

C. ip a 10.10.10.1/24 dev ens33 del

D. ip del a 10.10.10.1/24 dev ens33

  1. *fdisk -l 命令的输出中代表什么?

A. 设备的分区标记为不可引导

B. 设备的分区标记为可引导

C. 设备的分区标记为只读

D. 设备的分区不可访问

  1. 哪个选项用于使用 fdisk 实用程序更改分区类型?

A. l

B. n

C. l

D. d

  1. 哪种数字类型代表使用 fdisk 实用程序的 NTFS 分区?

A. 7

B. 8

C. 6

D. 5

  1. 哪个选项用于使用 parted 实用程序更改分区的大小?

A. changesizepart

B. sizechangepart

C. resizepart

D. sizeresizepart

  1. 哪个选项可以用于使用 lsblk 命令显示驱动器的 UUID 等信息?

A. -a

B. -f

C. -l

D. -i

  1. 哪个选项用于使用 df 命令以人类可读的格式显示信息?

A. -a

B. -c

C. -r

D. -h

  1. 以下哪种是定义变量的正确方法?

A. a=1

B. a=Loop Free

C. a= 1 2 3

D. a=#1

  1. 哪个选项用于允许用户使用 mount 命令定义用户、uid、gid?

A. -v

B. -t

C. -u

D. -o

  1. 哪个命令可用于在 Fedora 发行版中切换显示管理器?

A. system-displaymanager

B. system-switch-displaymanager

C. switch-displaymanager

D. system-switch-display

  1. 哪个文件可以在 Ubuntu 发行版中保存默认的显示管理器?

A. /etc/X11/default-display-manager

B. /etc/X11/display/default-manager

C. /etc/X11/default-manager/display

D. /etc/X11/default-display/manager

  1. 哪个文件保存了给定用户执行的命令?

A. ~/.bash_history

B. /etc/.bash_history

C. /var/bash/.bash_history

D. /bash_history

  1. 哪个选项用于使用 useradd 命令显示新用户的默认值?

A. -d

B. -c

C. -D

D. -s

  1. 哪个文件保存了所有用户的实际哈希密码?

A. /etc/passwd

B. /etc/shadow

C. /etc/gshadow

D. /etc/hidden/password

  1. 哪个选项用于使用 useradd 命令为新用户定义 shell?

A. -s

B. -S

C. -shell

D. -Shell

  1. 哪个选项用于使用 chage 命令为用户定义过期日期?

A. -e

B. -l

C. -a

D. -E

  1. 哪个选项用于使用 passwd 命令显示有关帐户当前状态的信息?

A. -a

B. --status

C. -s

D. --list-status

  1. 哪个字母表示使用 passwd 命令时帐户的当前状态已解锁?

A. U

B. L

C. P

D. A

  1. 哪个选项显示了系统启动时的日期?

A. -a

B. -c

C. -r

D. -e

  1. 哪个命令显示最近登录的用户?

A. which

B. whois

C. last

D. recent

  1. 哪个命令用于创建一个组?

A. add-group

B. groupadd

C. add -G

D. group -G

  1. 哪个选项定义了一个用户将一个组用作其主要组?

A. -G

B. --group

C. --group-new

D. -g

  1. 哪个选项用于使用 netstat 命令仅显示 TCP 连接?

A. -t

B. -u

C. -r

D. -c

  1. HTTPS 使用哪个端口?

A. 80

B. 21

C. 443

D. 69

  1. 哪个命令处理 Fedora 28 发行版中的系统日志文件?

A. log

B. journalctl

C. log.service

D. logging.service

  1. 172.16.0.1属于哪个类别范围?

A. B 类

B. Class D

C. A 类

D. E 类

  1. TFTP 使用哪个端口?

A. 21

B. 53

C. 69

D. 443

  1. 哪个选项使用netstat命令打印程序 ID 和程序名称?

A. -r

B. -a

C. -l

D. -p

  1. 哪个选项用于仅列出systemctl命令的目标?

A. -t

B. -r

C. -type

D. -M

  1. 哪个命令可用于生成测试日志消息?

A. log-test

B. test-log

C. logger

D. log

  1. DNS 使用哪个端口?

A. 139

B. 110

C. 143

D. 53

  1. 哪个选项将 rsyslog 更改为使用 TCP 进行接收?

A. module(load="tcp")

B. module(load="imtcp")

C. module("imtcp"=load)

D. module("tcp"=load)

  1. 以下哪个是 rsyslog 的配置文件?

A. /etc/rsyslog.d/rsyslog.conf

B. /etc/rsyslog/rsyslog.conf

C. /etc/rsyslog.conf

D. /etc/rsyslog.d/rsyslog.service

  1. 以下哪个指定只有信息消息应发送到 rsyslog 服务器?

A. *.info

B. info.*

C. *.message-type=informational

D. message*.type=information

  1. 应将挂载点放在哪个配置文件中,以便在系统引导时自动挂载?

A. /etc/mounts.conf

B. /etc/auto.mount.cfg

C. /etc/fstab

D. /etc/mn.conf

  1. 哪个 mysql 选择语句是正确的?

A. select * from netaccess where set=public_places

B. select * from netaccess where custID='Philip'

C. select * from netaccess where custID=Philip

D. select * from netacces update set custID=Philip

  1. 哪个配置文件定义了名称服务器?

A. /etc/hosts

B. /etc/name.conf

C. /etc/resolv.conf

D. /etc/dig.conf

  1. 以下哪个代表链路本地 IPv6 范围?

A. fe80::/10

B. fd80::/7

C. fc00::/7

D. ff00::/10

  1. /etc/gshadow中的组没有设置密码时使用哪个字符?

A. #

B. %

C. !

D. &

  1. 用于更改给定组的组 ID 的命令是什么?

A. groupmod

B. groupadd

C. gidmod

D. usermod

  1. 以下哪个用于立即终止 sudo 身份验证计时器?

A. -l

B. -k

C. -a

D. -r

  1. 以下哪个用于立即终止 sudo 身份验证计时器?

A. -l

B. -k

C. -a

D. -r

  1. 以下哪个必须放在/etc/sudoers中的组前面?

A. #

B. @

C. %

D. &

  1. 哪个选项用于仅显示具有ip a 命令的特定接口?

A. s

B. d

C. v

D. i

  1. 哪个选项用于使用ip link命令定义类型?

A. --type

B. type

C. --link-type

D. --type-id

  1. 哪个 IP 代表本地环回地址?

A. 128.0.0.1

B. 192.168.0.1

C. 127.0.0.1

D. 127.0.0.0

  1. 以下哪个代表/28的子网掩码的点十进制格式?

A. 255.255.255.240

B. 255.255.252.240

C. 255.255.254.240

D. 255.255.253.240

  1. 使用ip命令显示统计信息和 CRC 计数器的哪个选项是正确的?

A. ip a -s link ls ens33

B. ip a -a link ls ens33

C. ip a -s -s link ens33

D. ip a -a -s link ls ens33

  1. 以下哪个 MySQL 选择语句是正确的,用于按降序对数据进行排序?

A. select * from Public_Places order by service_provided;

B. select * from Public_Places order by service_provided DESC;

C. select * from Public_Places DESC order by service_provided;

D. select DESC * from Public_Places order by service_provided;

  1. 哪个选项使用dpkg命令显示由软件包拥有的文件?

A. -a

B. -s

C. -l

D. -L

  1. 在 Linux 发行版中,SysV 中启动的第一个进程是什么?

A. SysV

B. ps

C. init

D. systemd

  1. 如果存在,哪个文件是符号链接到/boot/grub/grub.conf

A. /boot/grub/grub2.cfg

B. /boot/grub2/grub.cfg

C. /boot/grub.d/menu.lst

D. /boot/grub/menu.lst

  1. 为 GRUB2 添加自定义引导项应该使用哪个目录?

A. /etc/default/grub

B. /etc/grub.d/

C. /etc/grub/default/custom

D. /etc/default/grub-custom

  1. 在进行 CentOS7 安装时,默认的分区方案是什么?

A. ext4

B. ext3

C. LVM

D. XFS

  1. 哪个 shell 脚本关键字使用户能够在 if 子句中的条件未满足时测试另一个条件?

A. elif

B. elseif

C. else

D. fi

  1. 哪个 shell 脚本关键字定义了 while 循环的结束?

A. loop end

B. fi

C. else

D. done

答案

1. C 2. A 3. B 4. C 5. A 6. B
7. C 8. A 9. C 10. B 11. D 12. A
13. D 14. B 15. A 16. A 17. C 18. B
19. A 20. D 21. B 22. C 23. A 24. C
25. B 26. D 27. A 28. C 29. B 30. A
31. C 32. D 33. A 34. C 35. D 36. B
37. C 38. A 39. C 40. B 41. C 42. A
43. C 44. A 45. B 46. B 47. C 48. A
49. B 50. C 51. A 52. C 53. B 54. D
55. C 56. D 57. B 58. C 59. A 60. A

第二十一章:评估

第一章:配置硬件设置

  1. 答案是 A - /dev

  2. 答案是 D - cat /proc/cpuinfo

  3. 答案是 C - cat /proc/meminfo

  4. 答案是 C - free -h

  5. 答案是 C - mkswap

  6. 答案是 D - swapon

  7. 答案是 B - swapon

  8. 答案是 B - /dev/null

  9. 答案是 D - lsmod

  10. 答案是 D - modprobe

第二章:启动系统

  1. 答案是 A - 引导扇区

  2. 答案是 D - System V

  3. 答案是 C - pstree

  4. 答案是 B - init

  5. 答案是 D - systemd

  6. 答案是 C - systemctl list-unit-files

  7. 答案是 D - dmesg

  8. 答案是 C - /boot/grub/

  9. 答案是 A - 标题

  10. 答案是 C - menuentry

  11. 答案是 B - E

第三章:更改运行级别和引导目标

  1. 答案是 B - 5

  2. 答案是 C - runlevel

  3. 答案是 D - who -r

  4. 答案是 B - 在更改为当前运行级别之前的先前运行级别

  5. 答案是 D - 单用户

  6. 答案是 B - init

  7. 答案是 C - telinit

  8. 答案是 A - systemctl get-default

  9. 答案是 C - systemctl list-dependencies -type target

  10. 答案是 B - systemctl isolate multi-user.target

  11. 答案是 A - systemctl status multi-user.target

第四章:设计硬盘布局

  1. 答案是 C - fdisk - l /dev/sda

  2. 答案是 D - n

  3. 答案是 B - a

  4. 答案是 A - l

  5. 答案是 B - n

  6. 答案是 D - w

  7. 答案是 B - parted

  8. 答案是 C - print

  9. 答案是 A - mount /dev/sdb1

  10. 答案是 A - blkid

第五章:安装 Linux 发行版

  1. 答案是 C - RAM

  2. 答案是 D - 尝试 Ubuntu 而不安装

  3. 答案是 A - 安装 Ubuntu…

  4. 答案是 B - 一个活动的互联网连接

  5. 答案是 A - 其他

  6. 答案是 C - 主要

  7. 答案是 B - 为了防止系统因意外删除/boot 中的文件而无法启动

  8. 答案是 B - 我将配置分区

  9. 答案是 A - grub-install

  10. 答案是 D - Minimal Install

第六章:使用 Debian 软件包管理

  1. 答案是 B - dpkg is -l

  2. 答案是 C - dpkg-query -s

  3. 答案是 A - cat /var/log/dpkg.log

  4. 答案是 A - dpkg --get-selections

  5. 答案是 D - dpkg is -i

  6. 答案是 C - dpkg is -P

  7. 答案是 B - apt-get update

  8. 答案是 B - apt-cache search

  9. 答案是 B - apt-get purge

  10. 答案是 C - aptitude update

第七章:使用 YUM 软件包管理

  1. 答案是 B - yum list

  2. 答案是 A - yum makecache fast

  3. 答案是 D - yum provides

  4. 答案是 A - dpkg --get-selections

  5. 答案是 B - yum clean all

  6. 答案是 A - yum update

  7. 答案是 B - dnf repolist all

  8. 答案是 A - dnf check-update

  9. 答案是 C - rpm -qip

  10. 答案是 B - rpm --erase

第八章:执行文件管理

  1. 答案是 D - /

  2. 答案是 C - cd

  3. 答案是 B - pwd

  4. 答案是 A - ls

  5. 答案是 D - -l

  6. 答案是 C - -a

  7. 答案是 B - rm

  8. 答案是 C - -empty -delete

  9. 答案是 D - updatedb

  10. 答案是 D - tee

第九章:创建、监视、终止和重新启动进程

  1. 答案是 C - ps

  2. 答案是 C - -e

  3. 答案是 B - --forest

  4. 答案是 C - -u

  5. 答案是 B - -l

  6. 答案是 D - 9

  7. 答案是 A - -u

  8. 答案是 C - d

  9. 答案是 D - reload

  10. 答案是 D - /usr/lib/systemd/system

第十章:修改进程执行

  1. 答案是 B - l

  2. 答案是 A - NI

  3. 答案是 D - NI

  4. 答案是 C - 20

  5. 答案是 D - -20

  6. 答案是 B - /lib/systemd/system

  7. 答案是 A - systemctl daemon-reload

  8. 答案是 B - PID

  9. 答案是 A - fg

  10. 答案是 C - bg

第十一章:显示管理器

  1. 答案是 A - X 显示管理器

  2. 答案是 B - /etc/X11/xdm

  3. 答案是 A - Xaccess

  4. 答案是 C - /etc/sysconfig/desktop

  5. 答案是 B - groupinstall

  6. 答案是 C - system-switch-displaymanager

  7. 答案是 A - 会话类型

  8. 答案是 D - dpkg-reconfigure

  9. 答案是 C - /etc/X11/default-display-manager

  10. 答案是 B - ls -l /etc/systemd/system/display-manager.service

第十二章:管理用户和组帐户

  1. 答案是 D - /etc/skel/.bashrc

  2. 答案是 A - /etc.skel/.bash_logout

  3. 答案是 B - ~/.bash_history

  4. 答案是 C - -D

  5. 答案是 D - -s

  6. 答案是 D - user-add

  7. 答案是 B - -l

  8. 答案是 C - L

  9. 答案是 A - -g

  10. 答案是 C - groupmod

第十三章:自动化任务

  1. 答案是 B - 乱码时间

  2. 答案是 C - 在下周的上午 9:00

  3. 答案是 B - 按下了CTRL+ D

  4. 答案是 D - -l

  5. 答案是 D - -r

  6. 答案是 C - atq

  7. 答案是 C - *****

  8. 答案是 B - -e

  9. 答案是 C - @每周

  10. 答案是 A - -f

第十四章:维护系统时间和日志记录

  1. 答案是 A - -s

  2. 答案是 C - set-ntp

  3. 答案是 D - +%T

  4. 答案是 A - 设置时间

  5. 答案是 D - /etc/localtime

  6. 答案是 B - tzdata

  7. 答案是 B - tzselect

  8. 答案是 D - -u

  9. 答案是 D - TCP

  10. 答案是 C - 记录器

第十五章:互联网协议基础

  1. 答案是 C - 10.0.0.1

  2. 答案是 C - 192.168.0.1

  3. 答案是 A - 127.0.0.1

  4. 答案是 A - 169.0.0.1

  5. 答案是 A - 128.0.0.1

  6. 答案是 C - ff00::/8

  7. 答案是 B - ::0/0

  8. 答案是 C - ::1/128

  9. 答案是 D - fe80::/10

  10. 答案是 C - TCP 80

第十六章:网络配置和故障排除

  1. 答案是 D - -a

  2. 答案是 A - 默认

  3. 答案是 C - ICMP

  4. 答案是 B - /etc/hostname

  5. 答案是 C - tracepath

  6. 答案是 D - dig

  7. 答案是 A - ip -6 route add default via 2001:db8:0:f101::2

  8. 答案是 D - -ulp

  9. 答案是 C - nmap

  10. 答案是 B - whois

第十七章:执行管理安全任务

  1. 答案是 C - 生成

  2. 答案是 B - 替代用户

  3. 答案是 A - 根用户

  4. 答案是 B - -c

  5. 答案是 D - %

  6. 答案是 A - ssh-keygen

  7. 答案是 A - ssh-add

  8. 答案是 B - ssh-copy-id

  9. 答案是 B - -e

  10. 答案是 C - -r

第十八章:Shell 脚本和 SQL 数据管理

  1. 答案是 C - #!

  2. 答案是 A - SHELL

  3. 答案是 C - 完成

  4. 答案是 A - .

  5. 答案是 D - 读取

  6. 答案是 B - ||

  7. 答案是 C - *

  8. 答案是 C - 在哪里

  9. 答案是 B - 创建表

  10. 答案是 C - 更新

posted @ 2024-05-16 19:38  绝不原创的飞龙  阅读(128)  评论(0)    收藏  举报