序言

你将学到什么

本书是为计算机相关专业的Linux基础课程编写,也适合初学Linux的读者。如果你有些基础,本书也能查漏补缺。不要一次性看完本书,需要什么看什么,才是正确方法。

本书降低了Linux学习门槛,让读者有选择的在十分钟甚至一分钟内解决问题,快速、简单、连续、基础是本书的基本原则。本书还介绍了很多重要的Linux使用技巧,也提供了有关远程主机连接设置、文件检索、文档查询等内容。

应当具备的基础知识

本书假设读者已经掌握基本的计算机知识:

  • 了解鼠标、键盘、屏幕、硬盘(分区)、WIFI、网线等常用电脑软硬件;

  • 了解Windows控制面板,了解如何在Windows上安装软件;

  • 有简单的网络知识,比如IP地址;

  • 对Linux有简单的认识,知道或听说过Linux发行版名称。

本书假设读者没有Linux基础,内容安排是从零开始的。因此,对于那些不是计算机相关专业的读者来说,本书也是适用的。 需要指出的是,根据读者不同的知识背景,本书有多种不同的学习方案。对于那些有较强计算机基础的读者来说,可以有选择地学习。

关于Linux

通过本入门指南学习Linux基础,你将借助Linux强大的魔力、经验和技巧让生活更轻松,效果立竿见影。本书内容教你如何使用终端学习Linux,旨在为你打下坚实的基础,让Linux为你服务。最终,你不会成为Linux专家。如果这是你想要的(你应该这样做,这会让你变得更好),你会在路上一帆风顺,拥有正确的知识和技能来帮助你达到目标。

你将按照我准备的十章入门指南学习Linux。这里有直白的文字、命令说明、例子、捷径和最佳实践。

首先,Linux看起来令人生畏、复杂和害怕。实际上,Linux非常简单直接(学过的人都这么说),一旦你完成了下面的部分,你就会明白发生了什么。

Linux的哲学:每个程序只做一件事。 Linux提供一堆砖块,你用砖块组合创造出特定的工具(集),用来解决某件事情。只要有一点创造力和逻辑思维,加上对程序模块工作方式的理解,你就可以组装出几乎能做任何事的工具(集)。我喜欢 "偷懒" 才用Linux。

可能有个问题在你脑子闪过,
"为什么我要麻烦学习Linux?图形界面更好用,也能很好的完成我所想的。"

某种程度上你是对的,我绝对不建议你抛弃图形界面。有些任务适合图形界面,文字处理、视频编辑是最好的例子。同时,有些任务更适合Linux,比如数据处理(报告)、文件管理。在这两种环境中,有些任务处理起来又没什么不同。将Linux加入你的武器库,才能如虎添翼。像往常一样,挑选合适的工具做事。

本书的组织

本书分为十三个章节。通常,我推荐你按顺序学习。假如你阅读本书是为了特定的需求,请忽略我的建议。你现在可以开始学习,或者阅读下面的内容,进一步了解本书。

  1. 安装虚拟机 - 熟悉虚拟机软件基本使用,并安装CentOS7;

  2. 客户端工具 - 介绍客户端工具,怎样使用工具连接远程主机;

  3. 传输文件 - 学习怎样用MobaXterm或 scp 命令上传下载文件或目录;

  4. 文件、目录与路径 - 了解什么是文件,什么是目录,认识相对路径和绝对路径;

  5. 文件和目录管理 - 练习文件和目录的创建、查看、编辑、压缩和解压等基础操作;

  6. 文件属性 - 了解用户、组和文件权限,熟悉基本操作;

  7. 输入输出重定向 - 了解标准输入、标准输出、标准错误;

  8. 管道 - 了解命令管道的组合应用;

  9. 常用命令 - 认识高频使用的Linux命令,练习基本使用;

  10. 内容搜索 - 练习搜索文件内容;

  11. 文件定位 - 增强文件检索能力;

  12. 软件包管理 - 练习安装卸载软件包,查看软件包信息等;

  13. 服务管理 - 关于服务管理的最佳实践。

1. 安装虚拟机

为方便练习,推荐使用虚拟机安装Linux。学会用最关键,以后再考虑在笔记本、PC或服务器等真机上安装Linux。

提到虚拟机软件,你可能听说过 VMware Workstation(下称 VM)。VM 功能丰富又强大,自然价格不便宜。

我不推荐使用 VM 的破解版,可能出现各种莫名问题,不稳定,捆绑软件甚至病毒。同时,作为IT行业的(可能)从业者,希望你一样尊重作者的版权。

VirtualBox (下称 VBOX)是一款免费、简单好用、稳定的虚拟机软件,用过的人都说好。

关于Linux发行版,我们选择红帽系、免费、稳定好用的CentOS。为什么不选择Ubuntu?因为,多数企业选择红帽或CentOS。

本教程将使用VBOX和CentOS,让你快速学会Linux基本使用。

VBOX依赖CPU的虚拟化支持,否则会提示“虚拟化未开启”之类的错误。

笔记本或台式机通常默认开启了CPU虚拟化支持。
品牌办公机、迷你一体机(苹果除外)之类的电脑由于成本问题,可能CPU不支持虚拟化技术。

怎么启用CPU虚拟化?

请在开机界面按特殊按键,进入BOIS设置。
具体设置步骤各不相同,请在搜索引擎搜索关键字,比如“Thinkpad E495 CPU 启用 虚拟化”、“神舟 战神 CPU 启用 虚拟化”。

1.1. 下载软件

请选择速度快的下载地址

1.1.2. CentOS7镜像文件

访问下载服务器地址,找到安装光盘的ISO文件,下载之。

建议下载迷你版安装光盘,文件名带 Minimal 字样。

如,"CentOS-7-x86_64-Minimal-2009.iso"。

阿里云镜像服务器地址

https://mirrors.aliyun.com/centos/7/isos/x86_64/

网易镜像服务器地址

https://mirrors.163.com/centos/7/isos/x86_64/

1.2. VirtualBox介绍

VirtualBox官网

https://www.virtualbox.org/

VirtualBox是一款强大的x86和AMD64/Intel64虚拟化产品,适用于企业和个人。作为通用的x86硬件全虚拟化器,志在服务器、桌面和嵌入式领域。

VirtualBox有极其丰富的功能和高性能以满足企业客户,同时也是唯一一款使用GPL协议开源的虚拟机软件,无需购买即可使用所有(高级)功能。

当前,VM可以运行在以下系统上:

Windows hosts (64-bit)
  • Windows 8.1

  • Windows 10 RTM (1507 / 2015 LTSB) build 10240

  • Windows 10 Anniversary Update (1607 / 2016 LTSB) build 14393

  • Windows 10 Fall Creators Update (1709) build 16299

  • Windows 10 April 2018 Update (1803) build 17134

  • Windows 10 October 2018 Update (1809 / 2019 LTSC) build 17763

  • Windows 10 May 2019 Update (19H1 / 1903) build 18362

  • Windows 10 November 2019 Update (19H2 / 1909) build 18363

  • Windows Server 2012

  • Windows Server 2012 R2

  • Windows Server 2016

  • Windows Server 2019

Mac OS X hosts (64-bit)
  • 10.13 (High Sierra)

  • 10.14 (Mojave)

  • 10.15 (Catalina)

Linux hosts (64-bit). Includes the following
  • Ubuntu 18.04 LTS, 19.03 and 19.10

  • Debian GNU/Linux 9 ("Stretch") and 10 ("Buster")

  • Oracle Linux 6, 7 and 8

  • Red Hat Enterprise Linux 6, 7 and 8

  • Fedora 30 and 31

  • Gentoo Linux

  • SUSE Linux Enterprise server 12 and 15

  • openSUSE Leap 15.1

随着VirtualBox活跃的开发,更快的版本更新,支持的系统和平台越来越多,越来越多的用户选择了它。

1.3. 在Windows上安装VirtualBox

1.3.1. 安装VirtualBox

  1. 找到刚才下载的 VBOX 安装包并双击运行

安装VirtualBox-1
  1. 单击安装界面的 “下一步”

安装VirtualBox-2
  1. 根据需要修改安装路径,建议保持默认不修改。然后单击 “下一步”

安装VirtualBox-3
  1. 保持默认勾选,直接单击 “下一步”

安装VirtualBox-4
  1. 单击 “是” 安装 VBOX 的网络功能

安装VirtualBox-5
  1. 直接单击 “安装”

安装VirtualBox-6
  1. 自动安装过程一

安装VirtualBox-7
  1. 自动安装过程二

安装VirtualBox-8
  1. 自动安装过程三

安装VirtualBox-9
  1. 自动安装过程四

安装VirtualBox-10
  1. 自动安装过程五

安装VirtualBox-11
  1. 直接单击 “完成”

安装VirtualBox-12
  1. 安装成功后,会自动运行 VBOX 软件,如下图所示:

安装VirtualBox-13

1.3.2. 安装VirtualBox扩展包

VBOX 的高级功能依赖于扩展包,包括 USB 2.0 和 USB 3.0 设备,VirtualBox 远程桌面,硬盘加密,NVMe(M2)固态硬盘等。

  1. 双击运行扩展包安装程序

安装VirtualBox-14
  1. 单击弹出窗口上的 “安装”

安装VirtualBox-15
  1. 拖动许可协议窗口右边滚动栏,拉到底部(重要!!!!!!)

安装VirtualBox-16
  1. 拉到底部之后,灰色不可用的 “我同意” 按钮变为可点击。然后,单击 “我同意”

安装VirtualBox-17
  1. 一切顺利的话,很快就能看到成功安装的提示框

安装VirtualBox-18

至此,VBOX 基础软件和扩展包已经安装完毕。

1.4. 创建第一个虚拟机

我前面提过,本教程使用 CentOS7(Linux发行版)作为系统平台。

根据下面的提示创建第一个(CentOS7)虚拟机。

1.4.1. 创建虚拟机

  1. 打开 VBOX 软件,在界面上单击 “新建” 按钮

创建第一个虚拟机-1
  1. 修改 “新建虚拟电脑” 中的 “名称”,这里我以 “CentOS7” 为例。至于 “文件夹”,建议新手默认,高级用户随意。其它设置保持默认,新手请勿修改。

创建第一个虚拟机-2
  1. 出于个人习惯,我将 “文件夹” 指定到了 D 盘

创建第一个虚拟机-3
  1. 同样根据个人需要自行修改 vdi 文件位置,新手默认。第一个虚拟机 “文件大小” 直接默认8G就虚拟机文件行,其余全部默认。然后,单击 “创建”

创建第一个虚拟机-4
  1. 创建完成

创建第一个虚拟机-4-0

1.4.2. 设置虚拟机

根据教程内容,你需要设置光驱加载ISO文件和桥接网卡。

  1. 注意下图中的 “[光驱] 没有盘片” 和 “网络地址转换(NAT)” ,单击 “设置”

创建第一个虚拟机-5
  1. 弹出默认虚拟机设置

创建第一个虚拟机-6
  1. 找到 “存储” 中的 “控制器:IDE”

创建第一个虚拟机-7
  1. 单击 “分配光驱” 后面的光盘图标

创建第一个虚拟机-8
  1. 选择 “Choose a disk file…​”

创建第一个虚拟机-9
  1. 找到提前下载好的ISO文件并单击,然后单击 “打开”

创建第一个虚拟机-10
  1. 设置效果,如图所示:

创建第一个虚拟机-11
  1. 不过,我们还需要修改开机启动顺序,设置为开机光驱启动。选择 “第一IDE控制器主通道”

创建第一个虚拟机-12
  1. 最终设置,如下图所示:

创建第一个虚拟机-13
  1. 接下来设置网卡,单击左侧的 “网络”

创建第一个虚拟机-14
  1. 单击 “连接方式(A)”

创建第一个虚拟机-15
  1. 选择列表中的第二个,即 “桥接网卡”

创建第一个虚拟机-16
  1. 界面名称保持默认,不要改动。否则可能导致网络不同。

创建第一个虚拟机-17
  1. 设置完毕,如图所示:

创建第一个虚拟机-18
  1. 单击 “OK”,回到软件主界面,光驱和网卡对应的文字已经发生变化。

创建第一个虚拟机-19

1.5. 在虚拟机中安装CentOS(上)

通常,
我说的 “单击” 是指点击鼠标左键 icon mouse left click,
我说的 “右击” 是指点击鼠标右键 icon mouse right click。

1.5.1. 开始

鼠标左键 icon mouse left click

单击虚拟机屏幕中的任何地方后,鼠标和键盘会被虚拟机捕获。之后,鼠标和键盘输入将对虚拟机有效,方便在虚拟机中输入文字等。不要紧张,你不是对它们失去了控制!

键盘右侧 Ctrl

鼠标键盘被捕获后,输入操作已经完成,用来退出虚拟机屏幕。按一下,会看到鼠标恢复正常控制。

  1. 打开 VBOX 软件界面,选中左侧的 “CentOS7” ,然后单击 “启动”

在虚拟机中安装CentOS(上)-1
  1. 虚拟机 “电源” 通电后,你会看到如下界面

在虚拟机中安装CentOS(上)-2
  1. icon mouse left click 单击右上角的蓝色 ch01.s5 3 close ,关闭提示

在虚拟机中安装CentOS(上)-3
  1. 关闭提示后,如图所示:

在虚拟机中安装CentOS(上)-4
  1. icon mouse left click 单击黑色背景区域,让鼠标被虚拟机捕获。这时,你可以使用键盘 箭头选择菜单中的 “Install CentOS 7”

在虚拟机中安装CentOS(上)-5
  1. 敲 Enter,启动安装过程

在虚拟机中安装CentOS(上)-6
  1. 等待启动完成,通常需要20秒左右

在虚拟机中安装CentOS(上)-7

1.5.2. 安装(上)—— 基本参数设置

鼠标左键 icon mouse left click

单击虚拟机屏幕中的任何地方后,鼠标和键盘会被虚拟机捕获。之后,鼠标和键盘输入将对虚拟机有效,方便在虚拟机中输入文字等。不要紧张,你不是对它们失去了控制!

键盘右侧 Ctrl

鼠标键盘被捕获后,输入操作已经完成,用来退出虚拟机屏幕。按一下,会看到鼠标恢复正常控制。

  1. CentOS 7 安装界面——欢迎界面

在虚拟机中安装CentOS(上)-8
  1. icon mouse left click 单击右上角的蓝色 ch01.s5 3 close ,关闭提示

在虚拟机中安装CentOS(上)-9
  1. 单击虚拟机屏幕,输入英文 “chinese” ,正上方会出现你要找的 “中文”

在虚拟机中安装CentOS(上)-10
  1. 选择 “中文” → “简体中文(中国)” ,然后单击 “继续”

在虚拟机中安装CentOS(上)-11
  1. CentOS 7 安装界面——安装信息摘要。稍等一会儿,下方灰色区域会变为可操作

在虚拟机中安装CentOS(上)-12
  1. 如图所示:

在虚拟机中安装CentOS(上)-13
  1. 向下拖动右边 隐藏 的滚动条,或使用鼠标滚轮向下拖动

在虚拟机中安装CentOS(上)-14
  1. 找到 “系统” → “安装位置”

问:为什么不使用自动分区?

答:
自动分区确实方便。安装程序默认会使用LVM创建卷,系统会安装在卷上。
以后你有可能学习硬盘分区或文件系统相关知识,LVM会引入不必要的复杂度,越学越蒙。
见过很多头铁不听忠告的,遇到问题要么学LVM要么手动分区。

如果你能hold住,欢迎尝试LVM。

1.5.3. 安装(上)—— 设置分区

鼠标左键 icon mouse left click

单击虚拟机屏幕中的任何地方后,鼠标和键盘会被虚拟机捕获。之后,鼠标和键盘输入将对虚拟机有效,方便在虚拟机中输入文字等。不要紧张,你不是对它们失去了控制!

键盘右侧 Ctrl

鼠标键盘被捕获后,输入操作已经完成,用来退出虚拟机屏幕。按一下,会看到鼠标恢复正常控制。

在虚拟机中安装CentOS(上)-15
  1. 单击 “安装位置”

在虚拟机中安装CentOS(上)-16
  1. “设备选择” 能看到之前配置的8G硬盘,保持勾选状态。

在虚拟机中安装CentOS(上)-17
  1. 单击 “我要配置分区”

在虚拟机中安装CentOS(上)-18
  1. 然后,单击 “完成” 按钮

在虚拟机中安装CentOS(上)-19
  1. 会自动弹出 “手动分区” 界面

在虚拟机中安装CentOS(上)-20
  1. 单击 “新挂载点将使用以下分区方案” 下的列表,选择 “标准分区”

在虚拟机中安装CentOS(上)-21
  1. 然后,单击上方的 “点这里自动创建他们”

在虚拟机中安装CentOS(上)-22
  1. 系统帮助你创建的分区如下:

在虚拟机中安装CentOS(上)-23
  1. 这里没什么要修改,直接单击 “完成”

在虚拟机中安装CentOS(上)-24
  1. 弹出 “更改摘要”

在虚拟机中安装CentOS(上)-25
  1. 选择 “接受更改”

在虚拟机中安装CentOS(上)-26

1.5.4. 安装(上)—— 网络设置

鼠标左键 icon mouse left click

单击虚拟机屏幕中的任何地方后,鼠标和键盘会被虚拟机捕获。之后,鼠标和键盘输入将对虚拟机有效,方便在虚拟机中输入文字等。不要紧张,你不是对它们失去了控制!

键盘右侧 Ctrl

鼠标键盘被捕获后,输入操作已经完成,用来退出虚拟机屏幕。按一下,会看到鼠标恢复正常控制。

  1. 分区设置完毕,又回到了欢迎界面。然后,单击 “网络和主机名” ,设置网络参数

在虚拟机中安装CentOS(上)-27
  1. 如图所示:

在虚拟机中安装CentOS(上)-28
  1. 将右边的网络开关按钮切换至 “打开” 。网络如果正常,旁边会显示IP地址信息。

在虚拟机中安装CentOS(上)-29
  1. 至于主机名看个人心情设置

主机名只能使用英文字母、数字、下划线和点,长度不能超过30个字符
在虚拟机中安装CentOS(上)-30
  1. 网络参数设置完毕,单击 “完成”

在虚拟机中安装CentOS(上)-31
  1. 回到欢迎界面,可以看到网络已经连接

在虚拟机中安装CentOS(上)-32

1.6. 在虚拟机中安装CentOS(下)

  1. 所有安装参数已经设置完毕,单击 “开始安装” 继续安装

在虚拟机中安装CentOS(下)-1
  1. 安装进行中,这时单击 “ROOT 密码” ,设置 root 用户密码

在虚拟机中安装CentOS(下)-2
  1. 第一次装虚拟机密码请尽量简单,方便记忆

在虚拟机中安装CentOS(下)-3
  1. 比如,你可以设置为 12345678

云服务器、云数据库等任何连接到互联网的系统或服务,请保证密码足够安全。123456、admin 等这种密码是绝对不安全的。
在虚拟机中安装CentOS(下)-4
  1. 第二次输入密码

在虚拟机中安装CentOS(下)-5
  1. 单击 “完成” 。如果你的密码少于六位数,必须 单击两次 才能设置成功,可以忽略 黄色警告 提示

在虚拟机中安装CentOS(下)-6
  1. 安装进行中

在虚拟机中安装CentOS(下)-7
  1. 安装进行中

在虚拟机中安装CentOS(下)-8
  1. 安装完成

在虚拟机中安装CentOS(下)-9
  1. 单击 “重启” 按钮

“重启” 操作只对虚拟机有效,不会重启你的 Windows。
在虚拟机中安装CentOS(下)-10

1.7. 启动CentOS

  1. 执行重启后,虚拟机会忽略之前设置的光驱启动,直接从刚才安装的 “CentOS7” 启动

启动CentOS-1
  1. 启动完成,进入登录界面

启动CentOS-2
  1. 单击虚拟机屏幕,进入虚拟机并输入用户名 root,密码 12345678,然后按 Enter。如果登录失败,会再次提示输入用户名和密码。

输入密码时,为了安全,系统不会在屏幕上显示密码或星号。不要为 “Password” 后面不显示而困扰。
启动CentOS-3
  1. 进入系统后,执行命令 ip a 查看IP地址(192.168.2.236)。请记住这个地址,下一章你需要使用客户端工具,通过网络连接CentOS7。

启动CentOS-4

2. 客户端工具

你需要了解这些
  • 通常支持客户端工具的工具,我们统称为 客户端工具;

  • Linux(如之前安装的 CentOS 7)上自带客户端工具(Linux终端)。

2.1. 客户端工具介绍

2.1.1. 图形界面工具

Linux社区有许多免费的图形化连接工具,足够日常使用,不需要使用收费软件,也没必要使用破解软件。比如Xshell、SecureCRT等。
Putty(开源)

迷你版的连接工具,欠缺方便的标签管理功能,每次连接远程主机比较麻烦。

不推荐作为主力工具使用。

MobaXterm(免费版)

强烈推荐Windows用户使用

主要特性
  • 支持Linux(SSH)、telnet、VNC、Windows(RDP)连接;

  • 支持X11-Forwarding;

  • 自动SFTP浏览支持;

  • 最多保存12个服务器标签(session);

  • 最多同时建立两个连接隧道。

2.1.2. 命令行工具

WSL终端

WSL是Windows 10上的迷你Ubuntu系统,能够运行几乎所有Linux命令,没有图形界面。可以把WSL看做运行在Windows 10系统下的Linux终端。

如果你使用Windows 10做主力系统,又能接受没图形界面,请移步 客户端工具之Linux终端 。

Linux终端

Linux系统自带的命令行工具,配合 ssh 命令连接远程主机非常方便。

如果你使用Linux做主力系统,请移步 客户端工具之Linux终端 。

2.1.3. 最后

现在,我开始介绍Windows下好用、功能丰富又免费的MobaXterm。

2.2. MobaXterm安装

2.2.2. 安装

解压下载的文件 MobaXterm_Installer_v12.4.zip,双击运行解压后的 MobaXterm_Installer_v12.4.msi。

ch02.s2-1

MobaXterm和大多数Windows软件一样,都使用安装向导。当你准备好之后,单击 Next 按钮。

ch02.s2-2

同意软件用户协议,勾选 " I accept the terms in the License Agreement" ,继续安装。

ch02.s2-3

软件安装位置,保持默认即可。

ch02.s2-4

单击 Install 开始安装。

ch02.s2-5

MobaXterm安装完成。

ch02.s2-6

2.2.3. 运行

安装后,可以在开始菜单中找到MobaXterm。

ch02.s2-7

桌面上也有MobaXterm快捷方式,双击MobaXterm图标,运行看看。

ch02.s2-8

2.2.4. 最后

你也看见了,MobaXterm启动后是英文界面。

可能有人正在百度搜索 "MobaXterm中文破解版"、"MobaXterm中文绿色版"。

MobaXterm不支持中文 ,你也不需要中文,不要高估自己的需求。

照猫画虎,跟着我学会日常使用。

2.3. MobaXterm连接远程主机

MobaXterm把连接称为Session,每个连接对应一个Session,在Session中可以配置连接参数(IP地址、端口、帐号、密码、私钥等)。

"连接" 在这里是名词,表示从你电脑到远程主机之间的一个网络连接。连接是你和远程主机的一个通道,通道拥有地址(IP地址)、车道(端口)、车牌号(帐号)等等属性。

单击 Session 按钮,创建一个连接。

ch02.s3-1

选择 SSH 按钮。

ch02.s3-2

这时,你可以看到 "Basic SSH settings" 标签,包含连接的基本信息。

功能说明
Remote Host

远程主机IP地址

Specify username

用户名

Port

端口

ch02.s3-3

"Remote Host" 中输入远程主机IP地址(192.168.2.236)。

不知道自己虚拟机IP地址?

请参考“准备VirtualBox虚拟机”→“1.7. 启动CentOS”查看远程主机IP地址。

ch02.s3-4

勾选 " Specify username"。

ch02.s3-5

输入用户名:root,单击 OK 按钮连接远程主机。

ch02.s3-6

在黑色窗口中,输入远程主机密码,然后按 Enter 键。

输入密码时,屏幕上不会显示密码。
ch02.s3-7

MobaXterm会提示是否保存远程主机密码。勾选 " Do not show this message again",按 Yes 按钮保存密码。

ch02.s3-8

一切顺利的话,你可以看到下面这样的提示信息。

ch02.s3-9

也许你好奇左边的目录是什么?

下一小节会介绍简单使用,更多的会在第三章中介绍。

2.4. MobaXterm设置无密码登录

2.4.1. 选择?

MobaXterm有记住密码功能,连接远程主机不会提示密码,使用方便。

这对大多数人来说已经足够,对无密码登录(密钥登录)没有需要,请跳过本节内容。

如果你有以下情况,建议开始阅读以下内容:

  • 远程主机未开启密码登录支持,仅支持密钥登录;

  • 可能存在多终端设备(如Windows、Mac、手机等)连接远程主机的情况;

  • 重视个人隐私,不希望有软件记录远程主机密码。

我笔记本的主力系统是Archlinux,写文案偶尔会切换到Windows系统。外出使用安卓手机的 JuiceSSH 终端。没有密钥登录,我简直寸步难行。想想远程主机的超长随机密码…​…​
本节操作步骤较多,慢慢操作,不要 "迷路" 。

2.4.2. 密钥对介绍

密码不方便记忆,有时候为了安全设置长密码让问题更凸显,也有时候是因为远程主机太多。

我个人的习惯是第一次登录之后立刻设置无密码登录,业内大家更喜欢称为密钥登录。

如果你是第一次使用无密码登录,需要生成密钥对。密钥对生成后,可以重复使用,不需要每次生成。我的远程主机使用密钥对已经超过十年。

如果你有密钥对,直接上传公钥(锁)到远程主机,使用私钥(钥匙)可以登录远程主机。不用再生成密钥对。

在开始之前,需要说明一下。

密钥对包括两个文件:私钥文件(Private Key),公钥文件(Public Key)。

私钥文件

相当于门钥匙,作为登录远程主机的关键。

公钥文件

相当于门锁,只要有钥匙就可以打开。公钥文件可以发布到任何地方,不需要保密。

私钥文件不能外泄,否则远程主机有严重的安全风险。

2.4.3. 生成密钥对

生成密钥对

MobaXterm的 "Tools" 中包含很多实用工具,也包含了密钥生成工具。

单击 Tools  MobaKeyGen(SSH key generator),打开操作界面。

ch02.s4-1

单击 Generate 按钮,开始生成密钥对。

ch02.s4-2

移动鼠标可以产生更多随机数,从而加速过程。

ch02.s4-3

生成需要约一分钟。

ch02.s4-4

密钥对生成完毕。

ch02.s4-5
准备工作

新建名为 "ProLinux" 的文件夹,用来保存公钥文件和私钥文件。

如,我在 D: 盘新建文件夹 "ProLinux":

ch02.s4-7
ch02.s4-8
如何新建文件夹? 鼠标右键  新建(W)  文件夹(F)

最终,我的文件夹绝对路径为:

"D:\ProLinux"

保存公钥

配置无密码登录不能直接用 Save public key 功能保存公钥,必须直接复制公钥内容才行。

ch02.s4-6

具体操作见下文。

复制下图文本框中的所有内容:

ch02.s4-6-1

双击进入 "ProLinux" 文件夹 → 新建一个 "文本文档" → 文件名设置为 "mk.pub":

ch02.s4-9
怎样新建文本文档? 在 "mk.pub" 文件上,单击 鼠标右键  新建(W)  文本文档

最后,用记事本打开 "mk.pub" 文件 → 粘贴公钥内容 → 按 Ctrl+S 保存:

ch02.s4-9
怎样用记事本打开? 鼠标右键  打开方式  记事本
保存私钥

单击 Save private key 按钮,开始保存 私钥文件 操作。

ch02.s4-10

未设置私钥密码,MobaXterm会弹出警告,选择 是(Y) 忽略之。

私钥密码相当于再给锁上加锁,更安全。即便遗失,也不用担心。连接远程主机时,必须输入密码才能使用私钥。
普通人不需要这样的安全等级,不需要设置私钥密码。
ch02.s4-11

进入刚才创建的 "ProLinux" 文件夹,在 "文件名(N):" 中填写私钥文件名,此处以 mk 为例。单击 保存(S) 按钮,保存文件。

保存类型(T) 默认是 "*.ppk",最终私钥文件名为 "mk.ppk"。
ch02.s4-12
查看密钥文件

按照步骤操作完毕后,会得到两个文件:

mk.pub

公钥文件,必须上传到远程主机(详情见下一小节)。

mk.ppk

私钥文件,在MobaXterm的Session属性中启用之后,连接远程主机生效(详情见下一小节)。

ch02.s4-13

2.4.4. 上传公钥

为降低难度,不打算让你 编辑文件,不管是 本地 还是 远程主机 上。

在准备好配置文件之后,让你用鼠标操作完成设置,简单直接。

设置完成后,在远程主机上的 ~/.ssh/authorized_keys 文件中会包含你的公钥。

准备authorized_keys文件

选中 "mk.pub" 按 Ctrl+C 复制文件。

ch02.s4-14

然后,直接按 Ctrl+V 粘贴文件,如图中的 "mk - 副本.pub"。

ch02.s4-15

选中文件 "mk - 副本.pub",按 F2 重命名文件名为 "authorized_keys"。

双击浏览器中的文字会直接选中,按 Ctrl+C 复制即可,比如上面的 "authorized_keys"。
ch02.s4-16

接着你会看见下面这个提示,选择 是(Y)。

ch02.s4-17

配置文件准备好了。

ch02.s4-18
上传公钥

双击 User sessions  192.168.2.236(root) 连接远程主机。

ch02.s4-19

下图左边的内容被称为目录树,可以用鼠标操作或编辑文件。
单击 "/root/" 上方中间的黄色 图标,

ch02.s4-20

创建名为 ".ssh" 的隐藏文件夹。

Linux系统中,以点 "." 开头的文件或文件夹均为隐藏文件。 ls 命令查看时,需要带参数 a,这样:ls -a。
ch02.s4-21

结果如图所示,然后双击进入 ".ssh" 文件夹。

ch02.s4-22

接着单击浅蓝色向上箭头 图标上传文件。

ch02.s4-23

在弹出的选择框中,找到 "Prolinux" 文件夹下的 "authorized_keys" 文件,双击选择。

ch02.s4-240

上传成功后,在目录树中会看到 "authorized_keys"。

ch02.s4-25
先不要关闭连接标签,接着配置SELinux。
关闭SELinux
SELinux功能过于复杂,关闭之是最好选择。否则,无密码登录将会失败。

在已经打开的连接标签中,复制下面三条命令,粘贴到黑色窗口中,然后敲回车执行:

echo SELINUX=disabled>/etc/selinux/config
echo SELINUXTYPE=targeted>>/etc/selinux/config

reboot

执行成功后,CentOS系统会被重启。等待重启成功后,可以继续后面的操作。

2.4.5. 启用私钥

选择 User sessions  192.168.2.236(root)  Edit session 编辑远程主机配置参数。

ch02.s4-27

弹出设置界面:

ch02.s4-28

选择 "Advanced SSH settings" 标签,找到 "User private key" 参数,单击输入框尾部的文件 图标。

ch02.s4-29

弹出文件选择框,双击私钥文件 "mk.ppk"。

ch02.s4-30

设置效果如图所示,单击 OK 保存配置。

ch02.s4-31

2.4.6. 测试无密码登录

启用私钥后,必须关闭连接。重新连接远程主机,才能确认私钥是否有效。

在MobaXterm主界面双击 User sessions  192.168.2.236(root),测试连接远程主机。

ch02.s4-32

如果登录成功,说明密钥设置没问题。

ch02.s4-33

3. 传输文件

本章内容是为有传输文件需求的你准备的,可以先跳过。等你准备好时,再来实践学习。

打开你的MobaXterm,连接上远程主机,开始练习…​…​

3.1. 用MobaXterm上传下载文件

3.1.1. 准备文件

为减少操作步骤,我会使用 Windows终端 简称(终端)创建文件。

打开Windows终端

在文件资源管理器中打开 D:\ProLinux,单击地址栏:

ch03.s1-1

输入 "cmd",按 Enter 键。

ch03.s1-2

Windows终端 如下图所示:

ch03.s1-3
创建文件
创建目录和文件相关操作都在终端中完成。
  • 在终端中创建目录,名称为 "files":

mkdir files
  • 在目录 "files" 下创建名为 "foo.txt" 的文件,文件内容为 "test text: foo":

echo 'test text: foo' > files/foo.txt
ch03.s1-11
  • 同样的方式创建 "bar.txt"

echo 'test text: bar' > files/bar.txt
ch03.s1-12
  • 查看目录 "files" 下的文件,确认是否创建成功:

dir files
ch03.s1-13
Figure 1. 操作演示
D:\ProLinux>dir files
 驱动器 D 中的卷没有标签。
 卷的序列号是 B4E5-398C

 D:\ProLinux\files 的目录

2020/02/26  17:18    <DIR>          .
2020/02/26  17:16    <DIR>          ..
2020/02/26  17:18                19 bar.txt
2020/02/26  17:17                19 foo.txt
               2 个文件             38 字节
               2 个目录 240,456,257,536 可用字节
  • 关闭终端

  • 在文件资源管理器中查看:

ch03.s1-4
ch03.s1-5

3.1.2. 上传文件或目录

登录远程主机之后,直接(按住左键)将 "files" 目录拖拽到MobaXterm左边的目录树:

ch03.s1-6
确认上传
  • 方法一:MobaXterm目录树

ch03.s1-7
ch03.s1-8
  • 方法二:Linux命令

    • 查看 "files" 目录:

ls -l ~
操作演示
[root@prolinux ~]# ls -l
total 4
-rw-------. 1 root root 1305 Dec  7 16:31 anaconda-ks.cfg
drwxr-xr-x. 2 root root   36 Feb 26 17:42 files
  • 查看 "files" 目录下的文件:

ls -l files/
操作演示
[root@prolinux ~]# ls -l files/
total 8
-rw-r--r--. 1 root root 19 Feb 26 17:42 bar.txt
-rw-r--r--. 1 root root 19 Feb 26 17:42 foo.txt

屏幕截图:

ch03.s1-9

3.1.3. 下载文件或目录

下载和上传方法都是一样的,直接把MobaXterm目录树中显示的文件或目录拖拽到本地就行了。

上传

MobaXterm目录树 Windows文件资源管理器

下载

Windows文件资源管理器 MobaXterm目录树

4. 文件、目录与路径

本章使用Gnome桌面+Linux终端完成演示效果

4.1. 什么是文件

Linux以文件的形式储存数据,常见的文件有图片、Word文档、PPT、PDF等等。

常以名称、大小来描述一个文件。

如下图所示:

ch04.s1-1
ch04.s1-1.1

4.1.1. 文件名称

ch04.s1-2
ch04.s1-2.1

上图的 "pic10" 是 名称 ,".jpg" 是 扩展名 ,合在一起就是完整的文件名称 "pic10.jpg"。

什么是文件名称?
呃呃呃…​就是一个名字(dog脸)。

为什么你知道 "pic10.jpg" 是一个图片文件,"book.pdf" 是一个PDF文件?
还不是因为扩展名。

那在Linux中扩展名有什么用呢?
小声告诉你~
其实没用,只为好看而已。

在Windows中,文件扩展名决定了Windows会用哪个软件打开。

最后要强调一下:

文件名称甚至扩展名只是一个名字,文件名称不影响文件内容或文件类型。

4.1.2. 文件大小

ch04.s1-3
ch04.s1-3.1

上面这个截图说,"pic10.jpg" 文件大小为 "72.3KB" 或 "72,322 字节"。

文件大小的基本度量单位是 byte(字节)。

大文件用字节表示时太长,可以用千字节(KiB/kB)、兆(MiB/MB)、吉(GiB/GB)、太(Tib/TB)来表示。

“为什么有Kib,又有KB?有什么不同?”
“因为采用的度量标准不同,Kib是用2的整数次幂计算(二进制乘数词头标准),kB是用10的整数次幂计算(国际单位制词头标准)。” “全部用byte(字节)表示就没这个问题(机智),就是太长(微笑)。”


举栗子,

“1. 我要换个头像,这张200kB的看起还将就~”

200kB = 200千字节 = 200 * 10的3次方字节 = 200000byte

“2. 新买的手机拍照效果很好,照片分辨率2592x3840,每张大概4MB、5MB的样子。”

4MB = 4兆 = 4 * 10的6次方字节 = 4000000byte

“3. 下了部加长版的阿凡达,1080P版本的,有42.5GB大。”

42.5GB = 42.5吉 = 42.5 * 10的9次方字节 = 42500000000byte

“4. 买了个2TB的希捷硬盘,用来放实验数据。”

2TB = 2太 = 2 * 10的12次方字节 = 2000000000000byte

“5. 在Linux终端下,用 『du -sh』命令统计Downloads目录下有15GiB的文件。”

15GiB = 15吉 = 15 * 2的30次方字节 = 16106127360byte


是不是已经凌乱了?确实,Linux、Windows、Mac以及各种软件都没有统一的度量标准这点让人头痛。

另外一个常见栗子:

“买了2T的硬盘,插到电脑上,只显示1.8T。奸商~”

“到底硬盘厂家是不是奸商呢?”
“因为计算容量的标准不同,硬盘厂家用10的整数次幂计算,你的电脑用的2的整数次幂计算。所以,硬盘容量最终是有差距。”


为了美好的生活,你只需要记住:

Windows、Linux终端使用二进制乘数词头计算文件大小,Linux桌面软件(比如,Gnome)、硬盘厂家则使用国际单位制词头。

如果你想成为优秀的程序员,那一定要搞清楚:MiB 和 MB 有什么区别?
去维基百科看看 二进制乘数词头 和 国际单位制词头 是不错的选择。

4.1.3. 空文件

大小为0或没内容的文件,称作 空文件。

4.2. 什么是目录(文件夹)

目录相当于一个容器,将多个文件或其它目录存储在一起。

Linux系统包含成千上万个目录。

多个文件通过存储在一个目录中,可以达到有组织的存储文件的目的。

在一个目录中的另一个目录被称作它的子目录(子文件夹)。这样,这些目录就构成了树状网络,或目录树。


ch04.s2-1

上面这个目录树有5个子目录和34个文件。

4.2.1. 目录还是文件?

在桌面中,你一眼就分辨出目录和文件了对吗?

ch04.s2-2

那现在呢?

ch04.s2-3

“这题我会~”

“蓝色 的是目录,白色 的是文件。”

“ohhhhh~”

友情提示,颜 色 可 是 会 变 的 哦?

换个直观的办法:

ch04.s2-4

看到第一二行的第一列没,都是 drwxrwxr-x.。第一个字母 d 是英文directory的缩写,有它出现的地方就是目录啦~

那文件呢? -(中横线)开头的就是文件。

其实,我也是经常用颜色区分的,主要还是方便~哈哈
关于目录名称的迷惑

我创建了一个目录 "pic123456.jpg"。它是这个样子:

ch04.s2-5

“没问题呀!”

那这样呢?

ch04.s2-6

“看起来像图片文件对不对?”
“它…​还是目录哦~”

和之前一样,用 颜色 或者字母 d 可以分辨出来。

4.2.2. 空目录

目录下没有文件或子目录,同样称作 空目录。

4.3. 什么是路径

路径表示文件或目录在Linux系统的位置,就像经纬度能够标示地球上的任何一个位置一样,防迷路。

各种路径:

  • /home/mk/Downloads/templated-radius/

  • /usr/share/zoneinfo/

  • /var/log/

  • /usr/share/zoneinfo/Asia/Shanghai

  • ../zoneinfo/Asia/Shanghai

  • /home/mk/Downloads/templated-radius/images/pic10.jpg

  • images/pic10.jpg

  • /home/mk/Downloads/templated-radius/assets/css/main.css

  • assets/css/main.css

  • ../../assets/css/main.css

路径以斜线(/)分隔,以文件名称或目录名称结尾。

我之前用树状结构(目录树)表示了文件和目录的关系。

现在,你会发现路径看起来像一条直线,更加直接。


为更精确表达,路径以文件名称结尾,称作文件路径。反之称作目录(文件夹)路径。

路径以斜线结尾(如,/var/log/)的,一定是目录(文件夹)路径。


路径太长时,用起来不方便。

Linux又有绝对路径和相对路径之分。

绝对路径太长时,用相对路径代替很方便。

接下来两小节,会详细介绍绝对路径和相对路径。

喜欢编程的小伙伴,在路径问题上踩过不少坑。还没踩坑的话,一定要看看下面两个小节哦~

4.4. 绝对路径

绝对路径以根目录(/)开头,不会因当前位置(工作目录)而变化。

根目录(/)是什么?

根目录是所有路径的起点,相当于Windows系统的 "C:\" 盘。

绝对路径例子:

  • /home/mk/Downloads/templated-radius/ ← 目录

  • /usr/share/zoneinfo/ ← 目录

  • /var/log/ ← 目录

  • /usr/share/zoneinfo/Asia/Shanghai ← 文件

  • /home/mk/Downloads/templated-radius/images/pic10.jpg ← 文件

  • /home/mk/Downloads/templated-radius/assets/css/main.css ← 文件

无法确定是文件路径还是目录路径时,可以使用 ls -l 或 file 命令查看,比如 file /usr/share/zoneinfo/Asia/Shanghai 。

绝对路径组成示例:

ch04.s4-1

4.5. 相对路径

相对路径是以当前目录(工作目录)为前提,使用 简短的路径 代替 绝对路径。

相对路径可能以 "./" 或 "../" 开头。一个点表示当前位置,连续两个点表示上级目录。当以 "./" 开头时,可以被省略。


由于当前目录随时在变化,可能导致文件或目录明明 存在,却 找不到 的情况。

建议:
在终端中手动操作文件或目录时使用相对路径,其它情况下使用绝对路径。

为什么手动操作时用相对路径呢? 因为打字少!

看看这两个绝对路径:

  • /usr/bin

  • /usr/bin/cat

用相对路径表示:

  • ../bin、./bin、bin、bin/

  • ./bin/cat、bin/cat、./cat

相对路径是否有效,取决于工作目录。

下面我以命令行和树状网络为例,详细说明:什么是相对路径?

4.5.1. 绝对路径与相对路径的转换:命令行

连接远程主机,跟我做:

  • ../bin、./bin、bin、bin/

操作演示
[mk@archlinux ~]$ ls -dl /usr/bin
drwxr-xr-x 7 root root 135168  2月 24 10:07 /usr/bin

[mk@archlinux ~]$ cd /usr/include/
[mk@archlinux include]$ ls -dl ../bin
drwxr-xr-x 7 root root 135168  2月 24 10:07 ../bin

[mk@archlinux ~]$ cd /usr
[mk@archlinux usr]$ ls -dl ./bin
drwxr-xr-x 7 root root 135168  2月 24 10:07 ./bin

[mk@archlinux usr]$ ls -dl bin
drwxr-xr-x 7 root root 135168  2月 24 10:07 bin

[mk@archlinux usr]$ ls -dl bin/
drwxr-xr-x 7 root root 135168  2月 24 10:07 bin/
  • ./bin/cat、bin/cat、./cat

操作演示
[mk@archlinux ~]$ ls -l /usr/bin/cat
-rwxr-xr-x 1 root root 39048 11月 12 19:00 /usr/bin/cat

[mk@archlinux ~]$ cd /usr/
[mk@archlinux usr]$ ls -l ./bin/cat
-rwxr-xr-x 1 root root 39048 11月 12 19:00 ./bin/cat

[mk@archlinux usr]$ ls -l bin/cat
-rwxr-xr-x 1 root root 39048 11月 12 19:00 bin/cat

[mk@archlinux usr]$ cd bin
[mk@archlinux bin]$ ls -l ./cat
-rwxr-xr-x 1 root root 39048 11月 12 19:00 ./cat

4.5.2. 绝对路径与相对路径的转换:树状网络

Diagram

工作目录:/usr/bin
绝对路径:/usr/bin/cat
相对路径:./cat

4.5.3. 树状网络、绝对路径及相对路径一览表

Diagram
Table 1. 路径一览表
工作目录:/usr/include/

绝对路径

相对路径

说明

/usr/include/

.(一个点)

绝对路径和当前目录(/usr/include)相同

/usr/include/pwd.h

./pwd.h 或者 pwd.h

当前目录(/usr/include)下的 pwd.h 文件

/usr/include/linux/nfc.h

./linux/nfc.h 或者 linux/nfc.h

当前目录(/usr/include)的子目录 linux 有文件 nfc.h

/usr/lib/

../lib/

上级目录 /usr 下的子目录 lib

4.5.4. 总结

通过上面的这么多例子相信你注意到了一个规律:如果文件路径没有以 / 开头,那它是相对路径。

以此类推,假如我有文件名为 my.png 的文件,执行命令:

ls my.png

那上面的 my.png 会被命令视作相对路径,等同于 ./my.png。

另外一个规律:如果将文件名作为参数用在命令行或软件中时,会被当作文件(相对)路径。同理,目录名称做参数时,情况相同。

4.6. 关于文件那些事儿

  • 区分大小写

  • 不关心扩展名

  • 隐藏文件:以 "." 开头的文件或目录

4.6.1. Linux区分大小写

这非常重要,也是Linux萌新常见问题的来源。

比如,我用Linux搭建了网站,有网页文件 "home.html",访问网址为:

一般情况下,访问 http://www.xquickstartguide.com/prolinux/test/HOME.html 会看到 "网页无法找到" 的错误提示。

大写的 "HOME.html" 文件实际是不存在的。

在Windows系统中,就没有 "HOME.html" 这样的问题。因为,Windows系统不区分大小写。

就日常使用来说,在Linux系统中可以创建两个或多个名字相同的文件和目录,只要大小写字母是不同的就行。如,foo.txt、FOO.txt、foo.TXT是三个同名文件。在Windows系统中创建 foo.txt 之后,创建文件 FOO.txt 会提示错误。

4.6.2. Linux不关心扩展(名)

在 [什么是文件] 一节中提过扩展(名),也许你之前难以理解。从这里开始,扩展名将变得更加具体。

扩展(名)一般由2到4个字符组成,用来表示文件类型。以下是常见扩展:

foo.exe

执行文件或程序

foo.txt

文本文件

foo.png/bar.gif/quz.jpg

图片

在Windows系统中扩展(名)非常重要,系统以此检测是什么类型的文件。Linux系统实际上会忽略扩展名,通过查看文件内容确定文件类型。比如,我有一个图片文件 my.png。我把文件重命名为 my.txt 之后,Linux还是会将之看作图片文件。因此,有时候很难确定某个特定文件是什么类型的文件。幸好有 file 的命令,它可以帮助确定文件类型。

用法

file 文件路径

示例
$ file my.txt
my.txt: PNG image data, 4480 x 1440, 8-bit/color RGBA, non-interlaced
现在,你肯定已经知道 "my.txt" 是 "./my.txt" 的简单用法。在 <相对路径_总结> 内容中已经说过,命令行中指定一个文件或目录(如 "my.txt")时,实际上会被视作文件路径("./my.txt")。

4.6.3. 隐藏文件

隐藏文件

在Linux系统中,任何以 "."(点)开头的文件是隐藏文件。默认情况下,不显示。比如,

# ls -l ~
总用量 4
-rw-------. 1 root root 948 8月  27 2019 anaconda-ks.cfg

用 ls 命令只看到一个名为 "anaconda-ks.cfg" 的文件。

使用 -a 参数再试一次呢?

# ls -al ~
总用量 52
dr-xr-x---.  4 root root 4096 8月  27 2019 .
dr-xr-xr-x. 17 root root 4096 8月  27 2019 ..
-rw-------.  1 root root  948 8月  27 2019 anaconda-ks.cfg
-rw-------.  1 root root 8403 8月  27 2019 .bash_history
-rw-r--r--.  1 root root   18 12月 29 2013 .bash_logout
-rw-r--r--.  1 root root  176 12月 29 2013 .bash_profile
-rw-r--r--.  1 root root  176 12月 29 2013 .bashrc
-rw-r--r--.  1 root root  100 12月 29 2013 .cshrc
drwxr-xr-x   4 root root   48 8月  27 2019 .kube
drwxr-----.  3 root root   18 8月  27 2019 .pki
-rw-r--r--.  1 root root  129 12月 29 2013 .tcshrc
-rw-------   1 root root 4243 8月  27 2019 .viminfo

好,这次用 ls -al 看到 "~"(/root) 目录下有很多以 "." 开头的文件(隐藏文件)。

隐藏目录

如果目录以 "." 开头就是隐藏目录。是不是很简单?

试一试创建一个隐藏目录:

mkdir ~/.test_dir

ls ~

ls -a

测试完,记得删除 ".test_dir" 目录:

rm -rf ~/.test_dir
隐藏文件用来做什么

在Linux系统中,大多数软件都有自己的配置文件或者目录。

通常,全局配置文件会放在 "/etc" 目录下,用 ls 直接可见。

用户配置文件则放在 "~"(用户家目录)下,都是隐藏文件,用 ls -a 才能看见。

家目录下的配置文件多数是软件自动创建,隐藏起来显得更清爽。

5. 文件和目录管理

在开始本章之前,你要明白一件事情:对于Linux系统来说,一切都是 "文件"。文本、目录、你的键盘和鼠标等等都是 "文件"。可能有些意外,不过这不影响什么。但,请记住这一点,因为它有助于理解Linux命令的行为。

本章有较多命令输入,请使用 Tab 键补全文件名,更方便。

怎么使用补全快捷键?

比如,你要执行命令 ls /usr,具体操作方法为:

输入 ls /u → 按 Tab 键,会自动补全为 ls /usr。

如果有多个相同字母开头的文件名,Tab 键补连续按两下,操作方法:

  1. 输入 ls /l;

  2. 按第一次 Tab 键,补全为 ls /lib;

  3. 再按一次 Tab 键,屏幕上会出现 lib/ lib64/;

  4. 在 ls /lib 基础上,你继续输入 ls /lib6;

  5. 再按一次 Tab 键,终端就会补全为 ls /lib64。

按 Tab 键的动作,只要你需要可以按无数次,特别是在文件名特别长的时候。

5.1. 在目录之间切换

cd 命令:在目录之间切换

5.1.1. 基础用法

cd 目录路径
参数
--help

查看帮助信息

5.1.2. 常用路径符号

"."

当前目录

".."

上级目录

"~"

家目录,root用户家目录为 "/root",其它用户家目录在 "/home" 下

5.1.3. 操作演示

绝对路径
目录变化

"/root" → "/usr"

[root@prolinux ~]# cd /usr
[root@prolinux usr]#
相对路径
目录变化

"/usr" → "/usr/local/bin"

[root@prolinux usr]# cd local/bin
[root@prolinux bin]#

或者

[root@prolinux usr]# cd ./local/bin
[root@prolinux bin]#
当前目录
目录变化

"/usr/local/bin" → "/usr/local/bin"

[root@prolinux bin]# cd .
[root@prolinux bin]#

看见了吧?

"." 没什么用,忘掉最好~

上级目录
目录变化

"/usr/local/bin" → "/usr/local"

[root@prolinux bin]# cd ..
[root@prolinux local]#
家目录
目录变化

"/usr/local" → "/root"

[root@prolinux local]# cd ~
[root@prolinux ~]#

偷懒的写法是,不要 "~",直接 cd→ Enter,不加参数。

想试一试?

没问题…​

先随便切换一个目录,比如 "/usr/local":

[root@prolinux ~]# cd /usr/local
[root@prolinux local]#

然后:

[root@prolinux local]# cd
[root@prolinux ~]#

5.2. 创建文件

5.2.1. 文件

创建空文件

创建一个空文件,如果文件已经存在,则会修改文件最后一次更新时间:

touch foo.txt
touch 命令本来用于修改文件时间。只是修改过程中,如果文件不存在,它会创建一个空文件。你就是利用这个特点创建的文件。
创建带内容的文件

有时,在创建文件之前,脑子里已经确定了内容,可以这样:

echo "这是测试文本。" > foo.txt
如果 foo.txt 文件已经存在,上面的命令会清空文件内容哦!

如果 foo.txt 文件已经存在,使用两个连续的大于符号( >> )可以追加一行或多行到文件最后。

echo "这是测试文本1。" >> foo.txt
echo "这是测试文本2。" >> foo.txt

最终,foo.txt 内容是这样:

这是测试文本。
这是测试文本1。
这是测试文本2。

5.2.2. 目录

创建目录,如果目录已经存在会报错,不用管:

mkdir ProLinux

有时,你会创建这样的目录 ProLinux/files/2020_03_03。创建多级目录也很简单,加参数 -p 就行:

mkdir -p ProLinux/files/2020_03_03

如果父目录 ProLinux 不存在,也能创建成功。同理,files 目录不存在也行。也就是说,路径中的所有子目录如果不存在,都会被创建。

划重点,-p 参数要考(滑稽)。

相对路径 ProLinux/files/2020_03_03 实际上省略了前面的 "./",可以写成:

  • ./ProLinux/files/2020_03_03

  • ./ProLinux/files/2020_03_03/

5.3. 列表目录

5.3.1. 查看目录

每次在终端上操作,你都需要确认你在哪个位置(工作目录或当前目录),才不至于 迷路。

刚好,pwd 命令可以帮到你:

操作演示
[root@prolinux ~]# pwd
/root

好的,你现在处于 /root 目录。执行 ls 命令,可以直接看到本目录下内容:

ls 命令不加参数时,会直接查看当前目录下的内容。
也可以使用 ls . 命令,前者只是省略了(相对)路径参数。
操作演示
[root@prolinux ~]# ls
files  ProLinux

[root@prolinux ~]# ls .
files  ProLinux

你要明白,上面的方法不是唯一的方法。也可以查看绝对路径下的目录内容:

ls /root/
操作演示
[root@prolinux ~]# ls /root/
files  ProLinux

ls .. 可以查看上级目录:

操作演示
[root@prolinux ~]# ls ..
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr

也可以指定更加复杂的相对路径:

ls ../usr/src/
操作演示
[root@prolinux ~]# ls ../usr/src/
debug  kernels

当然,也可以查看当前目录下的子目录内容:

ls files/
操作演示
[root@prolinux ~]# ls files/
bar.txt  foo.txt
查看隐藏文件

凡是以 . 开头的文件或目录,都称为隐藏文件或目录。配合 -a 参数可以看到:

操作演示
 [root@prolinux ~]# ls -a
.   .bash_history  .bash_profile  .cache   .cshrc  .lesshst  ProLinux  .tcshrc
..  .bash_logout   .bashrc        .config  files   .pki      .ssh      .viminfo

5.3.2. 列出更多信息

有时,你需要知道文件的修改时间或者权限。ls -l 或 ll 命令会以列表的方式,将文件信息打印到屏幕上。

ll 是 ls -l 的命令快捷式,两者没有区别。
操作演示
[root@prolinux ~]# ls -l
total 0
drwxr-xr-x. 2 root root 36 Mar  3 19:21 files
drwxr-xr-x. 2 root root 36 Feb 26 15:10 ProLinux

[root@prolinux ~]# ll
total 0
drwxr-xr-x. 2 root root 36 Mar  3 19:21 files
drwxr-xr-x. 2 root root 36 Feb 26 15:10 ProLinux
查看隐藏文件

和之前一样,加 -a 参数配合使用。

操作演示
[root@prolinux ~]# ls -al
总用量 52
dr-xr-x---.  4 root root 4096 8月  27 2019 .
dr-xr-xr-x. 17 root root 4096 8月  27 2019 ..
-rw-------.  1 root root  948 8月  27 2019 anaconda-ks.cfg
-rw-------.  1 root root 8403 8月  27 2019 .bash_history
-rw-r--r--.  1 root root   18 12月 29 2013 .bash_logout
-rw-r--r--.  1 root root  176 12月 29 2013 .bash_profile
-rw-r--r--.  1 root root  176 12月 29 2013 .bashrc
-rw-r--r--.  1 root root  100 12月 29 2013 .cshrc
drwxr-xr-x   4 root root   48 8月  27 2019 .kube
drwxr-----.  3 root root   18 8月  27 2019 .pki
-rw-r--r--.  1 root root  129 12月 29 2013 .tcshrc
-rw-------   1 root root 4243 8月  27 2019 .viminfo
只看目录,不看子目录
操作演示
[root@prolinux ~]# ls -dl files/
drwxr-xr-x. 2 root root 36 Mar  3 19:21 files/
查看内容,包括子目录
操作演示
[root@prolinux ~]# ls -R
.:
files  ProLinux

./files:
bar.txt  foo.txt

./ProLinux:
bar.txt  foo.txt

加上 -l 参数,文件信息更详细。

操作演示
[root@prolinux ~]# ls -Rl
.:
total 0
drwxr-xr-x. 2 root root 36 Mar  3 19:21 files
drwxr-xr-x. 2 root root 36 Feb 26 15:10 ProLinux

./files:
total 8
-rw-r----r----. 1 root root 19 Mar  3 19:21 bar.txt
-rw-r----r----. 1 root root 19 Mar  3 19:21 foo.txt

./ProLinux:
total 8
-rw-r----r----. 1 root root 15 Feb 26 15:12 bar.txt
-rw-r----r----. 1 root root 15 Feb 26 15:12 foo.txt

5.4. 编辑文件

在Linux服务器环境(非图形界面)下,我更多使用 vim 编辑文件。vim 强大而丰富的功能吸引了很多人,有人愿意花几天小时甚至几周学习 "如何用好vim编辑器",并且没有一点怨言。

但是,vim 非常不适合新人。

如果你只是改个数据密码之类的简单需求,花几分钟了解一下 nano 则是更好的选择。

为什么不在Windows上改完文件,通过工具上传到服务器?

大部分时候,仅仅修改一下数据密码或邮箱,直接用 vim 或 nano 之类的命令行编辑器操作就行了。
不想在本地改完了还要操作上传,太麻烦了。

按照惯例,先安装Nano编辑器:

yum install -y nano

5.4.1. 用Nano创建和打开文件

如果你想创建新文件或打开文件,命令是这样:

nano

这样:

nano foo.txt

或者这样:

nano /data/foo.txt
直接指定文件的绝对路径时,文件的父目录必须存在,否则会报错。比如 nano /data/foo.txt 中的 /data 。如果不存在,不要忘了使用 mkdir /data 创建。

第二、三种方法也可以用来打开一个已经存在的文件。

请记住,如果你要打开一个不在当前目录的文件,需要像第三个例子一样写明文件的绝对路径或相对路径。

以下是用Nano编辑器打开文件的截图:

ch05.s3-1

如你所见,在编辑器窗口底部有键盘快捷键的提示信息。方便执行一些基本操作,比如复制粘贴文字。退出编辑器和查看帮助的快捷键也都在这里。

5.4.2. 编辑内容

在Nano编辑器中,敲击键盘就能输入内容,Enter 键可以换行。

怎么移动光标呢?

试一试键盘右下方的上下左右箭头按键。

我从其它地方复制了文字,怎么粘贴进Nano编辑框?

鼠标右键,找到粘贴功能(常见 "粘贴" 或 "paste"),选中单击。

5.4.3. 在Nano编辑器中保存文件

保存文件的快捷键是 Ctrl+o (不要按错了哦!是字母o)。当你按了快捷键,编辑器会询问保存文件名称(或确认文件名称)。文件名称设置完毕,按 Enter 键保存文件。

保存文件操作截图:

ch05.s3-2

保存完毕后,按 Ctrl+x 可以退出。

在没保存的情况下,直接按 Ctrl+x,然后输入文件名称,一步完成保存退出操作。是不是更快呢?

5.4.4. 总结

关于Nano编辑器的基本使用就讲到这里。如果有更加复杂的操作,在Windows上改完再上传是更快的办法。

用Nano本就是图简单,花半个小时学这个就不值得了。

5.5. 打印内容

5.5.1. cat 命令

有时,想把文件所有内容打印到屏幕上:

cat foo.txt
这是测试文本。
这是测试文本1。
这是测试文本2。

也可以打印行号:

cat -n foo.txt
     1	这是测试文本。
     2	这是测试文本1。
     3	这是测试文本2。

5.5.2. less 命令

相较于 cat 命令将文件所有内容打印到屏幕上,less 命令仅仅打印一屏的行为非常奇特。

为什么 less 会这样呢?

在文件内容特别多时,文件内容分批次打印到屏幕才是方便的。不然,所有内容全部打印到屏幕,屏幕至少滚动10秒钟才会停下,我自然也找不到我想要的内容。

5.6. 压缩(打包)和解压文件

5.6.1. 准备测试文件

cd
mkdir -p prolinux
echo "测试文本1" > prolinux/foo.txt
echo "测试文本2" > prolinux/bar.txt
echo "测试文本3" > quz.txt

5.6.2. 压缩(打包)和解压演示

压缩(打包)演示

下文出现的 foo.tar.gz 是相对路径 ./foo.tar.gz 的简化版。根据实际情况,你可以指定任何相对或绝对路径,比如:

  • ../foo.tar.gz

  • ~/foo.tar.gz

  • /tmp/foo.tar.gz

cd
tar zcvf foo.tar.gz prolinux/ quz.txt
解释
zcf

创建一个压缩包文件

v

显示详细过程

foo.tar.gz

压缩包文件名

files/

指定加入压缩包的目录,紧跟在压缩包文件名之后

quz.txt

指定加入压缩包的文件,紧跟在压缩包文件名之后

压缩包文件名后可以指定多个目录或文件哦!自己动手试试看。
查看压缩包内容
tar tf foo.tar.gz
解压演示

解压内容到目录 foo 中:

mkdir -p foo
cd foo
tar xvf ../foo.tar.gz
解释
xf

解压文件

v

显示详细过程

foo.tar.gz

等待解压的(压缩包)文件名

说明

尽量将需要打包的目录或文件放到同一个目录下,这样本节演示的压缩和解压方法就是万能的。不再需要学更复杂的操作。作为Linux老司机,我极少遇到解决不了的。

如果解决不了怎么办?

那我就分别打几个压缩包,这样更快。

5.7. 压缩不同目录下的文件

在你没遇到这个情况的时候,请你跳过本节内容。在需要时,再来看看。

5.7.1. 准备测试文件

  1. 在绝对路径 /tmp (目录)下创建5个1M的文件,文件内容为随机数据:

mkdir -p /tmp/files
dd if=/dev/urandom bs=1M count=5 of=/tmp/files/tmp_random_file
split -d -b 1M /tmp/files/tmp_random_file /tmp/files/tmp_random_file.
rm -f /tmp/files/tmp_random_file

在 /tmp/files 目录下,会自动生成如下文件:

tmp_random_file.00  tmp_random_file.01  tmp_random_file.02  tmp_random_file.03  tmp_random_file.04
  1. 在相对路径 prolinux/ (目录)下创建5个1M的文件,文件内容为随机数据:

cd ~
mkdir -p prolinux/
dd if=/dev/urandom bs=1M count=5 of=prolinux/prolinux_random_file
split -d -b 1M prolinux/prolinux_random_file prolinux/prolinux_random_file.
rm -f prolinux/prolinux_random_file

在 ~/prolinux 目录下,会自动生成如下文件:

prolinux_random_file.00  prolinux_random_file.01  prolinux_random_file.02  prolinux_random_file.03  prolinux_random_file.04

5.7.2. 带路径打包

tar zcvf foo.tar.gz /tmp/files

"foo.tar.gz" 内容列表如下:

tmp/files/
tmp/files/tmp_random_file.03
tmp/files/tmp_random_file.01
tmp/files/tmp_random_file.00
tmp/files/tmp_random_file.04
tmp/files/tmp_random_file.02

5.7.3. 不带路径打包

方法一:

cd /tmp/files/
tar zcvf ~/foo.tar.gz tmp_random_file.*

方法二:

tar zcvf ~/foo.tar.gz -C /tmp/files/ tmp_random_file.*

"foo.tar.gz" 内容列表如下:

tmp_random_file.00
tmp_random_file.01
tmp_random_file.02
tmp_random_file.03
tmp_random_file.04

第一种方法逻辑更简单,第二种方法一行搞定。我推荐你在多数情况下使用第一种方法。

5.7.4. 多目录打包

将以下文件打包到压缩文件 foo.tar.gz:

  • /tmp 下的 files 目录及其文件

  • ~/prolinux 目录下以 prolinux_random_file. 开头的文件

tar zcvf ~/foo.tar.gz -C /tmp/ files/ -C ~/prolinux/ prolinux_random_file.{00..04}

或

tar zcvf ~/foo.tar.gz -C /tmp/ files/ -C ~/prolinux/ .
使用 -C 参数时,不能使用 prolinux_random_file.* 这样的星号通配符。

"foo.tar.gz" 内容列表如下:

files/tmp_random_file.00
files/tmp_random_file.01
files/tmp_random_file.02
files/tmp_random_file.03
files/tmp_random_file.04
prolinux_random_file.00
prolinux_random_file.01
prolinux_random_file.02
prolinux_random_file.03
prolinux_random_file.04

5.7.5. 归档文件和压缩文件的区别

  • 归档文件只是把多个文件打包放一起,包文件大小更大。

  • 压缩文件使用了压缩算法,包文件更小。

创建归档文件:"bar.tar",创建压缩文件:"foo.tar.gz",

tar vcf ~/bar.tar ~/prolinux
tar zvcf ~/foo.tar.gz ~/prolinux

查看两个文件大小,单位 kb:

du -sk ~/foo.tar.gz ~/bar.tar

可以明显看出 "foo.tar.gz"(5124kb) 比 "bar.tar"(5132kb) 更小:

5124	/root/foo.tar.gz
5132	/root/bar.tar

再看看两个文件类型信息:

file ~/foo.tar.gz ~/bar.tar

"foo.tar.gz" 是 zip 压缩的,"bar.tar" 仅仅是将文件打包。

/root/foo.tar.gz: gzip compressed data, from Unix, last modified: Mon Apr  6 14:48:30 2020
/root/bar.tar:    POSIX tar archive (GNU)

5.7.6. 清理测试文件

rm -f ~/foo.tar.gz ~/bar.tar
rm -rf prolinux /tmp/files

5.8. 统计大小

du 命令基本用法: du -sh 目录或文件路径1 [目录或文件路径2] …​,比如:

du -sh foo.tar.gz

5.8.1. 查看文件大小

du -sh ~/foo.tar.gz
屏幕内容
58M     /root/foo.tar.gz

5.8.2. 统计目录大小

du -sh /usr
屏幕内容
1.7G    /usr

5.8.3. 统计多个目录大小

du -sh /usr/* /var /tmp
屏幕内容
67M    /usr/bin
48K    /usr/etc
4.0K   /usr/games
13M    /usr/include
913M   /usr/lib
138M   /usr/lib64
40M    /usr/libexec
169M   /usr/local
40M    /usr/sbin
291M   /usr/share
75M    /usr/src
0      /usr/tmp
277M   /var
21M    /tmp

5.8.4. 其它选择

du 命令不是唯一的选择。你也可以这样查看文件大小:

ls -hl
屏幕内容
total 5.1M
-rw-r--r-- 1 root root 5.1M Apr  6 17:06 foo.tar.gz
drwxr-xr-x 2 root root 4.0K Apr  6 17:06 prolinux

但是,ls -hl 不会统计目录下所有文件的总大小,仅仅显示目录大小为 "4.0K"。最终,还是 du 命令更香。

5.9. 查看文件类型

在第三章我讲过,文件名或扩展名不决定文件类型。那怎么判断文件类型呢?

file 命令可以检测文件类型。它还会显示文本文件的字符编码,简直是诊断乱码问题的神器。

5.9.1. 准备测试文件

cd
mkdir -p prolinux
touch prolinux/foo.txt
echo 'This is a test text.' > prolinux/bar.txt
echo '这是测试文本。' > prolinux/quz.txt
tar zcf foo.tar.gz prolinux

5.9.2. 运行 file 命令

file 命令基本用法: file 文件路径,比如:

file prolinux/foo.txt

检测多个文件的类型:

file prolinux/*.txt foo.tar.gz
屏幕内容
prolinux/bar.txt: ASCII text
prolinux/foo.txt: empty
prolinux/quz.txt: UTF-8 Unicode text
foo.tar.gz:       gzip compressed data, from Unix, last modified: Mon Apr  6 17:06:11 2020

如果你学过HTML,那你一定对这个眼熟:

file -i prolinux/*.txt foo.tar.gz
屏幕内容
prolinux/bar.txt: text/plain; charset=us-ascii
prolinux/foo.txt: inode/x-empty; charset=binary
prolinux/quz.txt: text/plain; charset=utf-8
foo.tar.gz:       application/x-gzip; charset=binary

加上 -i 参数,会打印出文件的MIME类型。

5.10. 清空内容

一点准备工作
cd
mkdir -p prolinux
echo 'foo123' > prolinux/foo.txt
echo 'bar123' > prolinux/bar.txt
ll prolinux

清空文件内容:

echo > prolinux/foo.txt

或

echo -n '' > prolinux/bar.txt

不加 -n 参数时,"foo.txt" 中有一个换行符(\n)。看看文件大小:

ls -l prolinux/*.txt
屏幕内容
-rw-r--r-- 1 root root  0 Apr  6 17:32 prolinux/bar.txt
-rw-r--r-- 1 root root  1 Apr  6 17:32 prolinux/foo.txt

"foo.txt" 大小为1个字节,"bar.txt" 大小为0个字节。

5.10.1. 扩展内容

如果你对换行符有兴趣,可以这样看:

cat -A prolinux/foo.txt
屏幕内容
$

上面的美元符号表示换行符(\n)。

也可以通过查看十六进制确认:

hexdump prolinux/foo.txt
屏幕内容
0000000 000a
0000001

上面的 "0a" 是换行符(\n)的十六进制表示。

5.11. 删除文件

不要在Linux系统上删除任何系统目录(比如 rm -rf / 或 rm -rf /usr 等等)。否则数据丢失,系统崩溃无法启动。

rm 命令基本用法:rm 目录或文件路径,比如:

rm prolinux/foo.txt

rm 在删除前会提示 "remove regular file ‘prolinux/foo.txt’? ",询问是否删除。

输入 y,按 Enter 键即可删除。

不想删除了?两种方法:

  1. 输入 n,按 Enter 键

  2. 按 Ctrl+c 键终止操作

如果不想要这个提示,加上 -f 参数:

rm -f prolinux/foo.txt

5.11.1. 删除目录

rm -r prolinux

rm 同样会询问是否删除。输入 y,按 Enter 键即可删除目录。

不想要提示怎么办?和之前一样,加上 -f 参数:

rm -rf prolinux

5.11.2. 误删文件怎么办?

Linux不像Windows桌面一样有 "回收站",使用 rm 删除的文件没有后悔药,无法找回。在这之前,一个良好的习惯尤为重要:

新建名为 trash 的目录,作为自己的文件回收站。将等待删除的文件移动(mv 命令)到这个目录,每隔一段时间删除 trash 目录下的所有文件。

操作演示
mkdir -p ~/trash
mv prolinux ~/trash

# 每隔一段时间清理回收站
rm -rf ~/trash/*

其实,我在修改重要文件时,也有类似的习惯。我会先复制一份保存做备份,防止误操作。假如改错东西,可以用备份恢复到最初状态。

操作演示
# 先复制一份做备份
cp prolinux/foo.txt prolinux/foo.txt.bak

# 然后,再修改
nano prolinux/foo.txt

# 如果后悔了,这样恢复
cp prolinux/foo.txt.bak prolinux/foo.txt

5.12. 复制文件

cp 命令:复制目录或文件。

5.12.1. 基础用法

cp 被复制的文件 新的文件名或路径
常用参数
-r

复制目录

-v

显示详细过程

--help

查看帮助信息

5.12.2. 操作演示

开始之前

为练习提前创建目录和文件:

cd
mkdir -p ~/prolinux
touch ~/prolinux/foo.txt ~/prolinux/bar.txt
复制文件

复制文件,保持文件名不变:

cp -v ./prolinux/foo.txt /tmp/

复制并修改文件名:

cp -v ./prolinux/foo.txt /tmp/new_foo.txt
如果指定的新文件名或路径已经存在,cp 命令会提示 "cp: overwrite ‘/tmp/foo.txt’?"",询问是否覆盖已经有的文件。输入 y,按 Enter 键就行。

在同一个目录下复制一个新文件:

cp -v ./prolinux/bar.txt ./prolinux/new_bar.txt

或

cd ~/prolinux/
cp -v bar.txt new_bar.txt
复制目录

复制当前目录下的 prolinux 文件夹到 /tmp 目录下:

cp -vr prolinux/ /tmp/

查看复制前后的区别:

find ~/prolinux/ /tmp/prolinux/
屏幕内容
/root/prolinux/
/root/prolinux/bar.txt
/root/prolinux/foo.txt
/tmp/prolinux/
/tmp/prolinux/bar.txt
/tmp/prolinux/foo.txt

如果复制文件一样,可以指定新的目录 "prolinux_test":

`cp -vr prolinux/ /tmp/prolinux_test`

复制后,"foo.txt" 的路径会是这样:"/tmp/prolinux_test/foo.txt"。

试一试下面这样复制目录:

cp -vr prolinux/ /tmp/prolinux_test
cp -vr prolinux/ /tmp/prolinux_test

find prolinux/ /tmp/prolinux_test

恭喜你?
你陷入了套娃模式~

结束之后

删除为练习创建的目录和文件:

cd
rm -rf prolinux /tmp/prolinux*

5.13. 移动(重命名)文件

mv 命令:移动(重命名)文件。

5.13.1. 基础用法

mv 和 cp 的基础用法类似。

mv 被移动的文件 新文件名或路径
常用参数
-v

显示详细过程

--help

查看帮助信息

5.13.2. 操作演示

开始之前

为练习提前创建目录和文件:

cd
mkdir -p ~/prolinux
touch ~/prolinux/foo.txt ~/prolinux/bar.txt
移动文件

移动文件,保持文件名不变:

mv -v ./prolinux/foo.txt /tmp/

移动并修改文件名:

mv -v ./prolinux/foo.txt /tmp/new_foo.txt

修改文件名,不改变文件位置:

mv -v ./prolinux/bar.txt ./prolinux/new_bar.txt

或

cd ~/prolinux/
mv -v bar.txt new_bar.txt
移动目录

移动当前目录下的 prolinux 文件夹到 /tmp 目录下:

mv -v prolinux/ /tmp/

查看移动后的情况:

find /tmp/prolinux/
屏幕内容
/tmp/prolinux/
/tmp/prolinux/bar.txt
/tmp/prolinux/foo.txt

如果移动文件一样,可以指定新的目录 "prolinux_test":

`mv -v prolinux/ /tmp/prolinux_test`

移动后,"foo.txt" 的路径会是这样:"/tmp/prolinux_test/foo.txt"。

结束之后

删除为练习创建的目录和文件:

cd
rm -rf prolinux /tmp/prolinux*

6. 文件属性

6.1. 简介

6.1.1. 看看我是谁

id 命令可以打印用户和组信息:

id
屏幕内容
uid=0(root) gid=0(root) groups=0(root)

       当前用户名:root,uid为0

用户所属组:root,gid为0

在当前用户和组的情况下,创建目录和文件后文件属性会显示 "root root" 字样,表示由root用户创建。

当然,id 也可以打印指定用户的信息: id 用户名。比如,id nobody。

6.1.2. 一点点准备

创建测试用目录和文件:

mkdir -p ~/prolinux
echo "foo123" > ~/prolinux/foo.txt
echo "bar1234567" > ~/prolinux/bar.txt
chown nobody ~/prolinux/bar.txt

6.1.3. 什么是用户、组和文件权限

查看目录和文件属性:

ls -dl ~/prolinux ~/prolinux/*.txt
屏幕内容
drwxr-xr-x 2 root   root 4096 Jun 15 14:18 /root/prolinux
-rw-r--r-- 1 nobody root   11 Jun 15 14:19 /root/prolinux/bar.txt
-rw-r--r-- 1 root   root    7 Jun 15 14:19 /root/prolinux/foo.txt

"root root" 和 "nobody root" 表示用户、组设置状态。

"drwxr-xr-x" 和 "-rw-r—​r--" 表示文件权限(读、写、执行权限)设置状态。

6.1.4. 文件属性中的用户、组和文件权限是什么关系

用户、组设置

类似游乐园的门票,属于某种形式的许可或凭证。通过门票类型确定游客类型属于A类还是B类,没有门票(许可)就不能进园区(访问文件)。这个层面,只关心游客类型,不关心游客进去后玩哪种娱乐项目。

用户和组设置作为文件安全的第一道大门,起到甄别用户或程序是否有访问权限的作用。
文件权限设置

类似进入游乐园后,A类游客只能玩A类包含的娱乐项目(旋转木马、摩天轮),B类游客也只能玩B类包含的娱乐项目(云霄飞车、激流勇进、海盗船)。
A类游客不允许玩儿B类的项目,要玩儿云霄飞车(读或写文件)就得补票,补B类型的门票(重新设置文件权限)。

文件权限设置可以让系统知道:用户或程序对文件有读权限、写权限还是执行权限。没有权限,系统会拒绝操作请求。

6.2. 文件用户和组

6.2.1. 每个文件都属于一个用户和一个组

Linux中的每个文件必定属于一个用户和一个组。不管用户还是组都只能一个,不能多个。

查看刚才准备的目录和文件,打印更简洁的文件属性:

ls -dl ~/prolinux/ ~/prolinux/*.txt | awk '{print "用户:"$3"    组:"$4"    名称:"$NF}'
屏幕内容
用户:  root    组:root    名称:/root/prolinux/
用户:nobody    组:root    名称:/root/prolinux/bar.txt
用户:  root    组:root    名称:/root/prolinux/foo.txt

用户和组不一定要相同,比如

用户:nobody    组:root    名称:/root/prolinux/bar.txt

上面这行表示文件 "/root/prolinux/bar.txt" 属于用户 "nobody" 和 组 "root"。

再看看 "nobody" 用户的信息:

id nobody
屏幕内容
uid=99(nobody) gid=99(nobody) groups=99(nobody)

可以看到用户 "nobody" 和 组 "root" 没有关系。

6.2.2. 修改文件的用户和组设置

chown -v 中的 "-v" 参数仅为打印日志信息,无实际作用,可以忽略。

将 "~/prolinux/foo.txt" 用户和组都修改为 "nobody":

chown -v nobody:nobody ~/prolinux/foo.txt
屏幕内容
changed ownership of ‘/root/prolinux/foo.txt’ from root:root to nobody:nobody

确认设置状态:

ls -l ~/prolinux/foo.txt
屏幕内容
-rw-r--r-- 1 nobody nobody 7 Jun 15 14:19 /root/prolinux/foo.txt

看到 "nobody nobody" 说明设置成功。

6.2.3. 修改目录的用户和组设置

chown -v 中的 "-v" 参数仅为打印日志信息,无实际作用,可以忽略。

-R 参数表示修改目录以及目录下的所有文件用户和组设置。

修改 "~/prolinux/" 目录的用户和组为 "root":

chown -vR root:root ~/prolinux/
屏幕内容
ownership of ‘/root/prolinux/bar.txt’ retained as root:root
changed ownership of ‘/root/prolinux/foo.txt’ from nobody:nobody to root:root
ownership of ‘/root/prolinux/’ retained as root:root

查看目录和目录下的文件属性:

ls -dl ~/prolinux/ ~/prolinux/*.txt
屏幕内容
drwxr-xr-x 2 root root 4096 Jun 15 14:18 /root/prolinux/
-rw-r--r-- 1 root root   11 Jun 15 14:19 /root/prolinux/bar.txt
-rw-r--r-- 1 root root    7 Jun 15 14:19 /root/prolinux/foo.txt

三行都是 "root root",设置成功。

6.2.4. 同时设置多个目录或文件的用户和组

直接在 chown 后加上路径即可,比如

chown -R root:root ~/prolinux/foo.txt ~/prolinux/

chown root:root ~/prolinux/foo.txt ~/prolinux/bar.txt

6.3. 文件权限

6.3.1. 理解文件权限标志

权限分组

每个文件或目录都有三个基于用户的权限组:

所有者

文件的所有者,具体指某个用户

组

文件所属的组

其它用户

所有者和组以外的用户

权限类型

每个文件或目录拥有三个基础权限类型:

可读

读取文件内容的权限

可写

写或修改文件的权限

可执行

查看目录列表(如 ls -l foo/)或执行脚本(如 sh ./foo.sh)的权限

chmod

Linux系统用 chmod 命令修改文件权限,chmod 有多种表示法(字母法和数字法)指定文件权限。如 chmod +x filename、chmod 755 filename。本文仅描述基于八进制的数字法。

数字法有四个八进制数字组成。如 "0755",不过会简写成 "755"。

第一个 "0" 涉及不常用功能,直接忽略之,熟悉后面三个数字即可。

Table 2. 数字法的基础数字
权限符号 八进制数字 描述

r

4

可读

w

2

可写

x

1

可执行

Table 3. 数字法对照表
权限符号组 八进制数字 描述

rwx

7

可读、可写、可执行

rw-

6

可读、可写、可执行

r-x

5

可读、可写、可执行

r--

4

可读、可写、可执行

-wx

3

可读、可写、可执行

-w-

2

可读、可写、可执行

--x

1

可读、可写、可执行

—

0

可读、可写、可执行

看不明白?没关系,看后面…​…​

一点点准备

为详细说明文件权限,提前设置文件的用户和组:

chown -R root:root ~/prolinux/
chown root:nobody ~/prolinux/foo.txt
文件权限说明

不管是系统管理,还是编程写代码,数字法用得最多。字母法和数字法之间的转换属于日常,下文用表格来解释。

提前解释下 stat 的参数
"%A"

第1列,文件权限字母表示法,如 "drwxr-xr-x"。

"%a"

第2列,文件权限数字表示法,如 "755"。

"%U"

第3列,文件所属用户,如 root"。

"%G"

第4列,文件所属组,如 "root"。

"%n"

第5列,目录或文件名称,如 "/root/prolinux/"。


示例1


列出 ~/prolinux/ 目录的文件属性:

ls -dl ~/prolinux/
stat -c '%A %a %U %G %n' ~/prolinux/
屏幕内容
drwxr-xr-x 2 root root   4096 Jun 15 14:18 /root/prolinux/
drwxr-xr-x 755 root root /root/prolinux/

用户和组

root

root

其它用户

权限分组

所有者权限

组权限

其它用户权限

文件权限

目录

可读

可写

可执行

可读

可执行

可读

可执行

权限模式
字母表示法

d

r

w

x

r

-

x

r

-

x

权限标识

4

2

1

4

1

4

1

权限模式
数字表示法

7

5

5


示例2


列出 ~/prolinux/bar.txt 的文件属性:

ls -l ~/prolinux/bar.txt
stat -c '%A %a %U %G %n' ~/prolinux/bar.txt
屏幕内容
-rw-r--r-- 1 root root     11 Jun 16 10:41 /root/prolinux/bar.txt
-rw-r--r-- 644 root root /root/prolinux/bar.txt

用户和组

root

root

其它用户

权限分组

所有者权限

组权限

其它用户权限

文件权限

文件

可读

可写

可读

可读

权限模式
字母表示法

-

r

w

-

r

-

-

r

-

-

权限标识

4

2

4

4

权限模式
数字表示法

6

4

4


示例3


列出 ~/prolinux/foo.txt 的文件属性:

ls -l ~/prolinux/foo.txt
stat -c '%A %a %U %G %n' ~/prolinux/foo.txt
屏幕内容
-rw-r--r-- 1 root nobody    7 Jun 16 10:41 /root/prolinux/foo.txt
-rw-r--r-- 644 root nobody /root/prolinux/foo.txt

用户和组

root

nobody

其它用户

权限分组

所有者权限

组权限

其它用户权限

文件权限

可读

可写

可读

可读

权限模式
字母表示法

-

r

w

-

r

-

-

r

-

-

权限标识

文件

4

2

4

4

权限模式
数字表示法

6

4

4

6.3.2. 修改文件权限

chmod -v 中的 "-v" 参数仅为打印日志信息,无实际作用,可以忽略。
chmod -v 755 ~/prolinux/foo.txt
屏幕内容
mode of ‘/root/prolinux/foo.txt’ changed from 0644 (rw-r--r--) to 0755 (rwxr-xr-x)

6.3.3. 修改目录权限

chmod -v 中的 "-v" 参数仅为打印日志信息,无实际作用,可以忽略。

-R 参数表示修改目录以及目录下的所有文件权限设置。

chmod -vR 755 ~/prolinux/
屏幕内容
mode of ‘/root/prolinux/’ retained as 0755 (rwxr-xr-x)
mode of ‘/root/prolinux/bar.txt’ changed from 0644 (rw-r--r--) to 0755 (rwxr-xr-x)
mode of ‘/root/prolinux/foo.txt’ retained as 0755 (rwxr-xr-x)

6.3.4. 同时设置多个目录和文件的权限

chmod -R 755 ~/prolinux/foo.txt ~/prolinux/

chmod 644 ~/prolinux/foo.txt ~/prolinux/bar.txt

7. 输入输出重定向

输入输出重定向,常偷懒称作IO重定向。

IO是Input/Output的简写。

7.1. 什么是IO重定向

“用 键盘 打字,屏幕 能实时看到输入的文字。”

  • 键盘是一种输入(input)设备,Linux中称作 标准输入(stdin)设备;

  • 屏幕是一种输出(output)设备,Linux中称作 标准输出(stdout)设备。

“打错字时,屏幕上能看到醒目的软件错误提示。比如, 发现未知单词 Lxinu。”

  • 屏幕是一种错误输出(output)设备,Linux中称作 标准错误输出,或 错误输出(stderr)设备。

IO重定向是Linux系统中常用的功能,可以在执行命令时改变标准输入/输出设备。

打印内容到屏幕的例子:

echo prolinux

加入重定向后的例子:

echo prolinux > ~/foo.txt

上面的例子,将本该显示到屏幕的执行结果保存到文件 "foo.txt"。通过重定向功能将输出设备从屏幕改成了文件。

7.2. 标准输出重定向(stdout)

">" 或 "1>" 符号

覆盖写入,文件内容先被清空,然后写入新内容。

">>" 或 "1>>" 符号

追加写入,新内容追加到文件末尾,不影响已有内容。

7.2.1. 什么是标准输出重定向

标准输出重定向把命令的执行结果(内容)写入文件,而不是显示在屏幕上。

除了文件,标准输出重定向还可以 “写入” 其它地方。这些不在本文讨论范围。

7.2.2. 标准输出重定向能做什么

覆盖写入

在终端执行某些命令时,通常会在屏幕上看到执行结果。比如:

[root@prolinux ~]# ls /usr/lib
binfmt.d  grub    modprobe.d      rpm               systemd
debug     kbd     modules         sendmail          tmpfiles.d
dracut    kdump   modules-load.d  sendmail.postfix  tuned
firmware  kernel  polkit-1        sse2              udev
games     locale  python2.7       sysctl.d          yum-plugins

ls /usr/lib 的执行结果较少,显示没问题。

在系统日志中查找服务启动日志,这样的情况就有问题了。

试一试:

journalctl | grep Starting
执行结果
8月 16 16:10:14 localhost.localdomain kernel: SELinux:  Starting in permissive mode
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Swap.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting -.slice.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting udev Control Socket.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting System Slice.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Slices.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting udev Kernel Socket.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Local File Systems.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Timers.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Journal Socket.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Create list of required static device nodes for the current kernel...
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Sockets.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting dracut cmdline hook...
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Setup Virtual Console...
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Apply Kernel Variables...
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Journal Service...
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Create Static Device Nodes in /dev...
...
...
...

内容太多,屏幕可能显示不完。

再试一试:

journalctl | grep Starting > ~/out.log
"> ~/out.log" 可以用 "1> ~/out.log" 代替。

“乱码”去哪儿了?

之前在屏幕上显示的内容,写到了 "~/out.log" 文件。如下:

[root@prolinux ~]# cat ~/out.log
8月 16 16:10:14 localhost.localdomain kernel: SELinux:  Starting in permissive mode
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Swap.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting -.slice.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting udev Control Socket.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting System Slice.
8月 16 16:10:14 localhost.localdomain systemd[1]: Starting Slices.
...
...
...
追加写入

一个简单的例子:

echo line1 > ~/foo.txt
echo line2 >> ~/foo.txt
echo line3 >> ~/foo.txt

看看文件内容:

[root@prolinux ~]# cat ~/foo.txt
line1
line2
line3

可以看到,新内容始终在结尾处追加写入。

看看覆盖写入会发生什么:

echo line4 > ~/foo.txt

当前的文件内容:

[root@prolinux ~]# cat ~/foo.txt
line4

7.3. 标准输入重定向(stdin)

"<" 或 "0<" 符号

将文件内容作为命令输入。

"<<" 符号(Here Document)

一种特殊目的的输入重定向,在交互式程序或命令中实现 "块" 输入。

7.3.1. 什么是标准输入重定向

执行命令时,用标准输入重定向能从文件内容或其它命令结果读取参数。

标准输入重定向常用于需要大量输入或某些交互式场景。

这样,我们不用手动输入参数,也可以运行命令。

7.3.2. 标准输入重定向能做什么

示例1:wc命令

下面两个示例分别演示如何用 wc 命令统计 "foo.txt" 的行数。

准备测试文件:

echo line1 > ~/foo.txt
echo line2 >> ~/foo.txt
echo line3 >> ~/foo.txt

统计行数:

命令1
wc -l ~/foo.txt
命令1-执行结果
3 /root/foo.txt

使用标准输入重定向统计行数:

命令2
wc -l < ~/foo.txt
命令2-执行结果
3

两个命令得到相同的文件行数:3。

命令1指定了参数:"~/foo.txt",所以结果中包含文件名。

命令2则没有指定文件名,而是通过标准输入重定向读取文件内容后,将文件内容传递给 wc 命令。

一个命令指定文件名,一个命令直接传递文件内容。

示例2:wc命令(Here Document)

Here Document 可以实现在没有 "foo.txt" 文件的情况下,统计出行数。

命令3
wc -l << EOF
line1
line2
line3
EOF
命令3-输出
3

命令3同样得到文件行数:3。

命令3中有两个重点:

  1. "<<",Here Document符号,表示标准输入重定向;

  2. "EOF",内容起止符号(成对出现),表示内容块开始和终止。

终止EOF符号前不能有空格。

7.3.3. 延伸

命令1/2/3执行结果相同,但实用程度排名则是这样:

正常 << 便捷 << 超级实用

对标准输入重定向理解到位,可是能极大提升Linux使用效率。

场景:导入/导出MySQL数据

Linux作为开发环境、服务器系统首选,搭配MySQL使用是很自然的事情。导入/导出MySQL数据基本成为了日常操作。

事实上,99%的人都是在用GUI图形工具处理导入导出。实际上,更简单的操作应该是这样:

使用标准输出重定向导出
mysqldump -u用户名 -p密码 数据库名称 > backup_数据库名称_2021xxxx.sql
使用标准输入重定向导入
mysql -u用户名 -p密码 数据库名称 < backup_数据库名称_2021xxxx.sql
场景:非交互式创建文件
cat << EOF > ~/foo.txt
line1
line2
line3
EOF

在脚本、技术文档或文章中用 "<< EOF" 这样的组合实在是非常舒服的一件事情。

7.4. 错误输出重定向(stderr)

错误输出重定向和标准输出重定向都是把命令的执行结果(内容)写入文件,而不是显示在屏幕上。
不同的地方在于,错误输出重定向仅在命令执行失败时有效。具体的,可以看后面的例子。

除了文件,错误输出重定向还可以 “写入” 其它地方。这些不在本文讨论范围。

在命令行中单个 "2>" 和两个 "2>>" 的用法和标准输出重定向相同。

注意是数字 2 不是 1。
极少数情况下会用到 2>&1。"2>&1" 表示将错误输出(stderr)重定向到标准输出(stdout)。

7.4.1. 例子

例子1

故意查看不存在的文件:

ls -l /usr/include ~/abcdefghijk /test/foo.txt
屏幕内容
[root@prolinux ~]# ls -l /usr/include ~/abcdefghijk /test/foo.txt
ls: 无法访问/root/abcdefghijk: 没有那个文件或目录
ls: 无法访问/test/foo.txt: 没有那个文件或目录
/usr/include:
总用量 0
drwxr-xr-x. 2 root root 26 8月  27 2019 python2.7

可以看到 "/usr/include" 的文件,另外两个文件则报错。

例子2

用错误输出重定向改造下,错误提示写到文件中:

ls -l /usr/include ~/abcdefghijk /test/foo.txt 2>~/error.log
屏幕内容
[root@prolinux ~]# ls -l /usr/include ~/abcdefghijk /test/foo.txt 2>~/error.log
/usr/include:
总用量 0
drwxr-xr-x. 2 root root 26 8月  27 2019 python2.7

这次屏幕看起来干净些,错误提示也“消失了”。

看看 "~/error.log" 的内容:

[root@prolinux ~]# cat ~/error.log
ls: 无法访问/root/abcdefghijk: 没有那个文件或目录
ls: 无法访问/test/foo.txt: 没有那个文件或目录

8. 管道

8.1. 管道

管道("|")可以将两个命令连接起来,上个命令的标准输出(stdout)作为下个命令的标准输入(stdin)。
结合管道可以完成更加复杂的命令操作。

8.1.1. 基础用法

命令1 | 命令2 | 命令3 | ... | 命令N
管道前后的空格只是为了好看。

8.1.2. 示例

列出 "/usr" 目录下的前5个文件或目录
ls -l /usr | head -n 5
输出
total 124
dr-xr-xr-x.   2 root root 36864 Feb  4 14:08 bin
drwxr-xr-x.   2 root root  4096 Apr 11  2018 etc
drwxr-xr-x.   2 root root  4096 Apr 11  2018 games
drwxr-xr-x.  46 root root  4096 Jul 11  2020 include
打印运行进程的用户名
ps aux | tail -n +2 | cut -d ' ' -f 1 | sort -u
输出
chrony
dbus
mysql
nginx
nobody
polkitd
root
tcpdump
参数说明
排除标题行

tail -n +2 可以过滤 ps aux 输出的第一行(标题行),最后只打印第二行到最后一行

分列

cut -d ' ' -f 1 表示用空格分隔行,打印第一列

排序去重

sort -u

这个示例比前面的更加复杂,也充分展示了管道的强大之处。

完成这样的小case不用脚本,不用编程,简直十分跟手。

另外,不需要担心这些没见过的“陌生人”,下一章会详细介绍这些命令的使用方法和参数。

8.1.3. 延伸

极少数命令会打印内容到错误输出(stderr),管道会失效。

“怎么办呢?”

“没关系,输出重定向就行了~”

就像这样:

strace -f -p 1038 2>&1 | grep NULL
输出
[pid  7888] futex(0x1ebe544, FUTEX_WAIT_PRIVATE, 8288, NULL <unfinished ...>
[pid   889] futex(0x1ebe544, FUTEX_WAIT_PRIVATE, 8288, NULL <unfinished ...>
[pid   888] futex(0x1ebe544, FUTEX_WAIT_PRIVATE, 8288, NULL <unfinished ...>
[pid 25199] futex(0x1ebe544, FUTEX_WAIT_PRIVATE, 8288, NULL <unfinished ...>
[pid 25198] futex(0x1ebe544, FUTEX_WAIT_PRIVATE, 8288, NULL <unfinished ...>
[pid  1671] futex(0x1ebe544, FUTEX_WAIT_PRIVATE, 8288, NULL <unfinished ...>
[pid  1344] futex(0x1e8b044, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
[pid  1343] rt_sigtimedwait([HUP QUIT TERM], NULL, NULL, 8 <unfinished ...>
[pid  1314] futex(0x33bb424, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
[pid  1311] futex(0x33bb304, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
[pid  1308] futex(0x33bb154, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
[pid  1307] futex(0x33bb0c4, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
[pid  1306] futex(0x33bb034, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
[pid  1305] futex(0x33bafa4, FUTEX_WAIT_PRIVATE, 3, NULL <unfinished ...>

"2>&1" 表示将错误输出(stderr)重定向到标准输出(stdout)。

系统默认未安装 strace 命令,需要提前安装:yum install -y strace

9. 常用命令

9.1. 我在哪儿(pwd)

pwd - 查看当前(工作)目录绝对路径

9.1.1. 基础用法

pwd

无常用参数。

9.1.2. 操作演示

查看当前路径
cd /usr
pwd

cd /usr/share/zoneinfo/Asia
pwd

cd
pwd
屏幕内容
/usr

/usr/share/zoneinfo/Asia

/root

9.2. 排序和去重(sort)

sort - 将管道、标准输入或文件的行排序后,打印到标准输出

9.2.1. 基础用法

sort 文件名或路径

命令 | sort
常用参数
-u

排序后,去重

--help

帮助信息

9.2.2. 操作演示

开始之前
创建演示文件
cat << EOF > ~/foo.txt
8888
5555
5555
8888
6666
ZZZZ
1111
aaaa
3333
0000
2222
ZZZZ
1111
aaaa
3333
0000
2222
EOF

cat << EOF > ~/ip.txt
8.8.8.8
8.8.8.8
125.64.74.81
125.93.75.146
58.47.128.241
4.4.4.4
4.4.4.4
58.47.128.241
124.94.202.242
124.225.123.2
60.16.181.208
116.255.130.10
117.81.43.159
61.146.41.106
113.6.18.36
123.6.150.215
123.188.196.36
116.52.35.6
121.228.43.0
122.224.236.26
EOF
排序

方法一:从文件读取行:

sort ~/foo.txt

方法二:从管道读取行:

cat ~/foo.txt | sort

方法三:从标准输入读取行(非主流的方法):

sort << EOF
8888
5555
5555
8888
6666
ZZZZ
1111
aaaa
3333
0000
2222
ZZZZ
1111
aaaa
3333
0000
2222
EOF

以上方法都会得到相同的结果:

屏幕内容
0000
0000
1111
1111
2222
2222
3333
3333
5555
5555
6666
8888
8888
aaaa
aaaa
ZZZZ
ZZZZ
排序去重

"-u" 参数是关键。试一试:

sort -u ~/foo.txt
屏幕内容
0000
1111
2222
3333
5555
6666
8888
aaaa
ZZZZ

现在,执行结果中的重复行已经被过滤掉。

可以试一试看 cat ~/foo.txt | sort -u 又是什么样。

延伸:排序IPv4地址
sort -u -t . -k 1n,1n -k 2n,2n -k 3n,3n -k 4n,4n ~/ip.txt

偷懒的方法:

sort -u -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n ~/ip.txt
参数说明
-u

排序后,去重

-t

指定分隔符,用 "." 分隔IP地址为4列

-k

排序关键字,参数值格式:"开始列号[排序规则],结束列号[排序规则]"。
比如,1n,1n 表示从第1列行首开始到第1列行尾结束,都以数字规则 "n" 排序

更加偷懒的方法:

sort -u -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 ~/ip.txt
参数说明
-u

同上

-t

同上

-n

以数字规则排序

-k

同上,用 "-n" 参数代替 "n" 后,"1n,1n" 简写成 "1,1"

以上方法都会得到相同的结果:

屏幕内容
4.4.4.4
8.8.8.8
58.47.128.241
60.16.181.208
61.146.41.106
113.6.18.36
116.52.35.6
116.255.130.10
117.81.43.159
121.228.43.0
122.224.236.26
123.6.150.215
123.188.196.36
124.94.202.242
124.225.123.2
125.64.74.81
125.93.75.146

“学废了没?”

“试试IPv6地址排序?”

“安排~”

结束之后

删除临时文件:

rm -f ~/foo.txt ~/ip.txt

9.3. 快捷方式(ln)

ln - 创建目录或文件的快捷方式,也可以称做软链接

ln 用法较多,本文仅讨论软链接。

9.3.1. 为什么要用软链接

  • 文件太大,不想移动文件;

  • 文件不能随便修改位置,可能导致软件运行出错;

  • 想加一个方便的入口;

  • …​…​

9.3.2. 基础用法

ln -s 源路径 目标路径
常用参数
-s

创建软链接

--help

帮助信息

9.3.3. 操作演示

开始之前

准备测试文件和目录:

mkdir -p /tmp/foo
echo 'Hello World!' > /tmp/foo/source.txt

看看文件:

ls -l /tmp/foo/source.txt

cat /tmp/foo/source.txt
屏幕内容
total 4
-rw-r--r-- 1 root root 13 Feb 19 22:27 /tmp/foo/source.txt

Hello World!
创建文件的快捷方式

创建 "source.txt" 的快捷方式:

ln -s /tmp/foo/source.txt ~/target.txt

看看 target.txt 的文件属性:

ls -l ~/target.txt
屏幕内容
lrwxrwxrwx 1 root root 14 Feb 19 22:30 /root/target.txt -> /tmp/foo/source.txt

箭头符号 "→" 是软链接最重要的标志。

那文件内容呢?再看:

cat ~/target.txt
屏幕内容
Hello World!

我家小朋友都看出来了,你呢?

"~/target.txt" 是 "/tmp/foo/source.txt" 的软链接。

最后强调下
  • 删除 "~/target.txt" 后,"/tmp/foo/source.txt" 还在

  • 删除 "/tmp/foo/source.txt" 后,"~/target.txt" 可就不能用了哦

创建目录的快捷方式

创建 "/tmp/foo" 的快捷方式:

ln -s /tmp/foo /tmp/foo.link

看看:

ls -l /tmp/foo.link
屏幕内容
lrwxrwxrwx 1 root root 8 Feb 19 22:48 /tmp/foo.link -> /tmp/foo

悄悄加个 "/" 在最后,再看看:

ls -l /tmp/foo.link/
屏幕内容
total 4
-rw-r--r-- 1 root root 13 Feb 19 22:27 source.txt

加不加,可是不一样的哦。

结束之后

删除临时文件:

rm -rf /tmp/foo

rm 也能删除软链接:

rm -f /tmp/foo.link ~/target.txt

9.4. 下载工具(curl)

curl - 一个用来传输数据的命令行工具(就是个功能丰富的下载工具)

curl 支持非常多的网络协议,本文仅介绍HTTP协议。

9.4.1. 基础用法

URL一定要用一对单引号包住,否则URL中的特殊符合会导致错误。
curl -I url

curl -v -I url

curl url -o 文件名

curl -H -X HTTP方法 url

curl -A "User-Agent" url
常用参数
-I

仅显示HTTP头信息

-v

显示更多HTTP信息,常用于诊断问题

-o

下载,另存为

-X

指定HTTP方法,HTTP协议的GET/POST/PUT/OPTIONS/DELETE/HEAD等等

-H

自定义HTTP头

-A

指定浏览器标识(User-Agent)

--help all

帮助信息

9.4.2. 操作演示

下载文件并保存

下载文件到当前路径,文件名为 "centos-logo-white.png":

curl 'https://www.centos.org/assets/img/centos-logo-white.png' -o centos-logo-white.png

指定文件路径:

curl 'https://www.centos.org/assets/img/centos-logo-white.png' -o /tmp/123.png

查看下载的文件:

file /tmp/123.png  centos-logo-white.png
屏幕内容
/tmp/123.png:          PNG image data, 331 x 93, 8-bit/color RGBA, non-interlaced
centos-logo-white.png: PNG image data, 331 x 93, 8-bit/color RGBA, non-interlaced

用 file 看到,从官网下载的CentOS LOGO图片分辨率为 "331 x 93"。

查看HTTP头信息

绝对的装X神技,开发者必备的常用技能。

一秒诊断网站故障:

curl -I 'https://www.centos.org/assets/img/centos-logo-white.png'
屏幕内容
HTTP/1.1 200 OK
Date: Thu, 04 Mar 2021 12:45:45 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips
Strict-Transport-Security: max-age=31536000
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Last-Modified: Thu, 04 Mar 2021 12:25:14 GMT
ETag: "1d8f-5bcb50f3dd2d8"
Accept-Ranges: bytes
Content-Length: 7567
Content-Type: image/png

看到 "HTTP/1.1 200 OK" 表示网站能够访问。出现403/404/502情况,说明网站无法访问。

更多HTTP协议细节,请移步 MDN Web Docs
查看更多HTTP头信息

显示更多访问细节:

curl -vI 'https://www.centos.org/assets/img/centos-logo-white.png'

或

curl -v -I 'https://www.centos.org/assets/img/centos-logo-white.png'
屏幕内容
* About to connect() to www.centos.org port 443 (#0)
*   Trying 81.171.33.202...
* Connected to www.centos.org (81.171.33.202) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
* 	subject: CN=centos.org
* 	start date: Jan 04 06:50:09 2021 GMT
* 	expire date: Apr 04 06:50:09 2021 GMT
* 	common name: centos.org
* 	issuer: CN=R3,O=Let's Encrypt,C=US
> HEAD / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.centos.org
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
......
......
指定浏览器标识(User-Agent)

模拟百度访问CentOS官网:

curl -vI 'https://www.centos.org/' -A 'Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)'
屏幕内容
* About to connect() to www.centos.org port 443 (#0)
*   Trying 81.171.33.202...
* Connected to www.centos.org (81.171.33.202) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
* 	subject: CN=centos.org
* 	start date: Jan 04 06:50:09 2021 GMT
* 	expire date: Apr 04 06:50:09 2021 GMT
* 	common name: centos.org
* 	issuer: CN=R3,O=Let's Encrypt,C=US
> HEAD / HTTP/1.1
> User-Agent: Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)
> Host: www.centos.org
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
......
......

注意屏幕中的 "User-Agent" 一行。

去掉HTTP头信息:

curl 'https://www.centos.org/' -A 'Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)' -o /dev/null
Linux最有意思的地方就是:你永远不知道还有多少黑科技! "/dev/null" 表示将内容写到黑洞,丢东西进去什么事情都不会发生。

9.4.3. 延伸

自定义HTTP头和指定HTTP方法
运行本示例需要可用的网站URL。"http://localhost:9200" 仅做示意,是无法访问的。

默认 curl 使用GET方法请求网站,也可以用 "-X" 指定其它的HTTP方法。

curl -H "Content-Type: application/json" -X POST 'http://localhost:9200/wecompany/employee/2?pretty' -d '
{
    "first_name" :  "Jane",
    "last_name" :   "Smith",
    "age" :         32,
    "about" :       "I like to collect rock albums",
    "interests":  [ "music" ]
}
'
"-H "Content-Type: application/json""

设置HTTP头:Content-Type,表示本次用JSON格式传输请求参数

"-X POST"

指定HTTP方法,向网站服务器发起POST请求

"-d …​"

POST请求的JSON格式参数

9.5. 下载工具(wget)

wget - 功能强大的下载工具,相比 curl 来说功能更加侧重下载。

wget 功能丰富,本文仅介绍基础功能。

9.5.1. 基础用法

URL一定要用一对单引号包住,否则URL中的特殊符合会导致错误。
wget -c url

wget url -O 文件保存位置

wget -c url -O 文件保存位置
常用参数
-c

断点续传下载文件

-O

指定下载文件保存位置,如果文件已经存在则覆盖

-h

帮助信息

9.5.2. 操作演示

断点续传下载文件

下载一个934M的安装镜像文件:

wget http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso
屏幕内容
--2021-03-29 13:10:43--  http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso
Resolving mirrors.163.com (mirrors.163.com)... 42.186.18.104, 42.186.18.105
Connecting to mirrors.163.com (mirrors.163.com)|42.186.18.104|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1020264448 (973M) [application/octet-stream]
Saving to: ‘CentOS-7-x86_64-Minimal-2009.iso’

 5% [====>                                                           ] 51,857,416  13.7MB/s  eta 60s

下载到约 "1%" 时,按 Ctrl+C 故意停止下载。

查看下载的ISO文件:

ll CentOS-7-x86_64-Minimal-2009.iso*
屏幕内容
-rw-r--r-- 1 root root 52018640 Mar 29 13:10 CentOS-7-x86_64-Minimal-2009.iso

看到 "52018640" 大概已经下载了50M,明显没有下载完。

再执行一次命令,接着下载:

wget http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso
屏幕内容
--2021-03-29 13:14:49--  http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso
Resolving mirrors.163.com (mirrors.163.com)... 42.186.18.105, 42.186.18.104
Connecting to mirrors.163.com (mirrors.163.com)|42.186.18.105|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1020264448 (973M) [application/octet-stream]
Saving to: ‘CentOS-7-x86_64-Minimal-2009.iso.1’

 4% [====>                                                                     ] 44,391,528  16.0MB/s

查看这次下载的ISO文件:

ll CentOS-7-x86_64-Minimal-2009.iso*
屏幕内容
-rw-r--r-- 1 root root 52018640 Mar 29 13:10 CentOS-7-x86_64-Minimal-2009.iso
-rw-r--r-- 1 root root 46634976 Mar 29 13:14 CentOS-7-x86_64-Minimal-2009.iso.1

多了一个 "CentOS-7-x86_64-Minimal-2009.iso.1"?

执行了两次 wget 得到两个单独的ISO文件,这不是我们想要的。

“我想断点续传…​…​”

加上 "-c" 表示断点续传:

wget -c http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso
屏幕内容
--2021-03-29 13:18:22--  http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso
Resolving mirrors.163.com (mirrors.163.com)... 42.186.18.105, 42.186.18.104
Connecting to mirrors.163.com (mirrors.163.com)|42.186.18.105|:80... connected.
HTTP request sent, awaiting response... 206 Partial Content
Length: 1020264448 (973M), 968245808 (923M) remaining [application/octet-stream]
Saving to: ‘CentOS-7-x86_64-Minimal-2009.iso’

12% [+++++========>                                                   ] 123,450,640 11.7MB/s  eta 60s

你可以用 ll 命令看看效果:

ll CentOS-7-x86_64-Minimal-2009.iso*
指定下载文件保存位置,如果文件已经存在则覆盖

下载文件名和保存文件名("CentOS-7-x86_64-Minimal-2009.torrent")相同:

wget http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.torrent -O /tmp/CentOS-7-x86_64-Minimal-2009.torrent

保存为不同的文件名("CentOS7_Minimal.torrent"):

wget http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.torrent -O /tmp/CentOS7_Minimal.torrent
指定下载文件保存位置,如果文件已经存在则断点续传

断点续传方式下载文件 "CentOS-7-x86_64-Minimal-2009.iso ",保存到目录 "/tmp":

wget -c http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso -O /tmp/CentOS-7-x86_64-Minimal-2009.iso
屏幕内容
--2021-03-29 13:38:56--  http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso
Resolving mirrors.163.com (mirrors.163.com)... 42.186.18.105, 42.186.18.104
Connecting to mirrors.163.com (mirrors.163.com)|42.186.18.105|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1020264448 (973M) [application/octet-stream]
Saving to: ‘/tmp/CentOS-7-x86_64-Minimal-2009.iso’

14% [================>                                                ] 149,493,656 11.7MB/s  eta 65s
屏幕内容(下载完毕)
--2021-03-29 13:43:15--  http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso
Resolving mirrors.163.com (mirrors.163.com)... 42.186.18.105, 42.186.18.104
Connecting to mirrors.163.com (mirrors.163.com)|42.186.18.105|:80... connected.
HTTP request sent, awaiting response... 206 Partial Content
Length: 1020264448 (973M), 942778880 (899M) remaining [application/octet-stream]
Saving to: ‘/tmp/CentOS-7-x86_64-Minimal-2009.iso’

100%[++++++++======================================================>] 1,020,264,448 11.7MB/s   in 76s

2021-03-29 13:44:31 (11.8 MB/s) - ‘/tmp/CentOS-7-x86_64-Minimal-2009.iso’ saved [1020264448/1020264448]
结束之后

删除临时文件:

rm -f /tmp/CentOS-7-x86_64-Minimal-2009.iso* CentOS-7-x86_64-Minimal-2009.iso* /tmp/CentOS-7-x86_64-Minimal-2009.torrent /tmp/CentOS7_Minimal.torrent

9.6. 打印前N行(head)

head - 打印文件的前N行到标准输出

9.6.1. 基础用法

head -n 数量 文件名或路径

命令 | head -n 数量
常用参数
-n

打印前N行。以 '-' 开头时,打印除最后N行以外的所有行。

--help

帮助信息

9.6.2. 操作演示

开始之前

准备演示用的文件:

ls -l / | cat -n > ~/foo.txt
foo.txt内容
     1	total 64
     2	lrwxrwxrwx.  1 root root     7 Feb 15  2019 bin -> usr/bin
     3	dr-xr-xr-x.  5 root root  4096 Aug  9  2019 boot
     4	drwxr-xr-x   5 root root  4096 Aug  1  2019 data
     5	drwxr-xr-x  19 root root  2980 Apr 21  2020 dev
     6	drwxr-xr-x. 91 root root  4096 Jul 11  2020 etc
     7	drwxr-xr-x.  3 root root  4096 Jun 27  2019 home
     8	lrwxrwxrwx.  1 root root     7 Feb 15  2019 lib -> usr/lib
     9	lrwxrwxrwx.  1 root root     9 Feb 15  2019 lib64 -> usr/lib64
    10	drwx------.  2 root root 16384 Feb 15  2019 lost+found
    11	drwxr-xr-x.  2 root root  4096 Apr 11  2018 media
    12	drwxr-xr-x.  2 root root  4096 Apr 11  2018 mnt
    13	drwxr-xr-x.  4 root root  4096 May 13  2019 opt
    14	dr-xr-xr-x  88 root root     0 Apr 12  2020 proc
    15	dr-xr-x---.  9 root root  4096 Feb 19 12:40 root
    16	drwxr-xr-x  25 root root   740 Feb  4 14:08 run
    17	lrwxrwxrwx.  1 root root     8 Feb 15  2019 sbin -> usr/sbin
    18	drwxr-xr-x.  2 root root  4096 Apr 11  2018 srv
    19	dr-xr-xr-x  13 root root     0 Feb 18 10:24 sys
    20	drwxrwxrwt.  8 root root  4096 Feb 19 03:11 tmp
    21	drwxr-xr-x. 13 root root  4096 Feb 15  2019 usr
    22	drwxr-xr-x. 20 root root  4096 May 27  2019 var
打印前14行
head -n 14 ~foo.txt
屏幕内容
     1	total 64
     2	lrwxrwxrwx.  1 root root     7 Feb 15  2019 bin -> usr/bin
     3	dr-xr-xr-x.  5 root root  4096 Aug  9  2019 boot
     4	drwxr-xr-x   5 root root  4096 Aug  1  2019 data
     5	drwxr-xr-x  19 root root  2980 Apr 21  2020 dev
     6	drwxr-xr-x. 91 root root  4096 Jul 11  2020 etc
     7	drwxr-xr-x.  3 root root  4096 Jun 27  2019 home
     8	lrwxrwxrwx.  1 root root     7 Feb 15  2019 lib -> usr/lib
     9	lrwxrwxrwx.  1 root root     9 Feb 15  2019 lib64 -> usr/lib64
    10	drwx------.  2 root root 16384 Feb 15  2019 lost+found
    11	drwxr-xr-x.  2 root root  4096 Apr 11  2018 media
    12	drwxr-xr-x.  2 root root  4096 Apr 11  2018 mnt
    13	drwxr-xr-x.  4 root root  4096 May 13  2019 opt
    14	dr-xr-xr-x  88 root root     0 Apr 12  2020 proc
打印最后8行以外的所有行
head -n -8 ~/foo.txt
屏幕内容
     1	total 64
     2	lrwxrwxrwx.  1 root root     7 Feb 15  2019 bin -> usr/bin
     3	dr-xr-xr-x.  5 root root  4096 Aug  9  2019 boot
     4	drwxr-xr-x   5 root root  4096 Aug  1  2019 data
     5	drwxr-xr-x  19 root root  2980 Apr 21  2020 dev
     6	drwxr-xr-x. 91 root root  4096 Jul 11  2020 etc
     7	drwxr-xr-x.  3 root root  4096 Jun 27  2019 home
     8	lrwxrwxrwx.  1 root root     7 Feb 15  2019 lib -> usr/lib
     9	lrwxrwxrwx.  1 root root     9 Feb 15  2019 lib64 -> usr/lib64
    10	drwx------.  2 root root 16384 Feb 15  2019 lost+found
    11	drwxr-xr-x.  2 root root  4096 Apr 11  2018 media
    12	drwxr-xr-x.  2 root root  4096 Apr 11  2018 mnt
    13	drwxr-xr-x.  4 root root  4096 May 13  2019 opt
    14	dr-xr-xr-x  88 root root     0 Apr 12  2020 proc
foo.txt共22行,"-n 14" 和 "-n -8" 得到的结果相同。
打印来自标准输出的前3行
cat ~/foo.txt | head -n 3
屏幕内容
     1	total 64
     2	lrwxrwxrwx.  1 root root     7 Feb 15  2019 bin -> usr/bin
     3	dr-xr-xr-x.  5 root root  4096 Aug  9  2019 boot
结束之后

删除临时文件:

rm -f ~/foo.txt

9.7. 打印后N行(tail)

tail - 打印文件的后N行到标准输出

9.7.1. 基础用法

tail -n 数量 文件名或路径

命令 | tail -n 数量

tail -f 文件名或路径
常用参数
-f

实时滚动刷新,打印新增的数据

-n

打印最后N行。以 '+' 开头时,从第N行开始打印所有行

--help

帮助信息

9.7.2. 操作演示

开始之前

准备演示用的文件:

ls -l / | cat -n > ~/foo.txt
touch ~/bar.txt
foo.txt内容
     1	total 64
     2	lrwxrwxrwx.  1 root root     7 Feb 15  2019 bin -> usr/bin
     3	dr-xr-xr-x.  5 root root  4096 Aug  9  2019 boot
     4	drwxr-xr-x   5 root root  4096 Aug  1  2019 data
     5	drwxr-xr-x  19 root root  2980 Apr 21  2020 dev
     6	drwxr-xr-x. 91 root root  4096 Jul 11  2020 etc
     7	drwxr-xr-x.  3 root root  4096 Jun 27  2019 home
     8	lrwxrwxrwx.  1 root root     7 Feb 15  2019 lib -> usr/lib
     9	lrwxrwxrwx.  1 root root     9 Feb 15  2019 lib64 -> usr/lib64
    10	drwx------.  2 root root 16384 Feb 15  2019 lost+found
    11	drwxr-xr-x.  2 root root  4096 Apr 11  2018 media
    12	drwxr-xr-x.  2 root root  4096 Apr 11  2018 mnt
    13	drwxr-xr-x.  4 root root  4096 May 13  2019 opt
    14	dr-xr-xr-x  88 root root     0 Apr 12  2020 proc
    15	dr-xr-x---.  9 root root  4096 Feb 19 12:40 root
    16	drwxr-xr-x  25 root root   740 Feb  4 14:08 run
    17	lrwxrwxrwx.  1 root root     8 Feb 15  2019 sbin -> usr/sbin
    18	drwxr-xr-x.  2 root root  4096 Apr 11  2018 srv
    19	dr-xr-xr-x  13 root root     0 Feb 18 10:24 sys
    20	drwxrwxrwt.  8 root root  4096 Feb 19 03:11 tmp
    21	drwxr-xr-x. 13 root root  4096 Feb 15  2019 usr
    22	drwxr-xr-x. 20 root root  4096 May 27  2019 var
打印最后10行
tail -n 10 ~/foo.txt
屏幕内容
    13	drwxr-xr-x.  4 root root  4096 May 13  2019 opt
    14	dr-xr-xr-x  88 root root     0 Apr 12  2020 proc
    15	dr-xr-x---.  9 root root  4096 Feb 19 12:40 root
    16	drwxr-xr-x  25 root root   740 Feb  4 14:08 run
    17	lrwxrwxrwx.  1 root root     8 Feb 15  2019 sbin -> usr/sbin
    18	drwxr-xr-x.  2 root root  4096 Apr 11  2018 srv
    19	dr-xr-xr-x  13 root root     0 Feb 18 10:24 sys
    20	drwxrwxrwt.  8 root root  4096 Feb 19 03:11 tmp
    21	drwxr-xr-x. 13 root root  4096 Feb 15  2019 usr
    22	drwxr-xr-x. 20 root root  4096 May 27  2019 var
从第8行开始打印所有行
tail -n +8 ~/foo.txt
屏幕内容
     8	lrwxrwxrwx.  1 root root     7 Feb 15  2019 lib -> usr/lib
     9	lrwxrwxrwx.  1 root root     9 Feb 15  2019 lib64 -> usr/lib64
    10	drwx------.  2 root root 16384 Feb 15  2019 lost+found
    11	drwxr-xr-x.  2 root root  4096 Apr 11  2018 media
    12	drwxr-xr-x.  2 root root  4096 Apr 11  2018 mnt
    13	drwxr-xr-x.  4 root root  4096 May 13  2019 opt
    14	dr-xr-xr-x  88 root root     0 Apr 12  2020 proc
    15	dr-xr-x---.  9 root root  4096 Feb 19 12:40 root
    16	drwxr-xr-x  25 root root   740 Feb  4 14:08 run
    17	lrwxrwxrwx.  1 root root     8 Feb 15  2019 sbin -> usr/sbin
    18	drwxr-xr-x.  2 root root  4096 Apr 11  2018 srv
    19	dr-xr-xr-x  13 root root     0 Feb 18 10:24 sys
    20	drwxrwxrwt.  8 root root  4096 Feb 19 03:11 tmp
    21	drwxr-xr-x. 13 root root  4096 Feb 15  2019 usr
    22	drwxr-xr-x. 20 root root  4096 May 27  2019 var
打印来自标准输出的最后5行
cat ~/foo.txt | tail -n 5
屏幕内容
    18	drwxr-xr-x.  2 root root  4096 Apr 11  2018 srv
    19	dr-xr-xr-x  13 root root     0 Feb 18 10:24 sys
    20	drwxrwxrwt.  8 root root  4096 Feb 19 03:11 tmp
    21	drwxr-xr-x. 13 root root  4096 Feb 15  2019 usr
    22	drwxr-xr-x. 20 root root  4096 May 27  2019 var
实时滚动刷新
本示例会用到两个终端。
终端1
tail -f ~/bar.txt

这时终端1的屏幕上没有任何内容显示。

终端1保持打开状态,不要关闭

保持终端1和终端2,在终端2中反复执行以下命令:

终端2
echo `date "+%Y.%m.%d %M:%H:%S.%N"` >> ~/bar.txt

在终端2中反复执行3次命令后,终端1的屏幕内容结果如下:

第1次
2021.02.19 18:13:23.935206258
第2次
2021.02.19 18:13:23.935206258
2021.02.19 18:13:25.647371570
第3次
2021.02.19 18:13:23.935206258
2021.02.19 18:13:25.647371570
2021.02.19 18:13:26.607005345

可以看到终端1的屏幕内容一直在实时滚动刷新。

tail -f access.log 在查看网站访问日志记录时非常实用。
结束之后

删除临时文件:

rm -f ~/foo.txt ~/bar.txt

9.8. 打印到标准输出(cat)

cat - 打印一个或多个文件的内容到标准输出

9.8.1. 基础用法

cat 文件名或路径

cat 文件名或路径 | 命令
常用参数
-n

在行首添加行序号

--help

帮助信息

9.8.2. 操作演示

开始之前

创建演示文件

echo 'foo.line1' > ~/foo.txt
echo 'foo.line2' >> ~/foo.txt

echo 'bar.line1' > ~/bar.txt
echo 'bar.line2' >> ~/bar.txt
打印文件内容
cat ~/foo.txt ~/bar.txt
屏幕内容
foo.line1
foo.line2
bar.line1
bar.line2
打印时加上序号
cat -n ~/foo.txt ~/bar.txt
屏幕内容
     1	foo.line1
     2	foo.line2
     3	bar.line1
     4	bar.line2
延伸:打印并排序文件内容
cat ~/foo.txt ~/bar.txt | sort
屏幕内容
bar.line1
bar.line2
foo.line1
foo.line2
结束之后

删除临时文件:

rm -f ~/foo.txt ~/bar.txt

9.9. 打印第N列(cut)

cut - 将行转为列,将指定列打印到标准输出

在Linux中处理数据时,分列和管道操作简直就是银弹,无敌的存在~

9.9.1. 基础用法

cut -d '分隔符' -f 列号 文件名或路径

命令 | cut -d '分隔符' -f 列号
常用参数
-d

列分隔符

-f

选中的列号列表,可以同时打印多列

--help

帮助信息

9.9.2. 操作演示

在前面讲管道的章节,演示过复杂的命令:

ps aux | tail -n +2 | cut -d ' ' -f 1 | sort -u

“有没有简单又形象的例子”

“往下看…​…​”

开始之前

网站日志分析是家常便饭,准备一些简化后的日志记录:

cat << EOF > ~/access.log
foo.com 80 118.118.47.239 [18/Feb/2021:23:22:23] "GET /360.html HTTP/1.1" 200
foo.com 80 115.202.80.105 [18/Feb/2021:23:22:24] "GET /login HTTP/1.1" 200
foo.com 80 123.6.49.36 [18/Feb/2021:23:22:24] "GET / HTTP/1.1" 200
foo.com 80 180.101.214.20 [18/Feb/2021:23:22:24] "GET /main.html HTTP/1.1" 200
foo.com 80 180.101.52.35 [18/Feb/2021:23:22:24] "GET /jquery.min.js HTTP/1.1" 200
foo.com 80 148.72.153.60 [18/Feb/2021:23:25:16] "GET /7.html HTTP/1.1" 200
foo.com 80 123.178.50.195 [18/Feb/2021:23:25:16] "GET /article/ HTTP/1.1" 200
EOF

仔细观察,看起来用空格分列就行了,试试~

打印日志记录的第1列
cut -d ' ' -f 1 ~/access.log
屏幕内容
foo.com
foo.com
foo.com
foo.com
foo.com
foo.com
foo.com
打印日志记录的第1/3/5列
cut -d ' ' -f 1,3,5 ~/access.log
屏幕内容
foo.com 118.118.47.239 "GET
foo.com 115.202.80.105 "GET
foo.com 123.6.49.36 "GET
foo.com 180.101.214.20 "GET
foo.com 180.101.52.35 "GET
foo.com 148.72.153.60 "GET
foo.com 123.178.50.195 "GET
打印日志记录的第3至4列
cut -d ' ' -f 3-4 ~/access.log
屏幕内容
118.118.47.239 [18/Feb/2021:23:22:23]
115.202.80.105 [18/Feb/2021:23:22:24]
123.6.49.36 [18/Feb/2021:23:22:24]
180.101.214.20 [18/Feb/2021:23:22:24]
180.101.52.35 [18/Feb/2021:23:22:24]
148.72.153.60 [18/Feb/2021:23:25:16]
123.178.50.195 [18/Feb/2021:23:25:16]
打印日志记录的第1至5列
cut -d ' ' -f -5 ~/access.log
屏幕内容
foo.com 80 118.118.47.239 [18/Feb/2021:23:22:23] "GET
foo.com 80 115.202.80.105 [18/Feb/2021:23:22:24] "GET
foo.com 80 123.6.49.36 [18/Feb/2021:23:22:24] "GET
foo.com 80 180.101.214.20 [18/Feb/2021:23:22:24] "GET
foo.com 80 180.101.52.35 [18/Feb/2021:23:22:24] "GET
foo.com 80 148.72.153.60 [18/Feb/2021:23:25:16] "GET
foo.com 80 123.178.50.195 [18/Feb/2021:23:25:16] "GET
打印日志记录的第5至最后1列
cut -d ' ' -f 5- ~/access.log
屏幕内容
"GET /360.html HTTP/1.1" 200
"GET /login HTTP/1.1" 200
"GET / HTTP/1.1" 200
"GET /main.html HTTP/1.1" 200
"GET /jquery.min.js HTTP/1.1" 200
"GET /7.html HTTP/1.1" 200
"GET /article/ HTTP/1.1" 200
结束之后

删除临时文件:

rm -f ~/access.log

9.10. 显示当前进程(ps)

ps - 显示当前运行的进程列表,常用于系统或程序排错

ps 命令功能强大、参数组合丰富,本文仅介绍基础功能。
作为了解系统运行状态的重要工具,ps 和 top 命令经常搭配使用。

9.10.1. 基础用法

ps -ef

ps -ef | grep python
常用参数
-e

列出所有进程

-f

显示进程命令行参数

--help all

帮助信息

9.10.2. 操作演示

列出所有进程
ps -ef
屏幕内容
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0  2020 ?        01:10:11 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root         2     0  0  2020 ?        00:00:00 [kthreadd]
root         3     2  0  2020 ?        00:14:11 [ksoftirqd/0]
root         5     2  0  2020 ?        00:00:00 [kworker/0:0H]
root         7     2  0  2020 ?        00:00:00 [migration/0]
root         8     2  0  2020 ?        00:00:00 [rcu_bh]
root         9     2  0  2020 ?        00:14:37 [rcu_sched]
root        10     2  0  2020 ?        00:00:00 [lru-add-drain]
root        11     2  0  2020 ?        00:03:14 [watchdog/0]
root        13     2  0  2020 ?        00:00:00 [kdevtmpfs]
root        14     2  0  2020 ?        00:00:00 [netns]
root        15     2  0  2020 ?        00:00:10 [khungtaskd]
......
过滤进程

ps 参数很多,不建议深入了解。直接用 grep 命令过滤输出结果为上策。

从输出结果中,找出包含 "python" 关键字的进程:

ps -ef | grep python
屏幕内容
root       941     1  0  2020 ?        01:05:04 /usr/bin/python2 -Es /usr/sbin/tuned -l -P
root     31798 30406  0 15:17 pts/0    00:00:00 grep --color=auto python
root     32050 31982  0  2020 ?        00:00:00 /opt/eff.org/certbot/venv/bin/python /tmp/tmp.VxCfwAqjDj/pipstrap.py
ps -ef | grep python | grep -v 'grep' 可以过滤掉多余的 grep 。

9.11. 文本替换(sed)

sed - 基于行的,用来过滤和转换文本的流编辑工具

sed 常用来替换每行中指定的字符串,非常方便。

其它功能不做介绍。

9.11.1. 基础用法

sed -i 's/old text/new text/g' 文件路径
常用参数
-i

修改文件,不使用该参数时修改的内容会直接打印到屏幕

s///g

"s" 表示替换动作,"g" 表示替换所有(否则,仅替换一次)

--help

帮助信息

9.11.2. 操作演示

开始之前
创建演示文件
cat << EOF > ~/word.txt
1,foobar
2,foo
3,qux
4,quux
5,quuz
EOF

为便于演示,以下操作移除了 -i 参数。实际使用过程中,用 sed -i 直接修改文件内容。

将每行中第1个 "u" 替换为 "U"
sed 's/u/U/' word.txt
屏幕内容
1,foobar
2,foo
3,qUx
4,qUux
5,qUuz
替换所有 "u" 为 "U"
sed 's/u/U/g' word.txt
屏幕内容
1,foobar
2,foo
3,qUx
4,qUUx
5,qUUz
替换文 "qux" 为 "QUX"
sed 's/qux/QUX/g' word.txt
屏幕内容
1,foobar
2,foo
3,QUX
4,quux
5,quuz
替换长度至少为3,并且以 "q" 开头的文本
sed 's/q../+++/g' word.txt
屏幕内容
1,foobar
2,foo
3,+++
4,+++x
5,+++z
替换 "5" 开头,"z" 结尾的文本
sed 's/^5.*z/+/g' word.txt
屏幕内容
1,foobar
2,foo
3,qux
4,quux
+
结束之后

删除临时文件:

rm -f ~/word.txt

9.12. 列数据组合(awk)

awk - 基于行的,文本模式扫描和处理的迷你编程语言

常用 awk 将行数据分列组合,可生成新的数据结果。相比其它类似命令(如,sed / cut),awk 更侧重列数据间的组合和拼接。

同样,awk 本文仅介绍基本用法。

不要尝试用 awk 完成复杂任务,用 Python 处理更加明智。

9.12.1. 基础用法

awk '{print $NF}' 文件路径

awk -F  ':' '{print $1 " - " $(NF-1) " - " $NF}' 文件路径
常用参数
-F

列分隔符,默认以空格分列

{ action }

执行的动作

print

打印数据到屏幕

" - "

中横线以及前后两个空格

$1

行数据的第一列

$(NF-1)

行数据的倒数第二列

$NF

行数据的最后一列

--help

帮助信息

9.12.2. 操作演示

开始之前
创建演示文件
head -n 10 /etc/group > ~/group.txt
打印第一列
awk -F ':' '{print $1}' ~/group.txt
屏幕内容
root
bin
daemon
sys
adm
tty
disk
lp
mem
kmem
打印最后一列
awk -F ':' '{print $NF}' ~/group.txt
屏幕内容
(空)
(空)
(空)
(空)
(空)
(空)
(空)
(空)
(空)
(空)
打印倒数第二列
awk -F ':' '{print $(NF-1)}' ~/group.txt
屏幕内容
0
1
2
3
4
5
6
7
8
9
打印指定列,并用中横线分隔
awk -F  ':' '{print $(NF-1) " - " $1}' ~/group.txt
屏幕内容
0 - root
1 - bin
2 - daemon
3 - sys
4 - adm
5 - tty
6 - disk
7 - lp
8 - mem
9 - kmem
结束之后

删除临时文件:

rm -f ~/group.txt

9.13. 查看内存(free)

free - 显示系统内存信息

9.13.1. 基础用法

free -h

free -m
常用参数
-h

以人类友好格式显示内存信息

-m

以Mib为单位显示内存信息

--help

帮助信息

输出说明
total

可用内存总量

used

已经分配的内存(计算方式: "total" - "free" - "buff/cache" )

free

未分配的内存

shared

(可忽略,无实际意义)

buff/cache

内核缓冲区、页面缓存和slab使用的内存数,必要时会分配给应用程序使用

available

应用程序可直接使用的内存数(估计)

Linux还剩多少内存可以给应用程序使用?

理想状态下,等于 "free" + "buff/cache"(实际中的数据有较大的误差)。

9.13.2. 操作演示

人类友好格式显示
free -h
屏幕内容
              total        used        free      shared  buff/cache   available
Mem:            23G         13G        214M         88M        9.8G        9.5G
Swap:           38G        1.2G         37G
Mib为单位显示
free -m
屏幕内容
              total        used        free      shared  buff/cache   available
Mem:          24066       13850         210          88       10005        9764
Swap:         39396        1274       38122

9.14. 查看硬盘空间(df)

df - 显示文件系统硬盘空间使用量

9.14.1. 基础用法

df -h

df -hT
常用参数
-h

以人类友好格式显示硬盘使用量

-T

打印文件系统类型

--help

帮助信息

输出说明
Filesystem

存储设备或文件系统,通常指硬盘设备、硬盘分区、网络硬盘设备、系统设备等

Type

存储设备的文件系统类型,如ext4、xfs等

Size

设备或分区总容量

Used

已用容量

Avail

可用容量

Use%

已用容量百分比

Mounted on

挂载点

操作演示

人类友好格式显示
df -h
屏幕内容
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        40G   34G  4.0G  90% /
devtmpfs        486M     0  486M   0% /dev
tmpfs           496M     0  496M   0% /dev/shm
tmpfs           496M  472K  496M   1% /run
tmpfs           496M     0  496M   0% /sys/fs/cgroup
tmpfs           100M     0  100M   0% /run/user/0
显示文件系统类型
df -hT
屏幕内容
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/vda1      ext4       40G   34G  4.0G  90% /
devtmpfs       devtmpfs  486M     0  486M   0% /dev
tmpfs          tmpfs     496M     0  496M   0% /dev/shm
tmpfs          tmpfs     496M  472K  496M   1% /run
tmpfs          tmpfs     496M     0  496M   0% /sys/fs/cgroup
tmpfs          tmpfs     100M     0  100M   0% /run/user/0

9.15. 文件格式转换(dos2unix)

dos2unix - 用于将Windows格式的纯文本文件转为Linux格式

unix2dos - 用于将Linux格式的纯文本文件转为Windows格式

以上两个命令常用于转换回车符(CR)和换行符(LF)互转。

Linux的文本文件中,换行符由单个换行符(LF)表示("\n")。

而Windows的文本文件中,换行符则由回车符(CR)和单个换行符(LF)表示("\r\n")。

9.15.1. 安装

yum install -y dos2unix unix2dos

9.15.2. 基础用法

dos2unix 文件路径

unix2dos 文件路径

无常用参数。

9.15.3. 操作演示

开始之前
创建演示文件
echo -ne "Hello\r\nWorld\r\n" > ~/foo.txt
确认文件格式
file ~/foo.txt
屏幕内容
foo.txt: ASCII text, with CRLF line terminators

"CRLF" 表示文件使用 "\r\n" 换行。

转为Linux格式
dos2unix ~/foo.txt
屏幕内容
dos2unix: converting file /root/foo.txt to Unix format ...
确认文件格式
file ~/foo.txt
屏幕内容
/root/foo.txt: ASCII text
转为Windows格式
unix2dos ~/foo.txt
屏幕内容
unix2dos: converting file /root/foo.txt to DOS format ...
确认文件格式
file ~/foo.txt
屏幕内容
/root/foo.txt: ASCII text, with CRLF line terminators
结束之后

删除临时文件:

rm -f ~/foo.txt

9.16. 显示命令路径(which)

which - 显示指定命令的完整路径

9.16.1. 基础用法

which 命令名称

无常用参数。

9.16.2. 操作演示

显示 ls 命令的路径
which ls
屏幕内容
alias ls='ls --color=auto'
	/usr/bin/ls
显示 ll 命令的路径
which ll
屏幕内容
alias ll='ls -l --color=auto'
	/usr/bin/ls
显示 mkdir 命令的路径
which mkdir
屏幕内容
/usr/bin/mkdir
显示 sshd 命令的路径
which sshd
屏幕内容
/usr/sbin/sshd

10. 内容搜索

10.1. 简介

前面已经提到过管道、cut、awk、sed、sort 等等命令。

还没来得及最受欢迎的 grep 命令。grep 可以过滤出想要的字符串,也就是一个字符串搜索工具。

当 grep 、管道以及其它命令结合在一起时,可以大大提升使用Linux的幸福感。

10.2. 基础用法

10.2.1. 一个简单示例

搜索文件中的某个字符串,指定搜索关键字和文件名即可:

grep mail /etc/passwd
屏幕内容
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

10.2.2. 忽略大小写

grep -i crond /var/log/cron
屏幕内容
May 23 03:50:01 cdgeekcamp CROND[6603]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 23 04:00:01 cdgeekcamp CROND[6610]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 23 04:01:01 cdgeekcamp CROND[6617]: (root) CMD (run-parts /etc/cron.hourly)
May 23 04:10:01 cdgeekcamp CROND[6630]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 23 04:20:01 cdgeekcamp CROND[6638]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 23 04:30:01 cdgeekcamp CROND[6645]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 23 04:40:01 cdgeekcamp CROND[6652]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 23 04:50:01 cdgeekcamp CROND[6660]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 23 05:00:01 cdgeekcamp CROND[6669]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 23 05:01:01 cdgeekcamp CROND[6676]: (root) CMD (run-parts /etc/cron.hourly)

10.2.3. 反向匹配

grep -v 'run-parts /etc/cron.hourly' /var/log/cron
关键字包含空格时,必须用单引号或双引号包起来。
屏幕内容
May 23 03:42:01 cdgeekcamp run-parts(/etc/cron.daily)[6576]: finished logrotate
May 23 03:42:01 cdgeekcamp run-parts(/etc/cron.daily)[6559]: starting man-db.cron
May 23 03:42:01 cdgeekcamp run-parts(/etc/cron.daily)[6587]: finished man-db.cron
May 23 03:42:01 cdgeekcamp run-parts(/etc/cron.daily)[6559]: starting mlocate
May 23 03:42:01 cdgeekcamp run-parts(/etc/cron.daily)[6598]: finished mlocate
May 23 03:42:01 cdgeekcamp anacron[6534]: Job `cron.daily' terminated
May 23 03:42:01 cdgeekcamp anacron[6534]: Normal exit (1 job run)
May 23 03:50:01 cdgeekcamp CROND[6603]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 23 04:00:01 cdgeekcamp CROND[6610]: (root) CMD (/usr/lib64/sa/sa1 1 1)
May 23 04:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6617]: starting 0anacron
May 23 04:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6626]: finished 0anacron

10.3. 搜索目录下文件的内容

grep -r -i crond /var/log/

或

grep -ri crond /var/log/
屏幕内容
/var/log/cron-20210509:May  2 03:10:01 cdgeekcamp CROND[22917]: (root) CMD (/usr/lib64/sa/sa1 1 1)
/var/log/cron-20210509:May  2 03:20:01 cdgeekcamp CROND[23403]: (root) CMD (/usr/lib64/sa/sa1 1 1)
/var/log/cron-20210509:May  2 03:30:01 cdgeekcamp CROND[23889]: (root) CMD (/usr/lib64/sa/sa1 1 1)
/var/log/cron-20210509:May  2 03:40:01 cdgeekcamp CROND[24375]: (root) CMD (/usr/lib64/sa/sa1 1 1)
/var/log/cron-20210509:May  2 03:50:01 cdgeekcamp CROND[24862]: (root) CMD (/usr/lib64/sa/sa1 1 1)
......
/var/log/audit/audit.log.1:type=USER_ACCT msg=audit(1620024001.562:647420): pid=29877 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:accounting grantors=pam_access,pam_unix,pam_localuser acct="root" exe="/usr/sbin/crond" hostname=? addr=? terminal=cron res=success'
/var/log/audit/audit.log.1:type=CRED_ACQ msg=audit(1620024001.562:647421): pid=29877 uid=0 auid=4294967295 ses=4294967295 msg='op=PAM:setcred grantors=pam_env,pam_unix acct="root" exe="/usr/sbin/crond" hostname=? addr=? terminal=cron res=success'

10.4. 搜索结果计数

grep 能做搜索过滤,还可以输出数字或计数信息。

10.4.1. 统计文本在文件中出现多少次

grep -c cron.hourly /var/log/cron
屏幕内容
318

文本 "cron.hourly" 在文件中出现 "318" 次。

10.4.2. 打印行号

grep -n cron.hourly /var/log/cron
屏幕内容
10:May 23 04:01:01 cdgeekcamp CROND[6617]: (root) CMD (run-parts /etc/cron.hourly)
11:May 23 04:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6617]: starting 0anacron
12:May 23 04:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6626]: finished 0anacron
19:May 23 05:01:01 cdgeekcamp CROND[6676]: (root) CMD (run-parts /etc/cron.hourly)
20:May 23 05:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6676]: starting 0anacron
21:May 23 05:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6685]: finished 0anacron
28:May 23 06:01:01 cdgeekcamp CROND[6733]: (root) CMD (run-parts /etc/cron.hourly)
29:May 23 06:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6733]: starting 0anacron
30:May 23 06:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6742]: finished 0anacron
......(省略部分内容)

每行的第一个数字表示行号。

10.4.3. 打印前N行内容,带上行号

打印前5行结果:

grep -n -m 5 cron.hourly /var/log/cron
屏幕内容
10:May 23 04:01:01 cdgeekcamp CROND[6617]: (root) CMD (run-parts /etc/cron.hourly)
11:May 23 04:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6617]: starting 0anacron
12:May 23 04:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6626]: finished 0anacron
19:May 23 05:01:01 cdgeekcamp CROND[6676]: (root) CMD (run-parts /etc/cron.hourly)
20:May 23 05:01:01 cdgeekcamp run-parts(/etc/cron.hourly)[6676]: starting 0anacron

10.5. 输出匹配位置的上下内容

想看看搜索关键字前后的内容,用 "-A"、"-B" 和 "-C" 三个选项就行。

10.5.1. "/etc/passwd" 文件部分内容

/etc/passwd部分内容
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin

在开始之前,留意下

nobody:x:99:99:Nobody:/:/sbin/nologin

前后的内容。

10.5.2. 打印匹配文本的行及其前面N行

找出包含 "nobody:" 的行,同时匹配行的前2行内容(共3行):

grep -B 2 'nobody:' /etc/passwd
屏幕内容
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin

10.5.3. 打印匹配文本的行及其后面N行

找出包含 "nobody:" 的行,同时匹配行的后2行内容(共3行):

grep -A 2 'nobody:' /etc/passwd
屏幕内容
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin

10.5.4. 打印匹配文本的行及其前后N行

找出包含 "nobody:" 的行,同时匹配行的前后2行内容(共5行):

grep -C 2 'nobody:' /etc/passwd
屏幕内容
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin

10.6. 使用正则表达式

现在你对 grep 的了解已经可以应付大多数情况,搜索关键字、搜索目录下的内容、结果计数甚至显示结果前后内容都不在话下。

这些都是在关键字明确的前提下。万一某天想搜索关键字的一部分,你该怎么做?又或者,需要更加复杂的搜索操作呢?

grep 结合正则表达式(grep -E)做搜索,就完事儿。

习惯简写成 egrep。

10.6.1. 行首行尾匹配

打印以字母 "n" 开头的行:

grep '^n' /etc/passwd
屏幕内容
nobody:x:99:99:Nobody:/:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
nginx:x:997:995:nginx user:/var/cache/nginx:/sbin/nologin

打印以字母 "h" 结尾的行:

grep 'h$' /etc/passwd
屏幕内容
root:x:0:0:root:/root:/bin/bash
www:x:1001:1001::/var/lib/www:/bin/bash

10.6.2. 字符串匹配

打印以字母 "t" 开头,字母 "n" 结尾的行:

egrep '^t.*n$' /etc/passwd
屏幕内容
tcpdump:x:72:72::/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
tomcat:x:53:53:Apache Tomcat:/usr/share/tomcat:/sbin/nologin

10.6.3. egrep 支持的正则表达式

一点点准备

创建一个测试数据文件:

cat << EOF > ~/access.log
foo.org 80 118.118.47.239 [18/Jan/2021:01:00:23] "GET /360.html HTTP/1.1" 200
bar.org 8080 115.202.80.105 [19/Feb/2021:02:12:24] "POST /login HTTP/1.1" 404
qux.com 80 123.6.49.36 [20/Mar/2021:03:22:24] "GET / HTTP/1.1" 200
quux.com 80 180.101.214.20 [21/Apr/2021:04:15:24] "GET /main.html HTTP/1.1" 200
quz.io 8080 180.101.52.35 [21/Aug/2021:13:18:24] "GET /log.jpg HTTP/1.1" 200
quuz.cn 8080 180.101.52.35 [21/Aug/2021:13:18:24] "GET /jquery.min.js HTTP/1.1" 403
quuuz.cn 8080 125.64.14.56 [21/Aug/2021:13:18:24] "GET /load.js HTTP/1.1" 200
corge.com 80 148.72.153.60 [22/May/2021:23:25:16] "GET /7.html HTTP/1.1" 500
garply.net 80 123.178.50.195 [23/Oct/2021:23:50:16] "POST /article/ HTTP/1.1" 301
garply.net 80 123.178.50.195 [23/Oct/2021:23:50:16] "POST /article_new/ HTTP/1.1" 200
EOF
在下文看到 egrep '正则表达式' ~/access.log 这样的命令时,复制到终端试一试。动手效果更好!

基础操作符

小原点 '.' 用作正则表达式符号时,表示匹配任意字符,'b'、'x'、'0' 等等都没问题。


匹配常见字符串是最基础的正则表达式,如 aa、0、.?、.{1,2} 等等。


大部分字符(包括大小写字母、数字)作表达式都表示自身(所见即所得)。比如,0 匹配数字零,aa 匹配两个小写字母a。


a. 能够匹配长度为2的行,第一个字符必须是小写字母 'a',第二个可以是任意字符,'a1'、'ab'、'a,' 都符合规则。


只匹配一个小写字母a和一个小原点('a.')则用 a\., \. 表示一个小原点本身。相反,. 表示匹配任意字符。


也就是说,表达式符号前多加一个斜杠表示字符本身,称作字符转义。


以下操作符号可以限定在匹配时,某个字符可以出现多少次:

操作符 说明 示例

?

匹配0次或1次

匹配包含 'quu' 的行

egrep 'quu.?' ~/access.log

匹配包含 'qu' 和 'qux' 的行

egrep 'qux?' ~/access.log

*

匹配0次或多次

匹配包含 'GET'、'500' 的行

egrep 'GET.*500' ~/access.log

匹配包含 'article_' 和 'article' 的行

egrep 'article_*' ~/access.log

+

匹配至少1次

匹配包含 'article' 的行

egrep 'article.+' ~/access.log

匹配包含 'article_' 的行

egrep 'article_+' ~/access.log

{n}

只匹配n次

匹配包含 'qux' 的行

egrep 'qux{1}' ~/access.log

匹配至少包含一个 'q' 和两个 '0' 的行

egrep 'q{1}.*0{2}' ~/access.log

{n,}

匹配至少n次

匹配包含 'quu' 的行

egrep 'qu{2,}' ~/access.log

{,m}

匹配最多m次

匹配包含 'quz' 和 'quuz' 的行

egrep 'qu{,2}z' ~/access.log

{n,m}

匹配至少n次,最多m次

匹配包含 'quuz' 和 'quuuz' 的行

egrep 'qu{2,3}z' ~/access.log

上面这些单表达式匹配的例子挺OK的,那同时找出包含 'article_' 和 'qux' 的行怎么做?

一个中竖线和一对圆括号连接多个表达式,轻松完成多表达式查找匹配:

egrep '(article_+)|(qux)' ~/access.log
屏幕内容
qux.com 80 123.6.49.36 [20/Mar/2021:03:22:24] "GET / HTTP/1.1" 200
garply.net 80 123.178.50.195 [23/Oct/2021:23:50:16] "POST /article_new/ HTTP/1.1" 200
| 前后不能有空格。

更多 egrep 支持的正则表达式内容,请阅读 egrep正则表达式扩展 。


egrep 支持的缩写

一个斜杠后紧跟某些普通字符时,具有特殊的含义:

\w

匹配英文单词,通常单词由下划线、大小写字母和数字组成,等同 [_[:alnum:]]。

egrep '\w' ~/access.log

\W

匹配非英文单词,也就是匹配下划线、大小写字母和数字以外的字符,等同 [^_[:alnum:]]。

egrep '\W' ~/access.log

\s

匹配空格, 等同 [[:space:]]。

egrep '\s' ~/access.log

\S

匹配非空格, 等同 [^[:space:]]。

egrep '\S' ~/access.log

动动手,练习一个多表达式的例子:

egrep '\w+\s' ~/access.log

匹配至少一个英文单词字符,并且紧跟一个空格的行。你会看到类似这样的输出结果:

garply.net 80 123.178.50.195 [23/Oct/2021:23:50:16] "POST /article_new/ HTTP/1.1" 200


egrep 的限制

egrep 的在功能实现时,对特定的表达式有限制。

会经常遇到中横线开头的表达式提示有错误,错误示范如下:

egrep '-foo' ~/access.log
错误提示
grep: oo: No such file or directory

正确的示范:

egrep '\-foo' ~/access.log

记住,表达式不能用中横线(-)开头,必须加转义后才行。

更多其它的限制,万年遇不到,直接略过~

10.7. grep和管道

Linux的两大神技 grep 和管道结合,才是使用频率最高的。

看看这个例子:

grep 'Accepted' /var/log/secure | cut -d ' ' -f 9,11 | sort -u
屏幕内容
git 171.221.150.93
git 182.138.181.132
root 171.221.150.93
root 182.138.181.132

换个写法:

cat /var/log/secure | grep 'Accepted' | cut -d ' ' -f 9,11 | sort -u

输出结果和上面是一样的。


再来一个新花样:

cat /var/log/secure | grep 'Accepted' | awk '{print "User:"$9", Login IP address:"$11}' | sort -u

或

cat /var/log/secure | egrep 'Accep\w+' | awk '{print "User:"$9", Login IP address:"$11}' | sort -u
屏幕内容
User:git, Login IP address:171.221.150.93
User:git, Login IP address:182.138.181.132
User:root, Login IP address:171.221.150.93
User:root, Login IP address:182.138.181.132

grep 可以直接查找文件中的内容,也可以直接查找管道前面(标准输出)的内容。

再结合 "-rni" 之类的参数, 让 grep 变成几乎万能的文件内容查找工具。

用过的人都说好!

11. 文件定位

11.1. 简介

安装软件后,怎么快速找出配置文件路径?
想不起自己安装的软件到哪儿去了?

不需要复杂的操作,用 locate 和 find 命令几秒钟解决文件搜索问题。

locate 在文件索引(不需要实时读取目录)中搜索指定文件名,搜索速度很快。Windows软件 Everything 和 locate 功能实现非常类似。

find 实时搜索指定目录中的文件名,搜索速度取决于硬盘速度。

两个命令用途相似,明确要查找某个目录下的文件时用 find,其它情况建议无脑 locate。

11.2. locate

locate 命令是软件 mlocate 的一部分,locate 在文件索引中搜索指定文件名。

mlocate 还有一个 updatedb 命令,负责更新文件索引。

11.2.1. 安装mlocate

安装mlocate软件包:

yum install -y mlocate

首次更新文件索引:

updatedb

默认情况下,CentOS计划任务会每天自动更新一次(执行一次 updatedb 命令)文件索引。

如果当前新安装了软件或上传了文件到CentOS,需要手动执行 updatedb。然后,locate 才能找到新文件。

在增加文件、删除文件后,使用 locate 前记得先 updatedb。

P.S. updatedb 可以执行无数次,不要有心理负担~

11.2.2. 示例

搜索包含 "linux" 和 "signal.h" 关键字的文件路径:

示例1
locate signal.h | grep linux
屏幕内容
/usr/include/linux/signal.h

搜索ssh服务相关的配置文件路径(必须同时包含 "config" 和 "etc"):

示例2
locate -b ssh | grep config | grep etc
屏幕内容
/etc/ssh/ssh_config
/etc/ssh/sshd_config
/etc/sysconfig/sshd

-b 参数表示只搜索文件名部分(如 "ssh_config"、"sshd_config"、"sshd" 等等),不搜索路径中的字符串。


用正则表达式搜索所有日志文件(以 ".log" 扩展名结尾的文件路径):

示例3
locate -r '\.log$'
屏幕内容
/usr/lib/rpm/rpm.log
/var/log/boot.log
/var/log/mysqld.log
/var/log/yum.log
/var/log/audit/audit.log
......

-r 参数表示使用正则表达式搜索,注意必须用单引号包住表达式。


搜索 "ssh" 相关的 "service" 文件:

示例4
locate .service | grep ssh

或

locate -r 'ssh.*service'
屏幕内容
/etc/systemd/system/multi-user.target.wants/sshd.service
/usr/lib/systemd/system/sshd-keygen.service
/usr/lib/systemd/system/sshd.service
/usr/lib/systemd/system/sshd@.service

11.3. find

find 命令属于系统自带的,不需要安装。

为和 locate 对比,以下示例和之前相同。

注意对比 find 命令和 locate 的执行速度。

11.3.1. 示例

搜索包含 "linux" 和 "signal.h" 关键字的文件路径:

示例1
find / | grep signal.h | grep linux
屏幕内容
/usr/include/linux/signal.h

搜索ssh服务相关的配置文件路径(必须同时包含 "config" 和 "etc"):

示例2
find / | grep ssh | grep config | grep etc
屏幕内容
/etc/ssh/ssh_config
/etc/ssh/sshd_config
/etc/sysconfig/sshd

用正则表达式搜索所有日志文件(以 ".log" 扩展名结尾的文件路径):

示例3
find / -name '*.log'
屏幕内容
/usr/lib/rpm/rpm.log
/var/log/boot.log
/var/log/mysqld.log
/var/log/yum.log
/var/log/audit/audit.log
......

-name 参数表示只搜索文件名部分(如 "rpm.log"、"boot.log" 等等),不搜索路径中的字符串。


搜索 "ssh" 相关的 "service" 文件:

示例4
find / -name '*.service' | grep ssh
屏幕内容
/sys/fs/cgroup/systemd/system.slice/sshd.service
/etc/systemd/system/multi-user.target.wants/sshd.service
/usr/lib/systemd/system/sshd@.service
/usr/lib/systemd/system/sshd.service
/usr/lib/systemd/system/sshd-keygen.service

上面的

/sys/fs/cgroup/systemd/system.slice/sshd.service

用 locate 是不会有的。因为 locate 会忽略类似 "/tmp"、"/proc"、"/sys" 之类的系统临时目录。

12. 软件包管理

12.1. 简介

yum是基于RPM的包管理器( ".rpm" 格式文件),可以从网络仓库查询、下载软件包,安装并升级系统至最新版。当然,移除软件包也是可以的。

yum会扫描软件的依赖关系,自动检测、下载并安装相关软件。不需要搜索官网下载软件安装包,不需要手动解决软件安装环境依赖。

yum可以配置外部(网络软件)仓库或源代码仓库,提供许多内置插件来增强和扩展功能。比如,增加第三方仓库、启用禁用仓库、设置网络代理等。

12.2. 安装

12.2.1. 基础用法

yum install -y 软件包名称或路径
常用参数
y

表示 yum 全自动执行(不交互回答问题)

12.2.2. 从仓库安装

yum install -y tree
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Resolving Dependencies
--> Running transaction check
---> Package tree.x86_64 0:1.6.0-10.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=========================================================
 Package   Arch    Version        Repository         Size
=========================================================
Installing:
 tree      x86_64  1.6.0-10.el7   base               46 k

Transaction Summary
=========================================================
Install  1 Package

Total download size: 46 k
Installed size: 87 k
Downloading packages:
tree-1.6.0-10.el7.x86_64.rpm           |  46 kB  00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : tree-1.6.0-10.el7.x86_64               1/1
  Verifying  : tree-1.6.0-10.el7.x86_64               1/1

Installed:
  tree.x86_64 0:1.6.0-10.el7

Complete!

12.2.3. 从URL安装

yum install -y https://mirrors.163.com/centos/7/os/x86_64/Packages/tree-1.6.0-10.el7.x86_64.rpm
屏幕内容
Loaded plugins: fastestmirror
tree-1.6.0-10.el7.x86_64.rpm                                           |  46 kB  00:00:00
Examining /var/tmp/yum-root-kombYG/tree-1.6.0-10.el7.x86_64.rpm: tree-1.6.0-10.el7.x86_64
Marking /var/tmp/yum-root-kombYG/tree-1.6.0-10.el7.x86_64.rpm to be installed
Resolving Dependencies
--> Running transaction check
---> Package tree.x86_64 0:1.6.0-10.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=========================================================================================
 Package     Arch       Version           Repository                                 Size
=========================================================================================
Installing:
 tree        x86_64     1.6.0-10.el7      /tree-1.6.0-10.el7.x86_64                  87 k

Transaction Summary
=========================================================================================
Install  1 Package

Total size: 87 k
Installed size: 87 k
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : tree-1.6.0-10.el7.x86_64                                               1/1
  Verifying  : tree-1.6.0-10.el7.x86_64                                               1/1

Installed:
  tree.x86_64 0:1.6.0-10.el7

Complete!

12.2.4. 从本地安装

下载RPM包
wget https://mirrors.163.com/centos/7/os/x86_64/Packages/tree-1.6.0-10.el7.x86_64.rpm -O ~/tree-1.6.0-10.el7.x86_64.rpm
屏幕内容
--2021-05-11 16:09:58--  https://mirrors.163.com/centos/7/os/x86_64/Packages/tree-1.6.0-10.el7.x86_64.rpm
Resolving mirrors.163.com (mirrors.163.com)... 101.6.8.193, 2402:f000:1:408:8100::1
Connecting to mirrors.163.com (mirrors.163.com)|101.6.8.193|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 47508 (46K) [application/x-redhat-package-manager]
Saving to: ‘/root/tree-1.6.0-10.el7.x86_64.rpm’

100%[===================================================================>] 47,508      --.-K/s   in 0.03s

2021-05-11 16:09:59 (1.67 MB/s) - ‘/root/tree-1.6.0-10.el7.x86_64.rpm’ saved [47508/47508]
从文件安装
yum install -y ~/tree-1.6.0-10.el7.x86_64.rpm
屏幕内容
Loaded plugins: fastestmirror
Examining /root/tree-1.6.0-10.el7.x86_64.rpm: tree-1.6.0-10.el7.x86_64
Marking /root/tree-1.6.0-10.el7.x86_64.rpm to be installed
Resolving Dependencies
--> Running transaction check
---> Package tree.x86_64 0:1.6.0-10.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=========================================================================================
 Package     Arch       Version           Repository                                 Size
=========================================================================================
Installing:
 tree        x86_64     1.6.0-10.el7      /tree-1.6.0-10.el7.x86_64                  87 k

Transaction Summary
=========================================================================================
Install  1 Package

Total size: 87 k
Installed size: 87 k
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : tree-1.6.0-10.el7.x86_64                                               1/1
  Verifying  : tree-1.6.0-10.el7.x86_64                                               1/1

Installed:
  tree.x86_64 0:1.6.0-10.el7

Complete!
使用 yum 会自动检测软件包依赖关系,从网络下载,自动安装依赖。

12.3. 重新安装

重新安装的命令: yum reinstall -y 软件包名称。

具体使用方法与 安装 相同。

12.4. 查询

12.4.1. 基础用法

yum list [软件包名称或星号表达式]

yum list installed [软件包名称或星号表达式]

yum list available [软件包名称或星号表达式]

yum info 软件包名称

12.4.2. 列出所有软件包

yum list
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Installed Packages
GeoIP.x86_64                              1.5.0-13.el7                 @anaconda
NetworkManager.x86_64                     1:1.12.0-10.el7_6            @updates
......(省略部分内容)......
Available Packages
0ad.x86_64                                0.0.22-1.el7                 epel
0ad-data.noarch                           0.0.22-1.el7                 epel
0install.x86_64                           2.11-1.el7                   epel
......(省略部分内容)......

12.4.3. 列出已经安装的软件包

yum list installed
屏幕内容
Loaded plugins: fastestmirror
Installed Packages
GeoIP.x86_64                          1.5.0-13.el7               @anaconda
NetworkManager.x86_64                 1:1.12.0-10.el7_6          @updates
NetworkManager-libnm.x86_64           1:1.12.0-10.el7_6          @updates
NetworkManager-team.x86_64            1:1.12.0-10.el7_6          @updates
NetworkManager-tui.x86_64             1:1.12.0-10.el7_6          @updates
......(省略部分内容)......

12.4.4. 列出仓库中可用的软件包

yum list available
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Available Packages
0ad.x86_64                                0.0.22-1.el7                   epel
0ad-data.noarch                           0.0.22-1.el7                   epel
0install.x86_64                           2.11-1.el7                     epel
2048-cli.x86_64                           0.9.1-1.el7                    epel
2048-cli-nocurses.x86_64                  0.9.1-1.el7                    epel
......(省略部分内容)......

12.4.5. 仅显示指定名称的软件包

yum list 命令可以在尾部添加软件包名称(支持星号模糊匹配),命令输出结果中只会显示名称相关的软件包。

星号占位符表示任意字符会出现一次以上(含一次)。

显示软件包名称中包含 "openssh" 字样的结果:

yum list *openssh*
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Installed Packages
openssh.x86_64                          7.4p1-16.el7                           @anaconda
openssh-clients.x86_64                  7.4p1-16.el7                           @anaconda
openssh-server.x86_64                   7.4p1-16.el7                           @anaconda
Available Packages
gsi-openssh.x86_64                      7.4p1-6.el7                            epel
gsi-openssh-clients.x86_64              7.4p1-6.el7                            epel
gsi-openssh-server.x86_64               7.4p1-6.el7                            epel
lxqt-openssh-askpass.x86_64             0.14.1-3.el7                           epel
lxqt-openssh-askpass-l10n.noarch        0.11.2-3.el7                           epel
lxqt-openssh-askpass-l10n.x86_64        0.14.1-3.el7                           epel
openssh.x86_64                          7.4p1-21.el7                           base
openssh-askpass.x86_64                  7.4p1-21.el7                           base
openssh-cavs.x86_64                     7.4p1-21.el7                           base
openssh-clients.x86_64                  7.4p1-21.el7                           base
openssh-keycat.x86_64                   7.4p1-21.el7                           base
openssh-ldap.x86_64                     7.4p1-21.el7                           base
openssh-ldap-authkeys.noarch            0.1.0~git20200205.aee4c46-2.el7        epel
openssh-server.x86_64                   7.4p1-21.el7                           base
openssh-server-sysvinit.x86_64          7.4p1-21.el7                           base
perl-Net-OpenSSH.noarch                 0.62-1.el7                             epel

可以试一试 yum list installed openssh 和 yum list available openssh,观察输出结果有什么不同?

去掉命令中的第一个或第二个星号,输出结果会明显不同。

12.4.6. 查看软件包信息

yum info tree
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Installed Packages
Name        : tree
Arch        : x86_64
Version     : 1.6.0
Release     : 10.el7
Size        : 87 k
Repo        : installed
Summary     : File system tree viewer
URL         : http://mama.indstate.edu/users/ice/tree/
License     : GPLv2+
Description : The tree utility recursively displays the contents of directories in a
            : tree-like format.  Tree is basically a UNIX port of the DOS tree
            : utility.

12.5. 查询(rpm)

除 yum 命令外,还可以使用更基础的 rpm 命令查询软件包信息。

rpm 仅对已经安装的软件包有效。

12.5.1. 列出已经安装的包

rpm -qa
屏幕内容
authconfig-6.2.8-30.el7.x86_64
kbd-legacy-1.15.5-15.el7.noarch
usermode-1.111-5.el7.x86_64
ncurses-base-5.9-14.20130511.el7_4.noarch
trousers-0.3.14-2.el7.x86_64
chrony-3.2-2.el7.x86_64
......
......
......

12.5.2. 查询文件属于哪个包

rpm -qf /usr/sbin/sshd
屏幕内容
openssh-server-7.4p1-16.el7.x86_64

12.5.3. 列出包中的文件

rpm -ql openssh-server

或

rpm -ql openssh-server-7.4p1-16.el7.x86_64
屏幕内容
/etc/pam.d/sshd
/etc/ssh/sshd_config
/etc/sysconfig/sshd
/usr/lib/systemd/system/sshd-keygen.service
/usr/lib/systemd/system/sshd.service
/usr/lib/systemd/system/sshd.socket
/usr/lib/systemd/system/sshd@.service
/usr/lib64/fipscheck/sshd.hmac
/usr/libexec/openssh/sftp-server
/usr/sbin/sshd
/usr/sbin/sshd-keygen
/usr/share/man/man5/moduli.5.gz
/usr/share/man/man5/sshd_config.5.gz
/usr/share/man/man8/sftp-server.8.gz
/usr/share/man/man8/sshd.8.gz
/var/empty/sshd

12.5.4. 列出包中的配置文件

rpm -qc openssh-server

或

rpm -qc openssh-server-7.4p1-16.el7.x86_64
屏幕内容
/etc/pam.d/sshd
/etc/ssh/sshd_config
/etc/sysconfig/sshd

12.5.5. 列出包中文件的状态

rpm -qs openssh-server
屏幕内容
normal        /etc/pam.d/sshd
normal        /etc/ssh/sshd_config
normal        /etc/sysconfig/sshd
normal        /usr/lib/systemd/system/sshd-keygen.service
normal        /usr/lib/systemd/system/sshd.service
normal        /usr/lib/systemd/system/sshd.socket
normal        /usr/lib/systemd/system/sshd@.service
normal        /usr/lib64/fipscheck/sshd.hmac
normal        /usr/libexec/openssh/sftp-server
normal        /usr/sbin/sshd
normal        /usr/sbin/sshd-keygen
normal        /usr/share/man/man5/moduli.5.gz
normal        /usr/share/man/man5/sshd_config.5.gz
normal        /usr/share/man/man8/sftp-server.8.gz
normal        /usr/share/man/man8/sshd.8.gz
normal        /var/empty/sshd

12.6. 升级

12.6.1. 基础用法

yum update -y [软件包名称或星号表达式]
常用参数
y

表示 yum 全自动执行(不交互回答问题)

12.6.2. 升级所有软件包

从网络仓库获取最新的软件包信息,下载并更新系统:

yum update -y
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Resolving Dependencies
--> Running transaction check
---> Package GeoIP.x86_64 0:1.5.0-13.el7 will be updated
---> Package GeoIP.x86_64 0:1.5.0-14.el7 will be an update
--> Processing Dependency: geoipupdate for package: GeoIP-1.5.0-14.el7.x86_64
---> Package NetworkManager.x86_64 1:1.12.0-10.el7_6 will be updated
---> Package NetworkManager.x86_64 1:1.18.8-2.el7_9 will be an update
......(省略部分内容)......
--> Running transaction check
---> Package bind-export-libs.x86_64 32:9.11.4-26.P2.el7_9.5 will be installed
---> Package geoipupdate.x86_64 0:2.5.0-1.el7 will be installed
--> Finished Dependency Resolution
--> Running transaction check
---> Package kernel.x86_64 0:3.10.0-957.el7 will be erased
--> Finished Dependency Resolution

Dependencies Resolved

=============================================================================
 Package          Arch    Version              Repository                Size
=============================================================================
Installing:
 iwl7260-firmware noarch  25.30.13.0-80.el7_9  updates                  6.1 M
     replacing  iwl7265-firmware.noarch 22.0.7.0-69.el7
 kernel           x86_64  3.10.0-1160.25.1.el7 updates                   50 M
 kernel-devel     x86_64  3.10.0-1160.25.1.el7 updates                   18 M
Updating:
 GeoIP           x86_64   1.5.0-14.el7         base                     1.5 M
 NetworkManager   x86_64  1:1.18.8-2.el7_9     updates                  1.9 M
......(省略部分内容)......
=============================================================================
Install    3 Packages (+2 Dependent packages)
Upgrade  265 Packages
Remove     1 Package

Total download size: 407 M
......(省略部分内容)......
Complete!

12.6.3. 升级一个或多个软件包

yum update -y vim openssh*
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Resolving Dependencies
--> Running transaction check
---> Package openssh.x86_64 0:7.4p1-16.el7 will be updated
......(省略部分内容)......
---> Package vim-common.x86_64 2:7.4.160-6.el7_6 will be updated
---> Package vim-common.x86_64 2:7.4.629-8.el7_9 will be an update
--> Finished Dependency Resolution

Dependencies Resolved

==================================================================
 Package            Arch      Version              Repository Size
==================================================================
Updating:
 openssh            x86_64    7.4p1-21.el7         base       510 k
 openssh-clients    x86_64    7.4p1-21.el7         base       655 k
 openssh-server     x86_64    7.4p1-21.el7         base       459 k
 vim-enhanced       x86_64    2:7.4.629-8.el7_9    updates    1.1 M
Updating for dependencies:
 vim-common         x86_64    2:7.4.629-8.el7_9    updates    5.9 M

Transaction Summary
==================================================================
Upgrade  4 Packages (+1 Dependent package)

Total size: 8.6 M
Total download size: 1.6 M
......(省略部分内容)......
Complete!

12.7. 移除

12.7.1. 基础用法

yum erase 软件包名称
为防止误操作,不建议使用 -y 参数或者星号表达式。

12.7.2. 从系统移除软件包

yum erase tree
屏幕内容
Loaded plugins: fastestmirror
Resolving Dependencies
--> Running transaction check
---> Package tree.x86_64 0:1.6.0-10.el7 will be erased
--> Finished Dependency Resolution

Dependencies Resolved

==============================================================================
 Package       Arch            Version               Repository          Size
==============================================================================
Removing:
 tree          x86_64          1.6.0-10.el7          installed           87 k

Transaction Summary
==============================================================================
Remove  1 Package

Installed size: 87 k
Is this ok [y/N]: y
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Erasing    : tree-1.6.0-10.el7.x86_64                                   1/1
  Verifying  : tree-1.6.0-10.el7.x86_64                                   1/1

Removed:
  tree.x86_64 0:1.6.0-10.el7

Complete!

12.8. 下载

12.8.1. 基础用法

yum install --downloadonly --downloaddir=下载目录 [软件包名称或星号表达式]

yumdownloader [软件包名称或星号表达式]

yumdownloader --resolve [软件包名称或星号表达式]

yumdownloader --urls --resolve [软件包名称或星号表达式]
常用参数
downloadonly

不安装,仅下载软件包文件及其依赖的软件包

downloaddir

软件包文件的下载目录

urls

仅打印软件包的下载地址,不下载

resolve

检查软件包依赖关系并下载

12.8.2. 下载软件包文件方法一:yum

下载软件包文件,保存在 /tmp 目录下:

yum install --downloadonly --downloaddir=/tmp vim
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
Resolving Dependencies
--> Running transaction check
---> Package vim-enhanced.x86_64 2:7.4.160-6.el7_6 will be updated
---> Package vim-enhanced.x86_64 2:7.4.629-8.el7_9 will be an update
--> Processing Dependency: vim-common = 2:7.4.629-8.el7_9 for package: 2:vim-enhanced-7.4.629-8.el7_9.x86_64
--> Running transaction check
---> Package vim-common.x86_64 2:7.4.160-6.el7_6 will be updated
---> Package vim-common.x86_64 2:7.4.629-8.el7_9 will be an update
--> Finished Dependency Resolution

Dependencies Resolved

============================================================================================================
 Package         Arch      Version              Repository                                              Size
============================================================================================================
Updating:
 vim-enhanced    x86_64    2:7.4.629-8.el7_9    updates                                               1.1 M
Updating for dependencies:
 vim-common      x86_64    2:7.4.629-8.el7_9    updates                                               5.9 M

Transaction Summary
============================================================================================================
Upgrade  1 Package (+1 Dependent package)

Total size: 7.0 M
Background downloading packages, then exiting:
exiting because "Download Only" specified

查看下载的软件包文件:

[root@cdgeekcamp ~]# ll /tmp/vim*
-rw-r--r-- 1 root root 6205700 Dec 18 04:37 /tmp/vim-common-7.4.629-8.el7_9.x86_64.rpm
-rw-r--r-- 1 root root 1106008 Dec 18 04:37 /tmp/vim-enhanced-7.4.629-8.el7_9.x86_64.rpm

12.8.3. 下载软件包文件方法二:yumdownloader

安装 yumdownloader 工具:

yum install -y yum-utils

查看包及其依赖关系的下载地址:

yumdownloader --urls --resolve vim
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
--> Running transaction check
---> Package vim-enhanced.x86_64 2:7.4.629-8.el7_9 will be installed
--> Processing Dependency: vim-common = 2:7.4.629-8.el7_9 for package: 2:vim-enhanced-7.4.629-8.el7_9.x86_64
--> Running transaction check
---> Package vim-common.x86_64 2:7.4.160-6.el7_6 will be updated
--> Processing Dependency: vim-common = 2:7.4.160-6.el7_6 for package: 2:vim-enhanced-7.4.160-6.el7_6.x86_64
---> Package vim-common.x86_64 2:7.4.629-8.el7_9 will be an update
--> Running transaction check
---> Package vim-enhanced.x86_64 2:7.4.160-6.el7_6 will be updated
--> Finished Dependency Resolution
http://mirrors.cloud.aliyuncs.com/centos/7/updates/x86_64/Packages/vim-enhanced-7.4.629-8.el7_9.x86_64.rpm
http://mirrors.cloud.aliyuncs.com/centos/7/updates/x86_64/Packages/vim-common-7.4.629-8.el7_9.x86_64.rpm

下载软件包及其依赖的软件包到当前目录:

yumdownloader --resolve vim
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
--> Running transaction check
---> Package vim-enhanced.x86_64 2:7.4.629-8.el7_9 will be installed
--> Processing Dependency: vim-common = 2:7.4.629-8.el7_9 for package: 2:vim-enhanced-7.4.629-8.el7_9.x86_64
--> Running transaction check
---> Package vim-common.x86_64 2:7.4.160-6.el7_6 will be updated
--> Processing Dependency: vim-common = 2:7.4.160-6.el7_6 for package: 2:vim-enhanced-7.4.160-6.el7_6.x86_64
---> Package vim-common.x86_64 2:7.4.629-8.el7_9 will be an update
--> Running transaction check
---> Package vim-enhanced.x86_64 2:7.4.160-6.el7_6 will be updated
--> Finished Dependency Resolution
Delta RPMs disabled because /usr/bin/applydeltarpm not installed.

查看下载的软件包文件:

[root@cdgeekcamp ~]# ll vim*
-rw-r--r-- 1 root root 6205700 Dec 18 04:37 vim-common-7.4.629-8.el7_9.x86_64.rpm
-rw-r--r-- 1 root root 1106008 Dec 18 04:37 vim-enhanced-7.4.629-8.el7_9.x86_64.rpm

12.9. 仓库管理

12.9.1. 基础用法

yum repolist

yum-config-manager --add-repo 文件路径或网址

yum-config-manager --enable Yum仓库名称

yum-config-manager --disable Yum仓库名称
常用参数
add-repo

从指定文件或网址增加Yum仓库(并启用)

enable

启用Yum仓库

disable

禁用Yum仓库

12.9.2. 安装依赖软件

安装 yum-config-manager 工具:

yum install -y yum-utils

12.9.3. 列出Yum仓库

yum repolist
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
repo id              repo name                                          status
base/7/x86_64        CentOS-7                                           10,072
epel/x86_64          Extra Packages for Enterprise Linux 7 - x86_64     13,592
extras/7/x86_64      CentOS-7                                              476
updates/7/x86_64     CentOS-7                                            2,189
repolist: 26,329

12.9.4. 增加并启用Yum仓库

创建临时文件 "~/nginx.repo":

cat << EOF > ~/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF

增加并启用Yum仓库:

yum-config-manager --add-repo ~/nginx.repo
屏幕内容
Loaded plugins: fastestmirror
adding repo from: /root/nginx.repo
grabbing file /root/nginx.repo to /etc/yum.repos.d/nginx.repo
repo saved to /etc/yum.repos.d/nginx.repo

确认nginx仓库已经启用:

yum repolist
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
repo id                repo name                                        status
base/7/x86_64          CentOS-7                                         10,072
epel/x86_64            Extra Packages for Enterprise Linux 7 - x86_64   13,592
extras/7/x86_64        CentOS-7                                            476
nginx-stable/7/x86_64  nginx stable repo                                   224
updates/7/x86_64       CentOS-7                                          2,189
repolist: 26,553

出现 "nginx-stable",表示nginx仓库已经启用。

12.9.5. 禁用Yum仓库

yum-config-manager --disable nginx-stable
屏幕内容
Loaded plugins: fastestmirror
============================= repo: nginx-stable =============================
[nginx-stable]
......(省略部分内容)......
enabled = 0
......(省略部分内容)......
yum repolist 命令可以帮助确认仓库状态。禁用nginx仓库后,命令结果不会有 nginx-stable 字样。

12.9.6. 启用Yum仓库

yum-config-manager --enable nginx-stable
屏幕内容
Loaded plugins: fastestmirror
============================= repo: nginx-stable =============================
[nginx-stable]
......(省略部分内容)......
enabled = 1
......(省略部分内容)......

12.10. 搜索

"search" 选项可以搜索软件包的名称、描述或简介中的文字。

12.10.1. 基础用法

yum search 关键字

12.10.2. 搜索nginx相关的软件包

yum search curl
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
======================================== N/S matched: nginx =======================================
collectd-curl.x86_64 : Curl plugin for collectd
collectd-curl_json.x86_64 : Curl JSON plugin for collectd
collectd-curl_xml.x86_64 : Curl XML plugin for collectd
curlftpfs.x86_64 : CurlFtpFS is a filesystem for accessing FTP hosts based on FUSE and libcurl
flickcurl-devel.x86_64 : Development files for flickcurl
libcurl-devel.x86_64 : Files needed for building applications with libcurl
libcurl-devel.i686 : Files needed for building applications with libcurl
nbdkit-plugin-curl.x86_64 : HTTP/FTP/SSH (cURL) plugin for nbdkit
ocaml-curl.x86_64 : OCaml Curl library (ocurl)
ocaml-curl-devel.x86_64 : Development files for ocaml-curl
perl-WWW-Curl.x86_64 : Perl extension interface for libcurl
php-pear-Net-Curl.noarch : OO interface to PHP's cURL extension
python-pycurl.x86_64 : A Python interface to libcurl
python34-pycurl.x86_64 : Python interface to libcurl for Python 3
python36-pycurl.x86_64 : Python interface to libcurl for Python 3
uwsgi-alarm-curl.x86_64 : uWSGI - Curl alarm plugin
uwsgi-plugin-curl-cron.x86_64 : uWSGI - Plugin for CURL Cron support
curl.x86_64 : A utility for getting files from remote servers (FTP, HTTP, and others)
flickcurl.x86_64 : C library for the Flickr API
libcurl.x86_64 : A library for getting files from web servers
libcurl.i686 : A library for getting files from web servers
python2-httpie.noarch : A Curl-like tool for humans
rubygem-curb.x86_64 : Ruby libcurl bindings
uget.x86_64 : Download manager using GTK+ and libcurl
uwsgi-alarm-xmpp.x86_64 : uWSGI - Curl alarm plugin

  Name and summary matches only, use "search all" for everything.
"search all" 使用频率极低。

curl 和 libcurl-devel 是我要找的软件包名称,安装之:

yum install -y curl libcurl-devel

你找到想要的软件包了吗?

12.11. 文件属于哪个软件包

知道某个文件的名称,但不清楚具体的软件包名称时,"provides" 选项很管用。

找到软件包名称后,直接 "yum install -y 软件包名称" 搞定!

12.11.1. 基础用法

yum provides 文件绝对路径或星号表达式

12.11.2. 不知道 "curl.h" 的绝对路径时

yum provides */curl.h
"*/curl.h" 开头的星号不能少。
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
libcurl-devel-7.29.0-59.el7.i686 : Files needed for building applications with libcurl
Repo        : base
Matched from:
Filename    : /usr/include/curl/curl.h


libcurl-devel-7.29.0-59.el7.x86_64 : Files needed for building applications with libcurl
Repo        : base
Matched from:
Filename    : /usr/include/curl/curl.h
......

从结果看,只有软件包 "libcurl-devel" 包含 "*/curl.h",文件绝对路径:"/usr/include/curl/curl.h"。

要不要试试 yum provides /curl. ?

12.11.3. 知道 "curl.h" 的绝对路径时

yum provides /usr/include/curl/curl.h
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
libcurl-devel-7.29.0-59.el7.i686 : Files needed for building applications with libcurl
Repo        : base
Matched from:
Filename    : /usr/include/curl/curl.h


libcurl-devel-7.29.0-59.el7.x86_64 : Files needed for building applications with libcurl
Repo        : base
Matched from:
Filename    : /usr/include/curl/curl.h
......

12.12. 加速网络访问

12.12.1. 用国内镜像服务器加速

备份配置文件:

cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak

使用阿里云镜像服务器:

new_mirror_url=http://mirrors.aliyun.com/

cat << EOF > /etc/yum.repos.d/CentOS-Base.repo
[base]
name=CentOS-\$releasever
enabled=1
failovermethod=priority
baseurl=${new_mirror_url}centos/\$releasever/os/\$basearch/
gpgcheck=1
gpgkey=${new_mirror_url}centos/RPM-GPG-KEY-CentOS-7

[updates]
name=CentOS-\$releasever
enabled=1
failovermethod=priority
baseurl=${new_mirror_url}centos/\$releasever/updates/\$basearch/
gpgcheck=1
gpgkey=${new_mirror_url}centos/RPM-GPG-KEY-CentOS-7

[extras]
name=CentOS-\$releasever
enabled=1
failovermethod=priority
baseurl=${new_mirror_url}centos/\$releasever/extras/\$basearch/
gpgcheck=1
gpgkey=${new_mirror_url}centos/RPM-GPG-KEY-CentOS-7
EOF

还可以用网易的镜像服务器:

new_mirror_url=http://mirrors.163.com/

cat << EOF > /etc/yum.repos.d/CentOS-Base.repo
[base]
name=CentOS-\$releasever
enabled=1
failovermethod=priority
baseurl=${new_mirror_url}centos/\$releasever/os/\$basearch/
gpgcheck=1
gpgkey=${new_mirror_url}centos/RPM-GPG-KEY-CentOS-7

[updates]
name=CentOS-\$releasever
enabled=1
failovermethod=priority
baseurl=${new_mirror_url}centos/\$releasever/updates/\$basearch/
gpgcheck=1
gpgkey=${new_mirror_url}centos/RPM-GPG-KEY-CentOS-7

[extras]
name=CentOS-\$releasever
enabled=1
failovermethod=priority
baseurl=${new_mirror_url}centos/\$releasever/extras/\$basearch/
gpgcheck=1
gpgkey=${new_mirror_url}centos/RPM-GPG-KEY-CentOS-7
EOF

12.12.2. 缓存仓库软件数据

yum的所有操作都会访问网络仓库服务器,makecache 后会减少多数网络请求,加速操作。

yum clean all
yum makecache
屏幕内容
Loaded plugins: fastestmirror
Determining fastest mirrors
base                                                   | 3.6 kB     00:00
epel                                                   | 4.7 kB     00:00
extras                                                 | 2.9 kB     00:00
updates                                                | 2.9 kB     00:00
(1/17): base/7/x86_64/group_gz                           | 153 kB   00:00
(2/17): base/7/x86_64/primary_db                         | 6.1 MB   00:00
(3/17): base/7/x86_64/other_db                           | 2.6 MB   00:00
(4/17): base/7/x86_64/filelists_db                       | 7.2 MB   00:00
(5/17): epel/x86_64/group_gz                             |  96 kB   00:00
(6/17): epel/x86_64/updateinfo                           | 1.0 MB   00:00
(7/17): epel/x86_64/prestodelta                          |  692 B   00:00
(8/17): epel/x86_64/filelists_db                         |  12 MB   00:00
(9/17): epel/x86_64/primary_db                           | 6.9 MB   00:00
(10/17): epel/x86_64/other_db                            | 3.4 MB   00:00
(11/17): extras/7/x86_64/primary_db                      | 236 kB   00:00
(12/17): extras/7/x86_64/filelists_db                    | 231 kB   00:00
(13/17): extras/7/x86_64/other_db                        | 139 kB   00:00
(14/17): nginx-stable/7/x86_64/primary_db                |  63 kB   00:00
(15/17): updates/7/x86_64/filelists_db                   | 4.7 MB   00:00
(16/17): updates/7/x86_64/primary_db                     | 8.0 MB   00:00
(17/17): updates/7/x86_64/other_db                       | 610 kB   00:00
Metadata Cache Created

12.13. EPEL扩展仓库

EPEL是官方维护的扩展仓库,包含很多实用的软件包。

12.13.1. 安装EPEL

yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

12.13.2. 用国内EPEL镜像服务器加速

由于官方服务器在国内速度慢,建议使用国内EPEL镜像服务器。此处以阿里云为例:

new_mirror_url=https://mirrors.aliyun.com/

cp /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.bak

sed -i "s|#baseurl=http://download.fedoraproject.org/pub/|baseurl=${new_mirror_url}|g" /etc/yum.repos.d/epel.repo

还可以替换成清华大学的服务器: "https://mirrors.tuna.tsinghua.edu.cn/"

12.13.3. 缓存仓库软件数据

设置完毕后,更新仓库缓存:

yum clean all
yum makecache

13. 服务管理

13.1. 简介

CentOS 7依靠Systemd管理各种系统服务,service start 服务名称 这种方式已经被过时,systemctl start 服务名称 才是首选。

Systemd是Linux的系统和服务管理器。提供许多特性,例如开机时并行启动服务(完美发挥SSD硬盘性能优势,不再等待排队启动服务)、按需启动服务、服务启动顺序(依赖关系)控制等。

13.1.1. 服务管理的基本逻辑

安装某个软件及其附带的服务后,设置为开机启动,大概要经过以下几个步骤:

  1. 安装(复制)服务文件("UNIT FILE")到 systemd 指定目录;

  2. 设置服务状态("STATE")为 "enabled",每次开机后服务会自动启动;

  3. 在当前系统状态下(无需重启),启动服务;

13.1.2. 一些准备工作

我们以Nginx为例,演示服务管理操作。

安装Nginx:

yum install -y nginx
屏幕内容
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
base                                                                   | 3.6 kB  00:00:00
epel                                                                   | 4.7 kB  00:00:00
extras                                                                 | 2.9 kB  00:00:00
nginx-stable                                                           | 2.9 kB  00:00:00
updates                                                                | 2.9 kB  00:00:00
(1/2): epel/x86_64/updateinfo                                          | 1.0 MB  00:00:00
(2/2): epel/x86_64/primary_db                                          | 6.9 MB  00:00:00
Resolving Dependencies
--> Running transaction check
---> Package nginx.x86_64 1:1.16.0-1.el7.ngx will be updated
---> Package nginx.x86_64 1:1.20.0-1.el7.ngx will be an update
--> Finished Dependency Resolution

Dependencies Resolved

==============================================================================================
 Package         Arch             Version                        Repository              Size
==============================================================================================
Updating:
 nginx           x86_64           1:1.20.0-1.el7.ngx             nginx-stable           790 k

Transaction Summary
==============================================================================================
Upgrade  1 Package

Total size: 790 k
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Updating   : 1:nginx-1.20.0-1.el7.ngx.x86_64                                            1/2
warning: /etc/nginx/conf.d/default.conf created as /etc/nginx/conf.d/default.conf.rpmnew
warning: /etc/nginx/nginx.conf created as /etc/nginx/nginx.conf.rpmnew
  Cleanup    : 1:nginx-1.16.0-1.el7.ngx.x86_64                                            2/2
  Verifying  : 1:nginx-1.20.0-1.el7.ngx.x86_64                                            1/2
  Verifying  : 1:nginx-1.16.0-1.el7.ngx.x86_64                                            2/2

Updated:
  nginx.x86_64 1:1.20.0-1.el7.ngx

Complete!

13.2. 列表服务

13.2.1. 基础用法

systemctl list-unit-files

systemctl list-unit --all

systemctl --failed
列表时,内容超出屏幕,显示不完。按 Enter、↓ 或 PgDn 向下翻,按 Ctrl+C 或 q 退出。

13.2.2. 列出已安装的服务文件及其状态

systemctl list-unit-files
屏幕内容
UNIT FILE                                     STATE
proc-sys-fs-binfmt_misc.automount             static
dev-hugepages.mount                           static
dev-mqueue.mount                              static
sys-kernel-debug.mount                        static
tmp.mount                                     disabled
brandbot.path                                 disabled
systemd-ask-password-console.path             static
systemd-ask-password-plymouth.path            static
systemd-ask-password-wall.path                static
session-482.scope                             static
aliyun.service                                disabled
arp-ethers.service                            disabled
atd.service                                   enabled
auditd.service                                enabled
autovt@.service                               enabled
.....
systemd-readahead-done.timer                  indirect
systemd-tmpfiles-clean.timer                  static

254 unit files listed.

13.2.3. 列出已加载的服务

systemctl list-units
屏幕内容
-.mount                           loaded active mounted   /
dev-hugepages.mount               loaded active mounted   Huge Pages File System
dev-mqueue.mount                  loaded active mounted   POSIX Message Queue File System
run-user-0.mount                  loaded active mounted   /run/user/0
sys-kernel-config.mount           loaded active mounted   Configuration File System
sys-kernel-debug.mount            loaded active mounted   Debug File System
systemd-ask-password-plymouth.path loaded active waiting   Forward Password Requests to Plym
systemd-ask-password-wall.path    loaded active waiting   Forward Password Requests to Wall
session-482.scope                 loaded active running   Session 482 of user root
aegis.service                     loaded active exited    LSB: aegis update.
atd.service                       loaded active running   Job spooling tools
auditd.service                    loaded active running   Security Auditing Service
chronyd.service                   loaded active running   NTP client/server
mysqld.service                    loaded active running   MySQL Server
network.service                   loaded active running   LSB: Bring up/down networking
nginx.service                     loaded active running   nginx - high performance web serve
.....
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.

95 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

13.2.4. 列出所有服务

systemctl list-units --all
屏幕内容
  UNIT                             LOAD      ACTIVE   SUB       DESCRIPTION
  dev-ttyS0.device                 loaded    active   plugged   /dev/ttyS0
  dev-ttyS1.device                 loaded    active   plugged   /dev/ttyS1
  dev-ttyS2.device                 loaded    active   plugged   /dev/ttyS2
  dev-ttyS3.device                 loaded    active   plugged   /dev/ttyS3
  dev-vda.device                   loaded    active   plugged   /dev/vda
  dev-vda1.device                  loaded    active   plugged   /dev/vda1
......
  time-sync.target                 loaded    inactive dead      System Time Synchronized
  timers.target                    loaded    active   active    Timers
  umount.target                    loaded    inactive dead      Unmount All Filesystems
  letsencrypt.timer                loaded    active   waiting   Monthly renewal of Let's Encry
  systemd-readahead-done.timer     loaded    inactive dead      Stop Read-Ahead Data Collectio
  systemd-tmpfiles-clean.timer     loaded    active   waiting   Daily Cleanup of Temporary Dir

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.

181 loaded units listed.
To show all installed unit files use 'systemctl list-unit-files'.

13.2.5. 列出失败状态的服务

systemctl --failed
屏幕内容
  UNIT                     LOAD   ACTIVE SUB    DESCRIPTION
● cloud-init-local.service loaded failed failed Initial cloud-init job (pre-networking)
● cloud-init.service       loaded failed failed Initial cloud-init job (metadata service crawl
● letsencrypt.service      loaded failed failed Let's Encrypt renewal
● postfix.service          loaded failed failed Postfix Mail Transport Agent

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.

4 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

13.3. 查找服务

13.3.1. 基础用法

systemctl list-unit 星号匹配表达式

systemctl list-unit --all 星号匹配表达式

13.3.2. 列出指定名称的服务文件及其状态

列出名称包含 "nginx" 字样的服务:

systemctl list-unit-files *nginx*
屏幕内容
UNIT FILE           STATE
nginx-debug.service disabled
nginx.service       enabled

2 unit files listed.

13.3.3. 列出指定名称的服务

列出名称包含 "nginx" 字样的服务:

systemctl list-units -all *nginx*
屏幕内容
UNIT          LOAD   ACTIVE   SUB  DESCRIPTION
nginx.service loaded inactive dead nginx - high performance web server

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.

1 loaded units listed.
To show all installed unit files use 'systemctl list-unit-files'.

13.4. 启动服务

13.4.1. 基础用法

systemctl start 服务名称

13.4.2. 启动Nginx服务

systemctl start nginx

如果启动或重启服务时,屏幕上出现类似提示:

Job for nginx.service failed because the control process exited with error code. See "systemctl status nginx.service" and "journalctl -xe" for details.

说明服务操作失败,通过查看服务状态( systemctl status nginx ) 或 系统日志( journalctl -xe )排错即可。

13.5. 状态检查

13.5.1. 基础用法

systemctl status 服务名称

13.5.2. 查看Nginx服务状态

systemctl status nginx
屏幕内容
● nginx.service - nginx - high performance web server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2021-05-20 20:01:10 CST; 3 days ago
     Docs: http://nginx.org/en/docs/
 Main PID: 7858 (nginx)
   CGroup: /system.slice/nginx.service
           ├─7858 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
           └─7859 nginx: worker process

May 20 20:01:09 cdgeekcamp systemd[1]: Starting nginx - high performance web server...
May 20 20:01:10 cdgeekcamp systemd[1]: PID file /var/run/nginx.pid not readable (yet?) a...rt.
May 20 20:01:10 cdgeekcamp systemd[1]: Started nginx - high performance web server.
Hint: Some lines were ellipsized, use -l to show in full.

启动成功后,可以看到 "Active: active (running)" 字样。

如果启动服务时出现错误,会看到这样的内容:

屏幕内容
● nginx.service - nginx - high performance web server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since Sun 2021-05-23 22:27:55 CST; 7min ago
     Docs: http://nginx.org/en/docs/
  Process: 7945 ExecStop=/bin/sh -c /bin/kill -s TERM $(/bin/cat /var/run/nginx.pid) (code=exited, status=0/SUCCESS)
  Process: 7935 ExecReload=/bin/sh -c /bin/kill -s HUP $(/bin/cat /var/run/nginx.pid) (code=exited, status=0/SUCCESS)
  Process: 7949 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=1/FAILURE)
 Main PID: 7916 (code=exited, status=0/SUCCESS)

May 23 22:27:55 cdgeekcamp systemd[1]: Stopped nginx - high performance web server.
May 23 22:27:55 cdgeekcamp systemd[1]: Starting nginx - high performance web server...
May 23 22:27:55 cdgeekcamp nginx[7949]: nginx: [emerg] unexpected ";" in /etc/nginx/ngin...:78
May 23 22:27:55 cdgeekcamp systemd[1]: nginx.service: control process exited, code=exite...s=1
May 23 22:27:55 cdgeekcamp systemd[1]: Failed to start nginx - high performance web server.
May 23 22:27:55 cdgeekcamp systemd[1]: Unit nginx.service entered failed state.
May 23 22:27:55 cdgeekcamp systemd[1]: nginx.service failed.
Hint: Some lines were ellipsized, use -l to show in full.

"Active: failed (Result: exit-code) " 说明启动服务时有错误。

注意软件打印的提示:

May 23 22:27:55 cdgeekcamp nginx[7949]: nginx: [emerg] unexpected ";" in /etc/nginx/ngin...:78

通常解决软件(此处为Nginx)配置错误后,重启服务即可。

13.6. 重启服务

13.6.1. 基础用法

systemctl restart 服务名称

13.6.2. 重启Nginx服务

systemctl restart nginx

13.7. 停止服务

13.7.1. 基础用法

systemctl stop 服务名称

13.7.2. 停止Nginx服务

systemctl stop nginx

确认Nginx服务状态:

systemctl status nginx
屏幕内容
● nginx.service - nginx - high performance web server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: inactive (dead) since Sun 2021-05-23 22:45:46 CST; 33s ago
     Docs: http://nginx.org/en/docs/
  Process: 8003 ExecStop=/bin/sh -c /bin/kill -s TERM $(/bin/cat /var/run/nginx.pid) (code=exited, status=0/SUCCESS)
  Process: 7935 ExecReload=/bin/sh -c /bin/kill -s HUP $(/bin/cat /var/run/nginx.pid) (code=exited, status=0/SUCCESS)
  Process: 7993 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
 Main PID: 7994 (code=exited, status=0/SUCCESS)

May 23 22:40:44 cdgeekcamp systemd[1]: Starting nginx - high performance web server...
May 23 22:40:45 cdgeekcamp systemd[1]: PID file /var/run/nginx.pid not readable (yet?) a...rt.
May 23 22:40:45 cdgeekcamp systemd[1]: Started nginx - high performance web server.
May 23 22:45:46 cdgeekcamp systemd[1]: Stopping nginx - high performance web server...
May 23 22:45:46 cdgeekcamp systemd[1]: Stopped nginx - high performance web server.
Hint: Some lines were ellipsized, use -l to show in full.

"Active: inactive (dead) " 表示服务未启动。

13.8. 重载服务

13.8.1. 基础用法

systemctl reload 服务名称

13.8.2. 重载Nginx服务

systemctl reload nginx

13.9. 查看服务

13.9.1. 基础用法

systemctl cat 服务名称

13.9.2. 查看Nginx服务文件内容

systemctl cat nginx
屏幕内容
# /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/sh -c "/bin/kill -s HUP $(/bin/cat /var/run/nginx.pid)"
ExecStop=/bin/sh -c "/bin/kill -s TERM $(/bin/cat /var/run/nginx.pid)"

[Install]
WantedBy=multi-user.target

13.10. 禁止开机启动

13.10.1. 基础用法

systemctl disable 服务名称

13.10.2. 禁止开机启动Nginx服务

systemctl disable nginx
屏幕内容
Removed symlink /etc/systemd/system/multi-user.target.wants/nginx.service.
已经禁止开机启动的服务,重复执行 disable 操作,屏幕不会显示任何提示。

确认Nginx服务状态:

systemctl is-enabled nginx
屏幕内容
disabled
systemctl mask nginx 可以直接禁止手动启动Nginx服务,反之则是 systemctl unmask nginx。

13.11. 启用开机启动

13.11.1. 基础用法

systemctl disable 服务名称

13.11.2. 开机启动Nginx服务

systemctl enable nginx
屏幕内容
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
已经禁止开机启动的服务,重复执行 enable 操作,屏幕不会显示任何提示。

确认Nginx服务状态:

systemctl is-enabled nginx
屏幕内容
enabled

附录 A: 客户端工具之Linux终端

A.1. Linux终端安装

笔记本或PC上安装有任何Linux发行版(Ubuntu、Deepin Linux、Manjaro Linux、ArchLinux等),系统自带Linux终端,无需单独安装。

A.2. Linux终端连接远程主机

使用 ssh 命令登录远程主机非常简单。如远程主机地址为 192.168.2.236,在终端输入以下命令:

ssh root@192.168.2.236

其中,root 是登录用户名。如果用户名是 mk,则这样登录:

ssh mk@192.168.2.236
appendix b.s2 1

如果你是第一次使用 ssh 连接这台远程主机,你会看到像下面这样的提示消息:

appendix b.s2 2

先 yes,后 Enter,继续连接

appendix b.s2 3

输入 root 用户密码,然后 Enter 。还是和设置密码时类似,密码不会显示在屏幕上

appendix b.s2 4

之前输入 yes 后,远程主机的指纹会添加到你的已知远程主机列表(~/.ssh/known_hosts),如下面的消息所示:

Warning: Permanently added '192.168.2.236' (ECDSA) to the list of known hosts.

正常情况下,每台远程主机只有一个指纹。这样做是为了网络安全,防止中间人攻击。

密码校验成功,你得到了远程主机的交互式终端权限

appendix b.s2 5

看看远程主机空间使用情况

appendix b.s2 6

A.3. Linux设置无密码登录

密码不方便记忆,有时候为了安全设置长密码让问题更凸显,也有时候是因为远程主机太多。

我个人的习惯是第一次登录之后立刻设置无密码登录,业内大家更喜欢称为密钥登录。

如果你是第一次使用无密码登录,需要生成密钥对。密钥对生成后,可以重复使用,不需要每次生成。我的远程主机使用密钥对已经超过十年。

如果你有密钥对,直接上传公钥(锁)到远程主机,使用私钥(钥匙)可以登录远程主机。不用再生成密钥对。

在开始之前,需要说明一下。

密钥对包括两个文件:私钥文件(Private Key),公钥文件(Public Key)。

私钥文件

相当于门钥匙,作为登录远程主机的关键。

公钥文件

相当于门锁,只要有钥匙就可以打开。公钥文件可以发布到任何地方,不需要保密。

私钥文件不能外泄,否则远程主机有严重的安全风险。
不然,某天你可能收到勒索邮件,对方要求支付10个比特币,否则删除数据库。

A.3.1. 生成密钥对

生成不带密码的密钥对: ssh-keygen -N "" -f ~/.ssh/mk

~/.ssh/mk 只是密钥对文件名前缀,可以随意更换。比如,~/.ssh/prolinux
appendix_b.s3-1

如下图所示,会生成两个文件:

  • 私钥文件: ~/.ssh/mk

  • 公钥文件: ~/.ssh/mk.pub

appendix_b.s3-2

A.3.2. 上传公钥文件到远程主机

OK,按照上面的命令,你得到了公钥文件 ~/.ssh/mk.pub 。

接下来,将公钥文件上传到 192.168.2.236(安装一把远程主机的“锁”)。

然后,你才能用私钥(钥匙)登录远程主机。

步骤如下:

  1. 首先,执行命令:

ssh-copy-id -i ~/.ssh/mk.pub root@192.168.2.236
appendix_b.s3-3
  1. 输入远程主机密码

在输入密码时,屏幕上是看不见密码的
appendix_b.s3-4
  1. 密码检验成功,你会看到与以下图片类似的结果

appendix_b.s3-5

至此,就给远程主机安装上了一把“锁”。

A.3.3. 在本地Linux终端中配置私钥

我们搞定“锁”之后,在本地Linux终端中配置“钥匙”。

多远程主机使用相同私钥

你可以增加 IdentityFile ~/.ssh/mk 一行到配置文件中。这样的话,可以使用 ~/.ssh/mk 登录所有远程主机。

echo "IdentityFile ~/.ssh/mk" >> ~/.ssh/config
appendix_b.s3-6
远程主机使用指定私钥

Host 参数也支持较复杂的私钥设置。

语法如下:

Host 192.168.2.236
    IdentityFile ~/.ssh/mk

还不会在Linux下编辑文件?

你可以一句话增加设置到文件:

cat << EOF >> ~/.ssh/config
Host 192.168.2.236
    IdentityFile ~/.ssh/mk
EOF
执行这个命令时,必须按两次 Enter。

Host 后面的IP地址表示登录远程主机:192.168.2.236 时,使用私钥 ~/.ssh/mk

appendix_b.s3-7

你猜得没错,Host 参数可以填写多个IP地址,以空格隔开:

Host 192.168.2.236 118.23.47.90

A.3.4. 测试无密码登录

远程主机已经装上锁,也创建了本地配置文件。现在可以测试下:

ssh root@192.168.2.236
appendix_b.s3-8

无密码登录远程主机成功。

exit 可以注销(退出登录)。我推荐按 Ctrl+D 退出,更方便。

appendix_b.s3-9
appendix_b.s3-10

A.3.5. Troubleshooting

保证以下关键点正确无误,就可以100%配置成功。

客户端:“~/.ssh/”文件夹
  • ~/.ssh/ 文件夹只能被当前用户写入,也就是下图标记的 drwxr-xr-x 中第一个 w 必须存在。

修复方法: chmod 700 ~/.ssh/

appendix_b.s3-11
客户端:“~/.ssh/mk”私钥文件
  • ~/.ssh/mk 文件权限必须是 600,也就是标记的这样 -rw-------

修复方法: chmod 600 ~/.ssh/mk

appendix_b.s3-12

文件权限错误时,私钥无法登录并报错

appendix_b.s3-13
服务端(192.168.2.236):“~/.ssh/”文件夹
  • ~/.ssh/ 文件夹只能被当前用户写入,也就是下图标记的 drwx------ 中第一个 w 必须存在。

修复方法: chmod 755 ~/.ssh/

appendix_b.s3-14
服务端(192.168.2.236):“~/.ssh/authorized_keys”文件
  • ~/.ssh/authorized_keys 文件同样只能被当前用户写入,权限可以是 400 ( -r------- )或者 600( -rw------- )。

修复方法: chmod 600 ~/.ssh/authorized_keys

使用 ssh-copy-id 上传公钥,权限必须是 600( -rw------- )。

如下图所示:

appendix_b.s3-15
  • ~/.ssh/authorized_keys 中每一行都是一把“锁”(公钥),对应一把“钥匙”(私钥)。也就是说,可以多人同时使用相同用户名但不同私钥登录远程主机。

appendix_b.s3-16
查看ssh命令日志

查看日志是诊断连接问题最重要的手段。

第一种是远程主机系统的登录日志文件,另一种是执行 ssh 命令时打印出来的调试信息。

这里以后者为例:ssh root@192.168.2.236 -v

appendix_b.s3-17

可以看到截图中有以下信息:

debug1: Trying private key: /home/mk/.ssh/mk
debug1: Authentication succeeded (publickey).
appendix_b.s3-18

这意味着,我们配置的 config 文件生效了。

如果这个地方没有你配置的私钥文件,请检查 ~/.ssh/config 文件配置

附录 B: 传输文件之Linux终端

B.1. Linux终端

跟着下面的例子练习,只用三分钟搞定 scp 命令传输文件。

按照本书惯例,
本地 是指当前的操作界面,可以是 电脑、手机、其它远程主机。比如,我操作的 mk@archlinux 终端。
远程主机 是指服务器用途的系统,可以是物理裸机、云服务器、虚拟机。比如,第一章安装的虚拟机(192.168.2.236)。

B.1.1. 准备文件

  • 在终端中创建目录,名称为 "ProLinux":

mkdir ProLinux
  • 在目录 "ProLinux" 下创建名为 "foo.txt" 的文件,文件内容为 "test text: foo":

echo 'test text: foo' > ProLinux/foo.txt
  • 同样的方式创建 "bar.txt"

echo 'test text: bar' > ProLinux/bar.txt
  • 查看目录 "ProLinux" 下的文件,确认是否创建成功:

ls -l ProLinux/
操作演示
[mk@archlinux ~]$ ls -l ProLinux/
总用量 8
-rw-r--r-- 1 mk mk 15  2月 26 15:06 bar.txt
-rw-r--r-- 1 mk mk 15  2月 26 15:06 foo.txt

B.1.2. 本地到远程主机

从本地上传目录到远程主机
  • 上传整个 "ProLinux" 目录到远程主机 "192.168.2.236" 上,登录用户名为 "root",保存路径为root用户的家目录 "~"(/root 目录):

scp -r ProLinux/ root@192.168.2.236:~
操作演示
[mk@archlinux ~]$ scp -r ProLinux/ root@192.168.2.236:~
bar.txt                                       100%   15     6.0KB/s   00:00
foo.txt                                       100%   15    26.4KB/s   00:00
从本地上传文件到远程主机
  • 上传指定文件:

scp ProLinux/bar.txt root@192.168.2.236:~/ProLinux/
操作演示
[mk@archlinux ~]$ scp ProLinux/bar.txt root@192.168.2.236:~/ProLinux/
bar.txt                                       100%   15     6.2KB/s   00:00
  • 上传多个文件:

scp ProLinux/foo.txt ProLinux/bar.txt  root@192.168.2.236:~/ProLinux/
操作演示
[mk@archlinux ~]$ scp ProLinux/foo.txt ProLinux/bar.txt root@192.168.2.236:~/ProLinux/
foo.txt                                       100%   15     5.6KB/s   00:00
bar.txt                                       100%   15    34.8KB/s   00:00
  • 可以使用星号 * 模糊匹配文件名,上传 "ProLinux" 目录下所有文件:

scp ProLinux/* root@192.168.2.236:~/ProLinux/
操作演示
[mk@archlinux ~]$ scp ProLinux/* root@192.168.2.236:~/ProLinux/
bar.txt                                       100%   15     5.3KB/s   00:00
foo.txt                                       100%   15    28.2KB/s   00:00
确认上传
  • 登录远程主机:

ssh root@192.168.2.236
  • 查看 "ProLinux" 目录:

ls -l ~
操作演示
[root@prolinux ~]# ls -l ~
total 0
drwxr-xr-x. 2 root root 36 Feb 26 15:10 ProLinux
  • 查看 "ProLinux" 目录下的文件:

ls -l ~/ProLinux
操作演示
[root@prolinux ~]# ls -l ~/ProLinux
total 8
-rw-r--r--. 1 root root 15 Feb 26 15:12 bar.txt
-rw-r--r--. 1 root root 15 Feb 26 15:12 foo.txt

B.1.3. 从远程主机下载文件到本地

方法简单,交换 scp 命令中间的两部分。

  • 从远程主机下载 "~/ProLinux" 目录:

scp -r root@192.168.2.236:~/ProLinux/ ~/
操作演示
[mk@archlinux ~]$ scp -r root@192.168.2.236:~/ProLinux/ ~/
bar.txt                                       100%   15     8.7KB/s   00:00
foo.txt                                       100%   15    38.7KB/s   00:00
  • 从远程主机下载 "foo.txt" 到本地:

scp root@192.168.2.236:~/ProLinux/foo.txt ~/ProLinux
操作演示
[mk@archlinux ~]$ scp root@192.168.2.236:~/ProLinux/foo.txt ~/ProLinux
foo.txt                                       100%   15    47.2KB/s   00:00

附录 C: egrep正则表达式扩展

C.1. 字符分类

根据习惯,可以将常见字符按范围分为:

大写字母

A、B、C、D、E、F、G、H、I、J、K、L、M、N、O、P、Q、R、S、T、U、V、W、X、Y、Z

小写字母

a、b、c、d、e、f、g、h、i、j、k、l、m、n、o、p、q、r、s、t、u、v、w、x、y、z

数字

0、1、2、3、4、5、6、7、8、9

空格

Space

制表符

Tab

英文标点符号

`、-、=、~、!、@、#、$、%、^、&、*、(、)、_、+、[、]、/、{、}、|、;、'、:、"、,、.、/、<、>、?

标准的正则表达式规范中,可以用 [A-Za-z] 这样的范围表达式来表示26个大写字母和26个小写字母。

C.2. 范围表达式

grep 使用特殊的范围表达式 [[:分类名称:]] 达到同样的效果。

具体的对照表如下:

分类名称 说明 示例

[:lower:]

26小写字母,相当于 [a-z]。

egrep '[[:lower:]]' ~/access.log

[:upper:]

26大写字母,相当于 [A-Z]。

egrep '[[:upper:]]' ~/access.log

[:digit:]

阿拉伯数字,相当于 [0-9]。

egrep '[[:digit:]]' ~/access.log

[:alpha:]

大小写字母,[:lower:] 和 [:upper:] 的简写,相当于 [A-Za-z]。

egrep '[[:alpha:]]' ~/access.log

[:alnum:]

大小写字母和阿拉伯数字,[:alpha:] 和 [:digit:] 的简写,相当于 [0-9A-Za-z]。

egrep '[[:alnum:]]' ~/access.log

[:space:]

空格(Space)。

egrep '[[:space:]]' ~/access.log

[:blank:]

空格(Space)和制表符号(Tab)。

egrep '[[:blank:]]' ~/access.log

[:punct:]

英文标点符号,包括:

  • `、-、=

  • ~、!、@、#、$、%、^、&、*、(、)、_、+

  • [、]、/

  • {、}、|

  • ;、'

  • :、"

  • ,、.、/

  • <、>、?

egrep '[[:punct:]]' ~/access.log

[:cntrl:]

(不可见的)控制符,包含ASCII编码中0~31(Null char~Unit Separator)、127(Delete)。

egrep '[[:cntrl:]]' ~/access.log

[:graph:]

可见字符,[:alnum:] 和 [:punct:] 的简写。

egrep '[[:graph:]]' ~/access.log

[:print:]

可打印的字符,[:alnum:]、[:punct:] 和 [:space:] 的简写。

egrep '[[:print:]]' ~/access.log

[:xdigit:]

十六进制数字:

  • 0、1、2、3、4、5、6、7、8、9

  • A、B、C、D、E、F

  • a、b、c、d、e、f

相当于 [0-9A-Fa-f]。

egrep '[[:xdigit:]]' ~/access.log

当然,egrep 也支持取反操作符(^)。如:

egrep '[^[:digit:]]' ~/access.log

匹配不含数字的行,等同匹配包含大小写字母或英文标点符号的行。

屏幕内容
foo.org 80 118.118.47.239 [18/Jan/2021:01:00:23] "GET /360.html HTTP/1.1" 200
bar.org 8080 115.202.80.105 [19/Feb/2021:02:12:24] "POST /login HTTP/1.1" 404
qux.com 80 123.6.49.36 [20/Mar/2021:03:22:24] "GET / HTTP/1.1" 200
quux.com 80 180.101.214.20 [21/Apr/2021:04:15:24] "GET /main.html HTTP/1.1" 200
quz.io 8080 180.101.52.35 [21/Aug/2021:13:18:24] "GET /log.jpg HTTP/1.1" 200
quuz.cn 8080 180.101.52.35 [21/Aug/2021:13:18:24] "GET /jquery.min.js HTTP/1.1" 403
quuuz.cn 8080 125.64.14.56 [21/Aug/2021:13:18:24] "GET /load.js HTTP/1.1" 200
corge.com 80 148.72.153.60 [22/May/2021:23:25:16] "GET /7.html HTTP/1.1" 500
garply.net 80 123.178.50.195 [23/Oct/2021:23:50:16] "POST /article/ HTTP/1.1" 301
garply.net 80 123.178.50.195 [23/Oct/2021:23:50:16] "POST /article_new/ HTTP/1.1" 200

以上每行都包含了字母,所以测试结果是正确的。

set 限制解除