0
点赞
收藏
分享

微信扫一扫

cut、awk、sed

悄然丝语 2022-02-07 阅读 25

正则表达式

  • BRE:POSIX基础正则表达式
  • ERE:POSIX扩展正则表达式
  • BRE模式
    • 行首 ^
    • 行尾 $
    • 点号字符:匹配除换行符之外的任意单个字符
    • 字符组:中括号[1bdfhg]
    • 排他型字符组:[^ab] 除ab字符外的任意字符
    • 区间:[a-ch-m],a-c和h-m区间内的字符
    • 特殊字符组
      • [[:alpha:]] 任意字母字符,包含大小写
      • [[:alnum:]] 0-9 A-Z a-z
      • [[:blank:]] 空格和制表符
      • [[:digit:]] 0-9
      • [[:lower:]] a-z
      • [[:upper:]] A-Z
      • [[:print:]] 任意可打印字符
      • [[:punct:]] 标点符号
      • [[:space:]] 任意空白字符:空格 制表符 NL FF VT CR
    • 星号:匹配模式出现0次到多次
  • ERE模式
    • 加号 + 至少出现一次
    • 问号 ? 最多出现一次
    • 花括号 {m}:出现m次 {m,n}:出现m到n次
    • 管道符号:或 /cat|dog/
    • 表达式分组:小括号,当使用此模式时,改组会被视为一个标准字符

cut

  • 选项
    • b 按字节分割
    • c 按字符分割
    • d 指定分割符
    • f 指定字段,与d搭配
    • n 不要分割多字符
who | cut -b 1-10,20-

# 返回:分割的1和3列
cut -d : -f 1,3 /etc/passwd

echo "我这一下下你怕是要嘤嘤嘤"|cut -c 3-5 # 一下下

# 乱码
echo "我这一下下你怕是要嘤嘤嘤"|cut -b 3-5

echo "我这一下下你怕是要嘤嘤嘤"|cut -n -b 3-5 # 一下下

awk gawk

  • 使用
BEGIN{...}
{...}
END{...}
  • 用途
    • 定义变量来保存数据
    • 使用算术和字符串操作符来处理数据
    • 使用结构化编程概念(if-then等)来为数据增加处理逻辑
    • 通过提取数据文件中的数据元素,将其重新格式化或排列,生成格式化报告
  • awk options program file
  • 选项
    • F 指定分割符
    • f file 从指定文件读取程序
  • 内建变量
    • FIELDWIDTHS 由空格分割的一串数字,定义了每个数据字段确切宽度
    • FS 输入字段分割符
    • RS 输入记录分割符
    • OFS 输出字段分割符
    • ORS 输出记录分割符
    • ARGC 命令行参数,awk脚本不算参数
    • ARGV 参数数组
    • ARGIND 当前文件在ARGV的位置
    • FNR 当前数据文件中已处理的输入记录数
    • NR 已处理的输入记录数
    • NF 数据文件的字段总数
  • 自定义变量
#script.awk
BEGIN{print "The starting value is",n; FS=","}
{print $n}
# 自定义变量使用-v来指定,这样BEGIN里变量才生效。如果使用 awk -f script.awk n=3 data1,则n变量在BEGIN不生效
awk -v n=3 -f script.awk data1
  • 处理数组
BEGIN{
     # 定义数组变量
     city["bj"]="BeiJing"
     city["sh"]="ShangHai"
     city["cq"]="ChongQing"

     # 遍历
     for(var in city){
          print "index:",var," - value:",city[var]
     }
     # 删除
     delete city["bj"]
     for(var in city){
          print "index:",var," - value:",city[var]
     }
}
  • 使用模式,匹配操作符(~)
# 找到匹配模式 111 的行,打印第一列数据
awk '/111/{print $1}' data.txt
# 第一列数据匹配模式/111/的打印整行
awk '$1 ~ /111/{print $0}' data.txt
# 第一列数据不匹配模式/111/的打印整行
awk '$1 !~ /111/{print $0}' data.txt
# 使用表达式,可使用的符号有==,<=,<,>=,>
awk '$4==0{print $1}' /etc/passwd
  • 结构化命令
# if( condition ){ statement } else { statement }
awk '{if($1>20) {print $1}}' data.txt
# while( condition ){ statement }
echo -e "1 2 3\n4 5 6\n7 8 9"|awk '{
     total = 0
     i = 1
     while( i<4 ){
          total += $i
          i++
     }
     avg = total / 3
     print "Average:",avg
}' 
# do{ statement } while( condition )
# for(i=1;i<100;i++){statement}
  • 格式化打印:printf ,%[修饰字符]控制字符
    • 控制字符
      • c 字符
      • d(i) 数字
      • e 科学计数法
      • f 浮点数
      • g 科学计数或浮点数显示(自动选择较短的格式)
      • o 八进制
      • s 字符串
      • x 十六进制 %#x
      • X 十六进制,但是使用大写的A~F, %#X
    • 修饰字符,[± #0][width].[prec]
      • width:指定了输出字段的最小宽度的数字值。如果输出短于这个值,printf会将文本右对齐,并用空格进行填充。如果输出的长度大于指定宽度字符,则按实际输出
      • prec:这是一个数字值,指定了浮点数中小数点后面的位数,或者文本字符串中显示的最大字符数
      • -(减号)左对齐
# 左对齐输出16进制数 带0X前缀
%#-10X
%10.2f
# 格式化输出
awk -F: '{printf "%-20s %s\n",$1,$7}' /etc/passwd
  • 内建函数
    • 数学函数
      • cos(x) sin(x)
      • log(x) x的自然对数
      • sqrt(x) x的平方根
      • exp(x) x的指数函数 e^x
      • int(x) x的取整
      • rand() 返回0-1之间的浮点数
      • srand(x) 为计算随机数指定一个种子值
      • and(v1,v2) 按位与运算
      • compl(v1) 补运算
      • lshift(v1,count) 向左移count位
      • or(v1,v2) 按位或
      • xor(v1,v2) 按位异或
      • rshift(v1,count)
    • 字符串函数
      • asort(s[,d]):将数组s按数据元素排序。索引值会被替换为新的排序顺序的连续数字,另外,如果指定了d,则排序后数组会存储在数组d中
      • asorti(s[,d]):将数组s按索引值排序。生成的数组会将索引值作为数据元素值,用连续数字索引来表明排序顺序,另外,如果指定了d,则排序后数组会存储在数组d中
      • gensub(r, s, h [,t]) 查找变量$0或字符串t来匹配正则表达式r。如果h是一个以g或G开头的字符串,就用s替换掉匹配的文本。如果h是一个数字,它表示要替换掉第h处匹配r的地方。返回值为替换后的文本,$0变量不会改变
      • gsub(r, s [,t]) 查找变量$0或字符串t来匹配正则表达式r。如果找到了,就用s替换掉匹配的文本。返回替换的次数,$0会被替换
      • index(s, t) 返回字符串t在字符串s中的索引值,如果没找到返回0,索引值从1开始
      • length([t]) 返回字符串t的长度,如果没有指定,则返回$0的长度
      • match(s, r [,a]) 返回字符串s中正则表达式r出现位置的索引,如果指定了数组a,它会存储s中匹配正则表达式的那部分
      • split(s, a [,r]) 将s用FS字符或正则表达式r(如果指定)分开到数组a中,返回字段的总数
      • sprintf(format,variables) 返回一个printf格式字符串
      • sub(r, s [,t]) 在变量$0或目标字符串t中查找正则表达式r的匹配。如果找到了,就用字符串s替换掉第一处匹配
      • substr(s, i [,n]) 截取字符串[i:n]
      • tolower(s) 小写转换
      • touppeer(s) 大写转换
    • 时间函数
      • mktime(datespec) 将YYYY MM DD HH MM SS[DST]格式指定日期转换为时间戳值
      • strftime(format [,timestamp]), 采用shell date()函数的格式,不提供采用当前时间戳
      • systime() 返回当前系统时间戳
awk -F: '{ $0=gensub("root","replace_root","g");print $0}' /etc/passwd|head -5
awk -F: '{ gsub("root","replace_root");print $0}' /etc/passwd|head -5

awk 'BEGIN{ print index("junmocsq","csq")}' # 6
  • 自定义函数,需要出现的所有块之前,包含BEGIN块 function myfunc([variables]){ statements }

sed

  • sed options function file

  • 处理数据流程

    • 一次从输入读取一行数据
    • 根据所提供的编辑器命令匹配数据
    • 按照命令修改流中的数据
    • 将新的数据输出到STDOUT
  • 选项

    • n 安静模式,只有经过处理的行才会被列出来,默认sed是展示所有行的
    • e 直接在命名行编辑,执行多个命令时用分号隔开。sed -e ‘s/root/jroot/g; s/bin/jbin/g’ passwd
    • f 直接将sed操作写在文件里,-f filename直接执行filename里的sed操作
    • r 扩展型正则语法
    • i 直接修改读取的文件内容
  • function

    • a 新增:在指定的行数下一行添加指定字符串(下一行)
    [work@VM-16-2-centos ~]$  head -5 passwd |nl|sed  '1,3ajunmo'
         1	root:x:0:0:root:/root:/bin/bash
    junmo
         2	bin:x:1:1:bin:/bin:/sbin/nologin
    junmo
         3	daemon:x:2:2:daemon:/sbin:/sbin/nologin
    junmo
         4	adm:x:3:4:adm:/var/adm:/sbin/nologin
         5	lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    
    • c 替换:替换行数为指定字符串
    [work@VM-16-2-centos ~]$ head -5 passwd |nl|sed  '1,3c\'
         4	adm:x:3:4:adm:/var/adm:/sbin/nologin
         5	lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    [work@VM-16-2-centos ~]$  head -5 passwd |nl|sed  '1,3cjunmo'
    junmo
         4	adm:x:3:4:adm:/var/adm:/sbin/nologin
         5	lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    
    • d 删除:删除指定行数
    $  head -5 passwd |nl|sed  '1,3d'
         4  adm:x:3:4:adm:/var/adm:/sbin/nologin
         5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    
     # 删除模式/1/ 和 模式/3/ 区间之内的行
     $ sed '/1/,/3/d' test.txt
    
    
    • i 插入:在指定的行数上一行添加指定字符串(上一行)
    [work@VM-16-2-centos ~]$  head -5 passwd |nl|sed  '1,3ijunmo'
    junmo
         1	root:x:0:0:root:/root:/bin/bash
    junmo
         2	bin:x:1:1:bin:/bin:/sbin/nologin
    junmo
         3	daemon:x:2:2:daemon:/sbin:/sbin/nologin
         4	adm:x:3:4:adm:/var/adm:/sbin/nologin
         5	lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    
    • p 打印
    • = 打印行号
    • l (小写L)列出不可打印的ASCII字符
    $ head -5 passwd|sed -n '=;l;y/123/789/'
     1
     root:x:0:0:root:/root:/bin/bash$
     2
     bin:x:1:1:bin:/bin:/sbin/nologin$
     3
     daemon:x:2:2:daemon:/sbin:/sbin/nologin$
     4
     adm:x:3:4:adm:/var/adm:/sbin/nologin$
     5
     lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin$
    
    • s 替换:采用正则替换
    [work@VM-16-2-centos ~]$  head -5 passwd |nl|sed  '1,3s/bin/junmo/g'
         1  root:x:0:0:root:/root:/junmo/bash
         2  junmo:x:1:1:junmo:/junmo:/sjunmo/nologin
         3  daemon:x:2:2:daemon:/sjunmo:/sjunmo/nologin
         4  adm:x:3:4:adm:/var/adm:/sbin/nologin
         5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    
    • c 修改整行
    # 匹配到adm的行替换为 字符串test abc
    $ head -5 passwd |nl |sed '/adm/c test abc'
          1  root:x:0:0:root:/root:/junmo/bash
          2  junmo:x:1:1:junmo:/junmo:/sjunmo/nologin
          3  daemon:x:2:2:daemon:/sjunmo:/sjunmo/nologin
     test abc
          5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    
    • y 转换命令:处理单个字符
    # 把1 2 3 分别替换为4 5 6
    $ sed 'y/123/789/' passwd 
     root:x:0:0:root:/root:/bin/bash
     bin:x:7:7:bin:/bin:/sbin/nologin
     daemon:x:8:8:daemon:/sbin:/sbin/nologin
     adm:x:9:4:adm:/var/adm:/sbin/nologin
     lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    
    • w 写入文件:[address]w filename
    • r 从文件读取数据:[address]r filename,从文件读取数据,添加到address之后。address只支持单个行号或文本模式地址
    sed '1,3w passwd.test' passwd
    sed '1r /etc/passwd' passwd
    
  • 原地编辑内容保存

[work@VM-16-2-centos ~]$ head -3 passwd
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
# 1-2行替换bin,并修改文件
[work@VM-16-2-centos ~]$ sed -i '1,2s/bin/--zl--/g' passwd
[work@VM-16-2-centos ~]$ head -3 passwd
     1  root:x:0:0:root:/root:/--zl--/bash
     2  --zl--:x:1:1:--zl--:/--zl--:/s--zl--/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
[work@VM-16-2-centos ~]$ 
  • 新增多行 用\分开
[work@VM-16-2-centos ~]$ head -5 passwd|sed -e '1,3a junmo\
csq\
kk'
     1  root:x:0:0:root:/root:/bin/bash
junmo
csq
kk
     2  bin:x:1:1:bin:/bin:/sbin/nologin
junmo
csq
kk
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
junmo
csq
kk
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[work@VM-16-2-centos ~]$ 
  • 正则替换
[work@VM-16-2-centos ~]$ ifconfig eth0|grep 'inet '
        inet 172.17.16.2  netmask 255.255.240.0  broadcast 172.17.31.255

[work@VM-16-2-centos ~]$ ifconfig eth0|grep 'inet '|sed -r 's/.*inet +//g'
172.17.16.2  netmask 255.255.240.0  broadcast 172.17.31.255

[work@VM-16-2-centos ~]$ ifconfig eth0|grep 'inet '|sed -r 's/.*inet +//g'|sed -r 's/ +netmask.*//g'
172.17.16.2

sed高级用法

  • 多行命令
    • N:将数据流中的下一行加进来创建一个多行组来处理
    • D:删除多行组中的一行
    • P:打印多行组中的一行
# 合并两个行:sed命令会查找单词first的那行,找到之后,它会将下一行和并到那行,然后用替换命令s将换行符替换成空格
sed '/first/{N ; s/\n/ /}' data.txt
  • 模式空间(pattern space):是一块活跃的缓冲区,在sed编辑器执行命令时它会保存检查的文本。
    • n 将模式空间文本移动到下一行
  • 保持空间(hold space):sed编辑器在处理某些行的时候。可以用来临时保存一些行
    • h 将模式空间复制到保持空间
    • H 将模式空间附加到保持空间
    • g 将保持空间复制到模式空间
    • G 将保持空间附加到模式空间
    • x 交换模式空间和保持空间的内容
  • 排除命令:感叹号
# 除了header那一行,其他的都打印出来
sed -n '/header/!p' data.txt
  • 反转文本(tac也可以):sed -n ‘{1!G; h ; $p}’ data.txt
    • 1.在模式空间中放置一行
    • 2.将模式空间中的行放到保持空间中
    • 3.在模式空间中放入下一行
    • 4.将保持空间附加到模式空间后
    • 5.将模式空间中的所有内容都放到保持空间
    • 6.重复执行3-5步,直到所有行都反序到了保持空间
    • 7.提取并打印行
  • 改变流
    • 分支branch:[address]b [label],根据地址跳转到标签
    # 第2,3行跳过后两个替换命令
    sed '{2,3b ; s/test/TEST/; s/abc/ABC/}' data.txt
    
    # 匹配到first的行跳转到第二个替换命令,没有匹配的使用第一个替换命令
    sed '{/first/ b jump1; s/test/no jump/; :jump1 s/test/jump/}' data.txt
    
    # 下面两个脚本都是循环替换逗号,但是第一个脚本有问题,会一直查找逗号,直到CTRL+C发送信号停止
    echo "This , is , a, test, to, remove, commas."|sed -n '{:start;s/,//1p;b start}'
    echo "This , is , a, test, to, remove, commas."|sed -n '{:start;s/,//1p;/,/b start}'
    
    • 测试test:[address]t [label],如果成功匹配并替换一个模式,测试命令就会跳转到指定的标签
    # 第一个匹配模式不成功则使用第二个模式匹配
    sed '{s/first/matched/ ;t ; s/This is the/No match on/}' data.txt
    # 模式匹配成功则继续循环执行
    echo "This , is , a, test, to, remove, commas."|sed -n '{:start ;s/,//1p;t start}'
    
  • 模式替代
    • &符号:代表替换命令中匹配的模式
    • 替代单独的单词:子模式,\1 \2 代替第一 第二个子模式,
    # the "cat" sleeps in his "hat".
    echo "the cat sleeps in his hat."|sed 's/.at/"&"/g'
    
    # That cat is pretty
    echo "That furry cat is pretty"|sed 's/furry \(.at\)/\1/'
    
    # 大数字之间插入逗号 1,234,567,890
    echo "1234567890"|sed '{:start; s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/; t start}'
    
  • 使用例子
# 加倍行间距,每一行将保持空间附加到模式空间
sed 'G' data.txt
# 加倍行间距,尾行不加倍
sed '$!G' data.txt
# 对可能含有空白行的文件加倍行间距
sed '/^$/d; $!G' data.txt
# 给文件加行编号nl和cat -n也有此功能
sed '=' data1.txt|sed 'N;s/\n/ /'
# 打印最后10行文件,$q如果文件为尾行,退出;N 否则,把下一行加入模式空间;11,$D,如果当前行在10行之后,则删除模式空间第一行
sed '{:start ; $q; N; 11,$D; b start}' data.txt
tail -10 data.txt
# 删除连续的空白行,当存在数据的一行和空白行连续时不删除,多余的空白行则删除
sed '/./,/^$/!d' data.txt
# 删除开头的空白行
sed '/./,$!d' data.txt
# 删除结尾的空白行
sed '{:start; /^\n*$/{$d ; N ; b start}}' data.txt
# 删除html标签
sed 's/<[^>]*>//g; /^$/d' data.txt
举报

相关推荐

0 条评论