【这里分享的知识可能需要有一点的Linux基础的,所有的案例不建议在生产环境下操作,最好自己准备测试机进行试练】
从事Linux运维工作已经快一年了,期间学到了一些比较实用的小技巧,有些新手可能还不太清楚,今天在这里姑且分享一下,当然限于个人水平和精力,可能有些地方描述不够清楚,欢迎各位读者朋友们进行斧正,并提出改进意见,在此先行谢过。
在进行实操之前,我们先拓展两个小知识点:
(1)反引号``,它的作用是引用命令并获取命令执行的结果,如:
a=‘hello‘ # 给变量a(变量不用单独定义,这点区别于C语言)赋值, 注意此处为单引号,非反引号,切记
echo $a # 输出hello , 而$可理解为C语言中的&(取地址符),意为获取变量的值 b=`echo $a # 引用a变量的内容,并赋值给b echo $b # 结果为 hello
(2)IFS: 是bash的内部的域分隔符,IFS的默认值为空白(包括:空格,tab, 和新行),这个有兴趣的自己可以好好研究一下 (3) 正则里面的两个匹配次数记忆小技巧,大家试一下这个方法看看效果会不会比较好: . 匹配一次任意一个字符 + 匹配 任意字符 1到无穷次 (+ 横竖都是1,联想到数字 1 ) * 匹配任意字符 0到无穷次 (* 看上去就像一个圆形的雪花,联想到 圆心(0,0)
总结:a.当时反引号并不局限于echo, 诸如ls,cat,pwd等Linux基本命令都是可以用的, 例如 ls `pwd`/filename 可以获取到当前目录下你所查询的文件的全路径; b.反引号``绝大多数等价于$(),如a=3,此时b=`echo $a`和b=$(echo $a)都得到3。众多网友说这两个命令等价,实际上并非如此。笔者所知有限,目前只能给一个实例: 如c=123,a=c ,现借助a把c的值赋给变量d, 两种方式获取的结果是不等值的: d1=`eval echo \$$a` 和 d2=$(eval echo \$$a),有兴趣的朋友自己去研究一下。
实例:
一. 批量删除sdb1,sdb2,sdc1,sdc2,sdd1,sdd2,sdd3分区(保留盘符sda*)
1.如果磁盘是挂载状态,请先行卸载,否则会因磁盘使用中导致删除分区失败。
for x in `df -h |grep ‘/dev/sd[a-d]*‘ | grep -v sda|awk ‘{print $1}‘`;do umount $x ;done
思路:(1)借助for 循环中的条件中借助反引号获取过滤后的磁盘盘符 (2)借助df获取挂载信息,借助grep正则过滤获取满足条件的盘符,然后用-v 滤除含有sda的盘符,最后用 awk获取第一列盘符信息 (3)for循环内部执行 卸盘操作 (umount 需要root权限才能执行) 总结:(1) 正则有标准和扩展两种,扩展的功能更多当然也兼容基本正则的,用egrep替代grep或用grep -E替代grep都可以切到扩展正则用法 (2)[a-zD-F]表示a~d和D~F内的任意一个字母,[15m]表示 1或5或m中的任何一个, 如ls 1[5m] 则能同时过滤到15和1m两个文件。 sd[a-z]*:表示匹配以sda~sdz为首的任意字符串 ,例如 sda sdb2 sddc. sdddc都能被匹配到
(3)文件file.txt 的内容为: a 1 b 2 ① awk ‘{print $1}‘ file.txt 获取file.txt的第1列数据; 而获取最后一列列的数据可用$NF代替$1即可,而此处只有两列,故$NF可替换为$2。 ②细心的读者应该发现了awk后{}被一对单引号扩起来了,那么双引号是否可行呢?现在看一个例子:
echo linux.com | awk -F‘.‘ ‘{print $1}‘ => linux # 单引号,$1为awk内置变量,会被识别为当前处理文本行的第一列 echo linux.com | awk -F‘.‘ "{print $1}" => linux.com # 双引号,$1为bash环境下的一个变量,非awk内置变量,故未得到预期结果 echo linux.com | awk -F‘.‘ "{print \$1}" => linux # 在此处进行转义后,将bash变量转义为awk语句的内部变量,OK了
上面的例子②给我们在跳板机上使用awk的启示,如服务器主机名格式为192-168-1-63,如何获取到所有主机名字的最后字段?(借助awk)
绝大多数朋友都能写出这个语句ssh IP "hostname|awk -F‘-‘ ‘{print $4}‘ " ,答案是什么呢?自己去试一下吧 请看下面这两种方案,请认真比较一下跟上面的语句的差异点是什么: (I) ssh IP "hostname|awk -F‘-‘ ‘{print \$4}‘" # 对$进行转义,使得当前的bash环境不会误判 (II)ssh IP "hostname"|awk -F‘-‘ ‘{print $4}‘ # 将获取的结果放到本地的bash环境下直接执行
2.删除除了sda*以外的分区:
for x in `df -h |grep /dev/sd* |grep -v sda /dev/sd[b-z][0-9]| cut -c1-8 |sort -u`;do echo -e "d\nw" | fdisk $x ;done
思路:思路跟卸载盘的思路很像,但此处涉及 fdisk用法,故sdb2,sdb3需要以sdb的形式出现,此处用cut截取1-8个字符(如/dev/sdd)后用sort -u去重。后面用
echo传递多行参数给fdisk命令,实现毋须手动确认实现分区删除。注意,echo 的-e参数作用是使用特殊字符(如换行符\n),d是 fdisk里面的 删除分区的命
令,w是fdisk中保存的含义。具体的含义可以利用fdisk查看,例如执行完 fdisk /dev/sdb后,按下 m,即可查看命令的含义。
总结:用for和while的方式都是可行的,不过个人更倾向于while,原因在于while read在处理一行数据时,不会因为有空格而有所变化,而for处理一行数据时,若
行数据没有空格,效果同while,可一旦遇到有空格的情况,缺陷就出来,当然for和IFS组合的时候也能实现行处理跟while read的方式,下面来演示一下:
[[email protected] my]# cat tmpfile a 1 b 2 c 3 [[email protected] my]# while read line ;do echo $line ;done < tmpfile # 注意这里的tmpfile是一个文件名 a 1 b 2 c 3
[[email protected] my]# for x in `cat c`;do echo $x;done # 这里如果直接用 for,那么会把 空格作为分割行,这样就不能达到我们需要的效果了 a 1 b 2 c 3 [[email protected] my]# for x in `cat c`;do IFS=‘‘;echo $x;done # 这个是修正版,通过 IFS 指定分割,就能避免这个问题 a 1 b 2 c 3
今天的分享到此结束,当然很多原理性的东西没有讲到,笔者专注的是使用技巧的分享,所以各位读者朋友们也不要太苛责了哈