本次分享的Shell指令主要包含两个核心的指令:
SED指令AWK指令 Shell分享一 SED指令 基本格式行寻址基本命令保持空间 AWK指令 程序结构 BEGIN 语句块BODY 语句块END 语句块基本语法 AWK命令行执行AWK程序文件 AWK基本使用示例 -v 变量赋值选项统计匹配模式的行数打印所有匹配模式的行打印某列或者字段 内建变量 ARGC命令行参数的个数FILENAME当前的文件名NR行号NF字段数目0代表当前行n表示当前行中的第n个字段 操作符 算数操作符增减操作符赋值操作符逻辑操作符字符串链接操作符 数组流程控制 条件判断循环 执行shell命令SED是流编辑器(stream editor)的缩写,它的工作流程一般包括为读取、执行和显示。 读取:SED从输入流(标准输入、管道或者文件)中读取一行并且存储到一个叫做模式空间的(pattern buffer)的内存缓冲区。 执行:一般的情况下,SED命令在模式空间中顺序执行,除非我们指定行的地址,否则SED会一条一条的执行。 显示:发送修改后的内容到输出流,当数据发送之后,模式空间的内容会被清空。 上述的过程在文件所有内容处理完成之前,会重复的执行。
注意点: - 模式空间(pattern buffer)是一块活跃的缓冲区,在SED编辑器执行命令时它会保存待检查的文本。 - 默认情况下,所有的SED命令都是在模式空间中执行,因此输入文件并不会发生改变。 - 还有另外一个缓冲区叫做保持空间(hold buffer),在处理模式空间中的某些行时,可以用保持空间来临时保存一些行。在每一个循环结束的时候,SED将会移除模式空间中的内容,但是该缓冲区中的内容在所有的循环过程中是持久存储的。SED命令无法直接在该缓冲区中执行,因此SED允许数据在 保持空间 和 模式空间之间切换。 - 初始情况下,保持空间 和 模式空间 这两个缓冲区都是空的。 - 如果没有提供输入文件的话,SED将会从标准输入接收请求。 - 如果没有提供地址范围的话,默认情况下SED将会对所有的行进行操作。
SED [option][filename] 选项: - * -i: 直接修改读取的文件内容,而不输出到终端* - * -n:使用安静模式,只有经过sed处理的行才会被显示出来* - * -e:指定要执行的命令,使用该参数,我们可以指定多个命令* - * -f:指定要执行命令的脚本文件* 例如: sed -e ‘1d’ -e ‘p’ sed.txt 这条指令我们执行了删除命令与打印了每行两次 echo ‘1d\n3d\n5d’ > com.txt , sed -f com.txt sed2.txt ,这条操作我们执行了com.txt文件中的命令来删除sed2.txt 文件中的第1、3、5行操作
默认情况下SED中使用的命令会作用于文本所有的行,如果需要对特定的行或者某些行进行操作,则可以使用行寻址功能。 在SED中包含两种形式的行寻址: 1. 数字形式的行寻址 语法格式:[address]command 例如: sed -n ‘3p’ sed2.txt 打印第三行 sed -n ‘2,5 p’ sed2.tx 打印第二行到第5行 2. 使用文本模式过滤器 语法格式:/pattern/command 例如:sed -n ‘/aaaa/ p’ sed2.txt 使用 “,” 操作符指定匹配多个匹配模式,例如我们可以这样: sed -n ‘/aaaaa/, /gggg/ p’ sed2.txt
这部分会列出SED中常用的一些命令,如DELET、WRITE、APPEND、CHANGE、INSERT、TRANSLATE、QUIT、READ、EXECUTE等命令。
删除命令:d 格式:[address1[,address2] d address1与address2是开始和截止地址,它可以是行号,也可以是字符串匹配模式,这两种地址都是可选的。 同样,delete是用来执行行删除操作的,但是注意,删除的行是删除模式空间的行,并不会影响原始文件内容。
例如:sed ‘d’ sed.txt 该命令不会输出任何内容,默认情况下,SED将会对每一行执行删除的操作,所以在标准输出中不会有任何的内容进行输出。 sed ‘2d’ sed.txt sed.txt删除文件中的第2行。 SED也接受使用逗号(,)分隔地址范围。所以我们可以构造地址范围来删除范围的内容。如:sed ‘2,4 d’ sed.txt。 当然也可以通过指定模式匹配作为地址来进行删除操作,例如:sed ‘/Storm/,/Fellowship/d’ books.txt
文件写入命令:w SED中提供了w命令用来将模式空间的内容写入到文件,它与d命令相似。 格式:[address1[,address2] w file w为写入命令,file为要写入的文件,值得注意的是,当我们写入的文件不存在的时候该文件会自动的创建,如果写入的文件存在的话,那么该文件的内容会被覆盖。
利用w命令,我们得到同cp相类似的效果,但是w命令还可以支持对文件的部分内容进行写操作,例如:sed -n ‘2~2 w part.txt’ sed.txt
同样,还有一个场景,当我们需要对文件进行分类的时候,这个时候可以使用w进行操作,同d命令一样,w命令支持匹配模式作为地址来进行写入操作,如:
sed -n -e '/Martin/ w Martin.txt' -e '/Paulo/ w Paulo.txt' -e '/Tolkien/ w Tolkien.txt' books.txt追加命令:a 格式:[address]a Append text 例如在第4行之后添加一本书的话,那么执行:
sed '4 a 7) Adultry, Paulo Coelho, 234' books.txt行替换命令:c SED中同过c命令来执行‘change’和‘replace’操作,该命令是利用新的行来替换已经存在的行。 格式:[address1[,address2] c Replace text 例如,替换文本中的第4行内容:
sed '4 c 4) Adultry, Paulo Coelho, 324' books.txt当然,行替换命令也是支持多行替换的,当提供地址范围的时候,所有的行都会被作为一组被单行给替换掉。下面将4-6行的内容替换为单行:
sed '4, 6 c 4) Adultry, Paulo Coelho, 324' books.txt插入命令:i 插入命令与追加命令有点类似,唯一的区别是插入命令是在指定的位置的前面插入新的一行。 格式:[address] i Insert text 下面的例子会在第3行前面插入新的一行
sed '3 i 7) Adultry, Paulo Coelho, 324' books.txt转换命令:y 转换命令是唯一可以处理单个字符的sed编辑器命令。 格式:[address] y/inchars/outchars/ 转换命令会对inchars和outchars进行一对一的映射,inchars中的第一个字符会被转换为outchars中的第一个字符,第二个字符会被转换成outchars中的第二个字符。这个映射过程一直会持续到处理完指定字符,值得注意的是,inchars与outchars保持同样的长度,否则会报错(“transform strings are not the same length”)。 例如:
echo "1 5 15 20" | sed 'y/1520/IVXX/'退出命令:q q命令不支持地址范围,只支持单个地址匹配。默认情况下sed会按照读取、执行、重复的工作流执行,但是遇到q命令的时候,它会退出当前的执行流。 格式:[address] q 例如:
sed '3 q' sed.txt或者 sed '/ww/ q' sed.txt文件读取命令:r 在SED中,我们可以让SED使用r命令从外部文件中读取内容并且在满足条件的时候显示出来 格式:[address] r file 需要注意的是,r命令和文件名之间必须只有一个空格。 下面的例子会将demo.txt内容插入到books.txt中
sed '3r demo.txt' books.txt 1) A Storm of Swords, George R. R. Martin, 1216 2) The Two Towers, J. R. R. Tolkien, 352 3) The Alchemist, Paulo Coelho, 197 this is content!!! 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 5) The Pilgrimage, Paulo Coelho, 288 6) A Game of Thrones, George R. R. Martin, 888执行外部命令:e 在SED中,我们可以使用e命令执行外部命令 格式:[address1[,address2] e [command] 默认情况下,如果不指定e命令之后的command,那么SED会将模式空间的内容作为要执行的命令进行执行。 下面的例子将文件中的进行执行
echo -e "date\ncal\nuname" > commands.txt sed 'e' commands.txt 日 7 9 22:47:49 CST 2017 七月 2017 日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Darwin排除命令:! 感叹号命令(!)用来排除命令,也就是让原本起作用的命令不起作用
sed -n '/Paulo/p' books.txt 3) The Alchemist, Paulo Coelho, 197 5) The Pilgrimage, Paulo Coelho, 288 sed -n '/Paulo/!p' books.txt 1) Storm of Swords, George R. R. Martin, 1216 2) The Two Towers, J. R. R. Tolkien, 352 4) The Fellowship of the Ring, J. R. R. Tolkien, 432 6) A Game of Thrones, George R. R. Martin, 888替换命令:s 文本替换命令是经常使用的一个命令,替换文本中的内容 格式:[address1[,address2] s/pattern/replace/ file 利用SED替换给定文本中的字符串
sed ‘s/pattern/replace_string/’file该条命令只会打印替换后的文本,并不会进行保存操作
Sed ‘s/pattern/replace_string/’file > newFile上述命令会修改文件的内容,并且将修改后的内容写入到newFile中
sed -i‘s/pattern/replace_string/’ file直接修改读取的文件内容,而不是由屏幕输出。 注意: sed 默认只将每一行中第一处符合条件下的内容进行修改,如果需要进行全局修改,则需要加上后缀“/g“,如果只需要进行从某处开始进行替换,则使用”/ng” 如果要进行某行替换,则:
sed ‘ns/pattern/repace/’ file在处理模式空间中的某些行时,可以使用保持空间来临时保存一些行。保存空间涉及的命令为: h:将模式空间复制到保持空间; H:将模式空间附加到保持空间; g:将保持空间复制到模式空间 G:将保持空间附加到模式空间 x:交换模式空间与保存空间的内容
我们以一个具体的例子来对上述命令进行说明:
cat sort.txt 1 2 3 4 5 6 7 sed '1!G;h;$!d' sort.txt 7 6 5 4 3 2 1在上述例子中实现了一个对文本内容倒序的操作 其中:1!G这条命令是除了第一行外,处理每一行的时候,将保存空间的内容追加到模式空间中; h:将模式空间的内容复制到保持空间 $!d:如果匹配到最后一行,该行不会进行删除
AWK命令的工作流遵循读取-执行-重复。 读取:AWK从输入流(文件,管道或者标准输入)中读取一行,然后存储到内存中。 执行:所有的AWK命令都依次在输入上执行。默认情况下,AWK会对每一行执行命令,我们可以通过提供模式限制这种行为。 重复:处理过程不断重复,直到到达文件结尾。
BEGIN语句块的格式为:
BEGIN {awk-commands}BEGIN语句块在程序开始的使用执行,它只执行一次,在这里可以初始化变量。BEGIN是AWK的关键字,因此它必须为大写,注意,这个语句块是可选的。
BODY语句块的格式为:
/pattern/ {awk-commands}BODY语句块中的命令会对输入的每一行执行,我们也可以通过提供模式来控制这种行为。注意,BODY语句块没有关键字。
END语句块的格式:
END {awk-commands}END语句块在程序的最后执行,END是AWK的关键字,因此必须为大写,它也是可选的。
我们可以使用单引号在命令行中指定AWK命令,其格式如下:
awk [options] file ...例如:
awk '{print}' marks.txt同样,我们可以使用脚本文件提供AWK命令,其格式如下:
awk [options] -f file ...例如:
awk -f command.awk marks.txt该选项将一个值赋予一个变量,它会在程序开始之前进行赋值,下面的例子描述了该选项的使用:
awk -v name=Jerry 'BEGIN {printf "Name=%s\n", name}'例子:统计文件中hello出现的个数。
awk '/hello/ {++count} END {print "Count = ", count}' marks.txt例子:打印匹配hello的行。
awk '/hello/ {print $0}' marks.txt 等价于 awk '/hello/' marks.txtbody 语句块缺失的话会自动执行打印操作。
例子:
awk '{print $3 "\t" $4}' marks.txt其中,我们只是打印了第三行和第四行的字段
AWK提供了很多内置的变量,它们在开发AWK脚本的过程中起着非常重要的角色。
例子:
awk 'BEGIN {printf "Arguments =",ARGC}' One Two Three例子:
awk 'END {print FILENAME}' marks.txt例子:
echo -e "one two\none two three\none two three four" | awk 'NR<3'例子:
echo -e "one two\none two three\none two three four" | awk '{print "Num of fields=",NF}'例子:
awk 'BEGIN {a=10;b=20;print "a+b",(a+b)}' 算数操作符支持加减乘除例子:
awk 'BEGIN {a=10;b=++a;print "a=",a,"b=",b}' 支持自加、自减操作例子:
awk 'BEGIN {a=10;a+=100;print "a=",a}' 支持赋值操作例子:
awk 'BEGIN{num=3;if(num<5 && num>2)print "num=",num}'例子:
awk 'BEGIN{str ="hello,";str1="world"; str2=str str1;print str2}'AWK中不仅支持以数字作为索引的数组,而且也支持以字符串作为索引的数组。数组不需要申明可以直接使用。 格式:
array_name[index]=value例子:
awk 'BEGIN{array[1]="jason";array[2]="kobe";print array[1]"\n"array[2]}'流程控制语句与大多数语言一样。
例子:
awk 'BEGIN {a=10;b=40;if(a>b)print "a>b";else print "a<b"}'循环操作主要包括for/while/do..while/break/continue语句。 例子:
awk 'BEGIN {sum =0;while(i<24){sum+=i;i++;print "sum=",sum}}'在AWK中执行shell命令有两种方式: - 使用system函数 - 使用管道
system函数用于执行操作系统命令并且返回命令的退出码到awk。 例子:
END {system("date | mail -s 'awk run done' root")}如果要执行的命令很多,可以将输出的命令直接用管道传递给”/bin/sh”执行 例子:
awk 'BEGIN { print "hello, world !!!" | "tr [a-z] [A-Z]" }'暂时记录这么多,后续再记录。