【Linux四剑客】find+grep+sed+awk
  O0fDkNCcKreB 2023年11月01日 62 0

find,grep,sed,awk

  • find:常用在目录下精确查找文件(最擅长找文件)
  • grep:常用来做全局数据的查询定位(最擅长文本过滤)
  • sed:常用来做行数据增删改查(最擅长取行)
  • awk:常用来做列数据切分与提取(最擅长取列)

1.find【擅长在目录下找文件】

find 命令用来在指定目录下查找文件

语法:find path -option

进阶:find path -option [-print][ -exec command] {} \;

注意:{} 表示查询的结果。

1.1 常用查询选项option

-name: 根据名称匹配

-iname: 忽略大小写

# 例如:查找当前目录下以log为结尾的文件:
$ find ./ -name '*log'

-user: 根据所属与的组进行查询

# 例如:查当前路径下,属于sichuan的文件:
$ find . -user sichuan

-type: 根据类型进行查找

  • f  文件        find ./ -type f
  • d  目录        find . -type d
  • c  字符设备文件    find . -type c
  • b  块设备文件     find . -type b
  • l   链接文件      find . -type l
  • p  管道文件      find . -type p
# 例如:查当前路径下所有文件
$ find ./ -type f

-size: 根据文件大小匹配

  • -n  小于 大小为 n 的文件
  • +n  大于 大小为 n 的文件
# 查找 /ect 目录下,小于 10000 字节的文件
$ find /etc -size -10000c
# 查找 /etc 目录下,大于 1M 的文件
$ find /etc -size +1M

-mindepth n: 从第 n 级目录开始搜索

# 从/etc 的第三级子目录开始搜索。
$ find /etc -mindepth 3 -name '*.conf'

-maxdepth n: 表示至多搜索到第 n-1 级子目录。

#在 /etc 中搜索符合条件的文件,但最多搜索到2级子目录。  
$ find /etc -type f -name '*.conf' -size +10k -maxdepthc 2

-regex: 基于正则表达式匹配文件路径

-iregex: 基于正则表达式匹配文件路径(忽略大小写)

# 匹配当前目录下,所有.txt和.pdf文件,用\转意
$ find ./ -regex ".*\(\.txt\|\.pdf\)$"

1.2 根据时间戳进行搜索

UNIX/Linux文件系统每个文件都有三种时间戳

  • 访问时间 (-atime/天,-amin/分钟):用户最近一次访问时间。
  • 修改时间 (-mtime/天,-mmin/分钟):文件最后一次修改时间。
  • 变化时间 (-ctime/天,-cmin/分钟):文件数据元(例如权限等)最后一次修改时间。

-mtime:根据文件更改时间查找,单位小时

  • -n   n 天以内修改的文件。
  • +n  n 天以外修改的文件。
  • n   正好 n天 修改的文件。 

-mmin: 根据文件更改时间查找,单位分钟 

  • -n  n 分钟以内修改过的文件
  • +n  n 分钟之前修改过的文件
# 查询 /etc 目录下30分钟之前修改过的文件。  
$ find /etc -mmin +30

# 查询 /etc 目录下30分钟之内修改过的目录。 
$ find /etc -mmin -30 -type d

# 查询 /etc 目录下,5天以内修改 且以 conf 结尾的文件
$ find /etc -mtime -5 -name '*.conf'

#查询 /etc 目录下,10天之前修改,且属于 sichuan的文件
find /etc -mtime +10 -user sichuan

1.3 对查找到的文件如何操作

-print: 打印输出。 默认的选项,即打印出找到的结果。

-exec: 对搜索到的文件执行特定的操作,固定的格式为:-exec 'commond' {} ; 注意:{} 表示查询的结果。

# 搜索 /etc 目录下的文件(非目录),文件以.conf结尾,且大于10k的文件 然后将其删除。
$ find /etc -type f -name '*.conf' -size +10k -exec rm -f {} \;

# 搜索条件同 例1 一样,但是不删除,只是将其复制到 /root/conf 目录下
$ find /etc -type f -name '*.conf' -size +10k -exec cp {} /root/conf/ \;

# 将 /data/log/ 目录下以.log 结尾的文件,且更改时间在 7 天以上的删除。
$ find /data/log -name '*.log' -mtime +7 -exec rm -f \;

-ok-exec 的功能一样,只是每次操作都会给用户提示。

逻辑运算符

-a:与 (默认情况查询条件之间都是 与 的关系)

-o:或

-not | ! 非

#或
$ find . \( -name "*.txt" -o -name "*.pdf" \)
$ find . -name "*.txt" -o -name "*.pdf"

#找出/home下不是以.txt结尾的文件
$ find /home ! -name "*.txt"

1.4 xargs

xargs: 可以将一个命令的输出作为参数发送给另一个命令。

🚩当前目录搜索所有文件,文件内容 包含 “aaa” 的内容

$ find ./ -type f -name "*" | xargs grep "aaa"
./a.txt:aaa
./b.txt:aaa

🚩统计代码行数

# 代码行数统计, grep -v '^$'过滤空白行  wc -l 
$ find ./ -name "*.java"|xargs cat|grep -v ^$|wc -l 

1.5 常用find命令

查找当前目录下所有.txt文件并把他们拼接起来写入到all.txt文件中

$ find ./ -type f -name "*.txt" -exec cat {} \;> ./all.txt

将30天前的.log文件移动到old目录中

$ find . -type f -mtime +30 -name "*.log" -exec cp {} old \;

找出当前目录下所有.txt文件并以“File:文件名”的形式打印出来

$ find . -type f -name "*.txt" -exec printf "File: %s\n" {} \;

因为单行命令中-exec参数中无法使用多个命令,以下方法可以实现在-exec之后接受多条命令

$ -exec ./text.sh {} \;

🚩要列出所有长度为零的文件

$ find . -empty

扩充:查找关键字出现的行数

Linux cat查看文件,查找关键字(grep),统计(wc -l)

#cat查找关键字出现的行数
语法:cat 文件 | grep 关键字 | wc -l
$cat /proc/meminfo |grep Swap | wc -l

Linux系统中的wc(Word Count)命令的功能为统计指定文件中的字节数、字数、行数,并将统计结果显示输出。
#1.命令格式:
wc [选项]文件...
#2.命令参数:
-c 统计字节数。
-l 统计行数。
-m 统计字符数。这个标志不能与 -c 标志一起使用。
-w 统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。
-L 打印最长行的长度。
-help 显示帮助信息
--version 显示版本信息

2.grep【擅长在文件中匹配文本】

grep命令 是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来(匹配的标红)

  • 语法:grep [option] pattern file

  • 简介:常用来做全局数据的查询定位(最擅长文本过滤)


命令参数:

  • -A<显示行数>:显示匹配行及后面n行内容
  • -B<显示行数>:显示匹配行及前面n行内容
  • -C<显示行数>:显示匹配行及前后n行内容
  • -c:统计匹配成功的行数
  • -e :实现多个选项间的逻辑or 关系 。或者使用egrep
    • $ egrep '^root|bash$' passwd
    • $ grep -e '^abc' -e 'b$' a.txt
  • -E:扩展的正则表达,相当于egrep
  • -f FILE:从FILE获取PATTERN匹配
  • -F :相当于fgrep
  • -l:列出文件内容符合指定的范本样式的文件名称。
  • -L:列出文件内容不符合指定的范本样式的文件名称
  • -i :字符忽略大小写
  • -n:显示匹配的行号
  • -o:仅显示匹配到的字符串
  • -q: 静默模式,不输出任何信息
  • -s:不显示错误信息。
  • -v:显示不被pattern 匹配到的行,相当于[^] 反向匹配
    • grep -v '^$' :命令的作用是过滤空白符 空白行:^$
  • -w :只匹配整个单词,而不是字符串的一部分(如匹配’magic’,而不是’magical’),
  • --color:匹配到的关键字会高亮显示
  • \< 和 \> 分别标注单词的开始与结尾。(类似模糊查询)
    • grep man * 会匹配 ‘Batman’、’manic’、’man’等
    • grep ‘\<man’ * 匹配’manic’和’man’,但不是’Batman’
    • grep ‘\<man\>’ 只匹配’man’,而不是’Batman’或’manic’等其他的字符串
    • 查询关键字高亮显示:grep xxx --color=auto

举例:

$cat test.txt 
aaa
bbbbb
AAAaaa
BBBBASDABBDA

#显示结果及后两行数据
$grep -A2 b test.txt
bbbbb
AAAaaa
BBBBASDABBDA

#统计行数
$grep -c aaa test.txt
$cat test.txt | grep -c aaa
2

#实现多个逻辑 or 或
$grep -e AAA -e bbb test.txt
bbbbb
AAAaaa

#忽略大小写并显示行号
$cat a.txt | grep -in bbb
2:<font color='red'>bbbbb</font>
4:BBBBASDABBDA

#仅显示匹配到的字符串
$grep -o ASDA test.txt
ASDA

#静默模式,不显示
$grep -q aa test.txt

#取反
$grep -v aaa test.txt
bbbbb
BBBBASDABBDA

#匹配整个单词
$grep -w aaa
aaa

#从file获取PATTERN匹配
$cat grep.txt
aaa
$grep -f grep.txt test
aaa
AAAaaa

# 使用-l选项,找出文件内容中包含first的文件名
$ grep -l "first" *.txt
1.txt

# 使用-L选项,找出文件内容中不包含first的文件名
$ grep -L "first" *.txt
2.txt
3.txt

# 以leo开头的行
$ grep '^leo' /etc/passwd

# 以bash结尾的行
$ grep 'bash$' /etc/passwd

# 我们尝试匹配bin这个“词”(只包含bin 比匹配sbin这样的)在正则表达式中,我们通常用尖括号表示一个“词”
$ grep '\<bin\>' /etc/passwd --color

2.1 grep,cat,管道符配合使用

$ cat test.txt |grep hello  # |管道符,将一个命令的输出作为另外一个命令的输

2.2 grep,ps,管道符配合使用

$ ps -ef|grep ssh|grep -v grep  #过滤ssh进程信息,并去除最后一行的grep信息

2.3 常用grep命令

查找xxx目录下所有文件带abc的行

$ grep abc /home/sichuan/lihewei/project/daquhua/getMd5Info/*
/home/sichuan/xxx/project/abc/a.txt:abc123
/home/sichuan/xxx/project/abc/b.txt:abcd123

检索日志,并显示该条日志的前后N(10)行记录,并显示行号(-n)

$ cat 日志文件 | grep -n -B10 -A10 "关键字"

3.sed【擅长取行】

sed 是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间” ,接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。

  • 简介:常用来做行数据增删改查(最擅长取行)

  • 格式:sed [option]... 'script' inputfile

  • 翻译:sed [选项] [脚本命令] 文件名

3.1 sed 格式说明

格式:sed [option]... 'script' inputfile

选项【option】:

  • -n 不输出模式空间内容到屏幕,即不自动打印
  • -e 多点编辑
  • -f /PATH/SCRIPT_FILE: 从指定文件中读取编辑脚本
  • -r 支持使用扩展正则表达式
  • -i 直接编辑文件(慎用)
  • -i.bak 备份文件并原处编辑

script 地址范围(选择第几行)

  1. 不给地址:对全文进行处理

  2. 单地址:
    #: 指定的行,$:最后一行
    /pattern/:被此处模式所能够匹配到的每一行

  3. 地址范围:
    #,#
    #,+#
    /pat1/,/pat2/
    #,/pat1/

  4. ~:步进
    1~2 奇数行
    2~2 偶数行

编辑命令:

  • d 删除模式空间匹配的行,并立即启用下一轮循环
  • p 打印当前模式空间内容,追加到默认输出之后(匹配成功的内容追加到文本最后)
  • a []text1 在指定行后面追加文本,支持使用\n实现多行追加
  • i []text 在行前面插入文本
  • c []text 表示把选定的行改为新的文本
  • w /path/somefile 保存模式匹配的行至指定文件
  • r /path/somefile 在指定的行后插入xx文本中所有内容
  • q 截止到选定的 script 地址时命令终止
  • = 为模式空间中的行打印行号
  • ! 模式空间中匹配行取反处理
  • s///:查找替换,支持使用其它分隔符,s@@@,s###

s///替换标记:【flags 标记】

#格式 1:
$sed ‘s///’ example.txt
#格式 2:
$sed ‘s@@@’ example.txt
  • 数字 1~512 同一行中第几次出现,例如s/a/x/2,能匹配上的只有 aaa 中间的a,数字代表第二次出现

  • g 选择的行内全局替换(否则匹配行内第一个)

  • p 显示替换成功的行

  • w /PATH/TO/SOMEFILE 将替换成功的行保存至文件中

  • & 用正则表达式匹配的内容进行替换;

  • \n 选中的行内匹配第 n 个子串,该子串之前在 pattern 中用 () 指定。

  • \ 转义(转义替换部分包含:&、\ 等)。


3.2 s 替换脚本命令

格式:sed '[address-range|pattern-range] s/original-string/replacement-string/[substitute-flags]' inputfile;

解释:

  • address-range:地址列表,表示从哪个地方开始执行,如:1,3 表示第1行到第 3 行;

  • pattern-range:样式列表,表示从哪个匹配串开始,如:/Jane/,表示从行中包含字符串 Jane 的行开始执行

  • s:表示要执行替换命令(substitute);

  • originalstring:需要被替换的字符串 ;

  • replacement-strings:替换后的字符串;

  • substitute-flags:可选替换标志符。

注意:如果没有[address-range|pattern-range],默认选择全文进行替换

  • d表示删除
  • $表示行尾
  • ^表示开头
  • \s空白符正则
  • \s*表示连续空格的字符串

案例:【sed 'script' inputfile`】

$ cat example.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

#1. 把第一行的 John 替换成 lili 字符串
$ sed '1 s/John/lili/' example.txt
101,lili Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

#2. 把第2~5行的 Manager 替换成 lili
$ sed '2,5 s/Manager/lili/' example.txt
101,John Doe,CEO
102,Jason Smith,IT lili
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler lili

#3. 把 John 所在字符串行当中的 CEO 替换成 XXX
$ sed '/John/ s/CEO/XXX/' example.txt
101,John Doe,XXX
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

#4. 从第四行而且包含字符串‘Ram’的行中,把 Developer 字符串替换成 XXX
$ sed '4,/Ram/ s/Developer/XXX/' example.txt
101,John Doe,XXX
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

#5. 如果没有 address-range 和 pattern-range,那么就会把每一行碰到的第一个匹配字符串给替换掉
$ sed 's/1/AAA/' example.txt
AAA01,John Doe,CEO
AAA02,Jason Smith,IT Manager
AAA03,Raj Reddy,Sysadmin
AAA04,Anand Ram,Developer
AAA05,Jane Miller,Saler Manager

#6 s///后的数字标记 1,2,3 把要匹行中第 n 个符合条件的匹配串替换成我们想要的字符串
# 把每一行第二个匹配的1,进行替换
$ sed 's/1/AAA/2' example.txt
10AAA,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

#7 $ 将 origin-string 替换到 replace-string 
$ sed 's/John/[&]/' example.txt
101,[John] Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

# 用文本模式指定行区间
$ grep demo /etc/passwd
demo:x:502:502::/home/Samantha:/bin/bash
# 用正斜线将要指定的 pattern 封起来,sed 会将该命令作用到包含指定文本模式的行上。
# 在包含'demo'的行中,进行s替换
$ sed '/demo/s/bash/csh/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
...
demo:x:502:502::/home/demo:/bin/csh
...

3.3. g,w,p,a,i,c,y,q,r,f,d 脚本命令

g 全局替换

#g 全局标志会把遇到的所有的满足条件的字符串给替换掉
$ sed 's/1/AAA/g' example.txt
AAA0AAA,John Doe,CEO
AAA02,Jason Smith,IT Manager
AAA03,Raj Reddy,Sysadmin
AAA04,Anand Ram,Developer
AAA05,Jane Miller,Saler Manager

w 输出到文本

#把每行碰到第一个字符串 John 替换成 lili 字符串,并写入 output.txt 中,不写数字默认就是第一个匹配到的
$ sed 's/1/AAA/1w output.txt' example.txt
$ cat output.txt
AAA01,John Doe,CEO

p 标记会输出修改过的行

#3. -n -p (-n 选项会禁止sed输出,但p标记会输出修改过的行)
$ sed -n 's/1/AAA/2p' example.txt
10AAA,John Doe,CEO

a 命令追加行(在匹配内容后面追加)

$ cat example.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

# 在行尾追加 xxx
$ sed '$ a xxx' example.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager
xxx

# 在文本匹配处增加多行
$ sed '/Jason/ a \aaa\bbb' example.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
aaabbb
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

使用 i 命令插入行(在匹配内容前面插入)

$ sed '2 i xxx' example.txt
101,John Doe,CEO
xxx
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

使用 c 命令修改所在行

$ sed '/Jason/ c xxx' example.txt
101,John Doe,CEO
xxx
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

使用 y 命令作字符转换

$ cat a.txt
abcdef
1234

$ sed 'y/abc/ABC/' a.txt
ABCdef
1234

使用 q 命令终止执行

#示例:sed '3 q' input-file 执行完第3行后终止
#格式:sed '/Anand/ q' input-file匹配到 Anand 行后退出

$ sed '3 q' example.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin

$ sed '/Jason/ q' example.txt
101,John Doe,CEO
102,Jason Smith,IT Manager

r 将文件中的内容插入到匹配位置后

# sed 命令会将 filename 文件中的内容插入到 address 指定行的后面,比如说:
$ cat data12.txt
This is an added line.
This is the second added line.
$ sed '3r data12.txt' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is an added line.
This is the second added line.
This is line number 4.

# 如果你想将指定文件中的数据插入到数据流的末尾,可以使用 $ 地址符,例如:
$ sed '$r data12.txt' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
This is an added line.
This is the second added line.

f 插入并使用sh脚本

$ cat test.txt
<html>
<title>First Wed</title>
<body>
h1Helloh1
h2Helloh2
h3Helloh3
</body>
</html>
#使用正则表示式给所有第一个的h1、h2、h3添加<>,给第二个h1、h2、h3添加</>
$ cat sed.sh
/h[0-9]/{
    s//\<&\>/1
    s//\<\/&\>/2
}
$ sed -f sed.sh test.txt
<h1>Hello</h1>
<h2>Hello</h2>
<h3>Hello</h3>

d 删除脚本命令

#当和指定地址一起使用时,删除命令显然能发挥出大的功用。可以从数据流中删除特定的文本行。
#通过行号指定,比如删除 data6.txt 文件内容中的第 3 行:
$ cat data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
$ sed '3d' data6.txt
This is line number 1.
This is line number 2.
This is line number 4.

#或者通过特定行区间指定,比如删除 data6.txt 文件内容中的第 1、3行:
$ sed '2,3d' data6.txt
This is line number 4.

#或者通过特殊的文件结尾字符,比如删除 data6.txt 文件内容中第 3 行开始的所有的内容:
$ sed '3,$d' data6.txt
This is line number 1.
This is line number 2.

3.4 sed实例

查看某段时间内的日志:

# sed -n ‘/开始时间日期/,/结束时间日期/p’ xx.log | grep “包含的关键字”
$ sed -n ‘/2018-06-21 14:30:20/,/2018-06-21 16:12:00/p’ log.txt | grep ‘keyword’

# 时间里有/的要用转意字符\转意
$ sed -n '/2022\/10\/26 14:27:16/,/2022\/10\/26 18:27:16/p' wrapper.log | grep 'POST'

# 对日志模糊查询
$ sed -n ‘/2022-10-24 21*/,/2022-10-24 22*/p’ xx.log

# 日志导出
$ sed -n ‘/2019-10-24 22:16:21/,/2019-10-21 20:16:58/p’ all.log > yoyo.log

将文本的前三位数截取出来,并加上大括号,去掉后面的全部内容

$ cat example.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Saler Manager

#1. 正则表达式的()前要加转义符\   \(\)
#2. (^[0-9]*\),.* 解释:以0-9开头的0个或多个元素 逗号 .*任意字符出现0次或多次
#3. \1 解释:\1指的是转义括号所捕获的字符
$ sed 's@\(^[0-9]*\),.*@{\1}@g' example.txt
$ sed 's/\(^[0-9]*\),.*/{\1}/g' example.txt
{101}
{102}
{103}
{104}
{105}

# 深入了解  \n 
$ echo 'abcabcabc' | sed 's@\(ab\)c@\1@'
ababcabc
$ echo 'abcabcabc' | sed 's@\(ab\)c@\1@g'
ababab
$ echo 'abcabcabc' | sed 's@\(ab\)\(c\)@\1d\2@g'
abdcabdcabdc

去掉注释行和空行 ( ^$ 表示空行)

# -i直接编辑文件 -e多点编辑
$ sed -i -e 's/^#.*//g; /^$/d'

行首添加#

#1,3行首添加#
sed 1,3 s/^/#/g
#12345
#23456
#34567
45678

4.awk【擅长对行按要求切割】

4.1 wak 格式说明

​ awk 命令也是逐行扫描文件(从第 1 行到最后一行),寻找含有目标文本的行,如果匹配成功,则会在该行上执行用户想要的操作;反之,则不对行做任何处理。

简介: 常用来做列数据切分与提取(最擅长取列)

语法:

awk [选项] '脚本命令' 文件名

awk [选项] '匹配规则{执行命令}' 文件名

语法解释:

​ 1. ’匹配规则‘:表示从哪个地方开始执行,如:1,3 表示第1行到第 3 行;或者写触发事件:BEGIN、END

​ 2. 整个‘脚本命令’是用单引号' '括起,而其中的 ‘执行命令’ 部分需要用大括号{}

​ 3. 如果没有指定 ’执行命令‘,则默认会把匹配的行输出;如果不指定’匹配规则‘,则默认匹配文本中所有的行

选项 含义
-F fs 指定以 fs 作为输入行的分隔符,awk 命令默认分隔符为空格或制表符。
-f file 从脚本文件中读取 awk 脚本指令,以取代直接在命令行中输入指令。
-v var=val 在执行处理过程之前,设置一个变量 var,并给其设备初始值为 val。

举例:

test.txt有N个空白行,就会输出N个Blank line。

$ awk '/^$/ {print "Blank line"}' test.txt  

以:分割,筛选以/root开头,显示结果每行的第一个字段和第七个阻断

$ awk -F ":" '/^root/{print $1,$7}' test.txt

4.2 awk 字段变量

awk 的主要特性之一是其处理文本文件中数据的能力,awk 在读取一行文本时会用预定义的字段分隔符划分每个数据字段。它会自动给一行中的每个数据元素分配一个变量。

默认情况下,awk 会将行按指定要求切割后分配如下变量:

  • $0 代表整个文本行;
  • $1 代表文本行中的第 1 个数据字段;
  • $2 代表文本行中的第 2 个数据字段;
  • $n 代表文本行中的第 n 个数据字段。

在 awk 中,默认的字段分隔符是任意的空白字符。

# awk 程序读取文本文件,只显示第 1 个数据字段的值:
$ cat data2.txt
One line of test text.
Two lines of test text.
Three lines of test text.
$ awk '{print $1}' data2.txt
One
Two
Three
# 可以用 -F 选项手动指定 例如:
$ awk -F'#''{print $1}' data2.txt

4.3 awk 脚本命令使用多个命令

awk 允许将多条命令组合成一个正常的程序。只要在命令之间放个;分号即可,例如:

$ echo "My name is Rich" | awk '{$4="Christine"; print $0}'
My name is Christine

#也可以分开写

$ awk '{
> $4="Christine"
> print $0}'
My name is Christine

注意:此例中因为没有在命令行中指定文件名,awk 程序需要用户输入获得数据,因此当运行这个程序的时候,它会一直等着用户输入文本,此时如果要退出程序,只需按下 Ctrl+D 组合键即可。

4.4 awk 从文件中读取程序

跟 sed 一样,awk 允许将脚本命令存储到文件中,然后再在命令行中引用,比如:

$ cat awk.sh
{print $1 "'s home directory is " $6}

$ awk -F: -f awk.sh /etc/passwd
root's home directory is '/root
bin's home directory is '/bin
daemon's home directory is '/sbin
adm's home directory is '/var/adm
lp's home directory is '/var/spool/lpd

注意:在程序文件中,也可以指定多条命令,只要一条命令放一行即可,之间不需要用分号。

4.5 BEGIN、END关键字

语法:awk '[BEGIN]{..}{..}[END{..}]' file

BEGIN和END顾名思义,在awk中,BEGIN只在开始处理之前运行一次,END只在结束处理之后运行一次,非常适合用在做一些前置操作时使用,通常求和类初始化值、设定分隔符等经常会用。

和 BEGIN 关键字相对应,END 关键字允许我们指定一些脚本命令,awk 会在读完数据后执行它们,例如:

$ cat data3.txt
Line 1
Line 2
Line 3
$ awk 'BEGIN {print "The data3 File Contents:"}{print $0}' data3.txt
The data3 File Contents:
Line 1
Line 2
Line 3

#1.求和
awk 'BEGIN{sum=0}{sum+=$1}END{print sum}' file
#2.求均值
awk 'BEGIN{sum=0}{sum+=$1}END{print sum/NR}' file
#NR为总记录数
#3.求最大值
awk 'BEGIN{max=0} {if($1 > max)max = $1} END{print max}'

可以看到,当 awk 程序打印完文件内容后,才会执行 END 中的脚本命令。

举例:统计文件行数

awk 'END{print NR}' file...

4.6 awk 内置变量

awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。

  • ARGC 命令行参数个数

  • ARGV 命令行参数排列

  • ENVIRON 支持队列中系统环境变量的使用

  • FILENAME awk浏览的文件名

  • FNR 浏览文件的记录数

  • FS 设置输入域分隔符,等价于命令行 -F选项

  • NF 浏览记录的域的个数(切割)

  • NR 已读的记录数

  • OFS 输出域分隔符

  • ORS 输出记录分隔符

  • RS 控制记录分隔符

实例:

# 统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:
$ awk -F ':' '{print"filename:" FILENAME ",NR:" NR", NF:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,NR:1,NF:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,NR:2,NF:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/sh
filename:/etc/passwd,NR:3,NF:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh
filename:/etc/passwd,NR:4,NF:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh

#使用printf替代print,可以让代码更加简洁,易读
$ awk  -F ':' '{printf("filename:%s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}'/etc/passwd

注意:命令结尾的路径是绝对路径

# 打印以'#'分隔后,数量=5的 第一段字符
$ awk -F '#' 'NF==5 {print $1}' test

# 看命令自己翻译
$ awk -F '#' 'NF>=4 && NF<=5 {print $1}' test

4.7 awk 自定义变量和赋值

除了awk的内置变量,awk还可以自定义变量。

# 统计/etc/passwd的账户人数,$0打印一整行
$ awk '{count++;print $0;} END{print "user count is ",count}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
......
user count is  40

count是自定义变量。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以;号隔开。

# 这里没有初始化count,虽然默认是0,但是妥当的做法还是初始化为0
$ awk 'BEGIN {count=0;print "[start]user count is ",count} {count=count+1;print $0;} END{print "[end]user count is ",count}' /etc/passwd

[start]user count is  0
root:x:0:0:root:/root:/bin/bash
...
[end]user count is  40

统计某个文件夹下的文件占用的字节数

$ ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print"[end]size is ", size}'
[end]size is  8657198

#如果以M为单位显示:
$ ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print"[end]size is ", size/1024/1024,"M"}'
[end]size is  8.25889 M

注意:ls -l,会罗列出所有文件的信息,默认以空格分个,$5正好是字节大小。统计不包括文件夹的子目录

5.regex

正则就是用有限的符号,表达无限的序列

5.1 匹配字符

  • . 匹配任意单个字符,不能匹配空行
  • [] 匹配指定范围内的任意单个字符,[0-9a-zA-Z]、[a-zA-Z]、 [A-Z]、[a-z]
  • ^[0-9] 以0-9开头
  • [0-9]$ 以0-9结尾
  • [^] 取反

5.2 配置次数

  • ***** 匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
  • .* 任意长度的任意字符,不包括0次
  • ? 匹配其前面的字符0 或 1次
  • \+ 匹配其前面的字符至少1次
  • {n} 匹配前面的字符n次
  • {m,n} 匹配前面的字符至少m 次,至多n次
  • {,n} 匹配前面的字符至多n次
  • {n,} 匹配前面的字符至少n次

注意:{}在正则表达式中需要转意,而{}()不需要。

5.3 出现位置

  • ^ 行首锚定,用于模式的最左侧
  • $ 行尾锚定,用于模式的最右侧
  • ^PATTERN$,用于模式匹配整行
  • ^$ 空行
  • ^[[:space:]].*$ 空白行
  • < 或 \b 词首锚定,用于单词模式的左侧
  • > 或 \b 词尾锚定;用于单词模式的右侧

5.4 转意字符

\是转移字符,其后面的字符会代表不同的意思,常用的转意字符:

转移字符 含义
\n 匹配换行符
\r 匹配回车符
\t 匹配制表符
\w 匹配任意一个数字、字母、下划线
\W 匹配非数字、字母、下划线的任意一个字符(特殊字符)
\d 匹配数子字符0~9
\D 匹配非数字字符 !0~9
\\ 匹配\

5.5 选择表达式

正则中用|来表示分组,a|b表示匹配a或者b的意思

123|456|789 // 匹配 123 或 456 或 789

5.6 分组与引用

引用的语法是 \数字,数字代表引用前面第几个捕获分组(括号中的匹配),注意非捕获分组不能被引用

\ 表示转意字符

<([a-z]+)><\/\1> // 可以匹配 `<span></span>` 或 `<div></div>`等

实例:

$ cat c.txt 
abc
abcc
abccc
abcccc
aaa
ac
yyycc

# \? 匹配其前面的字符0或1次(匹配的是ABC出现的次数)
$ grep "abc\?" c.txt
abc
abcc
abccc
abcccc
abccccc

# \+ 匹配其前面的字符至少1次(匹配的是ABC出现的次数)
$ grep "abc\+" c.txt
abc
abcc
abccc
abcccc
abccccc

$ grep "c\+" c.txt 
abc
abcc
abccc
abcccc
abccccc
ac
yyycc

#前面字符至少出现过3次
$ grep "c\{3,\}" c.txt
abccc
abcccc
abccccc

#以a开头
$ grep "^a" c.txt
abc
abcc
abccc
abcccc
abccccc
aaa
ac

#以c结尾
$ grep "c$" c.txt
abc
abcc
abccc
abcccc
abccccc
ac
yyycc

#匹配y开头,c结尾的字符  \是转意字符
$ grep "\<y.*c\>" c.txt
yyycc
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  2Vtxr3XfwhHq   2024年05月17日   55   0   0 Java
  Tnh5bgG19sRf   2024年05月20日   110   0   0 Java
  8s1LUHPryisj   2024年05月17日   46   0   0 Java
  aRSRdgycpgWt   2024年05月17日   47   0   0 Java
O0fDkNCcKreB
作者其他文章 更多