开源之家
  • 首页
  • 精品培训视频
  • 计算机电子书
  • 软件工具
  • 知识库
    • Linux入门教程
    • Shell脚本学习指南
    • Nginx入门教程
    • Docker 入门实战
    • Kubernetes(k8s)手册
    • 快乐的Linux命令行
  • Linux命令手册
登录

Linux入门教程

01 Linux简介
  • 1.0 Linux学习路线
  • 1.1 操作系统概述
  • 1.2 Linux是什么,有哪些特点?
  • 1.3 Linux和UNIX的关系及区别(详解版)
  • 1.4 类UNIX系统是什么鬼?
  • 1.5 Linux中大量使用脚本语言,而不是C语言!
  • 1.6 为什么要学Linux,它比Windows好在哪里?
  • 1.7 Linux系统的优缺点
  • 1.8 常见Linux发行版本有哪些?
  • 1.9 初学者应选择哪个Linux发行版?
  • 1.10 Linux桌面系统大比拼|附带优缺点
  • 1.11 Linux的主要应用领域有哪些?
  • 1.12 Linux已经霸占了服务器领域!
  • 1.13 开源软件是什么?有哪些?
  • 1.14 开源协议是什么?有哪些?如何选择?
  • 1.15 开源就等于免费吗?用事实来说话
  • 1.16 Linux该如何学习(新手入门必看)
  • 1.17 想学好Linux,这些习惯必须养成(初学者必读)
02 Linux安装
  • 2.1 安装Linux系统对硬件有什么要求?
  • 2.2 虚拟机是什么
  • 2.3 为什么建议使用虚拟机来安装Linux?
  • 2.4 小白必看:零基础安装Linux系统(超级详细)
  • 2.5 使用U盘安装Linux系统
  • 2.6 使用dd命令安装Linux系统
  • 2.7 使用LiveCD从光盘直接运行Linux,无需安装
  • 2.8 忘记root账户密码怎么办?
  • 2.9 使用系统光盘修复Linux系统
  • 2.10 破解密码这么简单,Linux是安全的操作系统吗?
  • 2.11 Linux四种远程管理协议
  • 2.12 Linux两种远程管理工具(PuTTY和SecureCRT)
  • 2.13 新手必读的Linux使用注意事项
  • 2.14 Linux文件目录结构一览表
  • 2.15 Linux中一切皆文件[包含优缺点]
  • 2.16 Linux挂载详解
  • 2.17 新手必看的Linux服务器管理和维护注意事项
03 Linux文件和目录管理
  • 3.1 Linux文件系统的层次结构
  • 3.2 Linux文件系统到底有什么用处?
  • 3.3 Linux绝对路径和相对路径详解
  • 3.4 Linux文件(目录)命名规则
  • 3.5 Linux命令行下如何识别文件类型?
  • 3.6 Linux命令基本格式
  • 3.7 Linux切换目录(cd命令)
  • 3.8 Linux显示当前工作路径(pwd命令)
  • 3.9 Linux查看目录中的文件(ls命令)
  • 3.10 Linux创建目录(mkdir命令)
  • 3.11 Linux删除空目录(rmdir命令)
  • 3.12 Linux创建文件及修改文件时间戳(touch命令)
  • 3.13 Linux建立软硬链接文件(ln命令)
  • 3.14 深度剖析Linux硬链接和软链接,直击它们的本质!
  • 3.15 Linux复制文件和目录(cp命令)
  • 3.16 Linux删除文件或目录(rm命令)
  • 3.17 Linux移动或重命名文件和目录(mv命令)
  • 3.18 Linux懒人神器:命令自动补全功能!
  • 3.19 Linux命令的执行过程是怎样的?(新手必读)
  • 3.20 什么是环境变量,Linux环境变量有哪些?
  • 3.21 Linux PATH环境变量及作用(初学者必读)
04 Linux打包和压缩详解
  • 4.1 打包和压缩的概念和区别
  • 4.2 Linux tar打包命令详解
  • 4.3 Linux压缩文件或目录为.zip格式(zip命令)
  • 4.4 Linux解压.zip格式的文件(unzip命令)
  • 4.5 Linux压缩文件或目录中文件为.gz格式(gzip命令)
  • 4.6 Linux解压.gz格式的文件(gunzip命令)
  • 4.7 Linux压缩文件或目录中文件为.bz2格式(bzip2命令)
  • 4.8 Linux解压.bz2格式的文件(bunzip2命令)
05 Vim文本编辑器
  • 5.1 Vim及其安装
  • 5.2 Vi和Vim之间到底有什么关系?
  • 5.3 Linux Vim三种工作模式
  • 5.4 Linux Vim基本操作
  • 5.5 Vim移动光标命令汇总
  • 5.6 Linux Vim撤销和恢复撤销快捷键
  • 5.7 Linux Vim可视化模式
  • 5.8 Vim多窗口编辑模式
  • 5.9 Linux Vim批量注释和自定义注释
  • 5.10 Vim显示行号
  • 5.11 Vim配置文件(.vimrc)详解
06 Linux文本处理
  • 6.1 Linux连接合并文件内容(cat命令)
  • 6.2 Linux分屏显示文件内容(more命令)
  • 6.3 Linux显示文件开头内容(head命令)
  • 6.4 Linux查看文件内容(less命令)
  • 6.5 Linux显示文件结尾内容(tail命令)
  • 6.6 Linux重定向(输入输出重定向)
  • 6.7 Linux grep(Linux三剑客之一)
  • 6.8 Linux sed(Linux三剑客之一)
  • 6.9 Linux sed命令的高级玩法
  • 6.10 Linux awk(Linux三剑客之一)
  • 6.11 Linux awk命令的高级玩法
07 Linux系统软件安装
  • 7.1 Linux软件包
  • 7.2 Linux RPM包统一命名规则
  • 7.3 Linux RPM包安装、卸载和升级
  • 7.4 Linux rpm命令查询软件包
  • 7.5 Linux RPM包验证和数字证书
  • 7.6 Linux提取RPM包
  • 7.7 Linux SRPM源码包安装
  • 7.8 Linux重建RPM数据库(修复损坏的RPM数据库)
  • 7.9 RPM包的依赖性及其解决方案
  • 7.10 Linux yum源及配置
  • 7.11 Linux yum命令
  • 7.12 Linux yum管理软件组
  • 7.13 Linux源码包安装和卸载
  • 7.14 Linux源码包升级
  • 7.15 RPM包和源码包,究竟应该选择哪种安装方式?
  • 7.16 Linux函数库(静态函数库和动态函数库)及其安装过程
  • 7.17 Linux脚本程序包及安装方法详解(以webmin为例)
08 Linux用户和用户组管理
  • 8.1 Linux用户和用户组
  • 8.2 Linux UID和GID
  • 8.3 Linux /etc/passwd
  • 8.4 Linux /etc/shadow
  • 8.5 Linux /etc/group
  • 8.6 Linux /etc/gshadow
  • 8.7 Linux初始组和附加组
  • 8.8 Linux /etc/login.defs
  • 8.9 Linux系统添加新用户(useradd命令)
  • 8.10 Linux修改系统用户密码(passwd命令)
  • 8.11 Linux修改系统用户信息(usermod命令)
  • 8.12 Linux强制系统用户登陆时修改密码(chage命令)
  • 8.13 Linux删除系统用户(userdel命令)
  • 8.14 Linux查看用户的UID和GID(id命令)
  • 8.15 Linux临时切换用户身份(su命令)
  • 8.16 Linux whoami和who am i命令
  • 8.17 Linux添加用户组(groupadd命令)
  • 8.18 Linux修改用户组(groupmod命令)
  • 8.19 Linux删除用户组(groupdel命令)
  • 8.20 Linux将系统用户加入或移除群组(gpasswd命令)
  • 8.21 Linux切换用户的有效群组(newgrp命令)
09 Linux权限管理
  • 9.1 Linux权限管理的重要性
  • 9.2 Linux修改文件和目录的所属组(chgrp命令)
  • 9.3 Linux修改文件和目录的所有者和所属组(chown命令)
  • 9.4 Linux文件权限到底是如何设定的?
  • 9.5 Linux读写执行权限(-r、-w、-x)的真正含义是什么?
  • 9.6 Linux修改文件或目录权限(chmod命令)
  • 9.7 Linux默认权限的设定和修改(umask)
  • 9.8 Linux ACL访问控制权限
  • 9.9 Linux ACL权限设置(setfacl和getfacl)
  • 9.10 Linux mask有效权限有什么用,如何修改?
  • 9.11 Linux SetUID(SUID)特殊权限
  • 9.12 不要轻易设置SetUID(SUID)权限,否则会带来重大安全隐患!
  • 9.13 Linux SetGID(SGID)特殊权限
  • 9.14 Linux Stick BIT(SBIT)特殊权限
  • 9.15 Linux文件特殊权限(SUID、SGID和SBIT)的设置
  • 9.16 Linux修改文件或目录的隐藏属性(chattr命令)
  • 9.17 Linux查看文件或目录的隐藏属性(lsattr命令)
  • 9.18 Linux sudo命令(包含和su命令的对比)
  • 9.19 Linux权限对指令执行的影响
10 Linux文件系统管理
  • 10.1 硬盘结构(机械硬盘和固态硬盘)详解
  • 10.2 Linux文件系统详解
  • 10.3 Linux系统是如何识别硬盘设备和硬盘分区的?
  • 10.4 Linux df用法详解:查看文件系统硬盘使用情况
  • 10.5 Linux du命令:统计目录或文件所占磁盘空间大小
  • 10.6 Linux mount命令详解:挂载Linux系统外的文件
  • 10.7 Linux挂载光盘(使用mount命令)
  • 10.8 Linux挂载U盘(使用mount命令)
  • 10.9 Linux开机自动挂载硬件设备(配置/etc/fatab文件)
  • 10.10 修改/etc/fstab文件出错导致Linux不能启动,该怎么办?
  • 10.11 Linux umount命令:卸载文件系统
  • 10.12 Linux fsck命令:检测和修复文件系统
  • 10.13 Linux dumpe2fs命令:查看文件系统信息
  • 10.14 Linux fdisk命令详解:给硬盘分区
  • 10.15 Linux fdisk创建分区(主分区、扩展分区和逻辑分区)过程详解
  • 10.16 Linux parted命令用法详解:创建分区
  • 10.17 Linux mkfs命令详解格式化分区(为分区写入文件系统)
  • 10.18 Linux mke2fs命令格式化硬盘(给硬盘写入文件系统)
  • 10.19 Linux虚拟内存和物理内存
  • 10.20 Linux swap分区及作用详解
11 Linux高级文件系统管理
  • 11.1 磁盘配额是什么
  • 11.2 磁盘配额启动前的准备工作
  • 11.3 Linux扫描文件系统并建立磁盘配额记录文件(quotacheck命令)
  • 11.4 Linux开启磁盘配额限制(quotaon命令)
  • 11.5 Linux关闭磁盘配额限制(quotaoff命令)
  • 11.6 Linux修改用户(群组)的磁盘配额(edquota命令)
  • 11.7 Linux非交互式设置磁盘配额(setquota命令)
  • 11.8 Linux查询已建立好的磁盘配额(quota和repquota命令)
  • 11.9 Linux磁盘配额测试过程完全攻略
  • 11.10 Linux LVM逻辑卷管理机制
  • 11.11 Linux PV物理卷
  • 11.12 Linux VG卷组
  • 11.13 Linux LV逻辑卷
  • 11.14 Linux LVM(逻辑卷管理)的删除
  • 11.15 Linux RAID(磁盘阵列)完全攻略
  • 11.16 使用图形界面来配置RAID
  • 11.17 使用mdadm命令来配置RAID
12 Linux系统管理
  • 12.1 Linux进程管理
  • 12.2 Linux进程启动的方式有几种?
  • 12.3 Linux如何查看正在运行的进程(ps命令)
  • 12.4 Linux实时监听进程运行状态(top命令)
  • 12.5 Linux查看进程树(pstree命令)
  • 12.6 Linux列出进程调用或打开的文件信息(lsof命令)
  • 12.7 Linux进程优先级
  • 12.8 Linux调整进程的优先级(nice和renice命令)
  • 12.9 Linux常用信号(进程间通信)
  • 12.10 Linux终止进程(kill命令)
  • 10.11 Linux umount命令:卸载文件系统
  • 10.12 Linux fsck命令:检测和修复文件系统
  • 10.13 Linux dumpe2fs命令:查看文件系统信息
  • 10.14 Linux fdisk命令详解:给硬盘分区
  • 10.15 Linux fdisk创建分区(主分区、扩展分区和逻辑分区)过程详解
  • 10.16 Linux parted命令用法详解:创建分区
  • 10.17 Linux mkfs命令详解格式化分区(为分区写入文件系统)
  • 10.18 Linux mke2fs命令格式化硬盘(给硬盘写入文件系统)
  • 10.19 Linux虚拟内存和物理内存
  • 10.20 Linux swap分区及作用详解
13 Linux数据备份与恢复
  • 13.1 Linux备份的重要性
  • 13.2 Linux中的哪些数据需要备份?
  • 13.3 Linux数据备份介质的选择
  • 13.4 Linux备份策略
  • 13.5 Linux tar命令备份数据
  • 13.6 Linux dump
  • 13.7 Linux restore
  • 13.8 Linux dd
  • 13.9 Linux rsync命令:支持本地备份和远程备份
14 Linux系统服务管理
  • 14.1 Linux系统服务
  • 14.2 Linux端口
  • 14.3 Linux独立服务管理
  • 14.4 Linux基于xinetd服务的管理
  • 14.5 Linux源码包服务管理
  • 14.6 Linux常见服务类别及功能
  • 14.7 影响Linux系统性能的因素有哪些?
  • 14.8 Linux分析系统性能(sar命令)
  • 14.9 Linux如何查看CPU运行状态?
  • 14.10 Linux如何查看内存的使用情况?
  • 14.11 Linux如何查看硬盘的读写性能?
15 Linux系统日志管理
  • 15.1 Linux rsyslogd服务
  • 15.2 Linux日志文件及功能
  • 15.3 Linux日志文件的格式分析
  • 15.4 rsyslogd配置文件格式及其内容
  • 15.5 Linux日志服务器设置
  • 15.6 Linux日志轮替(日志转储)
  • 15.7 Linux logrotate命令
  • 15.8 Linux日志分析工具
16 Linux系统启动管理
  • 16.1 Linux系统启动流程
  • 16.2 BIOS开机自检
  • 16.3 主引导目录(MBR)结构及作用
  • 16.4 Linux内核(内核模块)的加载
  • 16.5 Linux /sbin/init
  • 16.6 Linux /etc/inittab
  • 16.7 Linux /etc/rc.d/rc.local配置文件
  • 16.8 Linux启动引导程序加载内核
  • 16.9 Linux /boot/grub/目录
  • 16.10 Linux GRUB磁盘分区表示法
  • 16.11 Linux GRUB配置文件
  • 16.12 Linux多系统并存的GRUB配置文件
  • 16.13 Linux GRUB手动安装
  • 16.14 Linux GRUB加密
  • 16.15 Linux字符界面调整分辨率
  • 16.16 Linux内核模块管理
  • 16.17 Linux NTFS文件系统安装
17 LAMP环境搭建和LNMP环境搭建
  • 17.1 Linux LAMP环境搭建的前期准备
  • 17.2 Linux libxml2安装
  • 17.3 Linux libmcrypt安装
  • 17.4 Linux mhash和mcrypt安装
  • 17.5 Linux zlib和libpng安装
  • 17.6 Linux jpeg6安装
  • 17.7 Linux freetype安装
  • 17.8 Linux gd库安装
  • 17.9 Linux Apache安装
  • 17.10 Linux ncurses安装
  • 17.11 Linux MySQL安装
  • 17.12 Linux PHP安装
  • 17.13 Linux memcache安装和配置
  • 17.14 Linux phpmyadmin安装及配置
  • 17.15 LNMP安装的前期准备
  • 17.16 LNMP一键安装
  • 17.17 LNMP安装php扩展模块
18 SELinux管理
  • 18.1 SELinux是什么
  • 18.2 SELinux的主要作用
  • 18.3 SELinux 的3种工作模式
  • 18.4 SELinux配置文件(/etc/selinux/config)
  • 18.5 SELinux工作模式设置
  • 18.6 SELinux安全上下文查看
  • 18.7 SELinux安全上下文的修改和设置
  • 18.8 SELinux默认安全上下文的查询和修改
  • 18.9 SELinux auditd日志系统的安装与启动
  • 18.10 SELinux auditd日志使用方法
  • 18.11 SELinux的3种策略类型
  • 18.12 SELinux策略规则查看的方法
  • 18.13 SELinux策略规则的开启和关闭

Shell脚本学习指南

01 Shell基础
  • 1.1 Shell是什么
  • 1.2 Shell是运维人员必须掌握的技能
  • 1.3 常用的Shell有哪些?
  • 1.4 进入Shell的两种方式
  • 1.5 Shell命令的基本格式
  • 1.6 Shell命令的本质到底是什么?如何自己实现一个命令?
  • 1.7 Shell命令的选项和参数在本质上是什么
  • 1.8 Shell命令提示符
  • 1.9 修改命令提示符
  • 1.10 第一个Shell脚本
  • 1.11 执行Shell脚本
  • 1.12 Shell四种运行方式
  • 1.13 Shell配置文件的加载
  • 1.14 如何编写自己的Shell配置文件?
02 Shell编程
  • 2.1 Shell变量
  • 2.2 Linux中的文件描述符到底是什么?
  • 2.3 Shell命令替换
  • 2.4 Shell位置参数
  • 2.5 Shell特殊变量
  • 2.6 Shell $*和$@之间的区别
  • 2.7 Shell $?
  • 2.8 Shell字符串详解
  • 2.9 Shell字符串拼接
  • 2.10 Shell字符串截取
  • 2.11 Shell数组
  • 2.12 Shell获取数组长度
  • 2.13 Shell数组拼接
  • 2.14 Shell删除数组元素
  • 2.15 Shell关联数组
  • 2.16 Shell内建命令
  • 2.17 Shell alias命令
  • 2.18 Shell echo命令
  • 2.19 Shell read命令
  • 2.20 Shell exit命令
  • 2.21 Shell declare和typeset命令
  • 2.22 Shell数学计算
  • 2.23 Shell (())
  • 2.24 Shell let命令
  • 2.25 Shell $[]
  • 2.26 Shell expr命令
  • 2.27 Linux bc命令
  • 2.28 Shell declare -i
  • 2.29 Shell if else
  • 2.30 Shell退出状态
  • 2.31 Shell test命令
  • 2.32 Shell [[]]
  • 2.33 Shell case in
  • 2.34 Shell while
  • 2.35 Shell until
  • 2.36 Shell for
  • 2.37 Shell select in
  • 2.38 Shell break和continue
  • 2.39 Shell函数
  • 2.40 Shell函数参数
  • 2.41 Shell函数返回值精讲
03 Shell高级教程
  • 3.1 Shell重定向
  • 3.2 Linux中的文件描述符到底是什么?
  • 3.3 结合文件描述符谈重定向,彻底理解重定向的本质!
  • 3.4 使用exec命令操作文件描述符
  • 3.5 使用exec命令操作文件描述符
  • 3.6 Shell Here Document
  • 3.7 Shell Here String
  • 3.8 Shell组命令
  • 3.9 Shell进程替换
  • 3.10 Linux管道
  • 3.11 Shell过滤器
  • 3.12 子Shell和子进程到底有什么区别?
  • 3.13 如何检测子Shell和子进程?
  • 3.14 Linux中的信号是什么
  • 3.15 Bash Shell中的信号
  • 3.16 Linux进程简明教程
  • 3.17 使用什么命令查看进程
  • 3.18 Shell向进程发送信号
  • 3.19 使用trap命令获取信号
  • 3.20 trap命令捕获信号实例演示
  • 3.21 移除(重置)信号捕获
  • 3.22 关于进程、信号和捕获的总结
  • 3.23 Shell模块化
04 Bash Shell快捷键
  • 4.1 Bash Shell快捷键大全
  • 4.2 Bash Shell命令自动补全功能
  • 4.3 Bash Shell历史命令

Nginx入门教程

01 Nginx基础
  • 1.1 前言
  • 1.2 Nginx 简介
  • 1.3 Nginx 源码架构分析
  • 1.4 Nginx 编译安装
  • 1.5 Tengine 编译安装
  • 1.6 OpenResty 编译安装
  • 1.7 Nginx 配置简述
  • 1.8 Nginx Docker 容器化配置
02 Nginx核心配置
  • 2.1 Nginx 核心配置指令
  • 2.2 Nginx 配置文件
  • 2.3 Nginx 进程配置指令
  • 2.4 Nginx 端口监听
  • 2.5 Nginx 主机名
  • 2.6 Nginx 处理HTTP请求
  • 2.7 Nginx 路由匹配规则
  • 2.8 Nginx 重定向配置
  • 2.9 Nginx 根目录配置
  • 2.10 Nginx 访问路径别名
  • 2.11 Nginx 文件判断
  • 2.12 Nginx 零复制
  • 2.13 Nginx 日志记录配置
03 Nginx HTTP模块
  • 3.1 Nginx 镜像模块
  • 3.2 Nginx 请求头控制模块
  • 3.3 Nginx IP访问控制模块
  • 3.4 Nginx 用户cookie模块
  • 3.5 Nginx 并发连接数限制模块
  • 3.6 Nginx 首页处理模块
  • 3.7 Nginx 请求频率限制模块
  • 3.8 Nginx 页面缓存时间配置
  • 3.9 Nginx gzip压缩及相关配置
04 Nginx Web服务
  • 4.1 Nginx 静态资源服务器搭建
  • 4.2 Nginx 文件下载服务器搭建
  • 4.3 Nginx 伪动态SSI服务器
  • 4.4 Nginx HTTPS服务器搭建
  • 4.5 Nginx FastCGI模块配置简述
  • 4.6 Nginx PHP服务器环境搭建
  • 4.7 Nginx 基于FastCGI负载均衡
  • 4.8 Nginx CGI网关接口
  • 4.9 Nginx uWSGI模块配置
  • 4.10 Nginx Python项目部署
  • 4.11 Nginx 伪流媒体服务器搭建
  • 4.12 Nginx HTTP2模块配置简述
  • 4.13 Nginx WebDAV模块配置简述
05 Nginx 代理服务器
  • 5.1 Nginx HTTP代理服务器
  • 5.2 Nginx stream模块简述
  • 5.3 Nginx TCPUDP代理简述
  • 5.4 Nginx 基于SSL的TCP代理服务器
  • 5.5 Nginx gRPC代理服务器
06 Nginx 缓存
  • 6.1 Nginx Web缓存配置
  • 6.2 Nginx 代理缓存配置
  • 6.3 Nginx Memcached 缓存模块
  • 6.4 Nginx 反向代理缓存服务器配置
  • 6.5 Nginx 客户端缓存控制
07 Nginx 负载均衡
  • 7.6 Nginx TCPUDP负载均衡
  • 7.5 Nginx upstream动态更新
  • 7.4 Nginx upstream容错机制
  • 7.3 Nginx 长连接负载均衡
  • 7.2 Nginx 负载均衡策略
  • 7.1 Nginx 负载均衡模块
08 Nginx 日志管理监控
  • 8.1 Nginx 日志分析简述
  • 8.2 Nginx 访问日志配置
  • 8.3 Nginx 错误日志配置
  • 8.4 Nginx 日志归档配置
  • 8.5 Nginx 日志分析工具 ELK
  • 8.6 Nginx 监控工具 Prometheus
09 Nginx 集群
  • 9.1 LVS简介
  • 9.2 Keepalived 配置简述
  • 9.3 Nginx 集群负载搭建
  • 9.4 Nginx 集群配置管理规划
  • 9.5 Nginx 配置归档工具GitLab
  • 9.6 Nginx 配置修改工具Ansible
  • 9.7 Jenkins 安装与配置简述
  • 9.8 Nginx 集群配置管理实例
10 Nginx 在 k8s 的应用
  • 10.1 Kubernetes(k8s)系统简述
  • 10.2 Kubernetes(k8s)集群部署
  • 10.3 Kubernetes(k8s)网络通信
  • 10.4 Nginx Ingress 简介
  • 10.5 Nginx Ingress 安装部署
  • 10.6 Nginx Ingress 配置映射
  • 10.7 Nginx Ingress 注解

Docker 入门实战

01 Docker基础
  • 1.1 前言
  • 1.2 Docker 架构
02 Docker安装
  • 2.1 CentOS Docker 安装
  • 2.2 Ubuntu Docker 安装
  • 2.3 Debian Docker 安装
  • 2.4 Windows Docker 安装
  • 2.5 MacOS Docker 安装
  • 2.6 Docker 镜像加速
03 Docker 使用
  • 3.1 Docker Hello World
  • 3.2 Docker 容器使用
  • 3.3 Docker 镜像使用
  • 3.4 Docker 容器连接
  • 3.5 Docker 仓库管理
  • 3.6 Docker Dockerfile
  • 07 Docker Compose
  • 08 Docker Machine
  • 09 Swarm 集群管理
04 Docker 实例
  • 4.1 Docker 安装 Ubuntu
  • 4.2 Docker 安装 CentOS
  • 4.3 Docker 安装 Nginx
  • 4.4 Docker 安装 Node.js
  • 4.5 Docker 安装 PHP
  • 4.6 Docker 安装 MySQL
  • 4.7 Docker 安装 Tomcat
  • 4.8 Docker 安装 Python
  • 4.9 Docker 安装 Redis
  • 4.10 Docker 安装 MongoDB
  • 4.11 Docker 安装 Apache
05 Docker 参考手册
  • 5.1 Docker 常用命令
  • 5.2 Docker 备忘单

Kubernetes(k8s)手册

01 kubernetes 概述
  • 01 kubernetes 简介
  • 02 Kubernetes 组件
  • 03 Kubernetes API
02 Kubernetes 安装
  • 01 Kubernetes Linux安装

快乐的Linux命令行

  • 第1章:引言
  • 第2章:什么是 shell
  • 第3章:文件系统中跳转
  • 第4章:探究操作系统
  • 第5章:操作文件和目录
  • 第6章:使用命令
  • 第7章:重定向
  • 第8章:从Shell眼中看世界
  • 第9章:键盘高级操作技巧
  • 第10章:权限
  • 第11章:进程
  • 第12章:Shell环境
  • 第13章:vi简介
  • 第14章:自定制Shell提示符
  • 第15章:软件包管理
  • 第16章:存储媒介
  • 第17章:网络系统
  • 第18章:查找文件
  • 第19章:归档和备份
  • 第20章:正则表达式
  • 第21章:文本处理
  • 第22章:格式化输出
  • 第23章:打印
  • 第24章:编译程序
  • 第25章:编写第一个Shell脚本
  • 第26章:启动一个项目
  • 第27章 : 自顶向下设计
  • 第28章 : 流程控制:if 分支结构
  • 第29章 : 读取键盘输入
  • 第30章 : 流程控制:while/until 循环
  • 第31章 : 疑难排解
  • 第32章 : 流程控制:case 分支
  • 第33章 : 位置参数
  • 第34章 : 流程控制:for 循环
  • 第35章 : 字符串和数字
  • 第36章 : 数组
  • 第37章 : 奇珍异宝

第20章:正则表达式

文章目录
  • 20.1 grep
  • 20.2 元字符和原义字符(Metacharacters And Literals)
  • 20.3 任何字符
  • 20.4 锚点
  • 20.5 中括号表达式和字符类
  • 20.6 否定
  • 20.7 传统的字符区域
  • 20.8 POSIX 字符集
  • 20.9 POSIX基本正则表达式 与 POSIX扩展正则表达式
  • 20.10 交替
  • 20.11 限定符
    • 20.11.1 ? - 匹配零个或一个元素
  • 20.12 * - 匹配零个或多个元素
    • 20.12.1 + - 匹配一个或多个元素
    • 20.12.2 { } - 匹配特定个数的元素
  • 20.13 让正则表达式工作起来
    • 20.13.1 通过 grep 命令来验证一个电话簿
    • 20.13.2 用 find 查找丑陋的文件名
    • 20.13.3 用 locate 查找文件
    • 20.13.4 在 less 和 vim 中查找文本
  • 20.14 总结归纳

第20章:正则表达式

接下来的几章中,我们将会看一下一些用来操作文本的工具。正如我们所见到的,在类 Unix 的操作系统中,比如 Linux 中,文本数据起着举足轻重的作用。但是在我们能完全理解这些工具提供的所有功能之前,我们不得不先看看,经常与这些工具的高级使用相关联的一门技术——正则表达式。

我们已经浏览了许多由命令行提供的功能和工具,我们遇到了一些真正神秘的 shell 功能和命令,比如 shell 展开和引用、键盘快捷键和命令历史,更不用说 vi 编辑器了。正则表达式延续了这种“传统”,而且有可能(备受争议地)是这些‘神秘功能’中最神秘的那个。这并不是说花费时间来学习它们是不值得的,而是恰恰相反。虽然它们的全部价值可能不能立即显现,但是较强理解这些功能使我们能够表演令人惊奇的技艺。什么是正则表达式?

简而言之,正则表达式是一种符号表示法,被用来识别文本模式。在某种程度上,它们与匹配文件和路径名的 shell 通配符比较相似,但其规模更庞大。许多命令行工具和大多数的编程语言都支持正则表达式,以此来帮助解决文本操作问题。然而,并不是所有的正则表达式都是一样的,这就进一步混淆了事情;不同工具以及不同语言之间的正则表达式都略有差异。我们将会限定POSIX 标准中描述的正则表达式(其包括了大多数的命令行工具),供我们讨论,与许多编程语言(最著名的 Perl 语言)相反,它们使用了更多和更丰富的符号集。

20.1 grep

我们将使用的主要程序是我们的老朋友,grep 程序,它会用到正则表达式。实际上,“grep”这个名字来自于短语“global regular expression print”,所以我们能看出 grep 程序和正则表达式有关联。本质上,grep 程序会在文本文件中查找一个指定的正则表达式,并把匹配行输出到标准输出。

到目前为止,我们已经使用 grep 程序查找了固定的字符串,就像这样:

[me@linuxbox ~]$ ls /usr/bin | grep zip

这个命令会列出,位于目录 /usr/bin 中,文件名中包含子字符串“zip”的所有文件。

grep 程序以这样的方式来接受选项和参数:

grep [options] regex [file...]

这里的 regex 是指一个正则表达式。

这是一个常用的 grep 选项列表:

​

表20-1: grep 选项
选项 描述
-i 忽略大小写。不会区分大小写字符。也可用--ignore-case 来指定。
-v 不匹配。通常,grep 程序会打印包含匹配项的文本行。这个选项导致 grep 程序只会打印不包含匹配项的文本行。也可用--invert-match 来指定。
-c 打印匹配的数量(或者是不匹配的数目,若指定了-v 选项),而不是文本行本身。
也可用--count 选项来指定。
-l 打印包含匹配项的文件名,而不是文本行本身,也可用--files-with-matches 选项来指定。
-L 相似于-l 选项,但是只是打印不包含匹配项的文件名。也可用--files-without-match 来指定。
-n 在每个匹配行之前打印出其位于文件中的相应行号。也可用--line-number 选项来指定。
-h 应用于多文件搜索,不输出文件名。也可用--no-filename 选项来指定。

为了更好的探究 grep 程序,让我们创建一些文本文件来搜寻:

[me@linuxbox ~]$ ls /bin > dirlist-bin.txt
[me@linuxbox ~]$ ls /usr/bin > dirlist-usr-bin.txt
[me@linuxbox ~]$ ls /sbin > dirlist-sbin.txt
[me@linuxbox ~]$ ls /usr/sbin > dirlist-usr-sbin.txt
[me@linuxbox ~]$ ls dirlist*.txt
dirlist-bin.txt     dirlist-sbin.txt    dirlist-usr-sbin.txt
dirlist-usr-bin.txt

我们能够对我们的文件列表执行简单的搜索,像这样:

[me@linuxbox ~]$ grep bzip dirlist*.txt
dirlist-bin.txt:bzip2
dirlist-bin.txt:bzip2recover

在这个例子里,grep 程序在所有列出的文件中搜索字符串 bzip,然后找到两个匹配项,其都在文件 dirlist-bin.txt 中。如果我们只是对包含匹配项的文件列表,而不是对匹配项本身感兴趣的话,我们可以指定-l 选项:

[me@linuxbox ~]$ grep -l bzip dirlist*.txt
dirlist-bin.txt

相反地,如果我们只想查看不包含匹配项的文件列表,我们可以这样操作:

[me@linuxbox ~]$ grep -L bzip dirlist*.txt
dirlist-sbin.txt
dirlist-usr-bin.txt
dirlist-usr-sbin.txt

20.2 元字符和原义字符(Metacharacters And Literals)

它可能看起来不明显,但是我们的 grep 程序一直使用了正则表达式,虽然是非常简单的例子。这个正则表达式“bzip”意味着,匹配项所在行至少包含4个字符,并且按照字符 “b”、“z”、 “i” 和 “p”的顺序出现在匹配行的某处,字符之间没有其它的字符。字符串“bzip”中的所有字符都是原义字符,因此它们匹配本身。除了原义字符之外,正则表达式也可能包含元字符,其被用来指定更复杂的匹配项。正则表达式元字符由以下字符组成:

^ $ . [ ] { } - ? * + ( ) | \

其它所有字符都被认为是原义字符。在个别情况下,反斜杠会被用来创建元序列,元字符也可以被转义为原义字符,而不是被解释为元字符。


注意:正如我们所见到的,当 shell 执行展开的时候,许多正则表达式元字符,也是对 shell 有特殊含义的字符。当我们在命令行中传递包含元字符的正则表达式的时候,把元字符用引号引起来至关重要,这样可以阻止 shell 试图展开它们。


20.3 任何字符

我们将要查看的第一个元字符是圆点字符,其被用来匹配任意字符。如果我们在正则表达式中包含它,它将会匹配在此位置的任意一个字符。这里有个例子:

[me@linuxbox ~]$ grep -h '.zip' dirlist*.txt
bunzip2
bzip2
bzip2recover
gunzip
gzip
funzip
gpg-zip
preunzip
prezip
prezip-bin
unzip
unzipsfx

我们在文件中查找包含正则表达式“.zip”的文本行。对于搜索结果,有几点需要注意一下。注意没有找到这个 zip 程序。这是因为在我们的正则表达式中包含的圆点字符把所要求的匹配项的长度增加到四个字符,并且因为字符串“zip”只包含三个字符,所以这个 zip 程序不匹配。另外,如果我们的文件列表中有一些文件的扩展名是.zip,则它们也会成为匹配项,因为文件扩展名中的圆点符号也会被看作是“任意字符”。

20.4 锚点

在正则表达式中,插入符号和美元符号被看作是锚点。这意味着正则表达式只有在文本行的开头或末尾被找到时,才算发生一次匹配。

[me@linuxbox ~]$ grep -h '^zip' dirlist*.txt
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
[me@linuxbox ~]$ grep -h 'zip$' dirlist*.txt
gunzip
gzip
funzip
gpg-zip
preunzip
prezip
unzip
zip
[me@linuxbox ~]$ grep -h '^zip$' dirlist*.txt
zip

这里我们分别在文件列表中搜索行首、行尾以及行首和行尾同时包含字符串“zip”(例如,zip 独占一行)的匹配行。注意正则表达式‘^$’(行首和行尾之间没有字符)会匹配空行。

字谜助手

到目前为止,甚至凭借我们有限的正则表达式知识,我们已经能做些有意义的事情了。

我妻子喜欢玩字谜游戏,有时候她会因为一个特殊的问题,而向我求助。类似这样的问题,“一个有五个字母的单词,它的第三个字母是‘j’,最后一个字母是‘r’,是哪个单词?”这类问题会让我动脑筋想想。

你知道你的 Linux 系统中带有一本英文字典吗?千真万确。看一下 /usr/share/dict 目录,你就能找到一本,或几本。存储在此目录下的字典文件,其内容仅仅是一个长长的单词列表,每行一个单词,按照字母顺序排列。在我的系统中,这个文件仅包含98,000个单词。为了找到可能的上述字谜的答案,我们可以这样做:

[me@linuxbox ~]$ grep -i '^..j.r$' /usr/share/dict/words
Major
major

使用这个正则表达式,我们能在我们的字典文件中查找到包含五个字母,且第三个字母是“j”,最后一个字母是“r”的所有单词。

20.5 中括号表达式和字符类

除了能够在正则表达式中的给定位置匹配任意字符之外,通过使用中括号表达式,我们也能够从一个指定的字符集合中匹配单个字符。通过中括号表达式,我们能够指定一个待匹配字符集合(包含在不加中括号的情况下会被解释为元字符的字符)。在这个例子里,使用了一个两个字符的集合:

[me@linuxbox ~]$ grep -h '[bg]zip' dirlist*.txt
bzip2
bzip2recover
gzip

我们匹配包含字符串“bzip”或者“gzip”的任意行。

一个字符集合可能包含任意多个字符,并且元字符被放置到中括号里面后会失去了它们的特殊含义。然而,在两种情况下,会在中括号表达式中使用元字符,并且有着不同的含义。第一个元字符是插入字符(^),其被用来表示否定;第二个是连字符字符(-),其被用来表示一个字符范围。

20.6 否定

如果在中括号表示式中的第一个字符是一个插入字符(^),则剩余的字符被看作是不会在给定的字符位置出现的字符集合。通过修改之前的例子,我们试验一下:

[me@linuxbox ~]$ grep -h '[^bg]zip' dirlist*.txt
bunzip2
gunzip
funzip
gpg-zip
preunzip
prezip
prezip-bin
unzip
unzipsfx

通过激活否定操作,我们得到一个文件列表,它们的文件名都包含字符串“zip”,并且“zip”的前一个字符是除了“b”和“g”之外的任意字符。注意文件 zip 没有被发现。一个否定的字符集仍然在给定位置要求一个字符,但是这个字符必须不是否定字符集的成员。

插入字符如果是中括号表达式中的第一个字符的时候,才会唤醒否定功能;否则,它会失去它的特殊含义,变成字符集中的一个普通字符。

20.7 传统的字符区域

如果我们想要构建一个正则表达式,它可以在我们的列表中找到每个以大写字母开头的文件,我们可以这样做:

[me@linuxbox ~]$ grep -h '^[ABCDEFGHIJKLMNOPQRSTUVWXZY]' dirlist*.txt

这只是一个在正则表达式中输入26个大写字母的问题。但是输入所有字母非常令人烦恼,所以有另外一种方式:

[me@linuxbox ~]$ grep -h '^[A-Z]' dirlist*.txt
MAKEDEV
ControlPanel
GET
HEAD
POST
X
X11
Xorg
MAKEFLOPPIES
NetworkManager
NetworkManagerDispatcher

通过使用一个三个符区域,我们能够缩写26个字母。任意字符的区域都能按照这种方式表达,包括多个区域,比如下面这个表达式就匹配了所有以字母和数字开头的文件名:

[me@linuxbox ~]$ grep -h '^[A-Za-z0-9]' dirlist*.txt

在字符区域中,我们看到这个连字符被特殊对待,所以我们怎样在一个正则表达式中包含一个连字符呢?方法就是使连字符成为表达式中的第一个字符。考虑一下这两个例子:

[me@linuxbox ~]$ grep -h '[A-Z]' dirlist*.txt

这会匹配包含一个大写字母的文件名。然而:

[me@linuxbox ~]$ grep -h '[-AZ]' dirlist*.txt

上面的表达式会匹配包含一个连字符,或一个大写字母“A”,或一个大写字母“Z”的文件名。

20.8 POSIX 字符集

传统的字符区域是一个易于理解和有效的方法,用来处理快速指定字符集合的问题。不幸的是,它们不总是工作。到目前为止,虽然我们在使用 grep 程序的时候没有遇到任何问题,但是我们可能在使用其它程序的时候会遭遇困难。

回到第5章,我们看看通配符怎样被用来完成路径名展开操作。在那次讨论中,我们说过在某种程度上,那个字符区域被使用的方式几乎与在正则表达式中的用法一样,但是有一个问题:

[me@linuxbox ~]$ ls /usr/sbin/[ABCDEFGHIJKLMNOPQRSTUVWXYZ]*
/usr/sbin/MAKEFLOPPIES
/usr/sbin/NetworkManagerDispatcher
/usr/sbin/NetworkManager

(依赖于不同的 Linux 发行版,我们将得到不同的文件列表,有可能是一个空列表。这个例子来自于 Ubuntu)这个命令产生了期望的结果——只有以大写字母开头的文件名,但是:

[me@linuxbox ~]$ ls /usr/sbin/[A-Z]*
/usr/sbin/biosdecode
/usr/sbin/chat
/usr/sbin/chgpasswd
/usr/sbin/chpasswd
/usr/sbin/chroot
/usr/sbin/cleanup-info
/usr/sbin/complain
/usr/sbin/console-kit-daemon

通过这个命令我们得到完全不同的结果(只列出了部分结果)。原因说来话长,简单来说就是:

追溯到 Unix 刚刚开发的时候,它只知道 ASCII 字符,并且Unix特性也如实反映了这一事实。在 ASCII 中,前32个字符(数字0-31)都是控制码(如 tabs、backspaces和回车)。随后的32个字符(32-63)包含可打印的字符,包括大多数的标点符号和数字0到9。再随后的32个字符(64-95)包含大写字符和一些更多的标点符号。最后的31个字符(96-127)包含小写字母和更多的标点符号。基于这种安排方式,使用ASCII的系统的排序规则像下面这样:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

这个不同于正常的字典顺序,其像这样:

aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ

随着 Unix 系统的知名度在美国之外的国家传播开来,就需要支持不在 U.S.英语范围内的字符。于是就扩展了这个 ASCII 字符表,使用了整个8位,添加了字符(数字128-255),这样就容纳了更多的语言。

为了支持这种功能,posix标准引入了"locale"概念,它能针对不同地区选择合适的字符集。:

[me@linuxbox ~]$ echo $LANG
en_US.UTF-8

通过这个设置,POSIX 相容的应用程序将会使用字典排列顺序而不是 ASCII 顺序。这就解释了上述命令的行为。当[A-Z]字符区域按照字典顺序解释的时候,包含除了小写字母“a”之外的所有字母,因此得到这样的结果。

为了部分地解决这个问题,POSIX 标准包含了大量的字符集,其提供了有用的字符区域。如下表中所示:

表20-2: POSIX 字符集
字符集 说明
[:alnum:] 字母数字字符。在 ASCII 中,等价于:[A-Za-z0-9]
[:word:] 与[:alnum:]相同, 但增加了下划线字符。
[:alpha:] 字母字符。在 ASCII 中,等价于:[A-Za-z]
[:blank:] 包含空格和 tab 字符。
[:cntrl:] ASCII 的控制码。包含了0到31,和127的 ASCII 字符。
[:digit:] 数字0到9
[:graph:] 可视字符。在 ASCII 中,它包含33到126的字符。
[:lower:] 小写字母。
[:punct:] 标点符号字符。在 ASCII 中,等价于:[-!"#$%&'()*+,./:;<=>?@[\\\]_`{|}~]
[:print:] 可打印的字符。在[:graph:]中的所有字符,再加上空格字符。
[:space:] 空白字符,包括空格、tab、回车、换行、vertical tab 和 form feed.在 ASCII 中,
等价于:[ \t\r\n\v\f]
[:upper:] 大写字母。
[:xdigit:] 用来表示十六进制数字的字符。在 ASCII 中,等价于:[0-9A-Fa-f]

甚至通过字符集,仍然没有便捷的方法来表达部分区域,比如[A-M]。

通过使用字符集,我们重做上述的例题,看到一个改进的结果:

[me@linuxbox ~]$ ls /usr/sbin/[[:upper:]]*
/usr/sbin/MAKEFLOPPIES
/usr/sbin/NetworkManagerDispatcher
/usr/sbin/NetworkManager

记住,然而,这不是一个正则表达式的例子,而是 shell 正在执行路径名展开操作。我们在这里展示这个例子,是因为 POSIX 规范的字符集适用于二者。

恢复到传统的排列顺序

通过改变环境变量 LANG 的值,你可以选择让你的系统使用传统的(ASCII)排列规则。如上所示,这个 LANG 变量包含了语种和字符集。这个值最初由你安装 Linux 系统时所选择的安装语言决定。

使用 locale 命令,来查看 locale 的设置。

[me@linuxbox ~]$ locale

LANG=en_US.UTF-8

LC_CTYPE="en_US.UTF-8"

LC_NUMERIC="en_US.UTF-8"

LC_TIME="en_US.UTF-8"

LC_COLLATE="en_US.UTF-8"

LC_MONETARY="en_US.UTF-8"

LC_MESSAGES="en_US.UTF-8"

LC_PAPER="en_US.UTF-8"

LC_NAME="en_US.UTF-8"

LC_ADDRESS="en_US.UTF-8"

LC_TELEPHONE="en_US.UTF-8"

LC_MEASUREMENT="en_US.UTF-8"

LC_IDENTIFICATION="en_US.UTF-8"

LC_ALL=

把这个 LANG 变量设置为 POSIX,来更改 locale,使其使用传统的 Unix 行为。

[me@linuxbox ~]$ export LANG=POSIX

注意这个改动使系统为它的字符集使用 U.S.英语(更准确地说,ASCII),所以要确认一下这是否是你真正想要的效果。通过把这条语句添加到你的.bashrc 文件中,你可以使这个更改永久有效。

export LANG=POSIX

20.9 POSIX基本正则表达式 与 POSIX扩展正则表达式

就在我们认为这已经非常令人困惑了,我们却发现 POSIX 把正则表达式的实现分成了两类:基本正则表达式(BRE)和扩展的正则表达式(ERE)。既服从 POSIX 规范又实现了BRE 的任意应用程序,都支持我们目前研究的所有正则表达式特性。我们的 grep 程序就是其中一个。

BRE 和 ERE 之间有什么区别呢?这是关于元字符的问题。BRE 可以辨别以下元字符:

^ $ . [ ] *

其它的所有字符被认为是文本字符。ERE 添加了以下元字符(以及与其相关的功能):

( ) { } ? + |

然而(这也是有趣的地方),在 BRE 中,字符“(”,“)”,“{”,和 “}”用反斜杠转义后,被看作是元字符,相反在 ERE 中,在任意元字符之前加上反斜杠会导致其被看作是一个文本字符。在随后的讨论中将会涵盖很多奇异的特性。

因为我们将要讨论的下一个特性是 ERE 的一部分,我们将要使用一个不同的 grep 程序。照惯例,一直由 egrep 程序来执行这项操作,但是 GNU 版本的 grep 程序在使用了-E 选项之后也支持扩展的正则表达式。

在 20 世纪 80 年代,Unix 成为一款非常流行的商业操作系统,但是到了1988年,Unix 世界一片混乱。许多计算机制造商从 Unix 的创建者 AT&T 那里得到了许可的 Unix 源码,并且供应各种版本的操作系统。然而,在他们努力创造产品差异化的同时,每个制造商都增加了专用的更改和扩展。这就开始限制了软件的兼容性。

专有软件供应商一如既往,每个供应商都试图玩嬴游戏“锁定”他们的客户。这个 Unix 历史上的黑暗时代,就是今天众所周知的 “the Balkanization”。

然后进入 IEEE( 电气与电子工程师协会 )时代。在上世纪 80 年代中叶,IEEE 开始制定一套标准,其将会定义 Unix 系统( 以及类 Unix 的系统 )如何执行。这些标准,正式成为 IEEE 1003,定义了应用程序编程接口( APIs ),shell 和一些实用程序,其将会在标准的类 Unix 操作系统中找到。“POSIX” 这个名字,象征着可移植的操作系统接口(为了时髦一点,添加了末尾的 “X” ),是由 Richard Stallman 建议的( 是的,的确是 Richard Stallman ),后来被 IEEE 采纳。

20.10 交替

我们将要讨论的扩展表达式的第一个特性叫做 alternation(交替),其是一款允许从一系列表达式之间选择匹配项的实用程序。就像中括号表达式允许从一系列指定的字符之间匹配单个字符那样,alternation 允许从一系列字符串或者是其它的正则表达式中选择匹配项。为了说明问题,我们将会结合 echo 程序来使用 grep 命令。首先,让我们试一个普通的字符串匹配:

[me@linuxbox ~]$ echo "AAA" | grep AAA
AAA
[me@linuxbox ~]$ echo "BBB" | grep AAA
[me@linuxbox ~]$

一个相当直截了当的例子,我们把 echo 的输出管道给 grep,然后看到输出结果。当出现一个匹配项时,我们看到它会打印出来;当没有匹配项时,我们看到没有输出结果。

现在我们将添加 alternation,以竖杠线元字符为标记:

[me@linuxbox ~]$ echo "AAA" | grep -E 'AAA|BBB'
AAA
[me@linuxbox ~]$ echo "BBB" | grep -E 'AAA|BBB'
BBB
[me@linuxbox ~]$ echo "CCC" | grep -E 'AAA|BBB'
[me@linuxbox ~]$

这里我们看到正则表达式'AAA|BBB',这意味着“匹配字符串 AAA 或者是字符串 BBB”。注意因为这是一个扩展的特性,我们给 grep 命令(虽然我们能以 egrep 程序来代替)添加了-E 选项,并且我们把这个正则表达式用单引号引起来,为的是阻止 shell 把竖杠线元字符解释为一个 pipe 操作符。Alternation 并不局限于两种选择:

[me@linuxbox ~]$ echo "AAA" | grep -E 'AAA|BBB|CCC'
AAA

为了把 alternation 和其它正则表达式元素结合起来,我们可以使用()来分离 alternation。

[me@linuxbox ~]$ grep -Eh '^(bz|gz|zip)' dirlist*.txt

这个表达式将会在我们的列表中匹配以“bz”,或“gz”,或“zip”开头的文件名。如果我们删除了圆括号,这个表达式的意思:

[me@linuxbox ~]$ grep -Eh '^bz|gz|zip' dirlist*.txt

会变成匹配任意以“bz”开头,或包含“gz”,或包含“zip”的文件名。

20.11 限定符

扩展的正则表达式支持几种方法,来指定一个元素被匹配的次数。

20.11.1 ? - 匹配零个或一个元素

这个限定符意味着,实际上,“使前面的元素可有可无。”比方说我们想要查看一个电话号码的真实性,如果它匹配下面两种格式的任意一种,我们就认为这个电话号码是真实的:

(nnn) nnn-nnnn

nnn nnn-nnnn

这里的“n”是一个数字。我们可以构建一个像这样的正则表达式:

^\(?[0-9][0-9][0-9]\)?  [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$

在这个表达式中,我们在圆括号之后加上一个问号,来表示它们将被匹配零次或一次。再一次,因为通常圆括号都是元字符(在 ERE 中),所以我们在圆括号之前加上了反斜杠,使它们成为文本字符。

让我们试一下:

[me@linuxbox ~]$ echo "(555) 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'
(555) 123-4567
[me@linuxbox ~]$ echo "555 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'
555 123-4567
[me@linuxbox ~]$ echo "AAA 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'
[me@linuxbox ~]$

这里我们看到这个表达式匹配这个电话号码的两种形式,但是不匹配包含非数字字符的号码。

20.12 * - 匹配零个或多个元素

像 ? 元字符一样,这个 * 被用来表示一个可选的字符;然而,又与 ? 不同,匹配的字符可以出现任意多次,不仅是一次。比方说我们想要知道是否一个字符串是一句话;也就是说,字符串开始于一个大写字母,然后包含任意多个大写和小写的字母和空格,最后以句号收尾。为了匹配这个(非常粗略的)语句的定义,我们能够使用一个像这样的正则表达式:

[[:upper:]][[:upper:][:lower:] ]*.

这个表达式由三个元素组成:一个包含[:upper:]字符集的中括号表达式,一个包含[:upper:]和[:lower:] 两个字符集以及一个空格的中括号表达式,和一个被反斜杠字符转义过的圆点。第二个元素末尾带有一个 *元字符,所以在开头的大写字母之后,可能会跟随着任意数目的大写和小写字母和空格,并且匹配:

[me@linuxbox ~]$ echo "This works." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
This works.
[me@linuxbox ~]$ echo "This Works." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
This Works.
[me@linuxbox ~]$ echo "this does not" | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
[me@linuxbox ~]$

这个表达式匹配前两个测试语句,但不匹配第三个,因为第三个句子缺少开头的大写字母和末尾的句号。

20.12.1 + - 匹配一个或多个元素

+ 元字符的作用与 * 非常相似,除了它要求前面的元素至少出现一次匹配。这个正则表达式只匹配那些由一个或多个字母字符组构成的文本行,字母字符之间由单个空格分开:

^([[:alpha:]]+ ?)+$
[me@linuxbox ~]$ echo "This that" | grep -E '^([[:alpha:]]+ ?)+$'
This that
[me@linuxbox ~]$ echo "a b c" | grep -E '^([[:alpha:]]+ ?)+$'
a b c
[me@linuxbox ~]$ echo "a b 9" | grep -E '^([[:alpha:]]+ ?)+$'
[me@linuxbox ~]$ echo "abc  d" | grep -E '^([[:alpha:]]+ ?)+$'
[me@linuxbox ~]$

我们看到这个正则表达式不匹配“a b 9”这一行,因为它包含了一个非字母的字符;它也不匹配 “abc d” ,因为在字符“c”和“d”之间不止一个空格。

20.12.2 { } - 匹配特定个数的元素

{ 和 } 元字符都被用来表达要求匹配的最小和最大数目。它们可以通过四种方法来指定:

表20-3: 指定匹配的数目
限定符 意思
{n} 匹配前面的元素,如果它确切地出现了 n 次。
{n,m} 匹配前面的元素,如果它至少出现了 n 次,但是不多于 m 次。
{n,} 匹配前面的元素,如果它出现了 n 次或多于 n 次。
{,m} 匹配前面的元素,如果它出现的次数不多于 m 次。

回到之前处理电话号码的例子,我们能够使用这种指定重复次数的方法来简化我们最初的正则表达式:

^\(?[0-9][0-9][0-9]\)?  [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$

简化为:

^\(?[0-9]{3}\)?  [0-9]{3}-[0-9]{4}$

让我们试一下:

[me@linuxbox ~]$ echo "(555) 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
(555) 123-4567
[me@linuxbox ~]$ echo "555 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
555 123-4567
[me@linuxbox ~]$ echo "5555 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
[me@linuxbox ~]$

我们可以看到,修改后的表达式能成功地匹配带有和不带有圆括号的号码,而不匹配那些格式不正确的号码。

20.13 让正则表达式工作起来

让我们看看一些我们已经知道的命令,然后看一下它们怎样使用正则表达式。

20.13.1 通过 grep 命令来验证一个电话簿

在我们先前的例子中,我们查看过单个电话号码,并且检查了它们的格式。一个更现实的情形是检查一个数字列表,所以我们先创建一个列表。我们将念一个神奇的咒语到命令行中。它会很神奇,因为我们还没有涵盖所涉及的大部分命令,但是不要担心。我们将在后面的章节里面讨论那些命令。这就是那个咒语:

[me@linuxbox ~]$ for i in {1..10}; do echo "(${RANDOM:0:3}) ${RANDOM:0:3}-${RANDOM:0:4}" >> phonelist.txt; done

这个命令会创建一个包含10个电话号码的名为 phonelist.txt 的文件。每次重复这个命令的时候,另外10个号码会被添加到这个列表中。我们也能够更改命令开头附近的数值10,来生成或多或少的电话号码。如果我们查看这个文件的内容,然而我们会发现一个问题:

[me@linuxbox ~]$ cat phonelist.txt
(232) 298-2265
(624) 381-1078
(540) 126-1980
(874) 163-2885
(286) 254-2860
(292) 108-518
(129) 44-1379
(458) 273-1642
(686) 299-8268
(198) 307-2440

一些号码是残缺不全的,这正是我们想要的,因为我们将使用 grep 命令来验证电话号码的正确性。

一个有用的验证方法是扫描这个文件,查找无效的号码,并把搜索结果显示到屏幕上:

[me@linuxbox ~]$ grep -Ev '^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$'    phonelist.txt
(292) 108-518
(129) 44-1379
[me@linuxbox ~]$

这里我们使用-v 选项来产生相反的匹配,因此我们将只输出不匹配指定表达式的文本行。这个表达式自身的两端都包含定位点(锚)元字符,是为了确保这个号码的两端没有多余的字符。这个表达式也要求圆括号出现在一个有效的号码中,不同于我们先前电话号码的实例。

20.13.2 用 find 查找丑陋的文件名

这个 find 命令支持一个基于正则表达式的测试。当在使用正则表达式方面比较 find 和 grep 命令的时候,还有一个重要问题要牢记在心。当某一行包含的字符串匹配上了一个表达式的时候,grep 命令会打印出这一行,然而 find 命令要求路径名精确地匹配这个正则表达式。在下面的例子里面,我们将使用带有一个正则表达式的 find 命令,来查找每个路径名,其包含的任意字符都不是以下字符集中的一员。

[-\_./0-9a-zA-Z]

这样一种扫描会发现包含空格和其它潜在不规范字符的路径名:

[me@linuxbox ~]$ find . -regex '.*[^-\_./0-9a-zA-Z].*'

由于要精确地匹配整个路径名,所以我们在表达式的两端使用了.*,来匹配零个或多个字符。在表达式中间,我们使用了否定的中括号表达式,其包含了我们一系列可接受的路径名字符。

20.13.3 用 locate 查找文件

这个 locate 程序支持基本的(--regexp 选项)和扩展的(--regex 选项)正则表达式。通过locate 命令,我们能够执行许多与先前操作 dirlist 文件时相同的操作:

[me@linuxbox ~]$ locate --regex 'bin/(bz|gz|zip)'
/bin/bzcat
/bin/bzcmp
/bin/bzdiff
/bin/bzegrep
/bin/bzexe
/bin/bzfgrep
/bin/bzgrep
/bin/bzip2
/bin/bzip2recover
/bin/bzless
/bin/bzmore
/bin/gzexe
/bin/gzip
/usr/bin/zip
/usr/bin/zipcloak
/usr/bin/zipgrep
/usr/bin/zipinfo
/usr/bin/zipnote
/usr/bin/zipsplit

通过使用 alternation,我们搜索包含 bin/bz,bin/gz,或/bin/zip 字符串的路径名。

20.13.4 在 less 和 vim 中查找文本

less 和 vim 两者享有相同的文本查找方法。按下/按键,然后输入正则表达式,来执行搜索任务。如果我们使用 less 程序来浏览我们的 phonelist.txt 文件:

[me@linuxbox ~]$ less phonelist.txt

然后查找我们有效的表达式:

(232) 298-2265
(624) 381-1078
(540) 126-1980
(874) 163-2885
(286) 254-2860
(292) 108-518
(129) 44-1379
(458) 273-1642
(686) 299-8268
(198) 307-2440
~
~
~
/^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$

less 将会高亮匹配到的字符串,这样就很容易看到无效的电话号码:

(232) 298-2265
(624) 381-1078
(540) 126-1980
(874) 163-2885
(286) 254-2860
(292) 108-518
(129) 44-1379
(458) 273-1642
(686) 299-8268
(198) 307-2440
~
~
~
(END)

另一方面,vim 支持基本的正则表达式,所以我们用于搜索的表达式看起来像这样:

/([0-9]\{3\}) [0-9]\{3\}-[0-9]\{4\}

我们看到表达式几乎一样;然而,在扩展表达式中,许多被认为是元字符的字符在基本的表达式中被看作是文本字符。只有用反斜杠把它们转义之后,它们才被看作是元字符。

依赖于系统中 vim 的特殊配置,匹配项将会被高亮。如若不是,试试这个命令模式:

:hlsearch

来激活搜索高亮功能。


注意:依赖于你的发行版,vim 有可能支持或不支持文本搜索高亮功能。尤其是 Ubuntu 自带了一款非常简化的 vim 版本。在这样的系统中,你可能要使用你的软件包管理器来安装一个功能更完备的 vim 版本。


20.14 总结归纳

在这章中,我们已经看到几个使用正则表达式例子。如果我们使用正则表达式来搜索那些使用正则表达式的应用程序,我们可以找到更多的使用实例。通过查找手册页,我们就能找到:

[me@linuxbox ~]$ cd /usr/share/man/man1
[me@linuxbox man1]$ zgrep -El 'regex|regular expression' *.gz

这个 zgrep 程序是 grep 的前端,允许 grep 来读取压缩文件。在我们的例子中,我们在手册文件所在的目录中,搜索压缩文件中的内容。这个命令的结果是一个包含字符串“regex”或者“regular expression”的文件列表。正如我们所看到的,正则表达式会出现在大量程序中。

基本正则表达式中有一个特性,我们没有涵盖。叫做反引用,这个特性在下一章中会被讨论到。

更新于 2022年10月2日
第19章:归档和备份第21章:文本处理

发表评论 取消回复

您需要登录后才可以发表评论...
登录... 后才能评论
文章目录
  • 20.1 grep
  • 20.2 元字符和原义字符(Metacharacters And Literals)
  • 20.3 任何字符
  • 20.4 锚点
  • 20.5 中括号表达式和字符类
  • 20.6 否定
  • 20.7 传统的字符区域
  • 20.8 POSIX 字符集
  • 20.9 POSIX基本正则表达式 与 POSIX扩展正则表达式
  • 20.10 交替
  • 20.11 限定符
    • 20.11.1 ? - 匹配零个或一个元素
  • 20.12 * - 匹配零个或多个元素
    • 20.12.1 + - 匹配一个或多个元素
    • 20.12.2 { } - 匹配特定个数的元素
  • 20.13 让正则表达式工作起来
    • 20.13.1 通过 grep 命令来验证一个电话簿
    • 20.13.2 用 find 查找丑陋的文件名
    • 20.13.3 用 locate 查找文件
    • 20.13.4 在 less 和 vim 中查找文本
  • 20.14 总结归纳

Copyright © 2015-2023 开源之家

  • 首页
  • 每日签到
  • 加入VIP
  • 顶部
AI&大数据 Java Java Linux Linux Python 前端 办公软件 办公软件 培训视频 娱乐休闲 小程序开发 数据库 系统相关 网络 英语 设计创意 软件测试