Linux文本三剑客

情到浓时终转凉″ 提交于 2019-12-04 11:26:04
```bash [root@CodeSheep ~]# ll /usr/bin/awk lrwxrwxrwx. 1 root root 4 Feb 15 2019 /usr/bin/awk -> gawk ``` ## 关于"三剑客"的特长 - grep 更适合单纯的查找和匹配文本 - sed 更适合编辑匹配的文本 - awk 更适合格式化文本,对文本进行较复杂格式处理 ## awk基础 **语法** awk [options] '{pattern + action}' {filenames} 其中的action 我们最常用的就是print以及prinf,对于action来说,每次经过一行,都会当前行执行一边action 比如 ```bash awk '{print "1",NR}' /etc/passwd ``` 你会发现有多少行,他就输出了多少个1 每行一个 ## awk的工作流程 首先awk并不是列操作,而是行操作,同样的他也是一行一行的处理的,其中$0表示当前行,比如在正常情况下我们输出全文是用cat来查看的,那么用awk的操作是这样的,另外awk的接受标准输入和文件 ```bash cat /etc/passwd awk '{print $0}' /etc/passwd # 如上的内容是一样的 ``` ## awk中的分隔符 为了处理好每一行中的每一个字段,awk引入了分隔符的概念,分隔符有三种表现的形式, 一种是不输入任何不指定任何,则默认为空格 一种是自定义的分隔符 使用 -F 指定 比如 -F: 另外一种是使用 内置变量指定 -v FS='#' **自定义分隔符** 既然默认的分隔符是空格,那么当然还有自定义的分隔符咯。我们使用-F选项来指定我们的分隔符 ```bash # 使用#分隔符 [root@CodeSheep ~]# cat demo3.text 123#123#dsdshj#dlsj# [root@CodeSheep ~]# awk -F# '{print $1}' demo3.text 123 [root@CodeSheep ~]# cat demo3.text 123#123#dsdshj#dlsj# [root@CodeSheep ~]# awk -v FS='#' '{print $1}' demo3.text 123 ``` 其实在awk中不仅仅有输入的分割符,还有输出的分隔符,默认也为空格 ```bash [root@CodeSheep ~]# awk -F# '{print $1,$2}' demo3.text 123 123 ``` OFS(output field separator)可以指定输出的分隔符,用法与FS相同 ```bash [root@CodeSheep ~]# awk -v FS='#' -v OFS='++++' '{print $1,$2}' demo3.text 123++++123 ``` ## awk的内建变量 awk支持内建变量和自定义变量 **内建变量** - $0 当前行 - $1~$n 第n个字段 - $NF 最后一个字段 - NF 当前行被分割字段总数 - NR 当前行行号 - FNR 各文件分别计数的行号 - FS 输入分隔符 - OFS 输出分隔符 - RS 输入换行符 - ORS 输出换行符 - FILENAME 当前文件名 - ARGC 命令行参数的个数 - ARGV 数组,保存的命令行所给定的各参数 ```bash # 给每一行添加行号,输出当前行号,以及当前行的内容 [root@CodeSheep ~]# df | awk '{print NR,$0}' 1 Filesystem 1K-blocks Used Available Use% Mounted on 2 /dev/vda1 41147472 6848400 32395580 18% / 3 devtmpfs 930656 0 930656 0% /dev 4 tmpfs 941116 0 941116 0% /dev/shm 5 tmpfs 941116 452 940664 1% /run 6 tmpfs 941116 0 941116 0% /sys/fs/cgroup 7 tmpfs 188224 0 188224 0% /run/user/0 # 多个文件使用NR时,会根据的文件顺序累加序号 # FNR则会分开标序 # ARGV,ARGC [root@CodeSheep ~]# awk 'BEGIN{print ARGV[0],ARGV[1],ARGV[2],ARGC}' demo1.txt demo2.text awk demo1.txt demo2.text 3 # 其中ARGV作为数组,第一个参数是awk ``` **自定义变量名** 自定义变量的两种形式,一种是在action外面 使用选项指定变量,比如 -v name="hzj" 另外一种则是在action前的pattern中定义,比如 {name="hzj"; action->print name} ```bash [root@CodeSheep ~]# awk -v name="hzj" 'BEGIN{print name}' hzj [root@CodeSheep ~]# awk 'BEGIN{name="hzj";print name}' hzj [root@CodeSheep ~]# name=hzj [root@CodeSheep ~]# awk -v name=$name 'BEGIN{print name}' hzj ``` ## awk 参数 ### options -v name="xx" -v外部定义变量 ### pattern+action **抛开Pattern 我们先来使用{action}** ```bash # 输出文本内容 [root@CodeSheep ~]# df Filesystem 1K-blocks Used Available Use% Mounted on /dev/vda1 41147472 6848500 32395480 18% / devtmpfs 930656 0 930656 0% /dev tmpfs 941116 0 941116 0% /dev/shm tmpfs 941116 452 940664 1% /run tmpfs 941116 0 941116 0% /sys/fs/cgroup tmpfs 188224 0 188224 0% /run/user/0 [root@CodeSheep ~]# df | awk '{print $1}' Filesystem /dev/vda1 devtmpfs tmpfs tmpfs tmpfs tmpfs ``` awk是逐行处理的,也就是说当awk处理一个文本的时候,他会一行一行的处理内容。其中awk默认以 换行符 为标记识别每一行。另外对于每一行的处理中 awk会按照用户指定的 分隔符 去分隔当前行,如果没有指定,则默认使用空格作为分隔符,当出现多个空格的时候,awk会自动将连续的空格理解成为一个分隔符。 其中 我们将被awk处理后的每一行都使用了特定的变量标记 $0表示当前处理的整行 $1表示第一个字段 $2表示第二个字段 $NF表示最后一个字段 NF表示当前行被分割后字段总数 因此 假设一行文本被空格分为8段,则$NF表示$8 NF=8 则$7=$(NF-1) ```bash # 输出多行 [root@CodeSheep ~]# df | awk '{print $1 $2 $3}' Filesystem1K-blocksUsed /dev/vda1411474726848536 devtmpfs9306560 tmpfs9411160 tmpfs941116452 tmpfs9411160 tmpfs1882240 [root@CodeSheep ~]# df | awk '{print $1, $2 ,$3}' Filesystem 1K-blocks Used /dev/vda1 41147472 6848536 devtmpfs 930656 0 tmpfs 941116 0 tmpfs 941116 452 tmpfs 941116 0 tmpfs 188224 0 # 自己添加字段 [root@CodeSheep ~]# df | awk '{print $1 ,"this print test"}' Filesystem this print test /dev/vda1 this print test devtmpfs this print test tmpfs this print test tmpfs this print test tmpfs this print test tmpfs this print test [root@CodeSheep ~]# df | awk '{print "$1="$1 , "testfield:""this print test"}' $1=Filesystem testfield:this print test $1=/dev/vda1 testfield:this print test $1=devtmpfs testfield:this print test $1=tmpfs testfield:this print test $1=tmpfs testfield:this print test $1=tmpfs testfield:this print test $1=tmpfs testfield:this print test #看上面的案例我们可以发现,当$1被双引号包裹的时候,他就是一个字符串,不再是变量 ``` awk中的Pattern 其实action的主要操作就是print输出,简单来用就是输出内容,更复杂的就是对输出的内容进行格式化的操作。而Pattern所存在的两种模式,愈加加强了awk的能力。 ## awk中的逻辑· 为了更好的格式化,awk中也带有逻辑参数,其中包括开始BEGIN和结尾END,他们之间用{}分隔,比如 ```bash awk -v test="test" 'BEGIN{print "1",NR}{print test}END{print "input end" }' /etc/passwd ``` 你会发现他输出了很多个test,首先begin进入,然后输出1和行号0 紧接着不断的进入行输出test 在最后一行输入时 执行input end **特殊模式下的BEGIN与END** - BEGIN 模式指定了处理文本之前需要执行的操作 - END 模式指定了处理完所有行之后所需要执行的操作 ```bash [root@CodeSheep ~]# df | awk 'BEGIN{print "$1","$2"}' $1 $2 [root@CodeSheep ~]# df | awk 'BEGIN{print "$1","$2"} {print $1,$2}' $1 $2 Filesystem 1K-blocks /dev/vda1 41147472 devtmpfs 930656 tmpfs 941116 tmpfs 941116 tmpfs 941116 tmpfs 188224 [root@CodeSheep ~]# df | awk 'BEGIN{print "$1","$2"} {print $1,$2} END{print "end for file"}' $1 $2 Filesystem 1K-blocks /dev/vda1 41147472 devtmpfs 930656 tmpfs 941116 tmpfs 941116 tmpfs 941116 tmpfs 188224 end for file ``` 在BEGIN的模式下,首先awk会执行BEGIN中的action 之后才做去执行其他的action,同理,在执行完所有的action之后,awk回去执行END模式下面的action。需要注意的是两个特殊的模式BEGIN以及END都需要大写 于是 awk的格式化能力表露无疑了,提取字段再加上BEGIN与END的两种特殊模式,一张完整的表不就出来了嘛 、 ### awk的格式化 在了解awk的格式化之前 ### 聊一聊awk的Pattern模式 在之前我们已经了解了两个特殊的模式BEGIN 和 END,接下里我们说一说普通模式 awk解析文本的大致流程为: 1.接受文本后逐行处理 2.把当前的pattern模式当成条件去匹配当前行,如果匹配成功,则处理当前行,如果不成功,则不处理. 3.执行下一行 ```bash [root@CodeSheep ~]# cat demo4.txt aaa bbb ccc ddd eee qqq ccc ddd zzz qqq fff [root@CodeSheep ~]# awk 'NF==4{print $0}' demo4.txt bbb ccc ddd eee ddd zzz qqq fff ``` **关系运算符** ```text = 大于等于 x>=y > 大于 x>y ~ 正则匹配 x ~ /正则/ !~ 正则不匹配 x !~ /正则/ ``` ### awk中的正则模式 既然上面的关系运算符中出现了正则,那我们就来讲一讲正则模式 需要注意的是 当使用{x,y}这种次数匹配的正则表达式时,需要配合--posix选项或者--re-interval选项 ```bash # 匹配/etc/passwd 中以 tss开头的行 [root@CodeSheep ~]# cat /etc/passwd | awk '/tss/{print $0}' tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin # 匹配/etc/passwd 中以 /bin/bash结尾的行 [root@CodeSheep ~]# cat /etc/passwd | awk '/\/bin\/bash$/{print $0}' root:x:0:0:root:/root:/bin/bash # 匹配/etc/passwd 中以/bin/bash结尾的行 到以 tss开头的行 [root@CodeSheep ~]# cat /etc/passwd | awk '/\/bin\/bash$/,/^tss/{print $0}' root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:99:99:Nobody:/:/sbin/nologin systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin polkitd:x:999:998:User for polkitd:/:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin postfix:x:89:89::/var/spool/postfix:/sbin/nologin chrony:x:998:996::/var/lib/chrony:/sbin/nologin ntp:x:38:38::/etc/ntp:/sbin/nologin tcpdump:x:72:72::/:/sbin/nologin nscd:x:28:28:NSCD Daemon:/:/sbin/nologin mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/false dockerroot:x:997:994:Docker User:/var/lib/docker:/sbin/nologin tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin # 匹配行号大于2 且小于6的行 [root@CodeSheep ~]# cat /etc/passwd | awk 'NR>2 && NR https://www.baidu.com echo '${url}' -------> ${url} 将命令结果附给变量 var=`command` var=$(command) 将文件log.txt附加给log echo $`cat log.txt` echo $(cat log.txt) 只读变量 url="https://wwww.baidu.com" readonly url 删除变量 url="https://www.baidu.com" unset url 获取变量长度 url="https://www.baidu.com" echo {#url} 字符串截取 ${string:start:length} 截取位置2到位置9的内容 url="https://www.baidu.com" echo ${url:2:9} 截取位置2到末尾的内容 echo ${url:2} ``` ### shell脚本的数组 ``` 用()表示数组 array=(array1,array2,array3...) 获取数组内容 ${array1[1]} 获取所有内容 ${array1[*]} 或者 ${array1[@]} 无需逐个元素地给数组赋值,下面的代码就是只给特定元素赋值 args=([3]=23 [5]=19 [10]=12) 删除数组元素 unset nums[1] ``` ### shell脚本的基本指令 let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。 ```tex 自加操作:let a++ 自减操作:let c-- 递加操作:let num+=10 递减操作:let num-=10 ``` -------------- declare为shell指令,在第一种语法中可用来声明变量并设置变量的属性([rix]即为变量的属性),在第二种语法中可用来显示shell函数。若不加上任何参数,则会显示全部的shell变量与函数(与执行set指令的效果相同)。 语法: declare [+/-][rix][变量名称=设置值] - +/- 可以用来设定变量的属性 + 取消属性 -附加属性 - [rix] r 将变量设置为只读 i[设置值]可以是数值 字符串 或者运算式 x 指定变量会成为环境变量,可供shell以外的程序来使用 shell编成中在定义变量的时候,=附近不能出现空格。 ```tex 用declare定义变量 declare -i name_index1="小明" 定义变量 name_index2="小红" echo $name_index2 echo $name_index1 echo ${name_index1}is studying 加{}可以作为区分其他字符的边界 ``` ----------------- read从键盘读取变量的值,该命令可以一次读取多个变量的值,但是变量和输入的值都需要使用空格隔开。如果read后面没有指定的变量名,则自动复制给变量REPLY 语法: read(选项)(参数) -p 指定数值时的提示符 -t 指定读取值时等待的时间 -a 读取内容到数组中,元素之间用空格隔开 -r 允许包含反斜杠 -d 指定符号结束输入 -s 输入时不现实内容 ```tex 读取并赋值给 xx read xx 读取内容到数组中 read -a array 输出数组中的内容 echo ${array[0]},${array[1]} 输入前给出提示 read -p "test" xx 输入等待时间3s read -t 3 xx 指定 ";" 结束输入 read -d ";" var ``` ---------------------------------------------------------------- ### shell脚本之while循环 ```tex 多行 while 条件;do 循环体 done 单行 while 条件;do 循环体;done ``` **常用方法** ```tex 无限循环输出累加 num=1;while ((1));do let num+=1; echo $num;done 计算1到10的和 #!/bin/bash declare a=1 declare sum=0 while ((a
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!