Shell编程

编译器,解释器
编程语言:机器语言,汇编语言,高级语言
静态语言:编译型语言
      强类型(变量)
      事先转换成可执行格式
      C,C++,JAVA,C#
动态语言:解释型语言 on the fly
      弱类型
      边解释边执行
      PHP,SHELL,Python,perl
面向过程:shell,c
面向对象:JAVA,python,perl,c++
变量:内存空间,命名
内存:编址的存储单元
shell:弱类型编程语言
强:变量在使用前,必须事先声明,甚至还需要初始;

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


bash变量类型:
    环境变量
    本地变量(局部变量)
    位置变量
    特殊变量
本地变量:
VARNAME=VALUE;作用域整个bash进程
局部变量:
local VARNAME=VALUE;作用域为当前代码段
环境变量:作用域为当前shell进程及其子进程
export VARNAME=VALUE
位置变量:
$1,$2,.....
特殊变量:
$?:上一个命令的执行状态返回值
程序执行以后,可能有两类返回值
   程序执行结果
   程序状态返回代码(0-255)
      0:正确执行
      1-255:错误执行,1,2,127系统预留
输出重定向:
>
>>
2>
2>>
&>
/dev/null:设备,软设备(软件模拟的设备),bit bucket数据黑洞
id student &> /dev/null
echo $? -> 0
撤销变量:
unset VARNAME
查看当前shell中变量
set
查看当前shell中的环境变量
printenv
env
export

ANIMALS=pig
ANIMALS=$ANIMALS:goat
echo $ANIMALS -> pig:goat
echo $PATH
export PATH=$PATH:/usr/local/apache/bin
A=2
B=3
C=$A+$B
echo $C -> 2+3

脚本在执行时会启动一个子shell进程
   命令行启动的脚本会继承当前shell环境变量;
   系统自动执行的脚本(非命令行启动)就需要自我定义需要各环境变量
    bash:
NAME=Jerry
echo $NAME -> Jerry
bash
echo $NAME -> 空
引用变量:${VARNAME},括号有时可省略
ANIMAL=pig
echo "There are some $ANIMALs." -> There are some .
echo "There are some ${ANIMAL}s." -> There are some pigs.
echo 'There are some ${ANIMAL}s.' -> There are some ${ANIMAL}s.
      
export NAME
echo $NAME -> Jerry
bash
echo $NAME -> Jerry
bash
echo $NAME -> Jerry
重新登录shell
echo $NAME -> 空
 
脚本:命令的堆砌,按实际需要,结合命令流程控制机制实现的源程序
shebang:魔数

vim first.sh
#!/bin/bash
#注释行,不执行
cat /etc/fstab
ls /var

chmod +x first.sh
echo $PATH
执行
./first.sh
      
chmod -x first.sh
bash first.sh     

练习:写一个脚本,完成一下任务
1.添加5个用户,user1.。。。user5
2.每个用户的密码同用户名,而且要求,添加密码完成后不显示passwd命令的执行结果
3.每个用户添加完成后,都要显示用户某某已添加成功
useradd user1
echo "user1" | passwd --stdin user1 &> /dev/null
echo "Add user1 successfully."
vim adduser2.sh
#!/bin/bash
! id user1 &> /dev/null && useradd user1 && echo "user1" | passwd --stdin user1 &> /dev/null || echo "user1 exists."

USERS=`wc -l /etc/passwd | cut -d: -f1`
echo "$USERS users."

chmod +x adduser2.sh
./adduser2.sh

练习:给定一个用户
   1.如果其UID为0,就显示此为管理员
   2.否则,就显示其为普通用户

vim third.sh
#!/bin/bash
NAME=user1
USERID=`id -u $NAME`
[ $USERID -eq 0 ] && echo "Admin" || echo "Common user."

NAME=user16
USERID=`id -u $NAME`
if [ $USERID -eq 0 ]; then
   echo "Admin"
else  
   echo "common user."

fi

条件判断:
   如果用户不存在
      添加用户,给密码并显示成功
   否则
      显示如果已经存在,没有添加
      
bash中如何实现条件判断?
条件测试类型:
    整数测试
    字符测试
    文件测试
    
条件测试的表达式:
    [ expression ]
    [[ expression ]]
    test expression

整数比较:
    -eq:测试两个整数是否相等;比如:$A -eq $B
        A=3
        B=6
        [ $A -eq $B ]
        $? -> 1
        B=3
        [ $A -eq $B ]
        $? -> 0
    -ne:测试两个整数是否不等;不等为真,相等为假
    -gt:测试一个数是否大于另一个数;大于为真,否则,为假
    -lt:测试一个数是否小于另一个数
    -ge:大于或等于
    -le:小于或等于

命令间逻辑关系:
  与:&&
  或:||
  非:!

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

双分支
if 判断条件; then
   statement1
   statement2
   ...
else
   statement3
   statement4
   ....
fi

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

vim usertest.sh
#!/bin/bash
NAME=user1

if id NAME &> /dev/null; then
   echo "$NAME exists."
else
#   echo "$NAME not exists."
    useradd $NAME
	echo $NAME | passwd --stdin $NAME &> /dev/null
	echo "Add $NAME finished."
fi
vim second.sh

#!/bin/bash
LINES= wc -l /etc/inittab
echo $LINES  

FINLINES=`echo $LINES | cut -d'' -f1`
echo $FINLINES

[ $FINLINES -gt 100 ] && echo "/etc/inittab is a big file." || echo "/etc/inittab is a small 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 || "user1 exists."


练习:写一个脚本
判断当前系统上是否有用户的默认shell为bash;
   如果有,就显示有多少个这类用户;否则,就显示没有这类用户;
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`;

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

vim bash.sh
#!/bin/bash
grep "\<bash$" /etc/passwd &> dev/null
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
   USERS=`grep "\<bash$" /etc/passwd | wc -l`
   echo "The shells of $USERS users is bash shell."
else
   echo "No such user."
fi

vim bash2.sh
#!/bin/bash
grep "\<bash$" /etc/passwd &> dev/null
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
   AUSER=`grep "\<bash$" /etc/passwd | head -l | cut -d: -f1`
   echo "$AUSER is one of such users"
else
   echo "No such user."
fi
练习:写一个脚本
给定一个用户,判断其UID与GID是否一样
如果一样,就显示此用户为“good guy”;否则,就显示此用户为“bad guy”。


#!/bin/bash
USERNAME=user1
USERID=`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=user1
if ! grep "^$USERNAME\>" /etc/passwd &> /dev/null; then
  echo "No such user: $USERNAME."
  exit 1
fi

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
练习:写一个脚本
给定一个文件,比如/etc/inittab
判断这个文件中是否有空白行;
如果有,则显示其空白行数;否则,显示没有空白行。

#!/bin/bash
A=`grep '^$' /etc/inittab | wc -l`
if [ $A -gt 0 ]; then
 echo "$A"
else
 echo "meiyoukongbaihang"
fi
                
#!/bin/bash
FILE=/etc/inittab
if [ ! -e $FILE ]; then
  echo "No $FILE."
  exit 8
fi

if grep "^$" $FILE &> /dev/null; then
  echo "Total blank lines: `grep "^$" $FILE | wc -l`."
else
  echo "No blank line."
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`

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

定义脚本退出状态码

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

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

bash -x 脚本   单步执行

vim etest
#!/bin/bash
FILE=/etc/inittab
if [ -e $FILE ]; then
  echo "OK"
else 
  echo "No such file."
fi
练习:写一个脚本
给定一个文件:
如果是一个普通文件,就显示之;
如果是一个目录,亦显示之;
否则,此为无法识别之文件;

vim filetest2.sh
#!/bin/bash
FILE=/etc/rc.d/rc.sysinit
if [ ! -e $FILE ]; then
   echo "No such file."
   exit 6
fi

if [ -f $FILE ]; then
   echo "Common file."
elif [ -d $FILE ]; then
   echo "Directory"
else 
   echo "Unknown."
fi
练习:写一个脚本
给定一个用户,获取其密码警告期限;
而后判断用户密码使用期限是否已经小于警告期限;
    提示:计算方法,最长使用期限减去已经使用的天数即为剩余使用期限;
如果小于,则显示“Warning”;否则,就显示“OK”。
圆整:丢弃小数点后的所有内容

/etc/shadow:用户名:密码:最近一次修改密码的时间:最短使用期限:最长使用期限:警告时间:非活动时间:过期时间

#!/bin/bash
W=`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
bash变量的类型:
    本地变量(局部变量)
    环境变量
    位置变量:
        $1, $2, ...
        shift
    特殊变量:
        $?
        $#:参数的个数
        $*: 参数列表
        $@:参数列表
    
./filetest.sh /etc/fstab /etc/inittab
$1: /etc/fstab
$2: /etc/inittab

练习:写一脚本
能接受一个参数(文件路径)
判定:此参数如果是一个存在的文件,就显示“OK.”;否则就显示"No such file."

vim filetest3.sh
#!/bin/bash
echo $#
echo $*
echo $@
if [ $# -lt 1 ]; then
   echo "Usage:./filetest3.sh arg1 [arg2...]"
   exit 7
fi

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

./filetest3.sh /etc/fstab

[root@VM_0_15_centos ~]# cat shift.sh
#!/bin/bash
echo $1
shift
echo $1
shift
echo $1
shift

[root@VM_0_15_centos ~]# ./shift.sh 1 2 3
1
2
3
练习:写一个脚本
给脚本传递两个参数(整数);
显示此两者之和,之乘积;
vim 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]."
sed命令用法:https://blog.csdn.net/yongchaocsdn/article/details/79703879

字符测试:
   == 比较两个字符串是否一致,相等则为真,
       A=hello
       B=hi
       [ $A==$B ] [ "$A"=="$B" ] [[ "$A"=="$B" ]] [[ "$A"="$B" ]] [[ '$A'='$B' ]] echo ?   0
       [[ "$A" == "$B" ]] [ $A = $B ] 正确,等号两端要有空格
   != 测试是否不等,不等为真,等为假
   >
   <
   -n string:测试指定字符串是否为空,空则真,不空为假
   -z string:-----------------不空,不空为真,空则为假

练习:写一个脚本
传递一个参数(单字符就行)给脚本,如参数为q,就退出脚本;否则,就显示用户的参数;
练习:写一个脚本
传递一个参数(单字符就行)给脚本,如参数为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

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

./calc.sh 5 / 2

echo "scale=2;111/22;" | bc
5.04
bc <<< "scale=2;111/22;"
5.04
写一个脚本:
给脚本传递三个整数,判断其中的最大数和最小数,并显示出来。
MAX=0
MAX -eq $1
MAX=$1
MAX -lt $2
MAX=$2

循环:进入条件,退出条件
for
while
until

for 变量 in 列表; do
    循环体
done

`seq [起始数 [步进长度]] 结束数`

declare -i SUM sum是一个整型

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

求1到100所有整数和

vim sum.sh
#!/bin/bash
#let SUM=0
declare -i SUM=0

for I in {1..100}; do
   let SUM=$[$SUM+$I]
done 
echo "The sum is: $SUM."
写一个脚本:
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

只向默认shell为bash的用户问声好

写一个脚本:
1、添加10个用户user1到user10,密码同用户名;但要求只有用户不存在的情况下才能添加;

扩展:
接受一个参数:
add: 添加用户user1..user10
del: 删除用户user1..user10
其它:退出
adminusers user1,user2,user3,hello,hi


写一个脚本:
计算100以内所有奇数的和以及所有偶数的和;分别显示之;


let I=$[$I+1]
SUM=$[$SUM+$I]

let SUM+=$I

let I+=1 相当于 let I++

-=
    let I-=1 相当于 let I--
    
    ++I, --I

*=
/=
%=

vim showsum.sh
#!/bin/bash
declare -i EVENSUM=0
declare -i OODSUM=0
for I in {1..100}; do
  if [ $[$I%2] -eq 0 ]; then
    let EVENSUM+=$I
  else
    let OODSUM+=$I
  fi
done

echo "Odd sum is: $OODSUM."
echo "EVEN sum is: $EVENSUM."
写一个脚本,分别显示当前系统上所有默认shell为bash的用户和默认shell为/sbin/nologin的用户,并统计各类shell下的用户总数。显示结果形如:
BASH,3users,they are:
root,redhat,gentoo

NOLOGIN, 2users, they are:
bin,ftp
#!/bin/bash
#
NUMBASH=`grep "bash$" /etc/passwd | wc -l`
BASHUSERS=`grep "bash$" /etc/passwd | cut -d: -f1`
BASHUSERS=`echo $BASHUSERS | sed 's@[[:space:]]@,@g'`

echo "BASH, $NUMBASH users, they are:"
echo "$BASHUSERS

1、添加10个用户user1到user10,密码同用户名;但要求只有用户不存在的情况下才能添加;
[root@VM_0_15_centos ~]# cat adduser.sh
#!/bin/bash
for I in {1..10}; do
  if id user$I &> /dev/null; then
     echo "user$I exists."
  else
     useradd user$I
     echo user$I | passwd --stdin user$I &> /dev/null
     echo "Add user user$I finished."
  fi
done
[root@VM_0_15_centos ~]# ./adduser.sh
Add user user1 finished.
Add user user2 finished.
Add user user3 finished.
Add user user4 finished.
Add user user5 finished.
Add user user6 finished.
Add user user7 finished.
Add user user8 finished.
Add user user9 finished.
Add user user10 finished.
如果用户存在就删除
[root@VM_0_15_centos ~]# cat deluser.sh
#!/bin/bash
for I in {1..10}; do
  if id user$I &> /dev/null; then
     userdel -r user$I
     echo "Delete user$I finished"
  else
     echo "user$I not exist."
  fi
done
[root@VM_0_15_centos ~]# ./deluser.sh
Delete user1 finished
Delete user2 finished
Delete user3 finished
Delete user4 finished
Delete user5 finished
Delete user6 finished
Delete user7 finished
Delete user8 finished
Delete user9 finished
Delete user10 finished
扩展:
接受一个参数:
add: 添加用户user1..user10
del: 删除用户user1..user10
其它:退出
adminusers user1,user2,user3,hello,hi
[root@VM_0_15_centos ~]# cat adminusers.sh
#!/bin/bash
if [ $# -lt 1 ]; then
  echo "Usage:adminusers ARG"
  exit 7
fi

if [ $1 == '--add' ]; then
  for I in {1..10}; do
     if id user$I &> /dev/null; then
       echo "user$I exists"
     else
       useradd user$I
       echo user$I | passwd --stdin user$I &> /dev/null
       echo "Add user$I finished."
     fi
  done
elif [ $1 == '--del' ]; then
  for I in {1..10}; do
     if id user$I &> /dev/null; then
       userdel -r user$I
       echo "Delete user$I finished."
     else
       echo "No user$I"
     fi
  done
else
  echo "Unknown ARG"
  exit 8
fi
[root@VM_0_15_centos ~]# ./adminusers.sh --add
Add user1 finished.
Add user2 finished.
Add user3 finished.
Add user4 finished.
Add user5 finished.
Add user6 finished.
Add user7 finished.
Add user8 finished.
Add user9 finished.
Add user10 finished.
[root@VM_0_15_centos ~]# ./adminusers.sh --del
Delete user1 finished.
Delete user2 finished.
Delete user3 finished.
Delete user4 finished.
Delete user5 finished.
Delete user6 finished.
Delete user7 finished.
Delete user8 finished.
Delete user9 finished.
Delete user10 finished.
[root@VM_0_15_centos ~]# ./adminusers.sh hello
Unknown ARG
[root@VM_0_15_centos ~]# cat adminusers2.sh
#!/bin/bash
echo $1
for I in `echo $1 | sed 's/,/ /g'`; do
   if id $I &> /dev/null; then
      echo "$I exists."
   else
      useradd $I
      echo $I | passwd --stdin $I &> /dev/null
      echo "add $I finished."
   fi
done
[root@VM_0_15_centos ~]# ./adminusers2.sh user1,user2,hello
user1,user2,hello
add user1 finished.
add user2 finished.
useradd: group hello exists - if you want to add this user to that group, use -g.
add hello finished.
[root@VM_0_15_centos ~]# cat adminusers2.sh
#!/bin/bash
if [ $1 == '--add' ]; then
        for I in `echo $2 | sed 's/,/ /g'`; do
           if id $I &> /dev/null; then
                  echo "$I exists."
           else
                  useradd $I
                  echo $I | passwd --stdin $I &> /dev/null
                  echo "add $I finished."
           fi
    done
elif [ $1 == '--del' ]; then
    for I in `echo $2 | sed 's/,/ /g'`; do
           if id $I &> /dev/null; then
                  userdel -r $I
                  echo "Delete $I finished"
           else
                  echo "$I NOT exist."
           fi
    done
else
    echo "Unknown options."
fi
[root@VM_0_15_centos ~]# ./adminusers2.sh --add natasha,nikita,ton,jerry
add natasha finished.
add nikita finished.
add ton finished.
add jerry finished.
[root@VM_0_15_centos ~]# ./adminusers2.sh --del natasha,nikita,ton
Delete natasha finished
Delete nikita finished
Delete ton finished
[root@VM_0_15_centos ~]# ./adminusers2.sh shiyongchao
Unknown options.
vim adminusers2.sh
#!/bin/bash
if [ $1 == '--add' ]; then
	for I in `echo $2 | sed 's/,/ /g'`; do
	   if id $I &> /dev/null; then
		  echo "$I exists."
	   else  
		  useradd $I
		  echo $I | passwd --stdin $I &> /dev/null
		  echo "add $I finished."
	   fi
    done
elif [ $1 == '--del' ]; then
    for I in `echo $2 | sed 's/,/ /g'`; do
	   if id $I &> /dev/null; then
		  userdel -r $I
		  echo "Delete $I finished"
	   else  
		  echo "$I NOT exist."
	   fi
    done
elif [ $1 == '--help' ]; then
    echo "Usage:adminusers2.sh --add USER1,USER2,...|--del USER1,USER2 | --help"
else
    echo "Unknown options."
fi

./adminusers2.sh --help
组合测试条件
    -a: 与关系
    -o: 或关系
    !: 非关系
if [ $# -gt 1 -a $# -le 3 ]
if [ $# -gt 1 ] && [ $# -le 3 ]

vim quit.sh
#!/bin/bash
if [ $1 == 'q' -o $1 == 'Q' -o $1 == 'Quit' -o $1 == 'quit' ]; then 
   echo "Quiting..."
   exit 0
else
   echo "Unknown Argument."
   exit 1
fi
几个命令:
w
who
每隔5秒钟,就来查看hadoop是否已经登录,如登录,显示其已经登录,并退出;
sleep

whoami

last,显示/var/log/wtmp文件,显示用户登录历史及系统重启历史
    -n #: 显示最近#次的相关信息
lastb,/var/log/btmp文件,显示用户错误的登录尝试
    -n #:
lastlog: 显示每一个用户最近一次的成功登录信息;
    -u USERNAME: 显示特定用户最近的登录信息

basename
    $0: 执行脚本时的脚本路径及名称
    
mail

hostname: 显示主机名
如果当前主机的主机名不是www.magedu.com,就将其改为www.magedu.com

如果当前主机的主机名是localhost,就将其改为www.magedu.com

如果当前主机的主机名为空,或者为(none),或者为localhost,就将其改为www.magedu.com
[ -z `hostname` ] || [ `hostname` == '(none)' -o `hostname` == 'localhost' ] && hostname www.magedu.com

生成随机数
RANDOM: 0-32768

随机数生成器:熵池
/dev/random:
/dev/urandom:
写一个脚本,利用RANDOM生成10个随机数,并找出其中的最大值,和最小值;
#!/bin/bash
#
declare -i MAX=0
declare -i MIN=0

for I in {1..10}; do
  MYRAND=$RANDOM
  [ $I -eq 1 ] && MIN=$MYRAND
  if [ $I -le 9 ]; then
    echo -n "$MYRAND,"
  else
    echo "$MYRAND"
  fi
  [ $MYRAND -gt $MAX ] && MAX=$MYRAND
  [ $MYRAND -lt $MIN ] && MIN=$MYRAND
done

echo $MAX, $MIN
case语句:选择结构

case SWITCH in
value1)
  statement
  ...
  ;;
value2)
  statement
  ...
  ;;
*)
  statement
  ...
  ;;
esac
只接受参数start,stop,restart,status其中之一
#!/bin/bash
#
DEBUG=0
ADD=0
DEL=0

for I in `seq 0 $#`; do
  if [ $# -gt 0 ]; then
	  case $1 in
	  -v|--verbose)
		DEBUG=1
		shift ;;
	  -h|--help)
		echo "Usage: `basename $0` --add USER_LIST --del USER_LIST -v|--verbose -h|--help"
		exit 0
		;;
	  --add)
		ADD=1
		ADDUSERS=$2
		shift 2
		;;
	  --del)
		DEL=1
		DELUSERS=$2
		shift 2
		;;
	  *)
		echo "Usage: `basename $0` --add USER_LIST --del USER_LIST -v|--verbose -h|--help"
		exit 7
		;;
    esac
  fi
done

if [ $ADD -eq 1 ]; then
  for USER in `echo $ADDUSERS | sed 's@,@ @g'`; do
    if id $USER &> /dev/null; then
      [ $DEBUG -eq 1 ] && echo "$USER exists."
    else
      useradd $USER
      [ $DEBUG -eq 1 ] && echo "Add user $USER finished."
    fi
  done
fi

if [ $DEL -eq 1 ]; then
  for USER in `echo $DELUSERS | sed 's@,@ @g'`; do
    if id $USER &> /dev/null; then
      userdel -r $USER
      [ $DEBUG -eq 1 ] && echo "Delete $USER finished."
    else
      [ $DEBUG -eq 1 ] && echo "$USER not exist."
    fi
  done
fi

练习:写一个脚本showlogged.sh,其用法格式为:
showlogged.sh -v -c -h|--help
其中,-h选项只能单独使用,用于显示帮助信息;-c选项时,显示当前系统上登录的所有用户数;如果同时使用了-v选项,则既显示同时登录的用户数,又显示登录的用户的相关信息;如
Logged users: 4.

They are:
root     tty2         Feb 18 02:41
root     pts/1        Mar  8 08:36 (172.16.100.177)
root     pts/5        Mar  8 07:56 (172.16.100.177)
hadoop   pts/6        Mar  8 09:16 (172.16.100.177)

#!/bin/bash
#
declare -i SHOWNUM=0
declare -i SHOWUSERS=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 SHOWUSERS=1
      shift ;;
    -c|--count)
      let SHOWNUM=1
      shift ;;
    *)
      echo "Usage: `basename $0` -h|--help -c|--count -v|--verbose"
      exit 8 ;;
    esac
  fi
done

if [ $SHOWNUM -eq 1 ]; then
  echo "Logged users: `who | wc -l`."
  if [ $SHOWUSERS -eq 1 ]; then
    echo "They are:"
    who
  fi
fi
练习:写一个脚本
从键盘让用户输入几个文件,脚本能够将此几个文件归档压缩成一个文件;
read:
    -p “PROMPT": 给出提示


vim sum.sh
#!/bin/bash
#echo -n "Input two intergers:"
read -t 5 -p "INput two intergers[100 and 1000]:" A B
[ -z $A ] && A=100
[ -z $B ] && B=1000
echo "$A plus $B is: $[$A+$B]"
./sum.sh

vim myar.sh
#!/bin/bash
read -p "Three files: " FILE1 FILE2 FILE3
read -p "Destination: " DEST
read -p "Compress[gzip|bzip2|xz]: " COMP

case $COMP in
gzip)
    tar -zcf ${DEST}.tar.gz $FILE1 $FILE2 $FILE3
	;;
bzip2)
    tar -jcf ${DEST}.tar.bz2 $FILE1 $FILE2 $FILE3
	;;
xz)
    tar -cf ${DEST}.tar $FILE1 $FILE2 $FILE3
	xz ${DEST}.tar
	;;
*)
    echo "Unknown."
	exit 9
	;;
esac
while, until, for
break: 提前退出循环
continue:提前结束本轮循环,而进入下一轮循环;
1000, SUM>5000
while的特殊用法一:
while :;do
done

while的特殊用法二:
while read LINE; do
done < /PATH/TO/SOMEFILE
/etc/passwd

循环控制:
break
中断循环,而后执行循环后面的语句;
continue
中断当前这一次循环,提前进入下一软循环

写一个脚本,完成以下功能:

说明:此脚本能于同一个repo文件中创建多个Yum源的指向;

1、接受一个文件名做为参数,此文件存放至/etc/yum.repos.d目录中,且文件名以.repo为后缀;要求,此文件不能事先存,否则,报错;

2、在脚本中,提醒用户输入repo id;如果为quit,则退出脚本;否则,继续完成下面的步骤;

3、repo name以及baseurl的路径,而后以repo文件的格式将其保存至指定的文件中;

4、enabled默认为1,而gpgcheck默认设定为;

5、此脚本会循环执行多次,除非用户为repoid指定为quit;

vim mkrepo.sh
#!/bin/bash
REPOFILE=/etc/yum.repos.d/$1]
if [ -e $REPOFILE ]; then
   echo “$1 exists.”
   exit 3
fi
read -p “Repository ID:”REPOID
until [ $REPOID == ‘quit’ ]; do
   echo “[$REPOID]” >> $REPOFILE
   read -p “Repository name:” REPONAME
   echo “name=$REPONAME” >> $REPOFILE
   read -p “Repository Baseurl:” REPOURL
   echo “baseurl=$REPOURL” >> $REPOFILE
   echo -e ‘enabled=1\ngpgcheck=0’ >> $REPOFILE
   read -p “Repository ID:” REPOID
done 

./mkrepo.sh hello.repo
hello
hello world
http://172.16.0.1/yum/Server
quit
vim odd.sh
#!/bin/bash
let SUM=0
let I=1
while [ $I -le 100 ]; do
  if [ $[$I%2] -eq 1 ]; then
let SUM+=$I
  fi
  let I++
done
echo $SUM

#!/bin/bash
let SUM=0
let I=1
while [ $I -lt 100 ]; do
  let I++
  if [ $[$I%2] -eq 1 ]; then
continue
  fi
  let SUM+=$I
done
echo $SUM

vim sum.sh
#!/bin/bash
declare -i SUM=0
for I in {1..1000}; do
  let SUM+=$I
  if [ $SUM -gt 5000 ]; then
break
  fi
done
echo $I
echo $SUM

vim showfile.sh
#!/bin/bash
while :;do
   read -p “File path:” FILEPATH
   [ $FILEPATH == ‘quit’ ] && break
   if [ -e $FILEPATH ]; then
     echo “$FILEPATH exists.”
   else
     echo “No $FILEPATH.”
   fi
done
echo “Quit”

如果用户名为bash shell,显示此用户的用户名

vim showuser.sh
#!/bin/bash
FILE=/etc/passwd
let I=0
while read LINE; do
   [ `echo $LINE | awk -F : ‘{print $3}’` -le 505 ] && continue
   [ `echo $LINE | awk -F : ‘{print $7}’` == ‘/bin/bash’ ] && echo $LINE | awk -F : ‘{print $1}’ && let I++
   [ $I -eq 6 ] && break
done < $FILE

写一个脚本:

1、判断一个指定的bash脚本是否有语法错误;如果有错误,则提醒用户键入Q或者q无视错误并退出,其它任何键可以通过vim打开这个指定的脚本;

2、如果用户通过vim打开编辑后保存退出时仍然有错误,则重复第1步中的内容;否则,就正常关闭退出。

vim syntax.sh
#!/bin/bash
until bash -n $1 &> /dev/null; do
	read -p "Syntax error, [Qq] to quit, others for editing: "  CHOICE
	case $CHOICE in
	q|Q)
	    echo "Something wrong, quiting."
	    exit 5
	    ;;
	*)
		vim + $1
		;;
	esac
done
echo "0K"

函数:功能, function

代码重用:

库:so

脚本编程之函数:

function: 功能

结构化编程,不能独立运行,需要调用时执行,可以被多次调用

定义一个函数:

function FUNCNAME {

 command

}

FUNCNAME() {

 command

}

自定义执行状态返回值:

return #

0-255

接受参数的函数:

./a.sh m n

$1: m

$2: n

TWOINT 5 6

$1: 5

$2: 6

#/bin/bash
function SHOWMENU {
cat << EOF
d|D) show disk usages
m|M) show memory usages
s|S) show swap usages
q|Q) quit.
EOF
}

SHOWMENU
read -p “Your choice:” CHOICE

until [ $CHOICE == ‘q’ -o $CHOICE == ‘Q’ ]; do
case $CHOICE in
d|D)
 df -lh
;;
m|M)
free -m | grep “^Mem”
;;
s|S)
free -m | grep “^Swap”
;;
*)
SHOWMENU
read -p “Your choice,again:” CHOICE
;;
esac
SHOWMENU
read -p “Your choice:” CHOICE
done 

vim showmenu.sh
function SHOWMENU {
cat << EOF
d|D) show disk usages
m|M) show memory usages
s|S) show swap usages
q|Q) quit.
EOF
}

SHOWMENU

求两个数的和

vim sum.sh
#!/bin/bash
TWOINT() {
A=9
B=7
C=$[$A+$B]
echo $C
}

M=11
SUM=$[$M+`TWOINT`]
echo $SUM

添加用户,用户不存在就添加

vim adduser.sh
ADDUSER() {
USERNAME=hadoop
if ! id -u $USERNAME &> /dev/null; then
  useradd $USERNAME
  echo $USERNAME | passwd --stdin $USERNAME &> /dev/null
  return 0
else
  return 1
fi
}

ADDUSER
if [ $? -eq 0 ]; then
  echo “add user finished.”
else
  echo “Failure.”
fi

通过参数求和

vim twosum.sh
#!/bin/bash
TWOSUM() {
  echo $[$1+$2]
}
SUM=`TWOSUM 5 6`
echo $SUM

10以内任意两个相邻数相加和

TWOSUM() {
   echo $[$1+$2]
}
for I in {1..10}; do
  let J=$[$I+1]
  echo “$I plus $J is `TWOSUM $I $J`”
done

练习:写一个脚本,判定192.168.0.200-192.168.0.254之间的主机哪些在线。要求:

1、使用函数来实现一台主机的判定过程;

2、在主程序中来调用此函数判定指定范围内的所有主机的在线情况。

#!/bin/bash
#
PING() {
  for I in {200..254};do
    if ping -c 1 -W 1 192.168.0.$I &> /dev/null; then
      echo "192.168.0.$I is up."
    else
      echo "192.168.0.$I is down."
    fi
  done
}

PING
#!/bin/bash
#
PING() {
    if ping -c 1 -W 1 $1 &> /dev/null; then
      echo "$1 is up."
    else
      echo "$1 is down."
    fi
}

for I in {200..254}; do
  PING 192.168.0.$I
done
#!/bin/bash
#
PING() {
    if ping -c 1 -W 1 $1 &> /dev/null; then
      return 0
    else
      return 1
    fi
}

for I in {200..254}; do
  PING 192.168.0.$I
  if [ $? -eq 0 ]; then
    echo "192.168.0.$I is up."
  else
    echo "192.168.0.$I is down."
  fi
done

写一个脚本:使用函数完成

1、函数能够接受一个参数,参数为用户名;

   判断一个用户是否存在

   如果存在,就返回此用户的shell和UID;并返回正常状态值;

   如果不存在,就说此用户不存在;并返回错误状态值;

2、在主程序中调用函数;

 

扩展1:在主程序中,让用户自己输入用户名后,传递给函数来进行判断;

扩展2:在主程序中,输入用户名判断后不退出脚本,而是提示用户继续输入下一个用户名;如果用户输入的用户不存在,请用户重新输入;但如果用户输入的是q或Q就退出;

#!/bin/bash
#
user () {
if id $1 &> /dev/null ;then
echo "`grep ^$1  /etc/passwd | cut -d: -f3,7`"
   return 0
else
   echo "no $1"
    return 1
fi
}
read -p "please input username:" username
until [ $username == q -o $username == Q ]; do
	user $username
	if [ $? == 0 ];then
		read -p "please input again:" username
	else
		read -p "no $username,please input again:" username
	fi
done

函数也可以接受参数, 即可以向函数传递参数

函数接受一个用户名参数,显示此用户的shell和UID;

写一个函数:接受一命令参数ls

/bin/ls, /mnt/sysroot/bin/ls

/sbin/ifconfig, /mnt/sysroot/sbin/ifconfig

计算100以内所有正整数的和
#!/bin/bash
declare -i I=1
declare -i SUM=0

while [ $I -le 100 ]; do
  let SUM+=$I
  let I++
done

echo $SUM
练习:转换用户输入的字符为大写,除了quit:
#!/bin/bash
#
read -p "Input something: " STRING

while [ $STRING != 'quit' ]; do
  echo $STRING | tr 'a-z' 'A-Z'
  read -p "Input something: " STRING
done
练习:每隔5秒查看hadoop用户是否登录,如果登录,显示其登录并退出;否则,显示当前时间,并说明hadoop尚未登录:

#!/bin/bash
#
who | grep "hadoop" &> /dev/null
RETVAL=$?

while [ $RETVAL -ne 0 ]; do
  echo "`date`, hadoop is not log." 
  sleep 5
  who | grep "hadoop" &> /dev/null
  RETVAL=$?
done

echo "hadoop is logged in."
写一个脚本:
1) 显示一个菜单给用户:
d|D) show disk usages.
m|M) show memory usages.
s|S) show swap usages.
*) quit.
2) 当用户给定选项后显示相应的内容;
   
扩展:
    当用户选择完成,显示相应信息后,不退出;而让用户再一次选择,再次显示相应内容;除了用户使用quit;

#!/bin/bash
#
cat << EOF
d|D) show disk usages.
m|M) show memory usages.
s|S) show swap usages.
*) quit.
EOF

read -p "Your choice: " CHOICE
while [ $CHOICE != 'quit' ];do
  case $CHOICE in
  d|D)
    echo "Disk usage: "
    df -Ph ;;
  m|M)
    echo "Memory usage: "
    free -m | grep "Mem" ;;
  s|S)
    echo "Swap usage: "
    free -m | grep "Swap" ;;
  *)
    echo "Unknown.." ;;
  esac

read -p "Again, your choice: " CHOICE
done	

echo -e "\033[1mHello\033[0m,world."
echo -e "\033[31mHello\033[0m,world."
echo -e "\033[32mHello\033[0m,world."
echo -e "\033[33mHello\033[0m,world."
echo -e "\033[34mHello\033[0m,world."
echo -e "\033[35mHello\033[0m,world."
echo -e "\033[36mHello\033[0m,world."
echo -e "\033[37mHello\033[0m,world."
echo -e "\033[41mHello\033[0m,world."
echo -e "\033[31;41mHello\033[0m,world."
echo -e "\033[1;37;41mHello\033[0m,world."

1、通过ping命令测试192.168.0.151到192.168.0.254之间的所有主机是否在线,

         如果在线,就显示"ipis up.",其中的IP要换为真正的IP地址,且以绿色显示;

         如果不在线,就显示"ipis down.",其中的IP要换为真正的IP地址,且以红色显示;

要求:分别使用while,until和for(两种形式)循环实现。

ping    -c    -W

awk 'PATTERN{ACTION}' file
	print $1
df -Ph | awk ‘{print $1,$3}’
df -Ph | awk ‘{print $0}’ 显示所有字段
fdisk -l 2> /dev/null | grep “^Disk /dev/[sh]d[a-z]”
fdisk -l 2> /dev/null | grep “^Disk /dev/[sh]d[a-z]” | awk -F:’{print $1}’
添加虚拟磁盘
IDE,SCSI 20G

写一个脚本(前提:请为虚拟机新增一块硬盘,假设它为/dev/sdb),为指定的硬盘创建分区:

1、列出当前系统上所有的磁盘,让用户选择,如果选择quit则退出脚本;如果用户选择错误,就让用户重新选择;

2、当用户选择后,提醒用户确认接下来的操作可能会损坏数据,并请用户确认;如果用户选择y就继续,n就退出;否则,让用户重新选择;

3、抹除那块硬盘上的所有分区(提示,抹除所有分区后执行sync命令,并让脚本睡眠3秒钟后再分区);并为其创建三个主分区,第一个为20M,第二个为512M, 第三个为128M,且第三个为swap分区类型;(提示:将分区命令通过echo传送给fdisk即可实现)

fdisk -l |grep "

dd if=/dev/zero of=/dev/sdb bs=512 count=1
sync把所有操作从内存同步到磁盘上
sleep 3

fdisk -l 2> /dev/null | grep “^Disk /dev/[sh]d[a-z]” | awk -F:’{print $1}’
vim setpart.sh
#!/bin/bash
echo ‘n
p
1

+20M
n
p
2

+512M
n
p
3

+128M
t
3
82
w’ | fdisk /dev/hda
chmod +x setpart.sh
fdisk -l
dd if=dev/zero of=/dev/hda bs=512 count=1
sync
partprobe
fdisk -l

vim partdisk.sh
#!/bin/bash
echo “Initial a disk...”
echo -e “\033[31mWarning: \033[0m”
fdisk -l 2> /dev/null | grep -o “^Disk /dev/[sh]d[a-z]”
read -p “Your choice:”PARTDISK
if [ $PARTDISK == ‘quit’ ]; then
  echo “quit”
  exit 7
fi

until fdisk -l 2> /dev/null | grep -o “^Disk /dev/[sh]d[a-z]” | grep “^Disk $PARTDISK$” &> /dev/null; do
  read -p “Wrong option,Your choice again:”PARTDISK
done

read -p “Will destroy all data,continue:”CHOICE
until [ $CHOICE == ‘y’ -o $CHOICE == ‘n’ ]; do
   read -p “Will destroy all data,continue:”CHOICE
done

if [ $CHOICE == ‘n’ ]; then
  echo “Quit”
  exit 9
else
dd if=/dev/zero of=$PARTDISK bs=512 count=1
sync
sleep 3
  echo ‘n
p
1

+20M
n
p
2

+512M
n
p
3

+128M
t
3
82
w’ | fdisk $PARTDISK &> /dev/null
partprobe $PARTDISK
sync
sleep 2
mke2fs -j ${PARTDISK}1 &> /dev/null
mke2fs -j ${PARTDISK}2 /dev/null
mkswap ${PARTDISK}3 /dev/null
fi

卸载
mount /dev/sdb1 /mnt
mount /dev/sdb2 /media/
swapon /dev/sdb3
mount
mount | grep “/dev/sdb” | awk ‘{print $1}’
vim umount.sh
#!/bin/bash
for I in `mount | grep “/dev/sdb” | awk ‘{print $1}’`; do
  fuser -km $I
  umount $I
  echo “$I umount ok.”
done


































  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值