shell编程 概念:

  • 编程语言分两大类:

    • 静态语言:编译型语言,通常为强类型(变量)语言 静态语言需要事先转换成可执行格式,不需要任何解释器,如C,C++,JAVA,C#
    • 动态语言:解释型语言(脚本语言),通常为弱类型(变量) 动态语言可以边解释边执行(on the fly)需要一个解释器(解释器本身通常是用静态语言写成的),如PHP,SHELL,python(学好python相当于如虎添翼!),perl(主要面向过程,也有面向对象)
  • 两种编程模型:

    • 面向对象:把整个我们需要实现的项目抽象成一个个的对象,并定义对象之间可发出的操作来完成的。 面向对象这种方式一般适合用来开发一些大型的项目。如:JAVA, Python, perl, C++
    • 面向过程:把编程着手点,立足点主要在于解决问题过程本身。 面向过程这种方式一般适合用来开发一些小型的项目,尽管如此Linux内核就是用面向过程的c语言来实现的。如:Shell, C
  • 变量:命名的内存空间,用完了可以释放,是一个不断变化的量。

  • 内存:编址的存储单元。

  • 进程:一个程序执行起来叫做进程,进程的所有指令和数据都是存放在内存当中的,在这个程序的执行过程中我们需要临时去存储一些数据的话,我们就有可能用到变量了。

  • 变量类型:事先确定数据的存储格式和长度 同时存储10,如果10是作为字符存储的话就需要16bit位,如果10是作为数字存储的话转化成二进制1010就需要8bit位,所以变量需要类型。

  • 变量初始化 强类型:变量在使用前,必须事先声明,甚至还需要初始化; 弱类型:变量用时声明,甚至不区分类型;

  • 逻辑运算:与,或,非,异或 1为真,0为假 与:1 0=0,0 1=0,0 0=0,1 1=1 或:1 0=1,0 1=1,0 0=0,1 1=1 异或:1 0=1,0 1=1,0 0=0,1 1=0 整个计算机内部设计都是由逻辑运算组成的!

  • 变量赋值:VAR_NAME=VALUE


bash的变量类型: 环境变量 本地变量(局部变量) 位置变量 特殊变量

  • 本地变量:比如在bash中直接写NAME=jerry 这就相当于定义NAME这个变量 set VARNAME=VALUE(set可省略): 作用域为整个bash进程; 引用变量的值时需要使用${VARNAME} 只要不影响变量名的,括号可以省略。

  • 局部变量: local VARNAME=VALUE:作用域为当前代码段;

  • 环境变量:导出(export)一个变量 export VARNAME=VALUE 作用域为当前shell进程及其子进程; VARNAME=VALUE export VARNAME

脚本在执行时会启动一个当前shell的子shell进程,所以当前shell的环境变量对子shell都是有效的。 即命令行中启动的脚本会继承当前shell的环境变量。 然而系统自动执行的脚本(非命令行模式)需要自我定义各环境变量。

  • 位置变量(引用脚本的参数): $1, $2, ...

  • 特殊变量(保存特殊参数的): $?: 保存上一个命令的执行状态返回值;

      程序执行,可能有两类返回值:
      		程序执行结果
      		程序执行状态返回代码(0-255)执行完一个指令后echo $?就可以看到返回代码
      				0: 正确执行
      				1-255:错误执行,1,2,127系统预留;
    

撤消变量: unset VARNAME

查看当前shell中的变量:不带任何参数的set命令。 查看当前shell中的环境变量:printenv,env,export都可以。 特殊变量和位置变量都无法查看

可以用:符号将多个变量存放到一个变量名中 比如:NAME =$NAME:david将david这个名字放在NAME这个变量名后。 NAME =jimmy:$NAME将jimmy这个名字放在NAME这个变量前。

默认shell中的变量都是字符串型,不会做算数运算。


脚本:命令的堆砌,按照实际的需要,结合命令流程机制实现的源程序。

  • 如何编写一个简单的脚本? 首先nano一个以.sh结尾的文件,随便写几个个命令去里面。 但是Linux内核只能识别ELF(可执行可链接)文件(比如file /bin/ls 显示出来的就是ELF文件格式),而nano创建的文件格式只是ASCII格式。所以在写脚本第一行时必须要指定脚本的魔数,nano第一行必须写#!/bin/bash(除了第一行的#,其余的#当作注释符号) 想要执行一个脚本有两种方法 第一,需要执行一个脚本必须要使这个脚本有执行权限,我们需要使用chmod +x scripname.sh,给脚本附加执行权限,最后在命令行输入脚本名称即可。(如果错误信息为not found 两种方法一种是在PATH环境变量中加脚本所在的路径,另一种就是在命令行打出脚本的路径和名称) 第二,我们也可以不给脚本赋执行权限,我们可以使用解释器来执行,bash scripname.sh,同样也可以执行。

如何在脚本中进行条件判断? 练习:写一个脚本,完成以下任务 1、添加5个用户, user1,..., user5 2、每个用户的密码同用户名,而且要求,添加密码完成后不显示passwd命令的执行结果信息; 3、每个用户添加完成后,都要显示用户某某已经成功添加;

条件判断: 如果用户不存在 添加用户,给密码并显示添加成功; 否则 显示如果已经没在,没有添加;

  • 这里需要用到逻辑判断 逻辑与: && 与:1 0=0,0 1=0,0 0=0,1 1=1 第一个条件为假时,第二条件不用再判断,因为第一个为假第二个不管是真还是假结果都是假,所以只执行第一个条件; 第一个条件为真时,第二条件必须得判断;

    逻辑或: || 或:1 0=1,0 1=1,0 0=0,1 1=1 第一个条件为假时,第二个条件必须得判断; 第一个条件为真时,第二个条件不要再判断;

如果用户user6不存在,就添加用户user6 ! id user6 && useradd user6 id user6 || useradd user6

如果/etc/inittab文件的行数大于100,就显示好大的文件; [ wc -l /etc/inittab | cut -d' ' -f1 -gt 100 ] && echo "Large file."

如果用户存在,就显示用户已存在;否则,就添加此用户; id user1 && echo "user1 exists." || useradd user1

如果用户不存在,就添加;否则,显示其已经存在; ! id user1 && useradd user1 || echo "user1 exists."

如果用户不存在,添加并且给密码;否则,显示其已经存在; ! id user1 && useradd user1 && echo "user1" | passwd --stdin user1 || echo "user1 exists."


bash中如何实现条件判断? 条件测试类型: 整数测试 字符测试 文件测试

条件测试的表达式: [ expression ] [[ expression ]] test expression

  • 整数比较: -eq: 测试两个整数是否相等;比如 $A -eq $B -ne: 测试两个整数是否不等;不等,为真;相等,为假; -gt: 测试一个数是否大于另一个数;大于,为真;否则,为假; -lt: 测试一个数是否小于另一个数;小于,为真;否则,为假; -ge: 大于或等于 -le:小于或等于

  • 文件测试: -e FILE:测试文件是否存在 -f FILE: 测试文件是否为普通文件 -d FILE: 测试指定路径是否为目录 -r FILE: 测试当前用户对指定文件是否有读取权限; -w -x [ -e /etc/inittab ] [ -x /etc/rc.d/rc.sysinit ]

  • 字符测试:(比较时记得等号两端需要加空格!!!否则会识别成赋值) ==:测试是否相等,相等为真,不等为假 !=: 测试是否不等,不等为真,等为假 -n string: 测试指定字符串是否为空,空则真,不空则假 -z string: 测试指定字符串是否不空,不空为真,空则为假

  • 组合条件测试:(前后都需要有空格) -a: 与关系 -o: 或关系 !: 非关系 但是比如说 if [ $1 = "A" -a $1 = "B" ]这个相当于如果$1是字符A或B就执行某操作,但如果要将其取反 if [ !($1 = "A" -a $1 = "B") ]这样是不可以的!!!只能写成if [ ! $1 = "A" ] && [ ! $1 = "B" ] 这个理解起来就和逻辑运算的与或一样,自己在一个方框里画两个有交集的圆就了解了。


  • 条件判断,控制结构: 单分支if语句 if 判断条件; then statement1 statement2 ... fi

  • 双分支的if语句: if 判断条件; then statement1 statement2 ... else statement3 statement4 ... fi

  • 多分支的if语句: if 判断条件1; then statement1 ... elif 判断条件2; then statement2 ... elif 判断条件3; then statement3 ... else statement4 ... fi


  • shell中如何进行算术运算: A=3 B=6 1、let 算术运算表达式 let C=$A+$B 2、$[算术运算表达式] C=$[$A+$B] 3、$((算术运算表达式)) C=$(($A+$B)) 4、expr 算术运算表达式,表达式中各操作数及运算符之间要有空格,而且要使用命令引用 C=expr $A + $B

  • 定义脚本退出状态码 exit: 退出脚本 exit 后面加数字,0是正确执行返回码,其余的都是错误执行返回码 如果脚本没有明确定义退出状态码,那么,最后执行的一条命令的退出码即为脚本的退出状态码;

  • 测试脚本是否有语法错误: bash -n 脚本

bash -x 脚本:单步执行


  • bash变量的类型: 本地变量(局部变量) 环境变量(当前shell及其子shell) 位置变量: $1, $2, ... shift(下一个变量$1 shift $2 ,变量二就提到了变量一的位置) 特殊变量: $?:命令执行的状态返回值 $#:参数的个数 $*: 参数列表 $@:参数列表

./filetest.sh /etc/fstab /etc/inittab $1: /etc/fstab $2: /etc/inittab

  • 练习:写一脚本 能接受一个参数(文件路径) 判定:此参数如果是一个存在的文件,就显示“OK.”;否则就显示"No such file." #!/bin/bash if [ -e $1 ]; then echo "ok" else echo "no file" fi 运行: ./filetest.sh /etc/fstab ok