正则表达式
学习三剑客之前我们首先要了解正则表达式,有了它能让你更强大。正则表达式在每种语言中都会有,功能就是匹配符合你预期要求的字符串。
符号 | 说明 | 示例 |
---|---|---|
. | 匹配除换行符(\n)之外的任意单个字符 | 匹配123:echo -e “123\n456” | grep ‘1.3’ |
^ | 匹配以字符串开头 | 匹配以abc开头的:echo -e “adb\nabcd” | grep ^abc |
$ | 匹配以字符串结尾 | 匹配以adb结尾的:echo -e “adb\nabcd” | grep bcd$ |
* | 匹配前一个字符0个或多个 | 匹配 x、xo 和 xoo:echo -e “x\nxo\nxoo\no\noo” | grep "xo*"x 是必须的,批量了 0 个或多个 |
+ | 匹配前面字符一个或多个 | 匹配 abc 和 abcc:echo -e “abc\nabcc\nadd” |grep -E 'ab+' 匹配单个数字:echo “113” |grep -o '[0-9]' 连续匹配多个数字:echo “113” |grep -E -o ‘[0-9]+’ |
? | 匹配前面字符0个或一个 | 匹配abc或bcd:echo -e “ac\nabc\nad\nbcd” | grep -E ‘bc?’ |
[] | 匹配括号中任意一个字符 | 匹配bch:echo -e “ab\ncd\nef\nhg\nlk” | grep -o ‘[bch]’ |
[ - ] | 匹配括号中范围的任意一个字符 | 匹配所有字母: echo -e “ab\ncd\nef” | grep -o ‘[a-z]’ |
[^] | 匹配除括号中的字符之外的任意一个字符 | 匹配除m、n、o之外的字符:echo -e “and\nor\nnot” | grep -o '[^m-o]' 匹配末尾数字:echo “abc:cde;123” | grep -E ‘[^;]+$’ |
^[^] | 匹配不是中括号之内任意一个字符开头的行 | 匹配非s开头的:echo -e “sho\nkst\nabc\ntest” | grep ‘^[^s]’ |
{n}或{n,} | 匹配花括号前面的字符至少n个字符 | 匹配任意至少2个字符以上的字符串:echo -e “a\nac\nadc\nnc” | grep -E ‘[a-z]{2}’ |
{n,m} | 匹配花括号前面至少n个字符,最多m个字符 | 匹配任意至少2个字符以上的字符串:echo -e “a\nac\nadc\nnc” | grep -E -w -o ‘[a-z]{1,2}’ |
\< | 边界符,匹配字符串开始 | 匹配以123开始的:echo -e “1\n\12\n123\n1234” | grep ‘<123’ |
\> | 边界符,匹配字符串结束 | 匹配以4结束的:echo -e “1\n\12\n123\n1234” | grep ‘4>’ |
() | 单元或组合:将小括号里面作为一个组合 分组:匹配小括号中正则表达式或字符。\n反向引用,n是数字,从1开始编号,表示引用第n个分组匹配的内容 | 单元:匹配123a字符串 echo “123abc” | grep -E -o '([0-9a-z]){4}' 分组:匹配11 echo “113abc” \I grep -E -o '(1)\1’ 匹配xo出现0次或多次: echo -e “x\n\xo\nxoo\no\noo” | egrep “(xo)*” |
| | 匹配竖杠两边的任意一个 | 匹配12和123: echo -e “1\n\12\n123\n1234” | grep -E ‘12>| 123>’ |
\ | 转义符,将特殊符号转成原有意义 | 1.2匹配1.2 : echo -e “1.2\n112” | grep -E ‘1\.2’ 否则112也会匹配到 |
grep
grep是global search regular expression and print out the line的缩写,意思是全面搜索正则表达式并把行打印出来,是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
常用参数
参数 | 说明 |
---|---|
-a 或 --text | 不要忽略二进制的数据。 |
-A<显示行数> | 除了显示符合样本的那行,并显示之后的N行 |
-B<显示行数> | 除了显示符合样本的那行,并显示之前的N行 |
-b 或 --byte-offset | 在显示符合样式的那行之前,标示出该行第一个字符的编号 |
-c 或 --count | 计算符合样式的列数 |
-C 或 --context=<显示行数> 或-<显示行数> | 除了显示符合样式的那行,并显示该行前后的内容 |
-d 或 --directories=<动作> | 当指定要查找的是目录而非文件时,必须使用这项参数,否则 grep 命令将回报信息并停止动作 |
-e <范本样式> 或 --regexp=<范本样式> | 指定字符串作为查找文件内容的样式 |
-E 或 --extend-regexp | 将样式为延伸的普通表示法来使用 |
-f <规则文件> 或 --file=<规则文件> | 指定规则文件,其内容含有一个或多个规则样式,让 grep 查找符合规则条件的文件内容,格式为每行一个规则样式 |
-F 或 --fixed-regexp | 将样式视为固定字符串的列表 |
-G 或 --basic-regexp | 将样式视为普通的表示法来使用 |
-h 或 --no-filename | 在显示符合样式的那行之前,不标示该行所属的文件名称 |
-H 或 --with-filename | 在显示符合样式的那行之前,标示该行所属的文件名称 |
-i 或–ignore-case | 忽略字符大小写的差别 |
-l 或 --file-with-matches | 列出文件内容符合指定的样式的文件名称 |
-L 或 --files-without-match | 列出文件内容不符合指定的样式的文件名称 |
-n 或 --line-number | 在显示符合样式的那行之前,标示出该行的列数编号 |
-o 或 --only-matching | 只显示匹配PATTERN部分 |
-q 或 --quiet 或 --silent | 不显示任何信息 |
-r 或 --recursive | 此参数的效果和指定 “-d recurse” 参数相同 |
-s 或 --no-messages | 不显示错误信息 |
-v 或 --revert-match | 显示不包含匹配文本的所有行 |
-V 或 --version | 显示版本信息 |
-w 或 --word-regexp | 只显示全字符合的列 |
-x 或 --line-regexp | 只显示全列符合的列 |
-y | 此参数的效果和指定 “-i” 参数相同 |
语法
grep [-abcEFGhHilLnqrsvVwxy][-A<显示列数>][-B<显示列数>][-C<显示列数>][-d<进行动作>][-e<范本样式>][-f<范本文件>][--help][范本样式][文件或目录...]
实例
我们新建个文件,内容如下
# 文件名称为lucky.sh
list=$(while read line; do echo ${line}; done<10.wx)
count=0;
index=0;
while ((count!=1))
do
((index+=1));
temp=$list
list=$(for i in $list;do ((RANDOM%2==1)) && echo $i; done);
echo;
cout=$(echo "$list" | wc -w);
if [ $cout -eq 0 ]
then
while ((cout==0))
do
echo "此次抽奖结果为空,继续抽奖!"
list=$(for i in $temp;do ((RANDOM%2==1)) && echo $i; done );
cout=$(echo "$list" | wc -w);
echo The $index times:$list;
done
else
echo The $index times:$list;
fi
count=$(echo "$list" | wc -l);
DONE
假设我们想从文件中搜索包含done字符串的行,可以使用如下命令:
grep done lucky.sh
# 输出显示为
list=$(while read line; do echo ${line}; done<10.wx)
list=$(for i in $list;do ((RANDOM%2==1)) && echo $i; done);
list=$(for i in $temp;do ((RANDOM%2==1)) && echo $i; done );
done
发现最后一行大写的DONE没有被打印出来,这是因为grep是默认区分大小写的,如果想要在搜索时不区分大小写,使用 -i 即可,如下:
grep -i done lucky.sh
如果我们想要知道包含 done 是哪些行,可以用如下命令:
grep -i -n done lucky.sh
或
grep -in done lucky.sh
# 输出结果为
1:list=$(while read line; do echo ${line}; done<10.wx)
8: list=$(for i in $list;do ((RANDOM%2==1)) && echo $i; done);
16: list=$(for i in $temp;do ((RANDOM%2==1)) && echo $i; done );
19: done
25:DONE
想知道总共有多少行符合,需要使用 -c,如下:
grep -c done lucky.sh
# 输出为
5
PS:此时如果和 -i 一起使用是不会打印出所有行的,只会统计行数。
如果只想展示搜索内容时,使用参数-o,使用方法如下:
grep -o done lucky.sh
# 输出结果如下
done
done
done
done
如果想显示样式之后的几行,需要用 -A 行数;显示之前的行数,需要用 -B 行数;显示前后的行数,需要用 -C 行数;如果想要精确匹配,需要使用参数-w,如下:
-------------------------------------------
# 新建文件testgrep
hello test
hellotest
nello
Hello test
HELLOtest
www.hellotest.com
123hello
hello456test
time456
---------------------------------------------
# 模糊匹配
grep hello testgrep
# 输出结果为
hello test
hellotest
www.hellotest.com
123hello
hello456test
---------------------------------------------
# 精确匹配
grep -w hello testgrep
# 输出结果为
hello test
PS:我们会发现只有上搜索样式作为独立的单词才会被匹配到。
如果要反向匹配,需要使用参数-v,如下:
grep -v hello testgrep
# 输出结果为
Hello test
HELLOtest
如果想要根据多个字符串匹配,需要使用-e,如下
grep -e 123 -e time testgrep
# 输出结果为
123hello
time456
PS:通过实例我们发现,只要匹配到一个条件的就会打印。
如果你只是想用grep判断文本中是否存在某个字符串,你只关心有没有匹配到,而不关心匹配内容,这时我们可以使用-q进行静默匹配,需要配合“echo $?”使用,实例如下:
grep -q hello testgrep
echo $?
# 输出结果为
0 表示匹配到了 / 1 表示没有匹配到
匹配所有IP
ifconfig | grep -E -o "[0-9]{1-3}\.[0-9]{1-3}\.[0-9]{1-3}\.[0-9]{1-3}"
--------------------------------敲黑板,重点来了--------------------------------
利用 [ ] 搜索集合字符,[ ] 表示其中的一个字符,例如
grep '[aci]' testgrep
# 输出结果为
www.hellotest.com
time456
如果想要查找除 [] 内之外的字符,可以用 [^ 字符],比如匹配非n开头包含e的字符串,例如
grep -n [^n]e testgrep
# 输出结果为
1:hello test
3:hellotest
4:Hello test
6:www.hellotest.com
7:123hello
8:hello456test
[] 还可以用范围表示,如[0-9]表示0~9的数字,[a-z]表示26个字母,[0-9a-z]表示任意数字字母
awk
awk是一种处理文本文件的语言,能用简短的程序处理标准输入或文件、数据排序、计算以及生成报表等等。
参数
参数 | 说明 |
---|---|
-F fs | 指定fs为输入字段的分隔符 |
-f file | 从文件中读取awk程序源文件 |
-v var=value | 变量赋值 |
–posix | 兼容posix正则表达式 |
–dump-variables=[file] | 把 awk 命令时的全局变量写入文件,默认文件是 awkvars.out |
–profile=[file] | 格式化 awk 语句到文件,默认是 awkprof.out |
模式 | 描述 |
---|---|
BEGIN{} | 给程序赋予初始状态,先执行的工作 |
END{} | 程序结束之后执行的一些扫尾工作 |
/regular expression/ | 为每个输入记录匹配正则表达式 |
pattern && pattern | 逻辑与,满足两个模式 |
pattern || pattern | 逻辑o或,满足其中一个 |
! pattern | 逻辑非,不满足模式 |
pattern1, pattern2 | 范围模式,匹配所有模式1的记录,知道匹配到模式2 |
$0 | 表示一整行数据 |
$n | 表示第n列 |
NF | 每一行拥有的字段总数 |
NR | 目前处理的是第几行数据 |
FS | 分隔符 |
实例
# 新建文本 awk.txt
1 hello welcome to awk
3 sdf sldkjk slkdj jklkl lkj
6 skd wer lx sdf sada
8 sdfa afg
2 sdflk
4 sdflkak sldkjflk iualj sada
打印第二列和第五列的数据
awk '{print $2,$5}' awk.txt
# 输出
hello awk
sdf jklkl
skd sdf
sdfa
sdflk
sdflkak sada
打印行数内容及行数、行字段总数
awk '{print "该行数据为" $0 "\t" "该行的字段总数为" NF "\t" "目前这是第几行" NR }' awk.txt
# 输出
该行数据为1 hello welcome to awk 该行的字段总数为5 目前这是第几行1
该行数据为3 sdf sldkjk slkdj jklkl lkj 该行的字段总数为6 目前这是第几行2
该行数据为6 skd wer lx sdf sada 该行的字段总数为6 目前这是第几行3
该行数据为8 sdfa afg 该行的字段总数为3 目前这是第几行4
该行数据为2 sdflk 该行的字段总数为2 目前这是第几行5
该行数据为4 sdflkak sldkjflk iualj sada 该行的字段总数为5 目前这是第几行6
设置变量
awk -v a=2 '{print $1,$1+a}' awk.txt
# 输出
1 3
3 5
6 8
8 10
2 4
4 6
打印奇数行第二列
awk 'NR % 2 == 1 {print "行数为" NR "\t" $2} ' awk.txt
# 输出
行数为1 hello
行数为3 skd
行数为5 sdflk
使用条件语句打印第二行之后的数据
awk '{if(NR>1) print $2}' awk.txt
# 输出
sdf
skd
sdfa
sdflk
sdflkak
sed
sed是一种流编辑器,用来过滤和替换文本。
参数
参数 | 说明 |
---|---|
a | 新增,a的后面可以接字符串,而这些字符串在新的一行出现(当前行的下一行) |
d | 删除选择的行 |
-e<script> | 以选项中指定的script来处理输入的文本文件 |
-f<script> | 以选项中指定的script来处理输入的文本文件 |
g | 全局替换标志。默认情况下,sed 命令替换每一行第一次出现的模式,它不会替换行中的其他的匹配结果。但是,提供了该替换标志时,所有匹配都将被替换。 |
-h | 显示帮助 |
i | 插入,i的后面可以接字符串,而这些字符串会在新的一行出现(当前行的上一行) |
-n或–quiet或–silent | 仅显示script处理后的结果 |
s | 替换指定字符,通常与正则联用 |
-V | 显示版本信息 |
实例
# 新建样本 sed.txt
This is my cat
my cat's name is betty
This is my dog
my dog's name is frank
This is my fish
my fish's name is george
This is my goat
my goat's name is adam
- 插入
sed -i "3i\test123" sed.txt
# 输出为
This is my cat
my cat's name is betty
test123
This is my dog
my dog's name is frank
This is my fish
my fish's name is george
This is my goat
my goat's name is adam
- 新增
sed -i "3a\test456" sed.txt
# 输出为
This is my cat
my cat's name is betty
test123
test456
This is my dog
my dog's name is frank
This is my fish
my fish's name is george
This is my goat
my goat's name is adam
- 替换
sed "s/my/hogward's/g" sed.txt
# 输出结果为
This is hogward's cat
hogward's cat's name is betty
This is hogward's dog
hogward's dog's name is frank
This is hogward's fish
hogward's fish's name is george
This is hogward's goat
hogward's goat's name is adam
- 输出
# 输出文件所有内容
sed -n '1,$p' /etc/hosts
# 将每行内容放到一行上进行展示,每行内容以逗号进行分隔。
sed ':t;N;s/\n/,/;b t' /etc/hosts
# 输出第二行到第四行之间三行的内容
sed -n "2,4p" /etc/hosts
- 删除
sed '/test123/d' sed.txt
# 输出为
This is my cat
my cat's name is betty
test456
This is my dog
my dog's name is frank
This is my fish
my fish's name is george
This is my goat
my goat's name is adam