在文件上传工具:Tiny File Manager的数据备份时,用到sed处理记录文件。
- sed 是一种流编辑器,主要用于对文本进行替换、删除、插入等操作。它逐行处理输入文本,并输出修改后的结果。
- awk 是一种以字段为单位的文本处理语言,擅长数据提取、统计和格式化输出。
- grep 是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
grep 使用
在目录下,搜索所有文件与子目录的文件:grep -inr 'logdn' ./
过滤配置文件中被注释的行:grep -Ev '^$|^\s*#' /etc/nginx/nginx.conf
查找多个关键字:ps -Ao user,pid,ppid,%mem,rss,%cpu,cmd --sort=+ppid|grep -E 'PID|nginx|php-fpm|mariadb'
常用选项
- -E:扩展正则表达式
- -i:忽略大小写进行匹配。
- -v:反向查找,只打印不匹配的行。
- -n:显示匹配行的行号。
- -r:递归查找子目录中的文件。
- -l:只打印匹配的文件名。
- -c:只打印匹配的行数。
grep 的一行多个关键字之间 and / or / not 匹配
与(AND)操作
- 使用管道符将多个grep命令连接起来,这样只有同时满足所有条件的行才会被显示。例如:
grep 'pattern1' filename | grep 'pattern2' - 使用
-E选项,结合正则表达式来实现与操作。例如:grep -E 'pattern1.*pattern2' filename或者grep -E 'pattern1.*pattern2|pattern2.*pattern1' filename,区别在于是否有先后出现顺序。
或(OR)操作
- 使用转义字符将管道符转为“或”符号:
grep 'pattern1\|pattern2' filename - 使用
-E选项:grep -E 'pattern1|pattern2' filename或者egrep 'pattern1|pattern2' filename - 用
-e选项:grep -e pattern1 -e pattern2 filename
非(NOT)操作
- 使用
-v选项,这样可以显示不符合指定模式的所有行。例如:grep -v 'pattern' filename
sed使用
Bash
sed -i '1i\'"${outText}" ${targetDIR}/${logFileName} # 将内容插入到第1行的前面,注意变量引用方式,"1i\${outText}"是无效的。'-i是指编辑已有文件${targetDIR}/${logFileName},如果没有此参数,只是显示处理后结果,文件不会被修改。'1i\'"${outText}"是指在第一行的前面,插入内容${outText}1代表行数,需要在文件中存在,否则会处理失败,且不会有报错提示。i\代表行的前面插入内容,而a\代表行的后面插入内容。
Bash
sed -i "s|${targetDIR}||" ${targetDIR}/${logFileName} # 替换targetDIR为空"s|${targetDIR}||"是查找变量值+替换为空,也就是删除。一般格式是's/查找内容/替换内容/',由于${targetDIR}是路径,包含了[/],所以使用[|]做为分隔符。也可使用其他特殊字符,做为分隔的定界符,比如[:]
更多:
- 删除空白行:
sed '/^$/d' file - 删除文件的第2行:
sed '2d' file - 删除文件的第2行到末尾所有行:
sed '2,$d' file - 删除文件最后一行:
sed '$d' file - 删除文件中所有开头是test的行:
sed '/^test/'d file
正则表达式替换
Bash
echo this is digit 7 in a number | sed 's/digit ([0-9])/\1/'
this is 7 in a numberawk
数值计算见:Shell中的运算符
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
常用命令选项
- -F fs fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:
- 默认使用空格与制表符作为字段分隔符,有多少个空格就分开几列,所以要避免有连续空格,或行开头就是空格。
-F'[ ]+'表示一个或多个空格作为分隔符。
- -v var=value 赋值一个用户定义变量,将外部变量传递给awk
- -f scripfile 从脚本文件中读取awk命令
- -m[fr] val 对val值设置内在限制,-mf选项限制分配给val的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
内容提取
场景:将指定目录的文件大小与文件名,生成到一个文件里。
ll命令的输出:
total 140M
drwxrwxr-- 2 pubFiles pubFiles 4.0K Nov 28 09:30 ./
drwxr-xr-x 5 root root 4.0K Nov 26 20:20 ../
-rw-r--r-- 1 lat ubuntu 110M Jul 26 06:44 AxureRP-Setup-3754.exe
-rw-r--r-- 1 root root 428 Nov 28 11:31 list.txt
-rw-r--r-- 1 lat ubuntu 25M Oct 20 20:28 rclone-v1.71.2-linux-amd64.deb
-rw-r--r-- 1 lat ubuntu 1.4M Jan 25 2025 rustdesk-server-hbbr_1.1.14_amd64.deb
-rw-r--r-- 1 lat ubuntu 4.1M Jan 25 2025 rustdesk-server-hbbs_1.1.14_amd64.deb
Bash
echo `date` > /data/downloads/list.txt
# tee file.txt 命令可以同时输出到屏幕+文件里,来代替 >>
ls -lhF /data/downloads | awk '{print $5,"\t",$9}' >> /data/downloads/list.txt
cat /data/downloads/list.txt-rw-r--r-- 1 lat ubuntu 110M Jul 26 06:44 AxureRP-Setup-3754.exe
中间是空格分隔,连续多个视为一个。
- $0是整行内容
- $1是-rw-r–r–
- $2是1
- $3是lat
- $4是ubuntu
- $5是110M
- $6是Jul
- $7是26
- $8是06:44
- $9是AxureRP-Setup-3754.exe,可以看出上面命令
awk '{print $5,"\t",$9}'在文件名有空格时,会不符合预期输出。
110M AxureRP-Setup-3754.exe
0 list.txt
25M rclone-v1.71.2-linux-amd64.deb
1.4M rustdesk-server-hbbr_1.1.14_amd64.deb
4.1M rustdesk-server-hbbs_1.1.14_amd64.deb
awk脚本基本结构
awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
awk "BEGIN{ i=0 } { i++ } END{ print i }" filename
BEGIN语句块、能够使用模式匹配的通用语句块、END语句块3部分组成,这三个部分是可选的。任意一个部分都可以不出现在脚本中,脚本通常是被 单引号 或 双引号 中。
awk的工作原理
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
- 第一步执行BEGIN{ commands }语句块中的语句;
- 第二步从文件或标准输入(stdin)读取一行,然后执行pattern{ commands }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
- 第三步当读至输入流末尾时,执行END{ commands }语句块。
示例
$ echo -e "A line 1\nA line 2" | awk 'BEGIN{ print "Start" } { print } END{ print "End" }'
Start
A line 1
A line 2
End
使用不带参数的print时,它就打印当前行,当print的参数是以逗号进行分隔时,打印时则以空格作为定界符。
内置参数
说明:[A][N][P][G]表示第一个支持变量的工具,[A]=awk、[N]=nawk、[P]=POSIXawk、[G]=gawk
**$n** 当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段。
**$0** 这个变量包含执行过程中当前行的文本内容。
[N] **ARGC** 命令行参数的数目。
[G] **ARGIND** 命令行中当前文件的位置(从0开始算)。
[N] **ARGV** 包含命令行参数的数组。
[G] **CONVFMT** 数字转换格式(默认值为%.6g)。
[P] **ENVIRON** 环境变量关联数组。
[N] **ERRNO** 最后一个系统错误的描述。
[G] **FIELDWIDTHS** 字段宽度列表(用空格键分隔)。
[A] **FILENAME** 当前输入文件的名。
[P] **FNR** 同NR,但相对于当前文件。
[A] **FS** 字段分隔符(默认是任何空格)。
[G] **IGNORECASE** 如果为真,则进行忽略大小写的匹配。
[A] **NF** 表示字段数,在执行过程中对应于当前的字段数。
[A] **NR** 表示记录数,在执行过程中对应于当前的行号。
[A] **OFMT** 数字的输出格式(默认值是%.6g)。
[A] **OFS** 输出字段分隔符(默认值是一个空格)。
[A] **ORS** 输出记录分隔符(默认值是一个换行符)。
[A] **RS** 记录分隔符(默认是一个换行符)。
[N] **RSTART** 由match函数所匹配的字符串的第一个位置。
[N] **RLENGTH** 由match函数所匹配的字符串的长度。
[N] **SUBSEP** 数组下标分隔符(默认值是34)。
由于NF为行的字段数,所以$NF表示为最后一个字段的内容,而$(NF-1)则是倒数第二个字段的内容;和$n一样,只是为最后一个。
示例:
$ echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk '{print "Line No:"NR", No of fields:"NF, "$0="$0, "$1="$1, "$2="$2, "$3="$3,"\t",$(NF-1),$NF}'
Line No:1, No of fields:3 $0=line1 f2 f3 $1=line1 $2=f2 $3=f3 f2 f3
Line No:2, No of fields:3 $0=line2 f4 f5 $1=line2 $2=f4 $3=f5 f4 f5
Line No:3, No of fields:3 $0=line3 f6 f7 $1=line3 $2=f6 $3=f7 f6 f7
示例解释
awk '{++S[\$NF]} END {for(a in S) print a, S[a]}'
{++S[$NF]}
$NF:代表当前行的最后一列(NF = Number of Fields,字段数量)S[$NF]:使用最后一列的值作为关联数组 S 的键++S[$NF]:每次遇到这个值时,对应的计数器加1
END {for(a in S) print a, S[a]}
END:处理完所有行后执行for(a in S):遍历数组 S 的所有键print a, S[a]:打印键(最后一列的值)和对应的计数
发表回复