Linux——shell编程

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

猜你喜欢

转载自blog.csdn.net/sinat_39440759/article/details/82919573