Linux学习----bash脚本编程


shell脚本编程

扩展知识

编译器 |  解释器

编程语言的分类:
机器语言、汇编语言、高级语言

静态语言:编译型语言
        强类型(变量类型):变量使用前必须事先声明,甚至需要初始化。未初始化的变量存储随机数。
        事先转换成可执行格式
        c\c++\java\c#

动态语言:解释型语言,  on the fly
        弱类型:变量无需事先声明,可直接使用。甚至不区分类型,默认为字符串。
        边解释边执行
        python\php\shell\perl

shell脚本属于面向过程。

一、变量的介绍

变量:内存空间

命名的内存空间。

字符型:10  ---16bit
数值型:10  ---> 1010 ----4bit  需要 8bit(最小存储单位)

不同变量类型具有不同的数据格式,所需的内存空间也不一样。
变量类型:事先定义数据的存储格式和长度。

        字符
        数值
               整型
               浮点型
        布尔型

变量赋值

set    VAR_NAME = VALUE

二、bash变量类型


本地变量(局部变量)
环境变量
位置变量
特殊变量

2.1 本地变量:

       VARNAME=VALUE  作用域是整个bash进程。
       局部变量:  local  VARNAME=VALUE  仅对当前代码段有效。

[root@localhost ~]# NAME=Beny
[root@localhost ~]# echo $NAME
Beny
[root@localhost ~]# bash
[root@localhost ~]# echo $NAME

引用变量:${VARNAME}  ,括号有时可省略
 
[root@localhost ~]# ANIMAL=pig
[root@localhost ~]# echo "There are some $ANIMALs.
> "
There are some .

[root@localhost ~]# echo "There are some ${ANIMAL}s."
There are some pigs.
单引号是强引用,不实现变量替换。双引号是弱引用,可以实现变量替换。
[root@localhost ~]# echo 'There are some ${ANIMAL}s.'
There are some ${ANIMAL}s.


2.2 环境变量:

作用域为当前shell进程及其子进程。
export    VARNAME=VALUE

VARNAME=VALUE
export   VARNAME

脚本在执行时会启动一个子shell进程。
        命令行中启动的脚本会继承当前shell环境变量。
        系统自动执行的脚本(非命令行启动)就需要自我定义需要的环境变量。

[root@localhost ~]# export NAME
[root@localhost ~]# echo $NAME
Beny
[root@localhost ~]# bash
[root@localhost ~]# echo $NAME
Beny
[root@localhost ~]# bash
[root@localhost ~]# echo $NAME
Beny


2.3 位置变量:

$1  $2   $3   ……
在脚本中引用参数。
./file.sh  /etc/fstab  /etc/inittab
$1: /etc/fstab
$2: /etc/inittab

练习:接受一个参数(文件路径),判断此参数如果存在,就显示OK,否则显示NO Such file。
[root@localhost shell_example]# bash -x filetest1.sh /etc/fstab 
+ '[' '!' -e /etc/fstab ']'
+ echo OK
OK
[root@localhost shell_example]# bash -x filetest1.sh
+ '[' '!' -e ']'
+ echo OK
OK

shift  将使用过的参数清空,后一个参数前移---$2变成$1
#!/bin/bash

echo $#
echo $*

echo $1
shift
echo $1
shift
echo $1
[root@localhost shell_example]# bash -x shift.sh 1 2 3
+ echo 3
3
+ echo 1 2 3
1 2 3
+ echo 1
1
+ shift
+ echo 2
2
+ shift
+ echo 3
3


#!/bin/bash


if [ $# -lt 2 ] ; then
    echo "usage: ./add.sh  arg1  arg2"
    exit 3
fi

echo "The sum is : $[$1+$2]."
echo "The prod is : $[$1*$2]."
[root@localhost shell_example]# ./add.sh  2 6
The sum is : 8.
The prod is : 12.
[root@localhost shell_example]# ./add.sh  2 6 3
The sum is : 8.
The prod is : 12.





2.4 特殊变量:

$? : 上一个命令执行状态返回值
[root@localhost ~]# ls /var/
account  caozesheng_py  empty  gopher    local  mail  preserve  target  yp
adm      crash          games  kerberos  lock   nis   run       tmp
cache    db             gdm    lib       log    opt   spool     var
[root@localhost ~]# echo $?
0
[root@localhost ~]# ls /vaarr
ls: 无法访问/vaarr: 没有那个文件或目录
[root@localhost ~]# echo $?
2
[root@localhost ~]# lss /var
bash: lss: 未找到命令...
相似命令是: 'ls'
[root@localhost ~]# echo $?
127

程序执行,可能有两类返回值:
        程序执行结果
        程序执行返回代码(0-255)
                    0:正确执行
                    1-255:错误执行。  1、2、127 系统预留。

输出重定向:
>
>>
2>
2>>
&>

/dev/null : 软件模拟的设备。 bit bucket  位桶。数据黑洞。


$#:参数的个数
$* :参数列表
$@:参数列表

#!/bin/bash

echo $#
echo $*
echo $@
if [ $# -lt 1 ] ;then
    echo "Usage:  ./filetest1.sh  arg1 [arg2,....]"
    exit 7
fi

if [ ! -e $1 ] ; then
    echo "no such file"
else
    echo "OK"
fi



 

2.5 如何撤销变量:

unset  VARNAME    撤销变量

[root@localhost ~]# echo $NAME
Beny
[root@localhost ~]# unset NAME
[root@localhost ~]# echo $NAME


查看当前shell中的变量:

set

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

printenv
env
export

[root@localhost ~]# ANIMALS=pig
[root@localhost ~]# ANIMALS=$ANIMALS:goat
[root@localhost ~]# echo $ANIMALS
pig:goat
[root@localhost ~]# ANIMALS=$ANIMALS:sheep
[root@localhost ~]# echo $ANIMALS
pig:goat:sheep

[root@localhost ~]# a=1
[root@localhost ~]# b=2
[root@localhost ~]# c=$a+$b
[root@localhost ~]# echo $c
1+2




三、脚本:命令的堆砌

按照实际需要,结合命令流程控制机制实现的源程序。
shebang:魔数
#!/usr/bin/bash
# 注释行,不执行。

[root@localhost ~]# bash first.sh 

#
# /etc/fstab
# Created by anaconda on Sat Apr 16 18:39:54 2016
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=0c8c0c2c-d3b8-4658-b899-0fed6a2e94d2 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0
account  caozesheng_py	empty  gopher	 local	mail  preserve	target	yp
adm	 crash		games  kerberos  lock	nis   run	tmp
cache	 db		gdm    lib	 log	opt   spool	var

练习:
添加5个用户,user1、user2.。。。。
密码同用户名。添加密码完成后不显示passwd命令的执行结果信息。
每个用户添加完成后,显示“用户xxxx已经成功添加”

#!/usr/bin/bash
for i in `seq 5`
do
useradd user${i}
echo user${i} |  passwd --stdin user${i}  &> /dev/null
echo "用户 user${i} 已经成功添加"
done


练习:
使用一个变量保存一个用户名
删除此变量中的用户,且一并删除其家目录。
显示“用户删除完成”类的信息。
#!/usr/bin/bash
USER=user1
userdel -r $USER
echo "用户删除完成"



         

3.1 条件判断


条件测试类型:
            整数测试
            字符测试
            文件测试


条件测试的表达式:
            [ expression ]    命令测试法
            [[ expression ]]     关键字测试法
            test  expression

3.1.1 整数比较:双目操作,一般需要两个操作数

-eq : 测试两个整数是否相等。 例:$A  -eq  $B  
[root@localhost shell_example]# A=3
[root@localhost shell_example]# B=6
[root@localhost shell_example]# [ $A -eq $B ]
[root@localhost shell_example]# echo $?
1
[root@localhost shell_example]# B=3
[root@localhost shell_example]# [ $A -eq $B ]
[root@localhost shell_example]# echo $?
0

-ne:测试两个整数 是否不等
-gt:测试一个数是否大于另一个数。大于为真,否则为假。
-lt:测试一个数是否小于另一个数。
-ge: 大于或等于
-le:小于或等于


命令间的逻辑关系
           逻辑与: &&
           
[root@localhost shell_example]# id user2 &> /dev/null && echo "Hello, user2"
Hello, user2
[root@localhost shell_example]# id user1 &> /dev/null && echo "Hello, user2"

           逻辑或: ||

id user0 && echo "user0 exists." || useradd user0

! id user0 && useradd user0 || echo "user0 exists."

! id user0 && useradd user0  && echo "user0" | passwd --stdin user0 || echo "user0 exists."


1、命令的执行状态结果可以作为判断条件 --  "$?"

条件判断,控制结构:

单分支if语句:


if  判断条件; then
    suit1
    suit2
    .......
fi

双分支if语句:


if  判断条件
then
    suit1
    suit2
    ...
else
    suit3
    suit4
    ...
fi


case语句

case SWITCH in
value1)
      statment
      ...
      ;;
value2)
      statment
      ....
      ;;
*)
     statment
     ……
     ;;
esac

#!/bin/bash

echo $1

case $1 in
[0-9])
    echo "A digit" ;;
[a-z])
    echo "Lower" ;;
[A-Z])
    echo "Upper" ;;
*)
    echo "Spicial character" ;;
esac






练习:
判断当前系统上是否有用户的默认shell为bash。如果有,就显示有多少个这类用户,否则显示没有这类用户。
显示其中一个这样的用户名。

#!/bin/bash

grep "\ /dev/null
RETVAL=$?
if [ $RETVAL -eq 0 ]
then
    AUSER=`grep "\

练习:
给定一个文件,/etc/inittab,判断是否有空白行,若有,显示空白行数,否则显示无空白行。
#!/bin/bash


FILE=/etc/inittab
if [ ! -e $FILE ]
then
    echo "File is not exists."
    exit 0
fi

if grep "^$" $FILE &> /dev/null
then
    echo "Tatal blank lines is : `grep "^$" $FILE | wc -l`"
else
    echo "No blank lines"
fi



练习:
给定用户,判断密码警告期限,判断时间间距是否小于警告期限,如果小于,提示warning,否则,ok
#!/bin/bash

USERNAME=root
TIMESTAMP=`date +%s`
TODAY=$[$TIMESTAMP/86400]
MAX=`grep "^root" /etc/shadow | cut -d: -f5`
CHANGE=`grep "^root" /etc/shadow | cut -d: -f3`
USE=$[$TODAY-$CHANGE]
REMAIN=$[$MAX-$USE]
WARNINGDAY=`grep "^root" /etc/shadow | cut -d: -f6`

if [ $WARNINGDAY -gt $REMAIN ]
then
    echo "Warning"
else
    echo "OK"
fi




shell中进行算术运算

[root@localhost ~]# A=3
[root@localhost ~]# B=3
[root@localhost ~]# C=$A+$B
[root@localhost ~]# echo $C
3+3
[root@localhost ~]# let C=$A+$B
[root@localhost ~]# echo $C
6


[root@localhost ~]# D=$[$A+$B]
[root@localhost ~]# echo $D
6

[root@localhost ~]# E=$(($A+$B))
[root@localhost ~]# echo $E
6

exper  算术运算表达式,表达式中各操作数及运算符之间要有空格,而且要使用命令引用
[root@localhost ~]# F=`expr $A + $B `
[root@localhost ~]# echo $F
6


3.2 文件测试

-e FILE:文件是否存在
-f  FILE: 文件是否为普通文件
-d  FILE:指定路径是否为目录
-r FILE:当前用户对指定文件是否有读权限
-w                                                            写
-x                                                             执行
 
[ -e /etc/passwd ]

多分支if语句

if 判断条件1
then
    suit1
    .......
elif  判断条件2
then
     suit2
     .....
elif  判断条件3
then
     suit3
     ......
else
     suit4
    .....
fi
#!/bin/bash

FILE=/etc/passwd

if [ ! -e $FILE ] ; then
    echo "NO such file"
    exit 6
fi

if [ -f $FILE ] ; then
    echo "It's common file"
elif [ -d $FILE ] ; then
    echo "It's a dictionary"
else
    echo "I don't kown"
fi



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

bash -x  单步执行的过程显示。
[root@localhost shell_example]# bash -x file.sh 
+ FILE=/etc/inittab
+ '[' '!' -e /etc/inittab ']'
+ grep '^$' /etc/inittab
+ echo 'No blank lines'
No blank lines

exit:退出脚本
exit  n 自定义运行结束状态码

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

[root@localhost shell_example]# bash -x filetest.sh 
+ FILE=/etc/asdf
+ '[' '!' -e /etc/asdf ']'
+ echo 'NO such file'
NO such file
+ exit 6


字符串测试

== / =  :两个字符串是否相等。 等号两端需要空格。
!=  :是否不等。 !=  需要空格。
>  
<
-n  string : 测试指定字符串是否为空,空则真。
-z  string : 测试指定字符串是否不空,不空则真。

[root@localhost shell_example]# [ $A == $B ]
[root@localhost shell_example]# echo $?
1
[root@localhost shell_example]# [ $A = $B ]
[root@localhost shell_example]# echo $?
1
[root@localhost shell_example]# B=hello
[root@localhost shell_example]# [ $A = $B ]
[root@localhost shell_example]# echo $?
0

[root@localhost shell_example]# [ -e asdf ]
[root@localhost shell_example]# echo $?
1
[root@localhost shell_example]# [ -e ]
[root@localhost shell_example]# echo $?
0


循环控制结构

for
while
until

for 变量 in  列表
do
     循环体
done

生成列表:
{1..100}

seq

SYNOPSIS
       seq [OPTION]... LAST
       seq [OPTION]... FIRST LAST
       seq [OPTION]... FIRST INCREMENT(步进) LAST

for i in `seq 10`
do
........
done

declare  -i  SUM  声明SUM就是个整型。

#!/bin/bash

let SUM=0

for i in `seq 100`
do
   let  SUM=$[$SUM+$i]
done

echo $SUM


组合测试条件:
-a  :与关系
-o  :或关系
!  :非关系

if [ $# -gt 1 -a $# -le 3 ]
if [ $# -gt 1 ] && [ $# -le 3 ]













练习:

1、向系统的所有用户问好,并显示shell
#!/bin/bash

LINES=`wc -l /etc/passwd | cut -d' ' -f1`
for i in `seq 1 $LINES`
do
    echo "hello `head -n $i /etc/passwd | tail -1 | cut -d: -f1` and your shell is `head -n $i /etc/passwd | tail -1 | cut -d: -f7`"
done
~    


2、添加10个用户,用户名等同密码。接受参数add添加,del删除,其他字符串,退出。

#!/bin/bash


if [ $1 == 'add' ] ; then
    for i in `seq 10` ; do
        useradd user$i
        echo "user$i" | passwd --stdin user$i &>/dev/null
    done
elif [ $1 == 'del' ]; then
    for i in `seq 10` ; do
        userdel -r user$i
    done
else
    echo "Quiting......"
    exit 10
fi


3、100以内被3整除的整数的和。

#!/bin/bash


declare -i sum=0

for i in `seq 100` ; do
    if [ $[$i%3] -eq 0 ] ;then
        sum=$[$sum+$i]
    else
        echo "$i not div 3"   
    fi
done

echo "The sum is : $sum"


4、100以内奇数的和和偶数的和,分别显示。

#!/bin/bash

declare -i sum1=0
declare -i sum2=0

for i in `seq 0 2 100`; do
    sum2=$[$sum2+$i]
done

for i in `seq 1 2 100`; do
    sum1=$[$sum1+$i]
done

echo "The odd number sum is : $sum1 ."
echo "The even number sum is : $sum2 ."

5、分别统计shell为bash,nologin的用户,并统计用户总数。

declare -i bashnum=0
declare -i nologinnum=0

let num=`wc -l /etc/passwd | cut -d' ' -f1`
for i in `seq $num` ;do
    username=`head -n $i /etc/passwd | tail -1 | cut -d: -f1`
    shell=`head -n $i /etc/passwd | tail -1 | cut -d: -f7`
    if [ `echo $shell | sed -r "s@^/.*/([^/]+/?)@\1@g" ` == 'bash' ]; then
        bashnum=$[$bashnum+1]
        echo $username >> /tmp/bash.txt
    elif [ `echo $shell | sed -r "s@^/.*/([^/]+/?)@\1@g"` == 'nologin' ]; then
        nologinnum=$[$nologinnum+1]
        echo $username >> /tmp/nologin.txt
    fi
done
















练习:

1、传递一个用户名参数给脚本,判断此用户的用户名跟其基本组的组名是否一致,并将结果输出
#!/bin/bash


if ! id $1 &>/dev/null
then
   echo "no such user"
   exit 10
fi
if [ `id -n -u $1` == `id -n -g $1` ]
then
    echo  "same"
else
    echo  "no same"
fi


2、传递三个参数给脚本,第一个是整数、第二个是运算符、第三个是整数,将计算结果输出,保留两位精度。

echo "scale=2;$1$2$3;" | bc
[root@localhost shell_example]# bc <<< "scale=2;5/3;"

3、传递三个用户名给脚本,将这些用户的账号信息提取出来放置于/tmp/testusers.txt文件中,每行行首有行号。

4、判断当前主机CPU生产商,/proc/cpuinfo 中 vandor id,判断是哪个生产商,就显示结果是AMD或Intel,否则是非主流公司,


5、给脚本3个整数,判断最大最小数并输出。
6、传递一个参数-单字符,如果参数为q或者Q,或quit,或Quit,退出,否则,显示用户的参数。
#!/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


7. 传递多个参数,-c -v -h 来查看当前系统的登录用户,以及详细信息。
#!/bin/bash
#


declare -i count=0
declare -i info=0


for i in `seq 1 $#`; do
    if [ $# -gt 0 ]; then
        case $1 in
        -h|--help)
            echo "usage: `basename $0` -h|--help -c|--count -v|--verbose"
            exit 0
            ;;
        -v|--verbose)
            let info=1
            shift
            ;;
        -c|--count)
	    let count=1
            shift
            ;;
	*)
            echo "usage: `basename $0` -h|--help -c|--count -v|--verbose"
            exit 7
	    ;;
	esac
    fi
done


if [ $count -eq 1 ]; then
    echo "Logged users: `who | wc -l`."
        if [ $info -eq 1 ]; then
            echo "Logged users: `who | wc -l`. "
            echo  "They are: "
            w 
        fi
fi














你可能感兴趣的:(Linux)