剑客一

grep

语法格式:

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

grep参数:

选项 含义
-v 不显示匹配的行信息
-i 忽略大小写
-n 显示行号
-r 递归搜索
-E 支持扩展正则表达式
-F 不按正则表达式匹配,按照字符串字面意思匹配
-c 只显示匹配行总数
-w 匹配整词
-x 匹配整行
-l 只显示文件名,不显示内容
-s 不显示错误信息

示例

# 准备file,内容如下
Python
Java
Python is good
Java is perfect
Php is the best lanuage

# 过滤含Python的行信息
grep Python file
->Python
->Python is good
grep -vi python file
->Java
->Java is perfect
->Php is the best lanuage

# 显示行号
grep -n Python file
->1:Python
->3:Python is good

# 支持扩展正则表达式(也可以直接使用egrep代替)
grep 'python|Python' file
->
grep -E 'python|Python' file
->Python
->Python is good

剑客二

sed

      Sed是流编辑器(Stream Editor)。 流编辑器用于对输入流(文件或来自管道的输入)执行基本的文本转换。尽管sed在某种程度上类似于允许进行粗略编辑(例如ed)的编辑器,但是Sed通过仅对输入进行一次传递来工作,因此效率更高。由于sed能够过滤管道中的文本,这使其与其他类型的编辑器特别不同。(java程序员应该很熟悉JDK8中的Stream)

语法格式:

stdout | sed [option] "pattern command"
sed [option] "pattern command" file

sed选项

选项 含义
-n 只打印模式匹配行(不会显示原行信息)
-e 直接在命令行进行sed编辑,默认选项
-f 编辑动作保存在文件中,执行文件执行
-r 支持扩展正则表达式
-i 直接修改文件内容

示例

# 匹配Python
# 会发现没匹配的行也被打印了,而匹配的行打印了两遍
# 因为sed默认就会把原行进行打印(p是打印command)
sed '/Python/p' file
->Python
->Python
->Java
->Python is good
->Python is good
->Java is perfect
->Php is the best lanuage

# 只打印匹配行,不打印原行
sed -n '/Python/p' file
->Python
->Python is good

# 多个pattern
sed -n -e '/Python/p' -e '/Java/p' file
->Python
->Java
->Python is good
->Java is perfect

# 扩展正则表达式
# 也许你会将上面两个pattern合并在一起:/Python|Java/p.十分可惜,默认sed不支持扩展正则表达式,需要加上-r
sed -n -r '/Python|Java/p' file
->Python
->Java
->Python is good
->Java is perfect

# '批'处理
# 如果我们有很多动作需要操作,可以直接写在文件里,使用-f选项引入动作文件即可,新建multsed.sed(不一定要.sed),内容为:
/Python/p
/Java/p

sed -n -f 'multsed.sed' file
->Python
->Java
->Python is good
->Java is perfect

sed的pattern

匹配模式 含义
10command 匹配到第10行
10,20command 匹配从第10行开始,到第20行结束
10,+5command 匹配从第10行开始,到第16行结束
/pattern1/command 匹配到pattern1行
/pattern1/,/pattern2/command 匹配到pattern1的行开始,到匹配到pattern2的行结束
10,/pattern1/command 匹配从第10行开始,到匹配到pattern1的行结束
/pattern1/,10command 匹配从匹配到pattern1的行开始,到第10行结束

示例

# 打印指定行号内容
sed -n '2p' file
->Java

# 打印起始行号到终止行号之间的信息(start不能小于1哦)
sed -n '1,3p' file
->Python
->Java
->Python is good

# 指定起始行号,打印后面n行
sed -n '1,+2p' file
->Python
->Java
->Python is good

# 打印匹配行
sed -n '/Python/p' file
->Python
->Python is good

# 打印两个匹配之间的行
sed -n '/Python/,/good/p' file
->Python
->Java
->Python is good

# 从指定起始行开始到匹配行结束
sed -n '2,/good/p' file
->Java
->Python is good

# 从匹配行开始到指定的行结束(如果匹配到的行号小于指定的结束行那就只会显示匹配行信息)
sed -n '/good/,4p' file
->Python is good
->Java is perfect

sed -n '/good/,2p' file
->Python is good

sed的命令

类别 命令 含义
增加 a 行后追加
i 行前追加
r 外部文件读入,行后追加
w 匹配行写入外部文件
删除 d 删除
修改 s/old/new 将行内第一个old替换为new
s/old/new/g 将行内全部old替换为new
s/old/new/2g 只替换第2个开始到剩下所有的old
s/old/new/ig 将行内old全部替换为new,忽略大小写
查询 p 打印
行号 = 显示行号

示例

# 在第1行后追加内容(如果需要修改文件则需要加上-i选项)
sed '1aScala' file
->Python
->Scala
->Java
->Python is good
->Java is perfect
->Php is the best lanuage

# 在匹配到的行前加上内容
sed '/Python/iHello Python' file
->Hello Python
->Python
->Java
->Hello Python
->Python is good
->Java is perfect
->Php is the best lanuage

# 读入外部文件读入(不写匹配模式则在每一行后面都追加数据)
sed 'rmultsed.sed' file
->Python
->/Python/p
->/Java/p
->Java
->/Python/p
->/Java/p
->Python is good
->/Python/p
->/Java/p
->Java is perfect
->/Python/p
->/Java/p
->Php is the best lanuage
->/Python/p
->/Java/p

# 将匹配到的行信息写入外部文件
sed '/Python/wpython.txt' file

# 将行内第一个匹配替换
sed -n 's/Python/Java/p' file
->Java Python python
->Java is good Python is good

# 将行内所有匹配替换
sed -n 's/Python/Java/gp' file
->Java Java python
->Java is good Java is good

# 将行内所有匹配替换(忽略大小写)
sed -n 's/Python/Java/igp' file
->Java Java Java
->Java is good Java is good

# 替换第3个匹配后的所有old(忽略大小写)
sed -n 's/Python/Java/3igp' file
->Python Python Java

# 显示匹配行行号
sed -n '/Python/=' file
->1
->3

# 如果pattern使用的是变量的值那么必须使用双引号,除非你也给变量标上单引号
var1=Python
sed -n '/$var1/=' file
->
sed -n "/$var1/=" file
->1
->3

sed -n '/'$var1'/=' file
->1
->3

如果pattern使用的是变量的值那么必须使用双引号,除非你也给变量标上单引号。

反向引用

      在sed中引用pattern匹配到的整个串这一行为我们称作反向引用,从下面这一例子来说明。

# 需求:将file按如下方式进行修改Python->Pythoner,Java->Javaer,Php->Phper
# 如果不知道反向引用我们就会多次使用修改命令进行修改
# 如果只是查找这几个单词倒十分简单
sed -n -r '/Python|Java|Php/p' file
# 如果需要替换则有一个难点:下面的这个新字符我们是无法给一个统一的
sed -n -r 's/Python|Java|Php/新字符er/p' file

# 借助反向引用
sed -n -r 's/Python|Java|Php/&er/p' file
->Pythoner Python python
->Javaer java
->Pythoner is good Python is good
->Javaer is perfect
->Phper is the best lanuage

# 除了使用&还可以使用\1,\2,\3等(记住括号),后者可以提取单独的某一个group
sed -n -r 's/(Python|Java|Php)/\1er/p' file
->Pythoner Python python
->Javaer java
->Pythoner is good Python is good
->Javaer is perfect
->Phper is the best lanuage

echo -e "Python Java Php" | sed -e "s/\(Python\) \(Java\) \(Php\)/\1er \2s \3best/g"
->Pythoner Javas Phpbest

小试牛刀

需求描述:处理一个类似MySQL配置文件my.cnf的文本,示例如下,编写脚本实现以下功能:输出文件有几个段,并且针对每个段可以统计参数总个数。

点我查看my.cnf

# this is read by the standalone daemon and embedded servers
[client]
port=3306
socket=/tmp/mysql.socket

#ThisSegmentForserver
[server]
innodb_buffer_pool_size=91750M
innodb_buffer_pool_instances=8
innodb_buffer_pool_load_at_startup=1
innodb_buffer_pool_dump_at_shutdown=1
innodb_data_file_path=ibdata1:1G:autoextend
innodb_flush_log_at_trx_commit=1
innodb_log_buffer_size=32M
innodb_log_file_size=2G
innodb_log_files_in_group=2
innodb_max_undo_log_size=4G
innodb_undo_directory=undolog
innodb_undo_tablespaces=95

#thisisonlyforthemysqldstandalonedaemon
[mysqld]
port=3306
socket=/tmp/mysql.sock
basedir=/usr/local/mysql
datadir=/data/mysql
pid-file=/data/mysql/mysql.pid
user=mysql
bind-address=0.0.0.0
sort_buffer_size=16M
join_buffer_size=16M
thread_cache_size=3000
interactive_timeout=600
wait_timeout=600

#ThisSegmentFormysqld_safe
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
max_connections=1000
open_files_limit=65535
thread_stack=512K
external-locking=FALSE
max_allowed_packet=32M

#thisisonlyforembeddedserver
[embedded]
gtid_mode=on
enforce_gtid_consistency=1
log_slave_updates
slave-rows-search-algorithms='INDEX_SCAN,HASH_SCAN'
binlog_format=row
binlog_checksum=1
relay_log_recovery=1
relay-log-purge=1


#usethisgroupforoptionsthatolderserversdon'tunderstand
[mysqld-5.5]
key_buffer_size=32M
read_buffer_size=8M
read_rnd_buffer_size=16M
bulk_insert_buffer_size=64M
myisam_sort_buffer_size=128M
myisam_max_sort_file_size=10G
myisam_repair_threads=1
lock_wait_timeout=3600
explicit_defaults_for_timestamp=1
innodb_file_per_table=1

点我看答案

#!/bin/bash

FILE_NAME="my.cnf"


function get_all_segment
{
    echo "`sed -n '/\[.*\]/p' $FILE_NAME | sed -r 's/(\[|\])//g'`"
}

# 统计每个段中配置项个数
function count_items_in_segment
{
    #段名
    segname=$1
    itemcount=`sed -n "/\[$segname\]/,/\[.*\]/p" $FILE_NAME | grep -v ^# | grep -v ^$ | grep -v "\[.*\]" | grep -c ""`
    echo $itemcount
}

sum=1
for segname in `get_all_segment`
do
    echo "配置项$sum:$segname `count_items_in_segment $segname`"
    sum=`expr $sum + 1`
done

剑客三

awk

      AWK是一种处理文本文件的语言,是一个强大的文本分析工具。之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。

语法格式:

stdout | awk 'BEGIN{}pattern{commands}END{}'
awk 'BEGIN{}pattern{commands}END{}' file_name

语法格式解释:

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

awk内置变量

内置变量 含义
$0 整行内容
$1~$n 当前行的第1-n个字段
NF 当前行的字段个数,也就是有多少列
NR 当前行的行号,从1开始计数
FNR 多文件处理时,每个文件行号单独计数都是从0开始
FS 输入字段分隔符,不指定则默认以空格或tab键分隔
RS 输入行分隔符,默认回车换行
OFS 输出字段分隔符,默认为空格
ORS 输出行分隔符,默认回车换行
FILENAME 当前输入的文件名字
ARGC 命令行参数个数
ARGV 命令行参数数组

示例

以下所有示例文件为/etc/passwd,请将其拷贝一份使用


# 打印整行内容
awk '{print $0}' passwd

# 使用":"号作为分隔符,输出第一个字段
awk 'BEGIN{FS=":"}{print $1}' passwd
->root
->bin
->daemon
->adm
->lp
->sync
->shutdown
->...

# 输出行号
awk '{print NR}' passwd

# 多个文件行号单独计数
awk '{print FNR}' passwd file2

# 指定行分隔符
echo "hello-world-hello-linux-hello-java" | awk 'BEGIN{RS="-"}{print $0}'
->hello
->world
->hello
->linux
->hello
->java
->

# 指定输出字段分隔符
awk 'BEGIN{FS=":";OFS=":"}{print NR,$1}' passwd
->1:root
->2:bin
->3:daemon
->4:adm
->5:lp
->...

printf格式化输出

格式符 含义
%s 打印字符串
%d 打印十进制数
%f 打印一个浮点数
%x 打印十六进制数
%o 打印八进制数
%e 打印数字的科学计数法形式
%c 打印单个字符的ASCII码
- 左对齐
+ 右对齐
# 显示8进制在前面加0,显示16进制在前面加0x

示例

# 以字符串格式打印第1个字段,以":"作为分隔符
awk 'BEGIN{FS=":"}{printf "%s\t",$1}' passwd
->root    bin    daemon    adm    lp ...

# 以字符串格式打印第1个字段和对应行号,输出格式为"行号:字段内容"
awk 'BEGIN{FS=":"}{printf "%d:%s\n",NR,$1}' passwd
->1:root
->2:bin
->3:daemon
->4:adm
->5:lp
->...

# 左对齐
# 在不指定位数的情况下默认左对齐,指定位数后为右对齐(必须指定位数)
awk 'BEGIN{FS=":"}{printf "%10d:%s\n",NR,$1}' passwd
->         1:root
->         2:bin
->         3:daemon
->         4:adm
->         5:lp
->...

awk 'BEGIN{FS=":"}{printf "%-10d:%s\n",NR,$1}' passwd
->1         :root
->2         :bin
->3         :daemon
->4         :adm
->5         :lp
->...

两种匹配模式

模式 含义
正则 按正则表达式匹配
关系运算 按关系运算匹配

关系运算符:

  • < : 小于
  • > : 大于
  • <= : 小于等于
  • >=: 大于等于
  • == : 等于
  • != : 不等于
  •  ~ : 匹配正则表达式
  • !~ : 不匹配正则表达式

布尔运算符:

  •  ||   : 或
  • && : 与
  •   !   : 非
# 匹配文件行中含有root字符串的所有行
awk 'BEGIN{FS=":"}/root/{print $0}' passwd
->root:x:0:0:root:/root:/bin/bash
->operator:x:11:0:operator:/root:/sbin/nologin

# 匹配第3个字段小于50的所有行信息
awk 'BEGIN{FS=":"}$3<50{print $0}' passwd

# 匹配文件中包含mail或ftp的所有行信息
awk 'BEGIN{FS=":"}/mail/||/ftp/{print $0}' passwd
->mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
->ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

# 匹配文件中第3个字段小于50并且第4个字段大于50的所有行信息
awk 'BEGIN{FS=":"}$3<50 && $4 > 50{print $0}' passwd
->games:x:12:100:games:/usr/games:/sbin/nologin

# 匹配文件中第3个字段小于50并且第7个字段匹配/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$3<50 && $7 ~ /\/bin\/bash/{print $0}' passwd
->root:x:0:0:root:/root:/bin/bash

awk表达式

运算符 含义
+
-
*
/
%
^或** 乘方
++x/--x 在返回x变量之前,x变量加(减)1
x++/x-- 在返回x变量之后,x变量加(减)1
# 统计空白行数目
awk '/^$/{sum++}END{print sum}' /etc/services
->17

# 统计一下学生成绩总分和平均分,报表形式展示
姓名    语文    数学    英语    物理
张三     80     60      85      90
李四     85     65      80      75
王五     70     60      85      90
李华     65     80      84      91
王八     90     90      95      90

awk 'BEGIN{printf "%-8s%-5s%-5s%-5s%-5s%-5s%-8s\n","姓名","语文","数学","英语","物理","总分","平均分"}{total=$2+$3+$4+$5;avg=total/4;printf "%-8s%-8d%-6d%-8d%-7d%-5d%0.2f\n",$1,$2,$3,$4,$5,total,avg}' stu.txt

姓名      语文   数学   英语   物理   总分   平均分     
张三      80      60    85      90     315  78.75
李四      85      65    80      75     305  76.25
王五      70      60    85      90     305  76.25
李华      65      80    84      91     320  80.00
王八      90      90    95      90     365  91.25

条件语句和循环语句

# 条件语句
if (条件表达式1){
    action1
}else if (条件表达式2){
    action2
}else{
    action3
}

# 以":"为分隔符,如果第3个字段小于50,打印小于50,如果等于50则打印等于50,否则打印大于50
awk 'BEGIN{FS=":"}{if($3<50){print "小于50" }else if($3==50){ print "等于50"}else{print "大于50"}}' passwd

# 我们可以将命令保存在一个文件(eg:oper.awk,后缀不硬性要求哦!)中使用-f选项引入
awk -f oper.awk passwd

# 循环语句 while
while(条件表达式){
    action
}

# 循环语句 do while
do{
    action
}while(条件表达式)

# 循环语句 for
for(初始化计数器;测试计数器;变更计数器){
    action
}

# 计算1+2+3+...+100的和。
awk 'BEGIN{do{i++;sum+=i;}while(i<100)print sum}'
awk 'BEGIN{while(i<100){i++;sum+=i;}print sum}'
awk 'BEGIN{for(i=0;i<=100;i++){sum+=i;}print sum}'

字符串函数

函数名 含义 函数返回值
length(str) 计算字符串长度 整数长度值
index(str1,str2) 在str1中查找str2的位置 位置索引,从1计数
tolower(str) 转换为小写 转换后的小写字符串
toupper(str) 转换为大写 转换后的大写字符串
substr(str,m,n) 从str的m个字符开始,截取n位 截取后的子串
split(str,arr,fs) 按fs切割字符串,结果保存在arr中 切割后的子串个数
match(str,RE) 在str中按照RE查找,返回位置 返回索引位置
sub(RE,RepStr,str) 在str中搜索符合RE的子串,将其替换为RepStr,只替换第一个 替换的个数
gsub(RE,RepStr,str) 在str中搜索符合RE的子串,将其替换为RepStr,替换所有 替换的个数

示例

# 以:为分隔符,返回文件每行中每个字段的长度
awk 'BEGIN{FS=":"}{for(i=1;i<=NF;i++){if(i==NF){printf "%d",length($i)}else{printf "%d:",length($i)}}print ""}' passwd

# 搜索字符串"I am a student"中student子串的位置
echo "I am a student" | awk '{print index($0,"student")}'
->8

awk常用选项

选项 含义
-v 参数传递
-f 指定脚本文件
-F 指定分隔符
-V 查看awk版本号
# 使用-v引用外部变量
num1=100
num2=200
awk -v var1="$num1" -v var2="$num2" 'BEGIN{print var1+var2}'

数组

      awk中数组(数组学习看这里)使用小括号包围起来,每一项之间使用空格分隔,如:arr=("one" "two" "three" "four" "five").在awk中数组下标从1开始,需要注意哦~
      awk可以使用关联数组这种数据结构,索引可以是数字或字符串。awk关联数 组也不需要提前声明其大小,因为它在运行时可以自动的增大或减小。

# 统计主机上所有的TCP,按照TCP状态进行分类
netstat -an | grep tcp | awk '{array[$6]++}END{for(item in array){print item,array[item]}}'
->LISTEN 8
->ESTABLISHED 26
Last modification:May 21st, 2020 at 05:45 pm
如果觉得我的文章对你有用,请随意赞赏