目录
一、正则表达式
1.1 正则表达式
1.2 基本正则表达式元字符
1.2.1 字符匹配
1.2.2 次数匹配
1.2.3 位置锚定
1.2.4 分组
1.2.5 逻辑或\|
1.2.6 非打印字符
1.3 扩展正则表达式
1.3.1 字符匹配
1.3.2 次数匹配
1.3.3 位置锚定
二、文本三剑客
2.1 grep
2.2 sed
2.3 awk
2.3.1 awk内置变量
2.3.2 BEGIN/END 模式
2.3.3 条件判断 if-else
2.3.4 关联数组
三、其他文本处理工具
3.1 cut
3.2 tr
3.3 sort
3.4 uniq
REGEXP(Regular Expressions)由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能,但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容。
正则表达式分为两类:
基本正则表达式
扩展正则表达式
. 匹配任意单个字符,可以是一个汉字
[] 匹配指定范围内的任意单个字符,示例:[abcd] [0-9] [a-z] [a-zA-Z]
[^] 匹配指定范围外的任意单个字符,即取反。注意 ^ 在括号内,在括号外代表行首,示例:[^abcd]
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
ls | grep "[^a.z]".txt 表示匹配的不是a或z的全部字符
* 匹配前面的字符任意次,包括 0 次
.* 任意长度的任意字符
\? 匹配其前面的字符 0 或 1 次,即:可有可无
\+ 匹配其前面的字符至少 1 次,即:>=1
\{n\} 匹配前面的字符 n 次
\{m,n\} 匹配前面的字符至少 m 次,至多 n 次
\{,n\} 匹配前面的字符至多 n 次,<=n
\{n,\} 匹配前面的字符至少 n 次
^ 行首锚定,用于模式的最左侧
$ 行尾锚定,用于模式的最右侧
^$ 空行
^[[:space:]]*$ 空行或包含空白字符的行
^PATTERN$ 用于模式匹配整行
\< 或 \b 匹配单词边界,表示锚定词首,其后面的字符必须作为单词首部出现
\> 或 \b 匹配单词边界,表示锚定词尾,其前面的字符必须作为单词尾部出现
\ 匹配整个单词
#查看 /etc/profile 文件内容,排除 # 开头的行和空白行
cat /etc/profile | grep -v "^#" | grep -v "^$"
grep -v "^$" /etc/profile | grep -v "^#"
() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
向后引用
分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为: \1, \2, \3,...
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
注: 后向引用引用前面的分组括号中的模式所匹配字符,而非模式本身
\n 匹配一个换行符
\r 匹配一个回车符
\t 匹配一个制表符
. 任意单个字符
[abc...] 指定范围的字符
[^abc...] 不在指定范围的字符
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:] 十六进制数字
[:graph:] 可打印的非空白字符
* 匹配前面字符任意次
? 0 或 1 次
+ 1 次或多次
{n} 匹配 n 次
{m,n} 至少 m,至多 n 次
{m,} 至少 m 次
{,n} 至多 n 次
^ 行首
$ 行尾
\< 或 \b 语首,从匹配正则表达式的行开始
\> 或 \b 语尾,到匹配正则表达式的行结束
作用:文本搜索工具,根据用户指定的 “模式” 对目标文本逐行进行匹配检查,打印匹配到的行。
格式:
grep [选项] [匹配模式] [文件]
常用命令选项:
-m 匹配指定次数后停止
-v 显示不被模式匹配到的行,取反
-i 忽略字符大小写
-n 显示行号
-c 统计匹配的行数
-o 仅显示匹配到的字符串
-q 静默模式,不输出任何信息
-e 实现多个选项间的逻辑 or 关系,如:grep -e "cat" -e "dog" file
-w 匹配整个单词
-E 使用扩展正则表达式,相当于 egrep
-F 不支持正则表达式,相当于 fgrep
-r 递归目录,但不处理软链接
-R 递归目录,但处理软链接
-f file 根据模式文件处理
-A n after, 后 n 行
-B n before, 前 n 行
-C n context, 前后各 n 行
示例:
#查询 /etc/passwd 文件中有 root 的行
[root@localhost opt]#grep "root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
#查看 /etc/profile 文件内容,排除 # 开头的行和空白行
[root@localhost opt]#grep -v "^$" /etc/profile | grep -v "^#"
pathmunge () {
case ":${PATH}:" in
*:"$1":*)
............
#使用扩展正则表达式实现,排除 # 开头的行和空白行
[root@localhost opt]#grep -Ev "^(#|$)" /etc/profile
#查看指定的主机磁盘使用率
[root@localhost opt]#df -h | grep "^/dev/sd*" | awk '{print $1,$5}'
/dev/sda2 11%
/dev/sda5 1%
/dev/sda1 18%
/dev/sr0 100%
#查看与本机建立连接的 IP 前三个
[root@localhost opt]#ss -nt | grep "^ESTAB" | tr -s ' ' : | cut -d: -f4 | sort | uniq -c | sort -nr | head -n3
1 192.168.10.20
#只显示模式匹配到的内容
[root@localhost opt]#grep -o 'r..t' /etc/passwd
root
root
root
root
r/ft
#显示当 IP
[root@localhost opt]#ifconfig ens33 | grep -Eo '([0-9]{1,3}\.){3}([0-9]{1,3})' | head -1
192.168.50.22
#多个模式条件匹配
[root@localhost opt]#grep -e "root" -e "/bin/bash" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
syhj:x:1000:1000:syhj:/home/syhj:/bin/bash
#位置锚定,匹配行首和行尾单词相同的行
[root@localhost opt]#grep "^\(.*\)\>.*\<\1$" /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
#扩展正则表达式实现,匹配行首和行尾单词相同的行
[root@localhost opt]#grep -E "^(.*)\>.*\<\1$" /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
#算出所有人年龄总和
[root@localhost opt]#cat /data/nianling.txt
xiaoming=20
xiaohong=18
xiaoqiang=22
[root@localhost opt]#cut -d"=" -f2 /data/nianling.txt|tr '\n' + | grep -Eo ".*[0-9]"|bc
60
[root@localhost opt]#grep -Eo "[0-9]+" /data/nianling.txt | tr '\n' + | grep -Eo ".*[0-9]"|bc
60
工作原理:
读取:sed 从输入流(文件、管道、标准输入)中读取一行内容并存储到临时的缓冲区中(又称模式空间,pattern space)
执行:默认情况下,所有的 sed 命令都在模式空间中顺序地执行,除非指定行的地址,否则 sed 命令将会在所有的行上依次执行
显示:发送修改后的内容到输出流。在发送数据后,模式空间将会被清空。
基本用法:
sed [命令选项] '操作1;操作2......' [文件]
sed [命令选项] -f scriptfile [文件]
常用命令选项:
-e 多点编辑,多个匹配模式组合
-f 表示用指定的脚本文件来读取操作命令
-n 表示仅显示处理后的结果
-i 直接编辑文本文件
操作符:
a 增加,在当前行下面增加一行指定内容,支持使用 \n 实现多行追加
i 插入,在选定行上面插入一行指定内容
c 替换,将选定行替换为指定内容
d 删除,删除选定的行
H 复制到剪贴板
w /PATH/file 保存模式匹配的行至指定文件
r /PATH/file 读取指定文件的文本至模式空间中匹配到的行后
p 打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以 ASCII 码输出。其通常与 "-n" 选项一起使用
Ip 忽略大小写输出
y 字符转换,和 s 用法类似,但只能替换大小写
= 为模式空间中的行打印行号
! 模式空间中匹配行取反处理
s 替换,替换指定字符,格式 s/pattern/string/修饰符
g 行内全局替换
p 显示替换成功的行
I/i 忽略大小写
w /PATH/FILE 将替换成功的行保存至文件中
示例:
#备份 seq.log 为 seq.log.bak,并编辑 seq.log 文件
sed -i.bak '2d;4d' seq.log
#删除空行
sed -i '/^$/d' test.log
#替换每行第二个 o 为 O
sed -i 's/o/O/2' test.log
#每行插入 # 号
sed -i 's/^/#/' test.log
#将匹配到的 the 每行开头插入 #
sed -i '/the/s/^/#/' test.log
#每行的行尾添加 EOF
sed -i 's/$/EOF/' test.log
#替换 3 到 5 行所有 the
sed -i '3,5s/the/THE/g' test.log
#关闭 selinux,-i 直接编辑文件,不输出信息到屏幕
sed -i 's/enforcing/disabled/g' /etc/selinux/config && reboot
#删除所有以 # 开头的行
sed -i '/^#/d' test.log
#只显示非 # 开头的行
sed -n '/^#/!p' test.log
#查看本机 IP,-r 为使用扩展正则表达式
ifconfig ens33 | sed -nr "2s/[^0-9]+([0-9.]+).*/\1/p"
ifconfig ens33 | sed -nr '2s/^[^0-9]+([0-9.]+).*$/\1/p'
ifconfig ens33 | sed -n '2s/^.*inet //;s/ netmask.*//p'
#取基名
echo "/etc/sysconfig/network-scripts/" | sed -r 's#(^/.*/)([^/]+/?)#\2#'
#取目录名
echo "/etc/sysconfig/network-scripts/" | sed -r 's#(^/.*/)([^/]+/?)#\1#'
#将 # 开头的行删除 #
sed -ri.bak '/^#/s/^#//' test.log
#取分区利用率
df | sed -nr '/^\/dev\/sd/s# .* ([0-9]+)%.*# \1#p'
#提取 file 文件中包含 the 的行,存放在 other.file 文件中
sed '/the/w other.file' file
#读取 /etc/hostname 文件内容,将其添加到 file 文件中所有包含 the 的行后
sed '/the/r /etc/hostname' file
#在 file 文件的第三行后添加 NEW
sed '3aNEW' file
#在 file 文件结尾添加 NEW 行
sed '$aNEW' file
#在所有包含 the 的行后加 NEW
sed '/the/aNEW' file
#第三行后添加 NEW1 NEW2,\n 换行
sed '3aNEW1\nNEW2' file
# -f 调用脚本实现操作
sed -f script.list file
实验:pxe自动装机/无人值守
systemctl stop firewalld
setenforce 0
cd /etc/yum.repos.d
mount /dev/cdrom /mnt
if [ ! -e local.repo ]
then
mkdir repos.bak
mv *.repo repos.bak
echo '[local]
name=local
baseurl=file:///mnt
gpgcheck=0
enabled=1' > local.repo
fi
yum clean all && yum makecache
yum -y install tftp-server xinetd dhcp syslinux vsftpd
sed -i -e "10 s/yes/no/" -e "14 s/yes/no/" /etc/xinetd.d/tftp
systemctl start tftp
systemctl enable tftp
systemctl start xinetd
systemctl enable xinetd
cp /usr/share/doc/dhcp-4.2.5/dhcpd.conf.example /etc/dhcp/dhcpd.conf
sed -i -e "32 s/10.254.239.0/192.168.50.0/" -e "32 s/224/0/" /etc/dhcp/dhcpd.conf
sed -i -e "33 s/10.254.239.10/192.168.50.100/" -e "33 s/10.254.239.20/192.168.50.200/" /etc/dhcp/dhcpd.conf
sed -i "34c option routers 192.168.50.22;" /etc/dhcp/dhcpd.conf
sed -i "14 s/^#//" /etc/dhcp/dhcpd.conf
sed -i "14a next-server 192.168.50.22;" /etc/dhcp/dhcpd.conf
sed -i "15a filename \"pxelinux.0\";" /etc/dhcp/dhcpd.conf
systemctl start dhcpd
systemctl enable dhcpd
cp /mnt/images/pxeboot/vmlinuz /var/lib/tftpboot/
cp /mnt/images/pxeboot/initrd.img /var/lib/tftpboot/
cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/
mkdir /var/ftp/centos7
cp -rf /mnt/* /var/ftp/centos7/
systemctl start vsftpd
systemctl enable vsftpd
mkdir /var/lib/tftpboot/pxelinux.cfg
echo "default auto
prompt 0
label auto
kernel vmlinuz
append initrd=initrd.img method=ftp://192.168.50.22/centos7 ks=ftp://192.168.50.22/ks.cfg
label linux text
kernel vmlinuz
append text initrd=initrd.img method=ftp://192.168.50.22/centos7
label linux rescue
kernel vmlinuz
append rescue initrd=initrd.img method=ftp://192.168.50.22/centos7
" > /var/lib/tftpboot/pxelinux.cfg/default
yum -y install system-config-kickstart.noarch
echo '#platform=x86, AMD64, or Intel EM64T
#version=DEVEL
# Install OS instead of upgrade
install
# Keyboard layouts
keyboard 'us'
# Root password
rootpw --iscrypted $1$azNge1rF$GqkP/j9OnkIqecxdU78wT1
# Use network installation
url --url="ftp://192.168.50.22/centos7"
# System language
lang zh_CN
# Firewall configuration
firewall --disabled
# System authorization information
auth --useshadow --passalgo=sha512
# Use graphical install
graphical
firstboot --disable
# SELinux configuration
selinux --disabled
# Network information
network --bootproto=dhcp --device=ens33
# Reboot after installation
reboot
# System timezone
timezone Asia/Shanghai
# System bootloader configuration
bootloader --location=mbr
# Clear the Master Boot Record
zerombr
# Partition clearing information
clearpart --all --initlabel
# Disk partitioning information
part /boot --fstype="xfs" --size=500
part swap --fstype="swap" --size=4096
part / --fstype="xfs" --grow --size=1
%packages
@base
@core
@desktop-debugging
@dial-up
@directory-client
@fonts
@gnome-desktop
@guest-desktop-agents
@input-methods
@internet-browser
@java-platform
@multimedia
@network-file-system-client
@print-client
@x11
binutils
chrony
ftp
gcc
kernel-devel
kexec-tools
make
open-vm-tools
patch
python
%end' > /var/ftp/ks.cfg
awk 是一种处理文本文件的语言,是一个强大的文本分析工具。之所以叫 awk 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。
awk 工作原理参考:
Linux AWK 工作原理
格式:
awk [选项] '模式或条件{编辑指令}' 文件1 文件2 ......
awk -f [脚本文件] 文件1 文件2 ......
常用命令选项:
-F "分隔符" 指明输入时用到的字段分隔符
-f 指定调用脚本
-v var=value 变量赋值
awk -F: '{print}' /etc/passwd #默认 print $0
awk -F: '{print $1,$7}' /etc/passwd #以 : 为分隔符,打印第一列和第七列
awk -F: '{print $1"\t"$7}' /etc/passwd # \t 制表符,规范输出格式
grep "^UUID" /etc/fstab |awk '{print $2,$3}'
awk '{print $1}' /var/log/cups/access_log | sort | uniq -c | sort -nr | head
df -h | tr -s ' ' @ | awk -F@ '{print $4}' #查看磁盘可用容量
df | awk -F"[[:space:]]+|%" '{print $5}' #以多个空格或者 % 作为分隔符
$0 代表整行
$1 代表第一列
$2 代表第二列
......
NF 一行的列数
NR 总行数
FS 输入字段分隔符,默认为空白字符,功能相当于 -F
OFS 输出字段分隔符,默认为空白字符
RS 输入记录分隔符,指定输入时的换行符
ORS 输出记录分隔符,输出时用指定符号代替换行符
FNR 各文件分别计数,记录号
ARGC 命令行参数的个数
ARGV 数组,保存的是命令行所给定的各参数
FILENAME 当前文件名
# $0
awk '{print $0}' /etc/passwd
# $1,$2...
awk -F: '{print $1,$7}' /etc/passwd
# NF
awk -F: '{print NF}' /etc/passwd
ss -nt | grep "^ESTAB" | awk -F'[[:space:]]+|:' '{print $(NF-2)}'
# NR
awk -F: '{print NR}' /etc/passwd
cat /etc/passwd | awk 'NR==2{print}' #打印第二行
awk -F: 'NR==2{print $7}' /etc/passwd #打印第二行第七列
# FS
awk -v FS=':' '{print $1FS$3}' /etc/passwd
awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
# OFS
awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd
# RS
awk -v RS=' ' '{print}' /etc/passwd
# ORS
awk -v RS=' ' -v ORS='###' '{print $0}' /etc/passwd
# FNR
awk '{print NR,$0}' /etc/issue /etc/redhat-release
# ARGC
awk '{print ARGC}' /etc/issue /etc/redhat-release
awk 'BEGIN{print ARGC}' /etc/issue /etc/redhat-release
# ARGV
awk 'BEGIN{print ARGV[0]}' /etc/issue /etc/redhat-release
awk 'BEGIN{print ARGV[1]}' /etc/issue /etc/redhat-release
# FILENAME
awk '{print FILENAME}' /etc/fstab
awk '{print FNR,FILENAME,$0}' /etc/issue /etc/redhat-release
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
awk -F: 'BEGIN {print "USER USERID"} {print $1":"$3} END{print "END FILE"}' /etc/passwd
awk -F: '{print "USER USERID";print $1":"$3} END{print "END FILE"}' /etc/passwd
awk -F: 'BEGIN{print "USER UID \n--------------- "}{print $1,$3}' /etc/passwd
awk -F: 'BEGIN{print "USER UID \n------"} {print $1,$3} END{print "========"}' /etc/passwd
调用函数 getline,读取一行数据的时候并不是得到当前行而是当前行的下一行
df -h | awk 'BEGIN{getline}/root/{print $0}'
seq 10 | awk '{getline;print $0}' #显示偶数行
seq 10 | awk '{print $0;getline}' #显示奇数行
使用场景:对 awk 取得的整行或某个字段做条件判断
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else{statement3}
awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
awk '{if(NF>5) print $0}' /etc/fstab
df | awk -F"[[:space:]]+|%" '/^\/dev\/sd/{if($5>80)print $1,$5}'
df -h | awk -F% '/^\/dev\/sd/{print $1}' | awk '$NF>=80{print $1,$5}'
awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd
awk -F: '{if($3>=1000) printf "Common user: %s\n",$1; else printf "root or Sysuser: %s\n",$1}' /etc/passwd
awk 'BEGIN{ test=100;if(test>90){print "very good"} else if(test>60){ print "good"} else{print "no pass"}}'
awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
awk '!line[$0]++' file
awk '{!line[$0]++;print $0, line[$0]}' file
#判断数组索引是否存在
awk 'BEGIN{array["i"]="x"; array["j"]="y" ; print "i" in array, "y" in array }'
awk 'BEGIN{array["i"]="x"; array["j"]="y" ;if ("i" in array){print "存在"}else{print "不存在"}}'
awk 'BEGIN{array["i"]="x"; array["j"]="y" ;if ("abc" in array){print "存在"}else{print "不存在"}}'
列截取工具,cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。
如果不指定 File 参数,cut 命令将读取标准输入。必须指定 -b、-c 或 -f 标志之一
格式:
cut 选项 参数
或
cat 文件名 | cut 选项
常用选项:
-b 按字节截取
-c 按字符截取,常用于中文
-d 指定以什么为分隔符截取,默认为制表符
-f 通常和 -d 一起
cut -d ":" -f 1-5 --output--delimiter="#" /etc/passwd 以:为分隔符,将1-5列分隔符替换成#
tr 可以用一个字符来替换另一个字符,或者可以完全除去一些字符,也可以用它来除去重复字符,从标准输入中替换、缩减或删除字符,并将结果写到标准输出。
格式:
tr [选项] [格式] [文件或内容]
常用命令选项:
-d 删除字符
-s 删除所有重复出现的字符,只保留第一个
#转换大小写
[root@localhost ~]#cat fruit | tr 'a-z' 'A-Z'
#对 p 字符去重,只保留第一个
cat file | tr -s 'p'
#压缩多个空格为一个
df -h | tr -s ' '
#删除所有 a
cat file | tr -d 'a'
#删除换行符
cat file | tr -d '\n'
#遇到多个回车只保留一个回车,相当于去除空行
cat file | tr -s '\n'
是一个以行为单位对文件内容进行排序的工具,也可以根据不同的数据类型来排序。
格式:
sort [选项] 参数
常用命令选项:
-t 指定分隔符,默认使用 Tab 键或空格分隔
-k 指定排序区域,哪个区间排序
-n 按照数字进行排序,默认是以文字形式排序
-u 等同于 uniq,表示相同的数据仅显示一行,注意:如果行尾有空格去重就不成功
-R 随机排序
-r 反向排序,默认是升序,-r 就是降序
-o 将排序后的结果转存至指定文件
uniq 主要用于去除连续的重复行,通常和 sort 结合使用先排序使之变成连续的行再执行去重操作,否则不连续的重复行不能去重。
格式:
uniq [选项] 参数
sort file.txt | uniq -c
常用命令选项:
-c 对重复的行进行计数
-d 仅显示重复行
-u 仅显示不重复的行
#统计日志访问量最多的请求
cut -d" " -f1 /PATH/to/access_log |sort |uniq -c|sort -nr |head -3
lastb -f file | tr -s ' ' |cut -d ' ' -f3|sort |uniq -c|sort -nr | head -3
#并发连接最多的远程主机 IP
ss -nt|tail -n+2 |tr -s ' ' : |cut -d: -f6|sort|uniq -c|sort -nr |head -n2
#取两个文件的相同的行
cat test1.txt test2.txt | sort |uniq -d
#取文件的不同行
cat test1.txt test2.txt | sort |uniq -u
#统计重复行的次数,不连续的重复行不算做重复行
cat file | uniq -c
#查看登陆过系统的用户
last | awk '{print $1}' | sort | uniq | grep -v "^$" | grep -v wtmp