我们在shell脚本中,最主要的需求就是字符的处理。
下面是一些我们在shell脚本中,经常使用的命令的了解
diff
diff命令:
用于比较两个文件或目录的不同
diff比较结果的解读:
[num1,num2] [a|c|d] [num3,num4]
num1,2表示在第一个文件中的行数。
num3,4表示在第二个文件中的行数
a(add) 添加
c(change) 更改
d(delete) 删除
< 表示第一个文件中的内容
> 表示第二个文件中的内容
--- 分割线
diff常用参数:
-b --ignore-space-change 不检查,忽略空格字符的不同
-B --ignore-blank-lines 不检查空行的不同
-c 显示两个文件的全部内容,并以!标出不同之处
-i --ignore-case 不检查大小写的不同
-p (和-c类似) 比较c语言源码文件时,显示差异所在的函数名称
-q --brief 仅显示有无差异,不显示详细的差异信息
-r --recursive 比较子目录中的文件(用来比较两个目录中是否有不同的子文件)
-u 以合并的方式来显示文件内容的不同
下图为例:
图一,二为使用diff命令对两个文件内容的简单差异对比
图一中,file2比file1多一行文字。diff结果可见,两对比文件参数的位置也会改变执行结果。
第一次diff结果说明:
file1从第2行开始(含第2行)与file2不同,file1的第2行回车后,加上(a)字符串line 3
即可与file2文件内容第3行之前(含第3行)的内容相同
而第二次diff结果正好相反(d)
注意的是,diff显示结果,都是指示如何编辑文件1,使之与文件2的内容相同
图二中,另外写了两个文件,这次两个文件有多处不同。
diff结果解读:
文件1内容在2行之前与文件2相同。
在文件1的第2行回车后,加上(a)字符串asd
即可与文件二3行以前的内容想匹配一致
进行上面修正后
文件1的4行之前(1-3行)内容与文件2的前3行相同
(这里的4行,指的是未进行上面的2a3的修改之前的文件1第4行,修改后的第5行)
在文件1的4行进行修改( c),将westos
更改为westosasd asd
,从而与文件2的5,6行相匹配
(另外,从下面的图八中可以看到,diff显示结果中的c即是指对于某一行,既要进行字符行的增加a,也要进行字符行行的删减d,这时,对于该字符行就会以c指示)
图三中,file1: "bye "
,file2: "bye"
(最后一图)图八中,可以明显看出,-代表删除该文字行,+代表添加该文字行,显示结果中不再有c(修改),只有a(增加),d(删除)。修改被增加和删除的组合代替。
diff配合patch命令更新脚本文件:
可以使用上面的-u生成补丁文件,再使用patch命令更新原文件
(-u参数的输出就是对于westos1文本的操作-删除该行,+添加该行)
diff -u westos1 westos2 > westos.path
生成用于将westos1同步更新为westos2的补丁文件westos.path
yum install -y patch
下载patch
patch -b westos1 westos.path 将westos1通过使用westos.path补丁文件更新到westos2
命令 参数 原文件 补丁文件(用于更新原文件)
-b参数,将原文件保留,重命名为westos1.orig文件
cut
cut命令:
用于字符的截取
常用方式:
-d " " 指定分隔符为空格(不加该参数,默认以制表符tab为分隔符)
-f 1,7/1-7 指定截取的列(第1和第7列/第1至7列)
-c 1,4/1-4 指定截取的字符位置为(第1和第4个字符/第1至4个字符)
cut -d : -f 1 passwd
截取操作文件passwd,以:作为分隔符,取出第一列
cut -d : -f 1-4 passwd
截取操作文件passwd,以:作为分隔符,取出第1至4列
cut -d : -f 1,4 passwd
截取操作文件passwd,以:作为分隔符,取出第1列和第4列
cut -c 1-4 passwd
截取操作文件passwd,取出第1-4列字符(这个命令没有分隔符,应该也会取出空格,空行等作为字符)
cut -c 1,4 passwd
截取操作文件passwd,取出第1和4列字符
应用示例:
ifconfig eth0 | grep 'inet ’ | cut -d " " -f 10
可以截取出虚拟机的eth0设备ip地址
sort
sort命令:
对文本排序
常用参数:
-n 按照纯数字排序
-r 倒序/逆序
-u 去掉重复数字
-o 输出到指定文件
-t 指定分隔符
-k 指定要排序的列
下图为例:
图一中,可以看出sort命令,不加-n参数下的排序,对于多个数字字符组成的数字整体并不能识别。仍是作为多个字符组成的字符串进行排序,即,先对每一行的第一个字符进行比较排序,当第一个字符相等时,才会去比较第二个字符…
而图二中,增加-n参数后,将多个字符组成的数字整体进行排序
图六中可以看出,-o参数与重定向的作用实际是一样的
最后一图,图七中,使用到了下面的uniq命令,可以先看一下uniq命令的使用在看该图
由于uniq -c
的显示结果前面有6个空格,因此实际上以空格分割的第8列才能按照实际数值的第二列排序
uniq
uniq命令:
用于对重复的字符进行相应的处理
常用参数:
-u 显示唯一的行的内容
-d 显示重复的行的内容(相同内容,显示一次)
-c 每行显示一次(多行同样内容的行只显示一次),并统计重复次数
下图为例:
下图可见,uniq命令,只会将相邻行,且内容相同的情况,作为重复的内容。
因此最好是sort filename | uniq -c 将sort命令的输出内容作为uniq的输入处理更加正确
该图中,uniq -c
的显示结果中,第一列是重复次数,第二列才是该行的内容
对命令执行的判断
&& 前面的语句正确(符合条件),执行该命令 || 前面的语句错误,执行该命令
但是,该方式只能检测单条语句逻辑,判断执行
若要对多条命令语句进行逻辑判断,就需要用到if等判断语句
应用示例:
检测能否ping通目标主机
vim ping.sh:
ping -c1 -w1 $1 &> /dev/null \
&& echo "$1 is up" \
|| echo "$1 is down"
sh ping.sh 即可执行该脚本
&&
||
后面都可以接大括号{},即相当于C语言中的复合语句
满足条件,可以执行大括号中的多条语句;而不再是只能执行一条语句
test
test命令:
用于进行逻辑判断
但是由于test命令在脚本中不太美观规范,也可以使用中括号[ ]的形式
test命令和[ ]等同
[ ]中,参数两边必须有空格
用于逻辑比较的常用参数:
-lt小于
-le小于等于
-gt大于
-ge大于等于
-ne不等于
-a(and) 与(test的条件要全部满足才为逻辑真,或者说是才视为命令执行结果正确)
-o(or) 或(test的条件至少要满足一个才为逻辑真)
应用示例:
每分钟定时检测一次/根目录挂载在系统中所占用的资源百分比,若超过百分之30,则报警,并写入/var/log/messages日志文件中
vim check_root.sh
#!/bin/bash
[ `df / | tail -n 1 | awk '{print $5}' | cut -d % -f 1` -ge "30" ]&&{ #df / 命令直接查看/根目录挂载信息
logger Warning: System root is full !! #logger命令可以生成日志
}
at now+1min <<EOF
/mnt/check_root.sh #设定延时任务,每隔一分钟就会执行一次该脚本,形成循环,变为定时任务
EOF
用于文件判断的常用参数:
-z 是否字符串为空
-n 是否为非空(与-z相反)
-ef 是否使用的是同一个节点区域(互为硬链接)
-nt(new than) 前一个文件建立的是否比后一个文件晚
-ot(old than) 前一个文件建立的是否比后一个文件早
-e 是否存在该文件
-f 是否为普通文件
-L 是否为软链接(快捷方式)
-S 是否为套接字
-b 是否为块设备(如,u盘插入后,sdb)
-d 是否为目录文件
-c 是否为字符设备(/dev/pts/1)
下图为例:
图一中,可见判断时最好书写规范,将$1等变量写在" "双引号内部。
即[ -n "$1" ]
,而不是[ -n $1 ]
。
因为从图中可见,虽然对于[ -z "$1" ]
和[ -z $1 ]
这两种写法并没有什么实际效果的区别。但是对于-n参数来说,[ -n "$1" ]
才是有效的表示方式。
另外,由图中实际的实验效果来看,当我将echo "$1"
写在&&执行命令部分以外时,空字符是以空行来表示的,而在&&内部执行时则是彻底地不显示出来,qwer与asd之间只有两个空格
图二中,我使用了ln命令创建/root/file文件的链接。
ln -s /root/file /root/file1
使用-s参数创建/root/file文件的软链接/root/file1
ln /root/file /root/file2
默认参数创建/root/file文件的硬链接/root/file2
由图中的对比可见:
-ef参数本身判断两个文件是否使用同一个节点区域,file1文件是file文件的硬链接,自然为执行正确,判断正确。而file2文件属于软链接,指向file文件,应该就相当于是file文件与自身对比,自然也是正确的。
如:
[ -e $1 ] &> /dev/null || echo "$1 is not exist!!!" \
&& { [ -f $1 ] && echo "$1 is common file" \
|| { [ -d $1 ] && echo "$1 is directory file" \
|| { [ -L $1 ] && echo "$1 is softlink file" \
|| { [ -z $1 ] && echo "please input filename following script!!!"
}
}
}
}
tr
tr命令
用于转换字符串中的大小写字符
常用方式:
echo hello HELLO | tr 'a-z' 'A-Z'
将小写字母转换为大写字母
echo hello HELLO | tr 'A-Z' 'a-z'
将大写字母转换为小写字母