AI智能
改变未来

Shell编程实战(四):文本处理三剑客


Ⅰ. 概述

  • grep是一个过滤器
  • sed是一个流编辑器
  • awk是报告生成器,对数据进行处理生成报告

Ⅱ. grep和egrep

egrep 是对 grep 的扩展

语法格式

  • 第一种形式:
    grep [option] [pattern] [file1, file2..]
  • 第二种形式:
    command | grep [option] [pattern]

grep参数

Ⅲ. sed

1. sed的工作模式

  • sed(Stream Editor),流编辑器,对标准输出或文件逐行进行处理

语法格式

  • 第一种:
    stdout | sed [option] \"/pattern/command\"

    stdout | sed [option] \"command\"
  • 第二种:
    sed [option] \"/pattern/command\" file

    sed [option] \"command\" file

2. sed的选项

例子

p命令之所以显示两次是因为第一次是显示原行信息,第二次是命令的结果

-n

的作用

-e

的作用

[flw@nlp2 ~]$ sed -n -e \'/python/p\' -e \'/PYTHON/p\' sed.txtI love pythonI love PYTHON[flw@nlp2 ~]$

-f

的作用

[flw@nlp2 ~]$ cat edit.sed/python/p[flw@nlp2 ~]$ sed -n -f edit.sed sed.txtI love python[flw@nlp2 ~]$

-r

的作用

#  \"|\" 是扩展正则表达式[flw@nlp2 ~]$ sed -n \'/python|PYTHON/p\' sed.txt[flw@nlp2 ~]$[flw@nlp2 ~]$[flw@nlp2 ~]$ sed -n -r \'/PYTHON|python/p\' sed.txtI love pythonI love PYTHON[flw@nlp2 ~]$

-i

的作用

-i

最常用

[flw@nlp2 ~]$ sed -n \'s/love/like/g;p\' sed.txtI like pythonI like PYTHONHadoop is bigdataframe[flw@nlp2 ~]$ cat sed.txtI love pythonI love PYTHONHadoop is bigdataframe[flw@nlp2 ~]$[flw@nlp2 ~]$ sed -i \'s/love/like/g\' sed.txt[flw@nlp2 ~]$ cat sed.txtI like pythonI like PYTHONHadoop is bigdataframe[flw@nlp2 ~]$

3. sed中的pattern详解

4. sed中的编辑命令详解

例子

a

行后追加

i

行前追加

r

命令

w

命令

[flw@nlp2 ~]$ sed -n \'/\\/bin\\/bash/w /tmp/user.txt\' passwd

s

修改

格式 作用
s/pattern/string/ 查找符合pattern模式的字符串,将其替换为string。
同一行内,只替换第一个,等价于

s/pattern/string/1
s/pattern/string/g 替换所有符合pattern模式的字符串
s/pattern/string/2 2: 同一行内,只替换前2个匹配的,剩下的不替换
s/pattern/string/2g 2g: 同一行内,只替换从第2个开始往后的所有的匹配的字符串
s/pattern/string/ig i: 表示匹配时忽略大小写

什么是反向引用

或者可以使用

sed -i \'s/\\(hermion.\\)/\\1s/g\' leihou

\\1

也可以表示反向引用,但是使用

\\1

时前面必须加括号

\\1

&

的区别

seg 引用变量时的注意事项

  1. 匹配变量中如果存在变量,要使用双引号
    [flw@nlp2 ~]$ old_string=\"hermionc\"[flw@nlp2 ~]$ new_string=\"hermione\"[flw@nlp2 ~]$ sed -i \"s/$old_string/$new_string/g\" leihou
  2. sed中需要引入自定义变量时,如果外面使用单引号,则自定义变量也必须使用单引号
    [flw@nlp2 ~]$ sed -i \'s/\'$old_string\'/\'$new_string\'/g\' leihou

5. 利用sed查询特定内容

例子

对mysql的配置文件 my.cnf 进行处理

#!/bin/bashFILE_NAME=$PWD/my.cnf# 获取所有的段function get_all_segments{echo `sed -n \'/^\\[.*\\]/p\' $FILE_NAME | sed -e \'s/\\[//g\' -e \'s/\\]//g\'`}# 统计每一段中配置项的个数function count_items_in_segment{# grep -v \"^$\" 删除空行# grep -v \"^#\" 删除注释行items=`sed -n \"/^\\[$1\\]/,/^\\[.*\\]/p\" $FILE_NAME | grep -v \"^#\" | grep -v \"^$\" | grep -v \"^\\[.*\\]\"`index=0for item in $itemsdoindex=`expr $index + 1`doneecho $index}line=0for seg in `get_all_segments`doline=$(($line+1))sum=`count_items_in_segment $seg`echo \"$line $seg: $sum\"done

my.cnf如下所示:

[client]port=3306socket=/tmp/mysql.socket#ThisSegmentForserver[server]innodb_buffer_pool_size=91750Minnodb_buffer_pool_instances=8innodb_buffer_pool_load_at_startup=1innodb_buffer_pool_dump_at_shutdown=1innodb_data_file_path=ibdata1:1G:autoextendinnodb_flush_log_at_trx_commit=1innodb_log_buffer_size=32Minnodb_log_file_size=2Ginnodb_log_files_in_group=2innodb_max_undo_log_size=4Ginnodb_undo_directory=undologinnodb_undo_tablespaces=95#thisisonlyforthemysqldstandalonedaemon[mysqld]port=3306socket=/tmp/mysql.sockbasedir=/usr/local/mysqldatadir=/data/mysqlpid-file=/data/mysql/mysql.piduser=mysqlbind-address=0.0.0.0sort_buffer_size=16Mjoin_buffer_size=16Mthread_cache_size=3000interactive_timeout=600wait_timeout=600#ThisSegmentFormysqld_safe[mysqld_safe]log-error=/var/log/mariadb/mariadb.logpid-file=/var/run/mariadb/mariadb.pidmax_connections=1000open_files_limit=65535thread_stack=512Kexternal-locking=FALSEmax_allowed_packet=32M#thisisonlyforembeddedserver[embedded]gtid_mode=onenforce_gtid_consistency=1log_slave_updatesslave-rows-search-algorithms=\'INDEX_SCAN,HASH_SCAN\'binlog_format=rowbinlog_checksum=1relay_log_recovery=1relay-log-purge=1#usethisgroupforoptionsthatolderserversdon\'tunderstand[mysqld-5.5]key_buffer_size=32Mread_buffer_size=8Mread_rnd_buffer_size=16Mbulk_insert_buffer_size=64Mmyisam_sort_buffer_size=128Mmyisam_max_sort_file_size=10Gmyisam_repair_threads=1lock_wait_timeout=3600explicit_defaults_for_timestamp=1innodb_file_per_table=1

结果如下所示:

[flw@nlp2 67]$ sh mysql_process.sh1 client: 22 server: 123 mysqld: 124 mysqld_safe: 75 embedded: 86 mysqld-5.5: 10

6. 利用sed删除文件内容

删除/etc/passwd中以yarn开头的行到最后的所有行

sed -i \'/^yarn/,$d\' passwd

删除配置文件中的所有注释行(#前面可能有空格)

sed -i \'/\\d*#/d\' nginx.conf

7, 利用sed修改文件内容

7. 利用sed追加文件内容

a

在第10行到第20行,每行后(后面一行)追加 “leihou”

sed -i \'10,20a leihou\' passwd

i

匹配到以yarn开头的行,在匹配行前面(前面一行)追加 “alielie”

sed -i \'/^yarn/i alielie\' passwd

r

将/etc/fstab文件的内容追加到passwd文件的第20行后面

sed -i \'20r /etc/fstab\' passwd

w

将passwd文件匹配到/bin/bash的行追加到/tmp/sed.txt文件中

sed -i \'/\\/bin\\/bash/w /tmp/sed.txt\' passwd

Ⅲ awk

1. awk工作模式介绍

awk是一个文本处理工具,通常用于处理数据并生成结果报告。

语法格式

  • 第一种:
    awk \'BEGIN{}[pattern]{commands}END{}\' file_name
  • 第二种:
    standard output | awk \'BEGIN{}[pattern]{commands}END{}\'

[] 代表可以不写

语法格式说明

语法格式 解释
BEGIN{} 正式处理数据之前执行
pattern 匹配模式,可以不写
{commands} 处理命令,可能多行
END{} 处理完所有匹配数据后执行

2. awk的内置变量

例子:

$0, $1

[flw@nlp2 72]$ awk \'{print $0}\' passwdroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologin[flw@nlp2 72]$[flw@nlp2 72]$ awk \'BEGIN{FS=\":\"}{print $1}\' passwd     # FS=\":\" 分隔符是:rootbin[flw@nlp2 72]$

NF

[flw@nlp2 72]$ cat listHadoop  Spark FlumeJava     Python JavaScript       GoHermione Harry Voldemort[flw@nlp2 72]$[flw@nlp2 72]$ awk \'{print $1}\' list            # 默认是以空格或者TAB为分隔符HadoopJavaHermione[flw@nlp2 72]$[flw@nlp2 72]$ awk \'{print NF}\' list            # 输出每一行字段个数343[flw@nlp2 72]$

NR, FNR

[flw@nlp2 72]$ awk \'{print NR}\' list passwd     # 行号12345[flw@nlp2 72]$[flw@nlp2 72]$ awk \'{print FNR}\' list passwd    # 行号,每个文件单独记数12312

FS, RS

默认以 空格TAB 为分隔符

[flw@nlp2 72]$ cat list2Hadoop|Sparkr:Flume--Java|Pythonr:JavaScript:Go--Hermione|Harry:Voldemort[flw@nlp2 72]$[flw@nlp2 72]$ awk \'BEGIN{FS=\":\";RS=\"--\"}{print $2}\' list2FlumeJavaScriptVoldemort[flw@nlp2 72]$ awk \'BEGIN{FS=\":\";RS=\"--\"}{print $1}\' list2Hadoop|SparkrJava|PythonrHermione|Harry[flw@nlp2 72]$

OFS, ORS

FILENAME

[flw@nlp2 72]$ cat listHadoop Sparkr FlumeJava Pythonr JavaScript GoHermione Harry Voldemort[flw@nlp2 72]$[flw@nlp2 72]$[flw@nlp2 72]$ awk \'{print FILENAME}\' listlistlistlist

3. awk格式化输出printf

printf的格式说明符

最常用的是前两种。

printf的修饰符

例子

# %-20s: \"-\"左对齐; 20表示字符串的长度是20[flw@nlp2 72]$ awk \'BEGIN{FS=\":\"}{printf \"%-20s %-20s-\\n\", $1, $2}\' passwdroot                 x                   -bin                  x                   -[flw@nlp2 72]$

4. awk模式匹配的两种用法

  • 第一种模式匹配:RegExp(正则表达式)
  • 第二种模式匹配:关系运算匹配

例子

1. 正则表达式

匹配 /etc/passwd 文件行中含义root字符串的所有行

awk \'/root/{print $0}\' passwd

匹配 /etc/passwd 文件行中以yarn开头的所有行

awk \'/^yarn/{print $0}\' passwd

2. 关系运算

以:为分隔符,匹配 /etc/passwd 文件中第3个字段小于50的所有行信息

awk \'BEGIN{FS=\":\"}$3<50{print $0}\' passwd

以:为分隔符,匹配 /etc/passwd 文件中第3个字段等于/bin/bash的所有行信息

awk \'BEGIN{FS=\":\"}$7==\"/bin/bash\"{print $0}\' passwd

以:为分隔符,匹配 /etc/passwd 文件中第3个字段为包含3个以上数字的所有行信息

awk \'BEGIN{S=\":\"}$3~/[0-9]{3,}/{print $0}\' passwd

以:为分隔符,匹配 /etc/passwd 文件中第1个字段为root或者bin的所有行信息

awk \'BEGIN{FS=\":\"}$1==\"root\"||$1==\"bin\"{print $0}\' passwd

以:为分隔符,匹配 /etc/passwd 文件中第3个字段小于50且第4个字段大于59的所有行信息

awk \'BEGIN{FS=\":\"} $3<50 && $4>50 {print $0}\' passwd

5. awk中表达式的用法

[flw@nlp2 72]$ awk \'BEGIN{var=20;var1=\"hello\";print var, var1}\'20 hello[flw@nlp2 72]$

计算passwd中的空白行数量

awk \'/^$/{sum++}END{print sum}\' passwd

计算学生课程分数平均值

[flw@nlp2 76]$ cat txt蓉儿    80      90      96      98盈盈    93      98      92      91赵敏    85      95      75      90赫敏    78      88      98      100[flw@nlp2 76]$[flw@nlp2 76]$[flw@nlp2 76]$ awk \'BEGIN{printf \"%-16s%-16s%-16s%-16s%-16s%-16s\\n\", \"name\", \"chinese\", \"english\", \"math\", \"physics\", \"average\"}{sum=$2+$3+$4+$5;ave=sum/4;printf \"%-16s%-16s%-16s%-16s%-16s%-16s\\n\", $1, $2, $3, $4, $5, ave}\' txtname            chinese         english         math            physics         average蓉儿              80              90              96              98              91盈盈              93              98              92              91              93.5赵敏              85              95              75              90              86.25赫敏              78              88              98              100             91[flw@nlp2 76]$

6. awk动作中的条件及循环语句

6.1 条件语句

例子

1

以:为分隔符,只打印/etc/passwd中第3个字符案的数值在50-100范围内的行信息

awk \'BEGIN{FS=\":\"}$3>=50 && $3<=100{print $0}\' passwd# 或者awk \'BEGIN{FS=\":\"}{if($3>=50 && $3<=100) print $0}\' passwd
2

以:为分隔符,以:为分隔符,只打印/etc/passwd中第3个字符案的数值小于50或者大于100的行信息

awk \'BEGIN{FS=\":\"}{if($3<50){ printf \"%-10s%-5d\\n\", \"小于50:\", $3} else if($3>100) {printf \"%-10s%-5d\\n\", \"大于100:\", $3}}\' passwd

或者可以把配置项写在文件中,如下:

6.2 循环语句

6.2.1 while循环

6.2.2 do-while循环

6.2.3 for循环

6.2.4 例子

1

计算1+2+…+100的和

[flw@nlp2 78]$ cat while.awkBEGIN{while(i<=100) {sum += ii++}print sum}[flw@nlp2 78]$[flw@nlp2 78]$[flw@nlp2 78]$ awk -f script1.awk passwd5050[flw@nlp2 78]$

计算每门课的平均成绩

[flw@nlp2 78]$ cat student.awkBEGIN{score_chinese=0score_english=0score_math=0score_physics=0count=0printf \"%-16s%-16s%-16s%-16s%-16s\\n\", \"name\", \"chinese\", \"english\", \"math\", \"physics\"}{score_chinese+=$2score_english+=$3score_math+=$4score_physics+=$5count++printf \"%-16s%-16s%-16s%-16s%-16s\\n\", $1, $2, $3, $4, $5}END{score_chinese/=countscore_english/=countscore_math/=countscore_physics/=countprintf \"%-16s%-16s%-16s%-16s%-16s\\n\", \"平均\", score_chinese, score_english, score_math, score_physics}[flw@nlp2 78]$[flw@nlp2 78]$[flw@nlp2 78]$ awk -f student.awk txtname            chinese         english         math            physics蓉儿              80              90              96              98盈盈              93              98              92              91赵敏              85              95              75              90赫敏              78              88              98              100平均              84              92.75           90.25           94.75[flw@nlp2 78]$

7. awk中的字符串函数

例子

以:为分隔符,返回/etc/passwd中每行中每个字段的长度

[flw@nlp2 79]$ cat e1.awkBEGIN{FS=\":\"}{for(i=1;i<=NF;i++) {if (i!=NF) {printf \"%d:\", length($i)}else {printf \"%d\", length($i)}}print \"\"            # print 自带换行}[flw@nlp2 79]$[flw@nlp2 79]$ awk -f e1.awk passwd4:1:1:1:4:5:93:1:1:1:3:4:13# ..[flw@nlp2 79]$

搜索字符串 “I have a dream” 中出现 “ea” 字符串的位置

[flw@nlp2 79]$ awk \'BEGIN{printf \"%d\\n\", index(\"I have a dream\", \"ea\")}\'    # 起始位置是112# 或者[flw@nlp2 79]$ awk \'BEGIN{printf \"%d\\n\", match(\"I have a dream\", \"ea\")}\'

将字符串 “Hadoop is a bigdata Framework” 全部 转换为大写

[flw@nlp2 79]$ awk \'BEGIN{printf \"%s\\n\", tolower(\"Hadoop is a bigdata Framework\")}\'hadoop is a bigdata framework

将字符串 “蓉儿 盈盈 赵敏 赫敏” 按空格分隔,分隔后每部分保存到数组array中

[flw@nlp2 79]$ awk \'BEGIN{split(\"蓉儿 盈盈 赵敏 赫敏\", arr, \" \"); print arr[0]}\'[flw@nlp2 79]$ awk \'BEGIN{split(\"蓉儿 盈盈 赵敏 赫敏\", arr, \" \"); print arr[1]}\'蓉儿[flw@nlp2 79]$

awk 中数组和字符串的下标都是从1开始记数

搜索字符串 “Tranction 2345 start:Select * from master” 中第一个数字出现的位置

[flw@nlp2 79]$ awk \'BEGIN{printf \"%d\\n\", match(\"Tranction 2345 start:Select * from master\", /[0-9]/)}\'11[flw@nlp2 79]$

在sed和awk中,如果要使用正则表达式,必须使用

/RegEpr/

这种形式

截取字符串 “transaction start” 的子串,截取条件从第4个字符开始,截取5位

[flw@nlp2 79]$ awk \'BEGIN{printf \"%s\\n\", substr(\"transaction start\", 4, 5)}\'nsact

替换字符串 “Transaction 243 Start, Event ID:9002” 中第一个匹配到的数字串为 $ 符号

[flw@nlp2 79]$ awk \'BEGIN{a=\"Transaction 243 Start, Event ID:9002\";sub(/[0-9]+/, \"$\", a);printf \"%s\\n\", a}\'Transaction $ Start, Event ID:9002[flw@nlp2 79]$ awk \'BEGIN{a=\"Transaction 243 Start, Event ID:9002\";gsub(/[0-9]+/, \"$\", a);printf \"%s\\n\", a}\'Transaction $ Start, Event ID:$

8. awk中的常用选项

1. -v

[flw@nlp2 79]$ num1=20[flw@nlp2 79]$ var=\"leihou\"[flw@nlp2 79]$[flw@nlp2 79]$[flw@nlp2 79]$ awk -v num2=\"$num1\" -v var1=\"$var\" \'BEGIN{printf \"%d--%s\\n\", num2, var1}\'20--leihou[flw@nlp2 79]$

2. -F

[flw@nlp2 79]$ awk \'BEGIN={FS=\":\"}{print $1}\' passwd# 等价于[flw@nlp2 79]$ awk -F \":\" \'{print $1}\' passwd

9. awk中数组的用法


例子

  1. 统计主机上所有的TCp连接,并统计不同状态的连接数
netstat -ntlp | grep tcp | awk \'{array[$6]++}END{for (a in array) {printf \"%-10s%-10s\\n\",a, array[a]}}\'
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Shell编程实战(四):文本处理三剑客