第六章 学习BASH

shell命令从本身来讲是用c语言写成的程序供我们进行调用,是我们跟内核沟通的一个桥梁,可以直接输入执行命令,也可以通过shell编写复杂的代码,来实现自己的需求。shell脚本对linux的操作和控制到现在为止都是很重要的,通过shell脚本可以很高效的编写系统管理程序。

Linux的shell有很多种,至于里面的历史进程和故事就不在这里多讲了,只知道后来的事情是这样的,Bash成了大多数Linux系统默认的ShellBASH的语法和c语言差不多,接下来介绍一下Bash的使用。

Bash有较多的语法和功能,作为一本入门级的教程,这里介绍Bash的基础。

Bash起步

在上一章中,介绍了vim的入门使用,现在就是使用它的时候了,编写第一个bash程序,起名为hello.shvim hello.sh用vim编写代码:

#!/bin/sh

a="hello word"
echo $a

上面就是一段简单的bash代码,其中#!/bin/sh 表示这是一段bash程序,需要用shell来执行。a是一个变量,赋值为"hello word",echo为输出变量a的值,相当于打印功能。

改变文件属性,添加可执行:

chmod +x hello.sh

输出的结果为:

hello word

如果你执行的过程中出现了如下的错误:

./hello.sh: 3: ./hello.sh: a: not found

这是因为bash在使用变量的时候,需要这样的一种格式 val=value,其中=两遍不能有空格,变量在赋值的时候使用的是a,在输出的时候使用的是$a,在有些地方shell程序的使用,跟现在的高级语言比起来,规矩比较多,也比较奇怪,这可能也是没有太多大型程序的原因之一。

理解了shell的使用以后,可以把经常使用的命令编写在文档中,方便调用。

管道的使用

对于shell程序的设计,可以化繁为简,把一段复杂的需求通过分解成几个简单的命令,设计起来也较为的轻松,这就是管道带给我们的好处。

如我们需要查看当前目录下,有多少文档,第一步是列出所有的文档,第二步是计算有多少的文档,通常来讲shell程序可以用这种设计规则进行编写。

如下:

ls -lh | wc -l

| 为管道,连接ls -lhwc -l的命令,把ls -lh的输出当成wc -l的输入,计算的结果为当前目录下文档的个数。wc命令前面必须有输入,作为管道命令,和wc一样作为管道命令如上:

  • 字符截取命令: cut, grep
  • 排序命令: sort, uniq, wc
  • 双向重导向: tee
  • 字符转换命令: tr, col, join, paste, expand
  • 分割命令: split
  • 参数代换: xargs

控制语句

bash控制程序的逻辑和现在高级语言一样,用ifwhilefor等关键字。bash属于比较老的语言,语法上和高级语言有点差别。

if语句和其他编程语言相似,都是流程控制语句。

if …; then
…
elif …; then
…
else
…
fi

使用if语句,控制流程,如果文件不存在的话,则创建文件:

#这里的-f参数判断$myFile是否存在  
if [ ! -f "$myFile" ]; then  
  touch "$myFile"  
fi  

if then fi,的控制语句,从关键词来看fi是有点别扭的,不知当时为何会采用fi,可能是if倒过来写就变成fi,但是从流畅程度和可读性是比较差的,if语句使用endif也比fi强。

使用for循环,对变量值进行遍历,for循环的语法:

done
for var in …; do
…
done

如下遍历命令ls的所有值:

#!/bin/sh

for i in `ls`;
do
    echo $i is file name\! ;
done

while语句的控制

while 条件语句
do
action
done;

while对循环的控制和for差不多,关于shell的关键字还有untilselect case,在控制的过程中都可以使用到。

实例

shell最经常用到的是在对系统的控制和对进程的管理,如下一段程序是查找mysql中慢查询的语句,并杀掉慢查询:

#It is used to kill processlist of mysql sleep
#!/bin/sh
while :
do
    n=`mysqladmin processlist -uadmin -pxxxxx|grep -i sleep |wc -l`
    date=`date +%Y%m%d\[%H:%M:%S]`
    echo $n
    if [ "$n" -gt 10 ]; then
        for i in `mysqladmin processlist -uadmin -pxxxxxx|grep -i sleep |awk '{print $2}'`
        do
            mysqladmin -uadmin -pxxxxxx kill $i
       done
       echo "sleep is too many I killed it " >> /tmp/sleep.log
      echo "$date : $n" >> /tmp/sleep.log
  fi
    sleep 1
done

mysqladmin processlist是mysql的命令,列出mysql所有的查询,通过第一层管道到grep -i sleep,过滤出sleep的查询,再通过管道wc -l查看有多少个进程,如果大于10个sleep进程,同样的方式列出当前mysql的查询进程,使用awk '{print $2}',得到第二列的数字,也就是查询进程的id,可以通过这个id,用kill杀死该进程。并把每次执行的结果记录下来。

如果用惯了当前的高级语言,写长篇的shell脚本还是有点费劲的,如果不是涉及到系统操作和进程管理的需求,可以用另外一门脚本语言代替,如python

总结了在下面的情况下,需要考虑下shell脚本是否适合你当前的需求,如果是下面的情况要斟酌考虑:

  • 你的脚本太长,多达几百行
  • 你需要比数组更复杂的数据结构
  • 出现了复杂的转义问题
  • 有太多的字符串操作
  • 不太需要调用其它程序和跟其它程序管道交互
  • 担心性能

继续阅读


来自您的鼓励

如果您感觉这一系列的教程,读后有点收获,并对知识有点了解,不妨小额捐助我一下,让我有动力继续写出更多好文章;或者在评论区留下你的意见。

所有评论

写了这么多年博客,收到的优秀评论少之又少。在这个属于 SNS 的时代也并不缺少向作者反馈的渠道。

还没有评论

撰写评论