第八章、bash脚本编程(上)

来源:互联网 发布:装修vr软件 编辑:程序博客网 时间:2024/06/06 07:14

第八章、bash脚本编程(上)


05_02_bash脚本编程之一 变量、变量类型等


shell编程: 脚本编程

 

语言转换器:编译器,解释器

 

编程语言:机器语言、汇编语言、高级语言

 

静态语言:编译型语言

         特点:强类型(变量)

                     事先转换成可执行格式

         包括:C、C++、JAVA、C#

        

动态语言:解释型语言, on the fly

         特点:弱类型

                   边解释边执行

         包括:PHP、SHELL、python、perl

 

面向过程:Shell, C

面向对象: JAVA, Python, perl, C++

 

变量:内存空间,命名

内存:编址的存储单元

 

变量类型:事先确定数据的存储格式和长度

         字符

         数值

                   整型

                   浮点型: 11.23, 1.123*10^1, 0.1123*10^2


存储日期:         

字符:2013/10/10 -  64bit

数值: 99999 - 24bit,


        布尔:真、假    

        

逻辑:1+1>2

逻辑运算:与、或、非、异或

1: 真

0: 假

 

1 & 0  = 0

0 & 1 = 0

0 & 0 = 0

1 & 1 = 1

 

或:

 

非:

! 真 = 假

! 假 = 真


异或:相异为1,相同为0

 

shell: 弱类型编程语言

 

强类型,弱类型的特点:

强:变量在使用前,必须事先声明,甚至还需要初始化;

弱:变量用时声明,甚至不区分类型;

 

变量赋值:VAR_NAME=VALUE

 

bash变量类型:

         环境变量

         本地变量(局部变量)

         位置变量

         特殊变量

        

1. 本地变量:<set> VARNAME=VALUE: 作用域为整个bash进程;set 可以省略

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

3. 环境变量:作用域为当前shell进程及其子进程;

                export VARNAME=VALUE

                或 

                VARNAME=VALUE; export VARNAME

                 export:“导出”

                export PATH=$PATH:/usr/local/mypath

 

4. 位置变量:$1, $2, ...

5. 特殊变量:$?: 上一个命令的执行状态返回值;

 

程序执行,可能有两类返回值:

         1. 程序执行结果

         2. 程序状态返回代码(0-255)

                   0: 正确执行

                   1-255:错误执行,1,2,127系统预留;

                  

输出重定向:

>  覆盖重定向

>>  追加重定向

2>  错误重定向   

2>>错误追加重定向

&> 同时重定向

 

/dev/null: 软件设备, bit bucket,数据黑洞    


撤消变量:

unset VARNAME

 

查看当shell中变量:

set:包括本地变量和环境变量

 

查看当前shell中的环境变量:

printenv

env

export

 

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

 

脚本的特殊标记:

shebang: 魔数

#!/bin/bash

# 注释行,不执行

        

脚本在执行时会启动一个子shell进程;

         1. 命令行中启动的脚本会继承当前shell环境变量;

         2. 系统自动执行的脚本(非命令行启动)就需要自我定义需要各环境变量;

        

        

05_03_bash脚本编程之二    条件判断


练习:写一个脚本,完成以下任务 - 答案为addusers.sh

1、添加5个用户, user1,..., user5

2、每个用户的密码同用户名,而且要求,添加密码完成后不显示passwd命令的执行结果信息;

3、每个用户添加完成后,都要显示用户某某已经成功添加;

#!/bin/bash

useradd user1

echo "user1" | passwd --stdin user1 &> /dev/null

echo "Add user1 successfully."

 

条件判断:

         如果用户不存在

                   添加用户,给密码并显示添加成功;

         否则

                   显示如果已经没在,没有添加;

 

bash中如何实现条件判断?

条件测试类型:

         整数测试

         字符测试

         文件测试

 

条件测试的表达式:

         [ expression ] : 中括号和expression之间必须有空格

         [[ expression ]]

         test expression

        

整数比较:

         -eq: 测试两个整数是否相等;比如 $A -eq $B

         -ne: 测试两个整数是否不等;不等,为真;相等,为假;

         -gt: 测试一个数是否大于另一个数;大于,为真;否则,为假;

         -lt: 测试一个数是否小于另一个数;小于,为真;否则,为假;

         -ge: 大于或等于

         -le:小于或等于

        

命令的逻辑关系:

         逻辑与: &&

                   第一个条件为假时,第二条件不用再判断,最终结果已经有;

                   第一个条件为真时,第二条件必须得判断;

         逻辑或: ||

        

如果用户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."

 

变量名称:

         1、只能包含字母、数字和下划线,并且不能数字开头;

         2、不应该跟系统中已有的环境变量重名;

         3、最好做到见名知义;

 

如果用户存在,就显示用户已存在;否则,就添加此用户;

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."

 

 

练习,写一个脚本,完成以下要求: - 答案为adduser2.sh文件

1、添加3个用户user1, user2, user3;但要先判断用户是否存在,不存在而后再添加;

2、添加完成后,显示一共添加了几个用户;当然,不能包括因为事先存在而没有添加的;

3、最后显示当前系统上共有多少个用户;


 

练习,写一个脚本,完成以下要求: - 答案为third.sh文件 

给定一个用户:

         1、如果其UID为0,就显示此为管理员;

         2、否则,就显示其为普通用户;


使用if语句:

如果 UID为0;那么

  显示为管理员

否则

  显示为普通用户

 

NAME=user16

USERID=`id -u $NAME`

if [ $USERID -eq 0 ]; then

  echo "Admin"

else

  echo "common user."

fi

 

NAME=user16

if [ `id -u $NAME` -eq 0 ]; then

  echo "Admin"

else

  echo "common user."

fi

 



05_04_bash脚本编程之三 条件判断及算术运算


1. 练习:写一个脚本  - 答案为 bash.sh

判断当前系统上是否有用户的默认shellbash

   如果有,就显示有多少个这类用户;否则,就显示没有这类用户;

grep "bash$" /etc/passwd &> /dev/null

RETVAL=$?

if [ $RETVAL -eq 0 ]; then

  

if grep "bash$" /etc/passwd &> /dev/null; then

        

提示:“引用”一个命令的执行结果,要使用命令引用;比如: RESAULTS=`wc -l /etc/passwd | cut -d: -f1`

      使用一个命令的执行状态结果,要直接执行此命令,一定不能引用;比如: if id user1一句中的id命令就一定不能加引号;

           如果想把一个命令的执行结果赋值给某变量,要使用命令引用,比如USERID=`id -u user1`;

      如果想把一个命令的执行状态结果保存下来,并作为命令执行成功与否的判断条件,则需要先执行此命令,而后引用其状态结果,如

                   id -u user1

                   RETVAL=$?

                   此句绝对不可以写为RETVAL=`id -u user1`

        

        

2. 练习:写一个脚本  - 答案为bash2.sh

判断当前系统上是否有用户的默认shellbash

   如果有,就显示其中一个的用户名;否则,就显示没有这类用户;

 

3. 练习:写一个脚本

给定一个文件,比如/etc/inittab

判断这个文件中是否有空白行;

如果有,则显示其空白行数;否则,显示没有空白行。

                                      

#!/bin/bashFILE=/etc/inittabif [ ! -e $FILE ]; then  echo "No $FILE."  exit 8fi if grep "^$" $FILE &> /dev/null; then  echo "Total blank lines: `grep "^$" $FILE | wc -l`."else  echo "No blank line."fi


 

4. 练习:写一个脚本

给定一个用户,判断其UIDGID是否一样

如果一样,就显示此用户为“good guy”;否则,就显示此用户为“bad guy”。

#!/bin/bashUSERNAME=user1USERID=`id -u $USERNAME`GROUPID=`id -g $USERNAME`if [ $USERID -eq $GROUPID ]; then  echo "Good guy."else  echo "Bad guy."fi


 

进一步要求:不使用id命令获得其id号;

 

#!/bin/bash#USERNAME=user1if ! grep "^$USERNAME\>" /etc/passwd &> /dev/null; then  echo "No such user: $USERNAME."  exit 1fi USERID=`grep "^$USERNAME\>" /etc/passwd | cut -d: -f3`GROUPID=`grep "^$USERNAME\>" /etc/passwd | cut -d: -f4`if [ $USERID -eq $GROUPID ]; then  echo "Good guy."else  echo "Bad guy."fi


 

5. 练习:写一个脚本

给定一个用户,获取其密码警告期限;

而后判断用户密码使用期限是否已经小于警告期限;

         提示:计算方法,最长使用期限减去已经使用的天数即为剩余使用期限;

        

如果小于,则显示“Warning”;否则,就显示“OK”。

 

圆整:丢弃小数点后的所有内容

 

#!/bin/bashW=`grep "student" /etc/shadow | cut -d: -f6`S=`date +%s`T=`expr $S/86400`L=`grep "^student" /etc/shadow | cut -d: -f5`N=`grep "^student" /etc/shadow | cut -d: -f3`SY=$[$L-$[$T-$N]] if [ $SY -lt $W ]; then  echo 'Warning'else  echo 'OK'fi

 

6. 练习:写一个脚本

判定命令历史中历史命令的总条目是否大于1000;如果大于,则显示“Some command will gone.”;否则显示“OK”。

 history | tail -1 | cut -d' ' -f1

需要去掉开头的空格,cut 无法解决,留疑

 

shell中如何进行算术运算:

A=3

B=6

1let 算术运算表达式

         let C=$A+$B

2$[算术运算表达式]

         C=$[$A+$B]

3$((算术运算表达式))

         C=$(($A+$B))

4expr 算术运算表达式,表达式中各操作数及运算符之间要有空格,而且要使用命令引用

         C=`expr $A + $B`

 

条件判断,控制结构:

1. 单分支if语句

if 判断条件; then

  statement1

  statement2

  ...

fi

 

2. 双分支的if语句:

if 判断条件; then

         statement1

         statement2

         ...

else

         statement3

         statement4

         ...

fi

 

3. 多分支的if语句:

if 判断条件1; then

  statement1

  ...

elif 判断条件2; then

  statement2

  ...

elif 判断条件3; then

  statement3

  ...

else

  statement4

  ...

fi



06_01_bash脚本编程之四 整数测试及特殊变量

     


复习:

测试方法:

[ expression ]

[[ expression ]]

test expression


bash中常用的条件测试有三种:整数,字符串,文件

整数测试:

 -gt

 -le

 -ne

 -eq

 -ge

 -lt


INT1=63

INT2=77

[ $INT1 -eq $INI2 ]

[[ $INT1 -eq $INT2 ]]

test $INT1 -eq $INT2 


文件测试:    

-e FILE:测试文件是否存在,exist的简写

-f FILE: 测试文件是否为普通文件

-d FILE: 测试指定路径是否为目录

-r FILE: 测试当前用户对指定文件是否有读取权限;

-w FILE:   ~写权限

-x FILE:    ~执行

 

e.g: 

[ -e /etc/inittab ]

[ -x /etc/rc.d/rc.sysinit ] 

 

练习:写一个脚本 - 答案为filetest2.sh

给定一个文件:

如果是一个普通文件,就显示之;

如果是一个目录,亦显示之;

否则,此为无法识别之文件;

 

定义脚本退出状态码

exit: 退出脚本

exit #

如果脚本没有明确定义退出状态码,那么,最后执行的一条命令的退出码即为脚本的退出状态码;

 

测试脚本是否有语法错误:

bash -n 脚本

 

调试脚本:

bash -x 脚本:打印每步执行

 

bash变量的类型:

         本地变量(局部变量)

         环境变量

         位置变量:

                   $1, $2, ...

                   shift [n]:移出前面的n(默认为1)个参数,后面的参数向前移

         特殊变量:

                   $?

                   $#:参数的个数

                   $*: 参数列表

                   $@:参数列表

    

e.g:     

./filetest.sh /etc/fstab /etc/inittab

$1: /etc/fstab

$2: /etc/inittab

 

练习:写一脚本 - 答案为 filetest3.sh

能接受一个参数(文件路径)

判定:此参数如果是一个存在的文件,就显示“OK.”;否则就显示"No such file."

 

练习:写一个脚本 - 答案为 cacl.sh

给脚本传递两个参数(整数)

显示此两者之和,之乘积;

#!/bin/bash

#

if [ $# -lt 2 ]; then

  echo "Usage: cacl.sh ARG1 ARG2"

  exit 8

fi

 

echo "The sum is: $[$1+$2]."

echo "The prod is: $[$1*$2]."

 

练习:写一个脚本,完成以下任务

1、使用一个变量保存一个用户名;

2、删除此变量中的用户,且一并删除其家目录;

3、显示“用户删除完成”类的信息;

 #!/bin/bash

#

USER=user1

if userdel -r $USER; then

    echo "Delete user finished."

else

    echo "Delete user failed."

fi



06_03_bash脚本编程之五 字符串测试及for循环

        

shell编程引用变量:${VARNAME}, 括号有时可省略。

 

1. 练习: - 答案为testuser.sh

传递一个用户名参数给脚本,判断此用户的用户名跟其基本组的组名是否一致,并将结果显示出来。

#!/bin/bash

if [ 'id -nu $1' == 'id -gu $1' ]; then

fi 


字符串测试:符号两端要有空格

==:测试是否相等,相等为真,不等为假

!=:测试是否不等,不等为真,等为假

>:一般不用

< :一般不用

-z string: 测试指定字符串是否为空,空则真,不空则假

-n string: 测试指定字符串是否不空,不空为真,空则为假

 

2. 练习:写一个脚本

传递一个参数(单字符就行)给脚本,如参数为q,就退出脚本;否则,就显示用户的参数;

 

3. 练习:写一个脚本

传递一个参数(单字符就行)给脚本,如参数为qQquitQuit,就退出脚本;否则,就显示用户的参数;

#!/bin/bash

if [ $1 = 'q' ];then

  echo "Quiting..."

  exit 1

elif [ $1 = 'Q' ];then

  echo "Quiting..."

  exit 2 

elif [ $1 = 'quit' ];then

  echo "Quiting..."

  exit 3

elif [ $1 = 'Quit' ];then

  echo "Quiting..."

  exit 4 

else

  echo $1

fi

 

4. 练习:

传递三个参数给脚本,第一个为整数,第二个为算术运算符,第三个为整数,将计算结果显示出来,要求保留两位精度。形如:

./calc.sh 5 / 2

提示:

scale=2保留两位精度

echo "scale=2;111/22;" | bc

bc <<< "scale=2;111/22;" 


#!/bin/bash

if [ $# -lt 3 ]; then 

    echo "Usage: `basename $0` num1 opt num2"

    exit 1

fi

bc <<< "scale=2;$1 $2 $3"


5. 练习:

传递3个参数给脚本,参数均为用户名。将此些用户的帐号信息提取出来后放置于/tmp/testusers.txt文件中,并要求每一行行首有行号。

        

6. 练习,写一个脚本:

判断当前主机的CPU生产商,其信息在/proc/cpuinfo文件中vendor_id一行中。

如果其生产商为AuthenticAMD,就显示其为AMD公司;

如果其生产商为GenuineIntel,就显示其为Intel公司;

否则,就说其为非主流公司;


#!/bin/bash

VENDOR_ID=`grep vendor_id /proc/cpuinfo | head -1 | cut -d' ' -f2` 

if [ $VENDOR_ID == "AuthenticAMD" ]; then

    echo "AMD company"

elif [ $VENDOR_ID == "GenuineIntel" ]; then

    echo "Intel company"

fi


7. 练习,写一个脚本:

给脚本传递三个整数,判断其中的最大数和最小数,并显示出来。

MAX=0

MAX -eq $1

MAX=$1

MAX -lt $2

MAX=$2

 

 

循环:一定要有:进入条件,退出条件

1. for

2. while

3. until

 

for循环语句

for 变量 in 列表; do

  循环体

done


列表遍历完成之后,退出; 


e.g:

for I in 1 2 3 4 5 6 7 8 9 10; do

  加法运算

done

 

如何生成列表:

1. {1..100}

2. seq命令:`seq [起始数 [步进长度]] 结束数`,

 

8. 练习:求1-100的和 - 答案为sum.sh


declare: 

         -i: 将一个变量声明为整型,integer

         -x: 将一个变量声明为环境变量

e.g: declare -i SUM=0


9. 写一个脚本:

1、设定变量FILE的值为/etc/passwd

2、依次向/etc/passwd中的每个用户问好,并显示对方的shell,形如: 

         Hello, root, your shell: /bin/bash

3、统计一共有多少个用户

 

for I in `seq 1 $LINES`; do echo "Hello, `head -n $I /etc/passwd | tail -1 | cut -d: -f1`"; done

 

只向默认shellbash的用户问声好

 




0 0
原创粉丝点击