目录
一、Sed
什么是 sed ?
sed 的处理过程
定址
Sed中的常用选项:
$ sed -n '3p' filename #只打印第三行
$ sed -n '$p' filename #只打印最后一行
$ sed -n '100,200p' filename # 只打印文件的第100至200行
$ sed '/My/, /You/d' a.txt # 删除包含"My"的行到包含"You"的行之间的行(包括匹配行)
$ sed '/My/,10d' a.txt # 删除包含 ‘My’的行到第十行的内容(包括匹配行和第10行)
-i :直接修改原文件
$ sed -i 's/tom/mick/' `grep -rl "tom" ./test`将当前 test 目录(以及子目录)中,包含 “tom” 的文件,每行的第一个tom字符串替换为mick$ sed -i 's/tom/mick/g' a.txt将文件 a.txt 中的 tom 改为 mick
$ sed -e "2d" -e "s/a/b/g" filename删除文件的第二行,并把文件中所有的 a 替换为 b补充:我如果要删除 a.txt 前两行中包含/aa/的行要怎么办呢?与 -e 的“并列” 关系不同,这次我要处理的数据是“前两行” 与 “包含aa”这两个条件的交集!为了完成这个需求,首先、我们这样使用 d 命令行不行呢?$ sed '1,2/aa/d' a.txtchar 4 :unknown command: "/"$ sed '1,2d/aa/' a.txtchar 5 : extra characters after command此时我们需要使用到 “{}”$ sed '1,2{/aa/d;}' a.txt
-r : 使用扩展的正则表达式
扩展后有如下不同:
组处理 \(pattern\) 可以直接写成 (pattern)
\{1,\} 可以直接写成 {1,}
\+ 可以直接写成 +
\? 可以直接写成 ?
Sed 中常用的命令
$ cat a.txt
aabb
aabb
aaaabb
aabb
$ sed '1,3s/aa/oo/' a.txt
oobb
oobb
ooaabb
aabb
$ sed 'smaamoom' a.txt # m 变成了分隔符
oobb
oobb
ooaabb
oobb
$ sed -n '1,20s/my$/you/gp' filename
匹配1到20行中以my结尾的行,将所有行尾的my 替换为 you ,将处理后的行打印出来。
p:命令 p 用于显示模式空间的内容
$ cat a.txt1111222233334444$ sed '1,2p' f.txt111111112222222233334444注:不使用选项 -n 的情况下,sed 会默认打印模式空间中的内容,如果再使用 p 命令的情况下,你会发现指定的行被打印了2次
d :删除符合条件的行
注意:d 命令只能放到筛选条件的后面
$ sed "/a/d" a.txt # 删除文件中包含 a 的行。
$ sed "/^$/d" a.txt # 删除文件中的所有空行
$ sed 'd/aa/' a.txt
char 2: extra characters after command
a \string :在指定的行后面追加新的行,内容为 string
有两种写法:
$ cat a.txt
aaa
bbb
ccc
$ sed '2a newline' a.txt
aaa
bbb
newline
ccc
$ sed '2a\newline' a.txt
aaa
bbb
newline
ccc
i\string :在指定的行前面添加新行,内容为 string
$ cat a.txt
aaa
bbb
ccc
$ sed '2i before' a.txt
aaa
before
bbb
ccc
$ sed '/bbb/i\before' a.txt
aaa
before
bbb
ccc
$ sed '1,2i before' a.txt
before
aaa
before
bbb
ccc
!
对所选行以外的所有行应用命令
$ cat a.txt
1
2
3
$ sed '2!ia' a.txt
a
1
2
a
3
$ sed '1,2!ia' a.txt
1
2
a
3
$ sed '1,2!d' a.txt
1
2
$ cat f.txt
11
22
33
$ sed '/aaa/r f.txt' a.txt
aaa
11
22
33
bbb
ccc
w FILE:将地址指定范围内的内容另存至指定的文件(文件不存在会自动创建)
$ cat a.txt111222333$ sed '1,2w f.txt' a.txt111222333$ cat f.txt111222$ sed '/333/w f.txt' a.txt111222333$ cat f.txt333注意:多次对一个文件进行写操作是以覆盖的形式进行的$ sed '1,4w/root/f.txt' a.txt # 将1至4行的内容写入到 /root/f.txt 中$ sed '1,4w ../f.txt' a.txt # 将1至4行的内容写入到当前目录的上级目录的 f.txt
Sed中的修饰符:
$ cat a.txt
abca
ACCA
AACA
$ sed 's/a/o/' a.txt
obca
ACCA
AACA
$ sed 's/a/o/g' a.txt
obco
ACCA
AACA
$ sed 's/a/o/gi' a.txt
obco
oCCo
ooCo
& :保存查找串以便在替换串中引用
$ cat a.txt
my name is
$ sed 's/my/**&**' a.txt
**my** name is
Sed 的正则匹配
$ sed 's/^#//g' /etc/inittab # 删除 /etc/inittab 文件中开头的 # 号$ sed 's/\(id:\)[0-9]\(:def\)/\15\2/g' a.txt # 将“id:3:def”中的3替换为5注:这里面用了 2 种正则结构\( \) : 将匹配的结构进行分组保存,后面可以直接使用 " \1" 来代表前面匹配到的值[0-9] :匹配一个数字
2)以行为匹配对象(^、$)
以单词为匹配对象(\<word 、 word\>)
$ cat a.txt
am i
ami nik
i am
i nicam
mickaml
$ sed -n '/^am/p' a.txt # 以 am 开头的行
am i
ami nik
$ sed -n '/am$/p' a.txt # 以am 结尾的行
i am
i nicam
$ sed -n '/\<am/p' a.txt # 行中包含以 am 开头的单词
am i
ami nik
i am
$ sed -n '/am\>/p' a.txt # 行中包含以 am 结尾的单词
am i
i am
i nicam
3)空白符
在 sed 的正则表达式中用 [[:space:]] 表示空白符(一个 Tab 或者 一个空格)
在 pattern 中空格可以直接匹配,但如果要匹配 Tab 就需要使用 [[:space:]]
$ cat a.txta b c # ab之间一个空格a b c # ab之间两个空格a b c # ab之间一个 Taba b c # ab之间两个 Tab$ sed 's/a *b/mm' a.txt # 替换,行中包含的结构( a 与 b 之间有零个或多个空格)为 mmmm cmm ca b ca b c$ sed 's/[[:space:]]//g' a.txt # 删除行中的空白符abcabcabcabc
$ cat a.txt
aal
all
a*ll
$ sed 's/a\*/o/' a.txt
aal
all
oll
$ sed 's/a*/o' a.txt
ol
oll
o*ll
Sed 的不常用命令
n 命令
sed 使用该命令获取输入文件的下一行,并将其读入到模式缓冲区中,任何 sed 命令都将应用到匹配行紧接着的下一行上。
注:如果需要对匹配行使用多条命令,或者需要在某个地址范围内嵌套地址,就必须用花括号将命令括起来,每行只写一条命令,或者用分号分割同一行中的多条命令
$ cat a.txt
testing
aa bb
aa cc
$ sed '/testing/{n;s/aa/oo/;}' a.txt
testing
oo bb
aa cc
$ sed -n '/testing/{n;s/aa/oo/;p}' a.txt
oo bb
--------------- 一些特殊用法 ---------------
$ cat a.txt
1
2
krootk
$ sed -n '/root/{=;p}' a.txt # 打印包含 root 的行及行号
3
krootk
$ sed -n '/root/{n;d}' filename # 将包含 root 行的下一行删除
$ sed -n '/root/{N;d}' filename # 删除 root 行以及下一行
q 命令
q此命令将导致 sed 程序退出,不再进行其它的处理
$ cat a.txtccaa bbaabbaaa b$ sed 's/aa/oo/' a.txtccoo bboobbooa b$ sed 's/aa/oo/q' a.txt # 这种写法是错的,因为 q 是个命令,而不是修饰符。$ sed '{s/aa/oo/;q}' a.txtcc只输出一个 cc 就退出了,而不是找到第一个 aa 做替换之后退出sed 从 a.txt 读入第一行,执行 { } 里面的内容,遇到 q 命令整个 sed 就退出了。
y:将字符按照一对一的方式从左到右进行转换。这个命令太局限常用的是 s 命令
$ cat a.txtabcABCdef$ sed '1,2y/abc/XYZ' a.txtXYZABCdef$ sed '1,2y/abc/WXYZ/' a.txt前后字符数量不一致,会报错
二、grep
(1)grep常用的参数:
-
-v:逆反模式,只输出“不含” RE 字符串的句子
-
-r:递归模式,可同时处理所有层级子目录里的文件
-
-q:静默模式。不输出任何结果(stderr除外,常用以获取 return value,符合 RE 则为true,反之为false)
-
-i:忽略大小写
-
-w :整词比对(精确匹配)
-
-n:同时输出行号
-
-c:只输出符合比对的行数,不显示匹配的内容
-
-l:只输出符合比对的文件名称(小写的L)
-
-E :切换为 egrep。
-
-?(数字) :同时显示匹配行上下的 ?行,如 grep -2 pattern filename 同时显示匹配行的上2行、下2行。
-
-o:show only the part of a line matching PATTERN
(2)grep 中常用的RE
^ :锚定行的开始,如:'^grep' 匹配所有以 grep 开头的行。
$:锚定行的结束,如:'grep$' 匹配所有以 grep 结尾的行。
. : 匹配一个非换行符的任意字符,如:'gr.p'匹配 gr 后接一个任意字符,然后是 b
*:匹配零个或多个先前字符,如:' *grep' 匹配所有一个或多个空格后紧跟grep的行。.*一起用代表任意字符。
[]:匹配一个指定范围内的字符,如:'[Gg]rep' 匹配 Grep 和 grep。
[^]:匹配一个不在指定范围内的字符,如:'[^A-FH-Z]rep'匹配不包含A-R和T-Z的一个字母开头,紧跟rep的行。
x\{m\} :重复字符 x ,m次,
如:‘p\{5\}’匹配包含5个p的行。
grep '\(grep\)\{3\}' gcx.txt 匹配包含3个连续 grep的字符串
x\{m,\}:重复字符x,至少m次,如:'a\{4,\}' 匹配至少有4个a的行
x\{m,n\} :重复字符x,至少 m次,不多于n次,如:'a\{5,10\}' 匹配5-10个a的行
\w:匹配文字和数字字符,也就是[A-Za-z0-9],如:'G\w*p' 匹配以G后跟零个或多个文字或数字字符,然后是p。
\W:是 \w 的反置形式,匹配非单词字符,如点号、句号等。
\b :单词锁定符,如:'\bgrep\b' 只匹配单词grep
\(.. \) :标记匹配字符,如 '\(love\)',love被标记为1。
例:
$ grep 'w\(es\)t.*\1' aa
如果 west 被匹配,则es就被存储到内存中,并标记为1,然后搜索任意个字符(.*),这些字符后面紧跟着另外一个 es(\1),找到就显示该行。
如果用 egrep 或 grep -E ,就不用 “\”号进行转义,直接写成 'w(es)t.*\1' 就可以了。
(3)例子
-w 精确匹配
$ cat goface.txt
goface
gofaceme
$ grep 'goface' goface.txt
goface
gofaceme
$ grep -w 'goface' goface.txt
goface
-r 递归搜索查找指定目录下的所有文件(包括子目录),匹配你要查找的字符串
如果指定的目录下文件太多或含有大文件,可以使用以下参数对文件进行过滤:
--include=PATTERN
--exclude=PATTERN
grep magic /usr/src # 显示 /usr/src 目录下的文件(不含子目录)包含magic的行
grep -r magic /usr/src # 显示 /usr/src 目录下的文件(包含子目录)包含 magic 的行
-o \ -r \ -l
-e :执行多个pattern匹配
用于 egrep 和 grep -E 的元字符扩展集
+:匹配一个或多个先前的字符
?:匹配0个或多个先前字符
a|b|c :匹配 a 或 b 或 c
egrep
为 grep 扩充版本,改良了许多传统 grep 不能或不便的操作,比方说:
-grep 之下不支持 ? 与 + 这两种修饰字符,但 egrep 则可。
-grep 不支持 a|b 或 (abc|xyz)这类“或一”比对,但 egrep 则可
-grep 在处理 {n,m}时,需要用 \{ 与 \} 处理,但 egrep 则不需。
fgrep
不作 RE 处理,表达式仅作一般字符串处理,所有meta均失去功能。
三、awk
awk格式
awk指令结构:
工作方式:
$ cat a.txt
1
2
3
$ awk 'BEGIN{k1="v1" print k1}{print}END{print k1}' a.txt
v1
1
2
3
v1
awk中自定义变量
######## 在 awk 语句块中定义变量 #######$ echo | awk 'BEGIN{ sun=4 } { print sun } END{ print sun }'44$ echo | awk 'BEGIN{ print sun } { sun=4; print sun } END{ print sun }'44$ echo | awk 'BEGIN{ print sun } {print sun } END{sun=4;print sun}'4$ echo | awk -v sun=4 'BEGIN{ print sun } {print sun } END{ print sun }' # 使用 -v 参数设置内部变量。444########### 传递外部变量 ##########$ var=100$ echo | awk 'BEGIN{print "start", vara} {print vara } END{print "end",vara}' vara=$varstart100end 100经测试:BEGIN 命令块中取不到变量 vara!vara=$var 只能放到最后
awk 命令内置的一些特殊变量:
NR :表示已处理的行数,在处理过程中对应当前行号;
NF :表示字段数量,在执行过程中对应当前行按照分隔符分割后的字段(field)数;
$0 :执行过程中表示当前行的文本内容;可省略;
$1 :第一个字段的文本内容;
$2 : 第二个字段的文本内容;
FILENAME:当前处理的文件名;
ENVIRON:环境变量,用法:ENVIRON["变量名称"]
bash 中常用的环境变量有:
$HOME:当前用户家目录
$PWD:当前工作目录
$SHELL :默认的解释器
$USER:当前登录用户
$ cat a.txta b ca b c$ awk '{print $2,$3}' a.txtb cb c$ awk -F: '$1==ENVIRON["USER"]{print $3}' /etc/passwd打印以 “ : ”分割后,第一个字段为当前shell用户名(echo "$USER")的行的第三个字段$ awk '{print NF}' file # 显示每行有几个字段$ awk '{print $NF}' file # 将每行的第 NF (最后) 一个字段打印出来
awk中的一些特殊符号:
\t :制表符
\n :换行符(可以用在 print 中 )
~: 匹配,与==相比不是精确比较(后面常跟正则)
!~ :不匹配,不精确比较
== : 等于,必须全部相等,精确比较
!= :不等于 ,精确比较
&& :逻辑与
|| :逻辑或
+ :匹配1次或多次
? : 匹配0次或一次
$ echo | awk 'END{print "A""\t""B" }'
A B
$ echo | awk 'END{print "A""\n""B" }'
A
B
awk的选项
-F 选项
使用 “ -F ”来设置分割符(默认为空格)
注:在使用 -F 指定一些特殊(shell 中的元字符)分隔符时,需要在分隔符前面加上 "\" 进行转义(如 :-F\")
-F'[:#/]' :定义三个分隔符
例一:$ awk -F: '{ print $NF }' /etc/passwd以 “ : ” 为分隔符,将 passwd 中的每行进行分割,并打印每行分割后的最后一个字段。
例二:假设文件(a.txt)中有如下内容:"usage":"0.64%""usage":"0.84%"以"分割可以NF=5如果我想取出 0.84 可以这样操作方法一:sed -n '$p' a.txt | awk -F: '{ print $2}' | awk -F% '{ print $1 }' | awk -F\" '{ print $2}'方法二:awk -F'["%]' NR==2'{print $4}' a.txt如果我进行如下操作又会得到什么结果呢?awk -F\" '{print $1}' a.txt答案是会得到两个空行以“ 进行切割会得到 5个字段$ awk -F\" '{ print NF }' a.txt55以 " % 进行切割会得到 6 个字段$ awk -F'["%]' '{print NF}' a.txt66注意:指定的分隔符里面有个 shell 中的元字符 " ,所以要在 ["%] 外面加上单引号以 : % 进行切割会得到3个字段$ awk -F[:%] '{print NF} a.txt33以 " % 进行切割会得到7个字段$ awk -F'["%:]' '{print NF}' a.txt77
-v 选项:
$ awk -F: -v i=1 '{ print $3+1 } ' /etc/passwd
Print 说明:
1、使用不带参数的 print 时,会打印当前行的所有内容
$ echo -e "line1\nline2" | awk 'BEGIN{ print "start"} { print } END{print "End"}'
line1
line2
2、print 以逗号分隔时,参数以空格定界
$ echo | awk '{ var1="v1"; var2="v2"; var3="v3"; print var1,var2,var3}'
v1 v2 v3
$ echo | awk '{ var1="v1"; var2="v2"; var3="v3"; print var1 var2 var3}'
v1v2v3
3、使用双引号来指定 Print 参数之间的“拼接符”
$ echo | awk '{var1="v1"; var2="v2"; var3="v3";print var1"-"var2"-"var3;}'
v1-v2-v3
awk 对行的条件过滤
$ awk 'NR==1,NR==4 {print}' file #将行号为[1,4]的行打印出来
$ awk 'NR==5||NR==6{print}' file #打印第5行和第6行
$ awk 'NR%2==1{print}' file # 打印出奇数行
$ awk 'NR==2{print}' file # 打印第二行
$ awk '$2!="xx"{print}' file # 打印第二个字段不为 "xx" 的行
$ awk 'NF==3{print}' file # 打印分割后只有三个字段的行
$ awk 'NF>=2{print}' file # 打印分割后有2个以上字段的行
$ awk 'NF>=2&&$2!="pop"{print}' file #打印分割后有2个以上字段,并且第二个字段不为“pop”的行。或关系用 “||”
awk 对行的正则过滤
awk的正则表达式与sed一样放在 “//” 之间
$ awk '/^ro/{print}' /etc/passwd # 打印以 ro 开头的行$ awk '$2!~/bash$/{print $1,$2}' file # 打印第二个字段不以 bash 结尾行的第一、第二个字段$ awk '$2~/bash$/{print $1,$2}' file # 打印第二列以 bash 结尾行的第一、第二字段$ awk '!/mysql/{print $0}' /etc/passwd打印不包含mysql的行$ awk '!/mysql|oracle/{print}' file打印不包含mysql或oracle的行awk -F: '/my/,/he/{print}' file #区间匹配打印从上往下第一个包含my的行至第一个包含he的行,包括边界
$ cat a.txt
bash
login bash
bash\>
$ awk 'BEGIN{x=0} /bash\\>/ {x++;print]END{print x}' a.txt
bash\>
1
经过测试 awk 的正则不支持 “\<”“\>” “\b”这三种单词定界符
awk中的 if 语句
必须用在 {}中,且内容用()括起来
$ awk -F: '{ if($1~/mail/) print $1}' file #简写
$ awk -F: '{ if($1~/mail/) {print $1}}' file #全写
$ awk -F: '{ if($3>100) {print $1} else {print $2}}' file
常见用法:
例一:
$ awk 'END{print NR}' a.txt # 统计文件的行数(包括空行)
3
例二:
$ awk 'BEGIN{a=12.3; print a+12} ' # 计算器
24.3
例三:累加每一行的第二个字段(field)
$ cat a.txt
10a3 2k
2b k9l
3c 2m
$ awk '{sum+=$2} END{print "=="; print sum }' a.txt
==
4
$ awk '{sum+=$1} END{print "=="; print sum }' a.txt
==
15
例四:统计当前目录下所有文件(不包含文件夹)的大小总和
$ ls -l | awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{ print "total size is",sum}'
四:bc
bash 中,默认的数据类型都是字符串类型,无法直接进行数值运算。
编写 shell 脚本的过程中我们经常使用 bc 对 浮点数进行处理
一:比较大小if [ $(echo "4.4<4"|bc) -eq 1 ];thenecho "4.4<4"|bc # 如果 4.4<4 则输出1,否则输出0二:浮点数的运算方法一:bc$ var=3.14var=`echo"$var*3"| bc`echo $var9.42方法二:awkvar=`echo "3.14 3.14"` | awk '{printf("%g",$1*$2 )}'
五:系统函数 read
$ read -t 7 -p "please input your name" NAME
在7秒内输入你的名字,并将值赋给NAME变量
六:系统函数 basename、dirname
1)basename基本语法:
basename [pathname][suffix]
pathname : 路径加文件名
suffix 为指定的后缀
在不指定后缀的情况下,此命令会删除路径,拿到文件名
如果 suffix 被指定了,basename会将文件名中的 suffix 去掉
basename 路径
$ basename /home/nfs/share/tools/a.txt
a.txt
$ basename /home/nfs/share/tools/a.txt .txt
a
$ basename ../../a.txt
a.txt
$ basename /1/2/3/a.txt/
a.txt
2)dirname基本语法
dirname 文件绝对路径
从给定的包含文件名的绝对路径中去除文件名,然后返回剩下的路径
$ dirname /home/gcx/test.txt
/home/gcx
$ dirname /1/2/3/4/
/1/2/3
$ dirname ./../1/2
./../1
七:xargs
命令结构:
常用参数:
对输入数据的处理
$ cat args.txt
a b c d e
f g h
i j k
$ cat args.txt | xargs
a b c d e f g h i j k # 默认合并成一行,默认命令是 echo
$ cat args.txt | xargs -n 5 # 每行设置5个参数
a b c d e
f g h i j
k
$ echo "axbxcxd" | xargs -d x # 修改参数分隔符为 x
a b c d
如何将参数添加到命令上
$ echo a b c| xargs echo ia ib
ia ib a b c
$ echo a b c | xargs -i echo {} ia ib
a b c ia ib
$ echo a b c|xargs -I {{}} echo {{}} ia ib
a b c ia ib
其它选项
$ echo ""|xargs -r echo ia ib此时不会运行后面的 echo