我的自学shell过程,中间参考过鸟哥,马哥,老男孩等各方的学习方法和过程! shell shell编程之变量 语言转换的设备或软件:编译器,解释器 编程语言:机器语言、汇编语言、高级语言 高级语言: 静态语言:编译型语言 有开发环境,不需要借助额外的二进制程序,写完代码后,通过编译器直接转换成二进制后再独立执行 特征:强类型(变量) 事先转换成可执行格式 语言类型:C、C++、JAVA、C# 动态语言:解释型语言 特征:弱类型 边解释边执行 语言类型:PHP、SHELL、Python、perl 编程模型 面向过程:SEHLL,C 编程重点在问题解决过程本身 适合开发小型 面向对象:JAVA,Python 把要实现的项目抽象成一个个对象,定义对象之间的动作 适合开发大型应用程序 变量:内存空间,命名的内存空间 内存:编址的存储单元 变量类型(定义存储数据的格式和长度): 字符 数值 整型 浮点型 时间 布尔型(逻辑型、真假型) 逻辑运算:与,或,非,异或 与 运算:两者为真才为真,只要有一个假就是假 或 运算:只要有一个为真,结果即为真 非 运算:取反 异或 运算:操作数相反为真,相同为假 强类型变量:变量在使用前,必须事先声明,甚至还需要初始化 初始化:数值初始化默认为0,字符默认初始化为空(NULL) 弱类型变量:变量使用时声明,不区分类型,默认为字符串 变量赋值: VAR_NAME=VALUE说明:变量名(VAR_NAME)=值(VALUE) bash变量类型: 环境变量: 本地变量:(局部变量) 位置变量: 特殊变量: 本地变量: VARNAME(变量名)=VALUE(值)作用域整个bash进程 局部变量 local VARNAME(变量名)=VALUE(值)作用域当前代码段 环境变量:作用域为当前shell进程及其子进程 export VARNAME(变量名)=VALUE(值)export 意为”导出“,即为导出一个环境变量 脚本在执行时会启动一个子shell进程 命令行中启动的脚本会继承当前shell环境变量 系统自动执行的脚本(非命令行启动),就需要自我定义需要各环境变量 位置变量: $n 第n个位置变量 特殊变量: $?上一个命令的执行状态返回值 示例:echo $? 程序执行,两类返回值 程序执行结果 程序状态返回代码(0-255) 0:正确执行 1-255:错误执行 撤销变量 unset VARNAME(变量名) 查看当前shell中的变量 set 查看当前shell中的环境变量 printenv env export 脚本:命令的堆砌,按实际需要,结合命令流程控制机制实现的源程序 第一个脚本 cat fisrt.sh #!/bin/bash # 注释行,不执行 cat /etc/fstab la /var 保存退出 chmod +x fisrt.sh /dev/null软件设备,bit bucket数据黑洞 引用变量:${VARNAME},括号可以省略 单引号,强引用,不作变量替换 双引号:弱引用,内部变量做替换 变量名规则 字母、数字、下划线,不能以数字开头 不能同系统中已有的变量名重名 最好见名知意 练习 练习1:写一个脚本 1、条件5个用户,user1....user5 2、每个用户的密码同用户名,而且要求,添加密码完成后不显示passwd命令的执行结果信息 3、每个用户添加完成后,显示用户某某已经完成添加 #!/bin/bash # 说明:键盘输入需创建的用户名,执行时自动生成与用户名相同的密码,但不显示passwd的执行过程信息 # 说明:添加完成后,显示用户某某已经完成添加 # read命令读取键盘输入 # 验证密码是否创建成功,用 su - read -p "input a user:" val useradd $val echo "$val" | passwd --stdin $val &> /dev/null echo "Add $val successfully!~" id $val 练习2:写一个脚本 1、使用一个变量保存一个用户名 2、删除此变量中的用户,并且一并删除其家目录 3、显示”用户删除完成“信息 #!/bin/bash #echo "查看有哪些用户: 'cat /etc/passwd |cut -f1 -d:'" echo -e "查看有哪些用户: \n$(cat /etc/passwd |cut -f1 -d:)" read -p "Delete a user:" val userdel -r $val echo "Del $val successfully!~" shell编程之条件判断 shell -n检查shell语法是否错误 shell -x检查shell执行过程 实现条件判断 条件测试类型 整数测试:等于不等于 字符测试:是不是 文件测试:存不存在 条件测试的表达式(expression指表达式) [ expression ]中括号两端必须有空格 [[ expression ]] test expression 整数比较(整数测试) -eq测试两个整数是否相等,比如:$A -eq $B -ne测试连个整数是否不等,不等为真,相等为假 -gt测试一个数是否大于另一个数:大于为真,否则为假 -lt测试一个数是否小于另一个数:小于为真,否则为假 -ge大于或等于 -le小于或等于 命令间的逻辑关系 逻辑与:&& 第一条件为真时,第二条件不用再判断,最终结果已经有 第一条件为真时,第二条件必须判断 示例:! id user6 && useradd user6 说明:如果 ! id user6 为真,就执行 useradd user6 如果 ! id user6 为假,就不执行 useradd user6 示例:! id user6 && useradd user6说明:用户存在就不创建,用户不存在就创建 逻辑或:|| 示例:id user6 || useradd user6说明:用户存在就不创建,用户不存在就创建 条件判断,控制结构 但分支if语句 if 判断条件;then statement1(语句1) statement2(语句2) ... fi 双分支if语句 if 判断条件;then statement1(语句1) statement2(语句2) ... else statement3(语句3) statement4(语句4) ... fi exit n 表示退出 (n) 示例: 判断用户是否存在,如果不存在就创建用户和密码,并提示创建成功! #!/bin/bash # read -p "please input:" NAME if id $NAME &> /dev/null;then echo "$NAME 用户已经存在" else useradd $NAME echo $NAME | passwd --stdin $NAME &> /dev/null echo "用户 $NAME 添加成功。" fi 示例:如果/etc/passwd 文件的行数大于100,就显示好大的文件 #!/bin/bash LINES=`wc -l /etc/passwd` FINLINES=`echo $LINES | cut -d' ' -f1` [ $FINLINES -gt 50 ] && echo "/etc/passwd is a big file." || echo "/etc/passwd is a small 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" 练习: 写一个脚本 1、添加3个用户user1,user2,user3.但要先判断用户是否存在,不存在而后添加 2、添加完成后,显示一共添加了几个用户,当然,不能包括因为事先存在而没有添加的 3、最后显示当前系统上共有多少个用户 #!/bin/bash # 创建用户 ! id user1 &> /dev/null && useradd user1 && echo "user1" | passwd --stdin user1 &> /dev/null || echo "user1 exists" ! id user2 &> /dev/null && useradd user2 && echo "user2" | passwd --stdin user2 &> /dev/null || echo "user2 exists" ! id user3 &> /dev/null && useradd user3 && echo "user3" | passwd --stdin user3 &> /dev/null || echo "user3 exists" # 显示当前用户数 USERS=`wc -l /etc/passwd | cut -d: -f1` echo "$USERS users." 练习: 添加用户,并判断是否存在,存在就显示”已经存在“,不存在就创建,并创建与用户同名的密码,并在创建成功后显示”Add $val successfully!~“ #!/bin/bash read -p "input a user:" val ! id $val && useradd $val && echo "$val" | passwd --stdin $val && echo "Add $val successfully!~" || echo "$val 已经存在" 练习: 写一个脚本,给定一个用户 1、如果其UID为0,就显示此为管理员 2、否则,就显示其为普通用户 第一种方法 #!/bin/bash read -p "请输入用户名: " NAME USERID=`id -u $NAME` if ! id $NAME &> /dev/null ;then echo "................ " else if [ $USERID -eq 0 ];then echo "................ " echo "$NAME为管理员." else echo "................ " echo "$NAME为普通用户" fi echo "................ " fi 第二种方法: #!/bin/bash # 需完善 read -p "请输入用户名:" NAME #NAME=fan USERID=`id -u $NAME` ! id $NAME && echo "用户不存在!" || [ $USERID -eq 0 ] && echo "admin" || echo "Common user." 练习: 判断当前系统是否有用户的默认shell为bash,如果有,就显示有多少个这类用户,否则,就显示没这类用户 #!/bin/bash # grep "\/dev/null RETVAL=$? if [ $RETVAL -eq 0 ];then USERS=`grep "\ /dev/null RETVAL=$? if [ $RETVAL -eq 0 ];then USERS=`grep "\ /dev/null;then echo "文件有 `grep '^$' $FILE | wc -l` 行空白行!" else echo "文件没有空白行!" fi 练习: 写一个脚本,判断其UID和GID是否一样,如果一样,此用户为”good“;否则,为”bad” 第一种方法: #!/bin/bash read -p "请输入用户:" ID Uid=`id -u $ID` Gid=`id -g $ID` if [ $Uid -eq $Gid ];then echo "good!~" else echo "bad!~" fi 第二种方法: #!/bin/bash read -p "请输入用户:" ID if ! grep "^$ID\>" /etc/passwd $> /dev/null;then echo "用户不存在" exit 1 fi UserID=`grep "^$ID\>" /etc/passwd | cut -d: -f3` GroupID=`grep "^$ID\>" /etc/passwd | cut -d: -f4` if [ $UserID -eq $GroupID ];then echo "good!~(UID和GID相同)" else echo "bad!~(UID和GID不同)" fi shell条件判断和算术运算 1、let 算术运算表达式 let C=$A+$B 2、$[算术运算表达式] C=$[$A+$B] 3、$((算术运算表达式)) C=$(($A+$B)) 4、expr C=`EXPR $A + $B` 练习: 给定一个用户,获取其密码警告期限,而后判断用户最近一次修改时间距是否已经小于警告期限 小于,则显示“warning”,否则,显示“find” 一方法: #!/bin/bash read -p "请输入用户:" ID TIMESTAMP=`date +%s` TODAY=`let today=$TIMESTAMP/86400` UserID=`grep "^$ID\>" /etc/passwd | cut -d: -f3` ti2=`let Ti1=$TODAY-$UserID` ti3=`grep "^$ID\>" /etc/passwd | cut -d: -f6` if [ $ti2 < $ti3 ];then echo " warning!!! " else echo "find!!! " fi 二方法: #!/bin/bash read -p "请输入用户:" ID W=`grep "^$ID\>" /etc/passwd | cut -d: -f6` S=`date +%s` T=`expr $s/86400` L=`grep "^$ID\>" /etc/passwd | cut -d: -f5` N=`grep "^$ID\>" /etc/passwd | cut -d: -f3` SY=$[$L-$[$T-$N]] if [ $SY-lt $W ];then echo " warning!!! " else echo "find!!! " fi shell 整数测试和特殊变量 整数测试 -eq测试两个整数是否相等,比如:$A -eq $B -ne测试连个整数是否不等,不等为真,相等为假 -gt测试一个数是否大于另一个数:大于为真,否则为假 -lt测试一个数是否小于另一个数:小于为真,否则为假 -ge大于或等于 -le小于或等于 整数测试方法: [ expression ]命令测试法 [[ expression ]]关键字测试法 test expression 示例:比较两个数值 [ $Num1 -eq $Num2 ] [[ $Num1 -eq $Num2 ]] test $Num1 -eq $Num2 文件测试: -e file测试文件是否存在 -f file测试文件是否为普通文件 -d file测试指定路径是否为目录 -r file测试当前用户对指定文件是否有读权限 -w file测试当前用户对指定文件是否有写权限 -x file测试当前用户对指定文件是否有执行权限 示例: 测试文件是否存在 [ -e filename ] 多分支if语句 if 判断条件1;then statement1 ... elif 判断条件2;then statement2 ... elif 判断条件3;then statement3 ... else statement4 ... fi 定义脚本退出码: exit 退出脚本 exit # 测试脚本是否有语法错误 bash -n 脚本 脚本单步执行 bash -x 脚本 bash变量类型: 环境变量: 本地变量:(局部变量) 位置变量: 特殊变量: 位置变量: $1,$2,... shift轮替(默认为1) 特殊变量: $?上一条命令的退出状态码 $#参数的个数 $*参数列表 $@参数列表 练习: vim shift.sh #!/bin/bash echo $1 shift 2 echo $1 shift 2 echo $1 练习: 写脚本,给脚本传递两个参数(整数);显示两者之和,之积 #!/bin/bash if [ $# -lt 2 ];then echo "Usge: ./.sh ARG1,ARG2." exit 8 fi echo "The sum is: $[$1+$2]." echo "the pro is: $[$1*$2]." 练习: 写一个脚本,接受参数,判定,此参数如果是一个存在的文件,就显示“OK”,否则就显示“No such file。” #!/bin/bash #说明:参数不能为空,否则会显示帮助"Usge: ./fan3.sh ARG1...[ARG2,ARG3,...]" if [ $# -lt 1 ];then echo "Usge: ./fan3.sh ARG1...[ARG2,ARG3,...]" exit 7 fi if [ -e $1 ];then echo "OK" else echo "No such file." fi shell字符串测试和for循环 字符串比较 == 等值比较,等则为真,不等为假(等号两端必须是空格) !=不等比较,不等为真,等则为假 -n string测试字符串是否为空,空为真,不空为假 -z string测试字符串是否为不空,不空为真,空为假 循环:进入条件,退出条件 for while until for循环 for 变量 in 列表;do 循环体 done 遍历完成后,退出 生成列表 {1..100}表示起始为1,结束为100 `seq [起始数[步进长度]] 结束数` 循环示例: 示例: 1加到100 #!/bin/bash # declare -i SUM=0 for I in {1..100};do let SUM=$[$SUM+$I] done echo "sum is :$SUM" 字符串比较示例: 示例: 传递一个用户名参数给脚本,判断此用户名跟基本组的组名是否一致 #!/bin/bash # if ! id $1 &> /dev/null;then echo "No such user." exit 10 fi if [ $1 == 'id -n -g $1' ];then echo "ok" else echo "No" fi 示例: 传一个参数(单字符),参数为q,就退出脚本,否则显示用户的参数 示例: 传一个参数(单字符),参数为q、Q、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 字符串练习: 传递三个参数,第一个为整数,第二个为运算符,第三个为整数,显示计算结果,要求保留两位精度 bc用法 echo " scale=2;a/b" | bs bc <<< "scale=2;a/b" 字符串练习: 比较三个整数的大小 练习: 判断当前主机的CPU生产商,其信息在/proc/cpuinfo文件中vendor id 一行中 如果其生产商为AuthenticAMD,就显示其为AMD公司 如果其生产商为GenuineIntel,就显示其为Intel公司 否则,就为非主流公司 #!/bin/bash # I=vendor_id N=`grep $I /proc/cpuinfo | sed -r 's#[[:space:]]+##g' | cut -d: -f2` if [ $N == GenuineIntel ];then echo "该CPU生产商为:Intel 公司" elif [ $N == AuthenticAMD ];then echo "该CPU生产商为 AMD 公司" else echo "该CPU生产商为非主流公司!" fi 字符串练习: 传递3个参数,参数均为用户名。将此用户的账号信息提取出来后放置于filename 中,行号一行首有行号 #!/bin/bash # A=root B=mail C=ntp echo `grep -n ^$A /etc/passwd` >>file.txt echo `grep -n ^$B /etc/passwd` >>file.txt echo `grep -n ^$C /etc/passwd` >>file.txt for循环练习题 遍历/etc/passwd中的用户,并问好!并显示对方的shell 提示: LINES=`wc -l /etc/passwd | cut -d' ' -f1` for I in `seq 1 $LINES`;do echo "hello,`head -n $I /etc/passwd | tail -l | cut -d: -f1`";done #!/bin/bash # LI=`wc -l /etc/passwd | cut -d' ' -f1` #echo "$LI" for I in `seq 1 $LI`;do echo "hello, `head -n $I /etc/passwd | tail -1 | cut -d: -f1`, 该用户对于的shell是:`head -n $I /etc/passwd | tail -1 | cut -d: -f7`"; done for循环练习题 添加10个用户user1到user10,密码同用户名;但要求只有用户不存在才能创建 #!/bin/bash for I in {1..10};do let N=$I U=user$N if id $U &>/dev/null;then echo "$U 已经存在!~" else useradd $U echo $U | passwd --stdin $U &> /dev/null echo "$U 已经添加成功!~" fi done 扩展: 删除用户user1...user10 #!/bin/bash for I in {1..10};do let N=$I U=user$N if id $U &>/dev/null;then userdel -r $U echo "$U 已经删除成功!~" else echo "$U 不存在!~" fi done 扩展:接受参数: add:添加用户user1...user10 del:删除用户user1...user10 #!/bin/bash if [ $# -lt 1 ];then echo "input add or del:" exit 7 fi if [ $1 == 'add' ];then for I in {1..10};do if id user$I &> /dev/null;then echo "user$I 已存在" else useradd user$I echo user$I | passwd --stdin user$I &> /dev/null echo "user$I 添加成功!~" fi done elif [ $1 == 'del' ];then for I in {1..10};do if id user$I &> /dev/null;then userdel -r user$I echo "user$I 删除成功" else echo "user$I 不存在" fi done else echo “Unknown ARG” exit 8 fi 执行:.sh add 添加用户 .sh del 删除用户 扩展: 输入 .sh user1,user2,user3 添加 #!/bin/bash echo $1 for I in `echo $1 | sed 's/,/ /g'`;do if id $I &>/dev/null;then echo "$I 存在" else useradd $I echo $I | passwd --stdin $I >/dev/null echo "$I 添加成功" fi done 扩展: 输入 .sh --add user1,user2,user3 .sh --del user1,user2,user3 #!/bin/bash if [ $1 == '--add' ];then for I in `echo $2 | sed 's/,/ /g'`;do if id $I &>/dev/null;then echo "$I 存在" else useradd $I echo $I | passwd --stdin $I >/dev/null echo "$I 添加成功" 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 "$I 删除成功" else echo "$I 不存在" fi done elif [ $1 == '--help' ];then echo "(1).命令格式:./ sh --[options] username!~" echo "(2).--add username | --del username | --help 不能同时出现" else echo “Unknown options” fi 缺点(待完善): 无法判断参数数 无法判断没有参数(忘记给参数) 无法判断参数错误(--add和--del同时使用) for循环练习题 计算100以内所有能被3整除的正整数 提示:取模,取余 #!/bin/bash let "sum=0" for i in {1..10} do let "m=i%3" if [ "$m" -eq 0 ] then let "sum=sum+i" fi done echo "the sum is :$sum" for循环练习题 计算100以内所有奇数的和以及所有偶数的和,分别显示之 #!/bin/bash declare "sum1=0" declare "sum2=0" for i in {1..100} do let "m=i%2" if [ "$m" -eq 0 ];then let "sum1=sum1+i" elif [ "$m" -eq 1 ];then let "sum2=sum2+i" fi done echo " 1-100以内的偶数和为: $sum1" echo " 1-100以内的奇数和为: $sum2" 练习题 分别显示默认shell为bash的用户和/sbin/nologin的用户,并统计各类shell下的用户总数 #!/bin/bash # FILE=/etc/passwd echo "默认shell为bash的用户有: `grep 'bash' $FILE | wc -l` 个!分别为:" B=`sed -n '/bash/p' $FILE | cut -d: -f1` BB=`echo $B|sed 's@[[:spqce:]]@,@g'` echo "$BB" echo "默认shell为nologin的用户有 `grep 'nologin' $FILE | wc -l` 个!分别为:" A=`sed -n '/nologin/p' $FILE | cut -d: -f1` AA=`echo $A|sed 's@[[:spqce:]]@,@g'` echo "$AA" 脚本选项·和组合条件测试 回顾: 整数测试: -eq测试两个整数是否相等,比如:$A -eq $B -ne测试连个整数是否不等,不等为真,相等为假 -gt测试一个数是否大于另一个数:大于为真,否则为假 -lt测试一个数是否小于另一个数:小于为真,否则为假 -ge大于或等于 -le小于或等于 字符测试 ==等于 !=不等于 >大于 <小于 -n字符串是否为空 -z字符串是否为不空 文件测试 -e file测试文件是否存在 -f file测试文件是否为普通文件 -d file测试指定路径是否为目录 -r file测试当前用户对指定文件是否有读权限 -w file测试当前用户对指定文件是否有写权限 -x file测试当前用户对指定文件是否有执行权限 组合测试 -o逻辑或 -a逻辑与 !逻辑非 添加10个用户user1到user10,密码同用户名;但要求只有用户不存在才能创建 #!/bin/bash for I in {1..10};do let N=$I U=user$N if id $U &>/dev/null;then echo "$U 已经存在!~" else useradd $U echo $U | passwd --stdin $U &> /dev/null echo "$U 已经添加成功!~" fi done 扩展: 删除用户user1...user10 #!/bin/bash for I in {1..10};do let N=$I U=user$N if id $U &>/dev/null;then userdel -r $U echo "$U 已经删除成功!~" else echo "$U 不存在!~" fi done 扩展:接受参数: add:添加用户user1...user10 del:删除用户user1...user10 #!/bin/bash if [ $# -lt 1 ];then echo "input add or del:" exit 7 fi if [ $1 == 'add' ];then for I in {1..10};do if id user$I &> /dev/null;then echo "user$I 已存在" else useradd user$I echo user$I | passwd --stdin user$I &> /dev/null echo "user$I 添加成功!~" fi done elif [ $1 == 'del' ];then for I in {1..10};do if id user$I &> /dev/null;then userdel -r user$I echo "user$I 删除成功" else echo "user$I 不存在" fi done else echo “Unknown ARG” exit 8 fi 执行:.sh add 添加用户 .sh del 删除用户 扩展: 输入 .sh user1,user2,user3 添加 #!/bin/bash echo $1 for I in `echo $1 | sed 's/,/ /g'`;do if id $I &>/dev/null;then echo "$I 存在" else useradd $I echo $I | passwd --stdin $I >/dev/null echo "$I 添加成功" fi done 扩展: 输入 .sh --add user1,user2,user3 .sh --del user1,user2,user3 #!/bin/bash if [ $1 == '--add' ];then for I in `echo $2 | sed 's/,/ /g'`;do if id $I &>/dev/null;then echo "$I 存在" else useradd $I echo $I | passwd --stdin $I >/dev/null echo "$I 添加成功" 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 "$I 删除成功" else echo "$I 不存在" fi done elif [ $1 == '--help' ];then echo "(1).命令格式:./ sh --[options] username!~" echo "(2).--add username | --del username | --help 不能同时出现" else echo “Unknown options” fi 缺点(待完善): 无法判断参数数 无法判断没有参数(忘记给参数) 无法判断参数错误(--add和--del同时使用) shell编程case语句和脚本选项进阶 面向过程 控制接口 顺序结构 选择结构 if..slif..else..fi 循环结构 case语句:选择结构 case SWITCH in value1) statement ... ;;#每一个选择条件必须两个;结束 value2) statement ... ;; *) statement ... ;; esac#case字母反过来写表示结尾 示例: 写一个脚本,只接受参数start,stop,restart,status其中之一 #!/bin/bash # read -p "iuput:" N case $N in 'start') echo "start server...";; 'stop') echo "stop server...";; 'restaer') echo "restart server...";; 'status') echo "Running..." *) echo "`basename $0` {start|stop|restart|status}";; esac 示例: 写一个脚本,可以接受选项及参数,而后获取每一个选项及参数,并能根据选项及参数作出特定的操作 比如:admin.sh --add tom,jer --del tom,jer --v|--verbose --h|--helo 选项可同时使用 例如:./test.sh -v --add tom,jer #!/bin/bash # DEBUG=0 ADD=0 DEL=0 for I in `seq 1 $#`;do if [ $# -gt 0 ]; then case $1 in -v|--verbose) DEBUG=1 shift ;; -h|--help) echo "Usage:`basename $0` --add UAERNAM --del USERNAME -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 UAERNAM --del USERNAME -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 写一个脚本 利用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 = $MAX" echo "min = $MIN" 示例: 写一个脚本:showlog.sh 用法为: showlog.sh -v -c -h|--help 其中:-h选项单独使用,用于显示帮助信息,-c显示当前登陆的所有用户,如果同时使用-v,极限是同时登陆的用户数,又显示登陆用户的相关信息 #!/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|-counts -v|--verbose" exit 0 ;; -v|--verbose) let SHOWUSERS=1 shift ;; -c|--count) let SHOWNUM=1 shift ;; *) echo "Usage:`basename $0` -h|--help -c|-counts -v|--verbose" exit 8 ;; esac fi done if [ $SHOWNUM -eq 1 ];then echo "log users:`who | wc -l`." if [ $SHOWUSERS -eq 1 ];then echo "They are:" who fi fi shell编程 while循环 while循环 适用于循环次数未知的场景 必须要有退出条件 语法格式 while CONDITON;do statement ... done 进入循环,条件满足 退出循环,条件不满足 循环的控制方法 break提前退出循环 continue提前进入下一循环 while特殊用法之一:死循环 while :;do done while特殊用法之二: while read LINE;do done < FILENAME 说明:whlie 循环读取FILENAME中的每一行,放在变量LINE中,然后再循环中处理LINE中的行 示例:(待完善) 判断/etc/passwd中的那个用户的shell是bash,如果是bash就显示用户名,否则不显示名字 #!/bin/bash # FILE=/etc/passwd let I=0 while read LINE;do [ `echo $LINE | awk -F : '{prinf $3}'` -le 505 ] && continue #用户ID大于505就不在判断,提前进入下一循环 [ `echo $LINE | awk -F : '{prinf $7}'` == '/bin/bash' ] && echo $LINE | awk -F : '{print $1}' && let I++ [ $I -eq 6 ] && break #只读取前6个用户 done < $FILE continue示例: 计算100以内所有偶数和 #!/bin/bash # let SUM=0 let I=0 while [ $I -lt 100 ];do let I++ if [ $[$I%2] -eq 0 ];then continue fi let SUM+=$I done echo $SUM break示例: 从1加到1000,知道和为5000就退出循环不再相加 #!/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=$I" echo "SUM=$SUM" break示例: 判断一个文件是否存在,用户输入quit就退出 #!/bin/bash # while :;do read -p "input filename:"FILENAME [ $FILENAME=='quit' ] && break if [ -e $FILENAME ];then echo "$FILENAME exists." else echo "No $FILENAME" fi done echo "Quit." 写一个脚本: 说明:此脚本能于同一个repo文件中创建多个yum源的指向 1、接受一个文件名作为参数,此文件存放至/etc/yum.repos.d目录中,且文件名以.repo为后缀,要求此文件不能事先存,否则,报错 2、在脚本中,提醒用户输出repo id ,如果为quit,则退出脚本,否则,继续完成下面的步骤 3、repo name以及baseurl的路径,而后以repo文件的格式将其保存到指定的文件中 4、enabled默认为1,而gpgcheck默认为0 5、此脚本会循环多次,除非用户为repo id指定为quit #!/bin/bash # REPOFILE=/etc/yum.repos.d/$1 if [ -e $REPODILE ];then echo "$1 exists." exit 3 fi read -p "input ID:" REPOID until [ $REPOID == 'quit' ];do echo "[$REPOID]" >> $REPOFILE read -p "input name: " REPONAME echo "name=$REPONAME" >> $REPOFILE read -p "input Baseurl:" REPOURL echo -e 'enabled-1\ngpgcheck=0' >> $REPOFILE read -p "input ID:" REPOID done 示例: 计算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是否已经登陆,如登陆,显示其已经登陆,就退出 提示:sleep sleep 3 延迟3秒 #!/bin/bash # who | grep "hadoop" &> /dev/null RETVAL=$? while [ $RETVAL -ne 0 ];do echo "`date`,hadoop not is log!" sleep 5 who | grep "hadoop" &> /dev/null RETVAL=$? done echo "`date` hadoop is logged!" 示例: 1.显示一个菜单给用户 d|D) show disk usages m|M) show menory usages s|S) show swap usages *) quit 2.当用户给定选项后显示响应的内容 #!/bin/bash cat << EOF d|D) show disk usages m|M) show menory usages s|S) show swap usages *) quit EOF read -p "Your choice:" CH case $CH in d|D) echo "Disk usages:" df -h ;; m|M) echo "Memory usages;" free -m | grep "Mem" ;; s|S) echo "Swap usages:" free -m | grep "Swap" ;; *) echo "Unknow.." exit 9 ;; esac ~ 扩展: 当用户选择完成,显示响应信息后,不退出,而让用户再一次选择,再次显示响应内容,除了用户使用quit #!/bin/bash cat << EOF d|D) show disk usages m|M) show menory usages s|S) show swap usages *) quit EOF read -p "Your choice:" CH while [ $CH != 'quit' ];do case $CH in d|D) echo "Disk usages:" df -h ;; m|M) echo "Memory usages;" free -m | grep "Mem" ;; s|S) echo "Swap usages:" free -m | grep "Swap" ;; *) echo "Unknow.." ;; esac read -p "Again,your choice:" CH done 写一个脚本: 1、提示用户输入一个用户名 2、显示一个菜单给用户。形如 U|u show UID G|g show GID S|s show SHELL Q|q quit 3、提醒用户选择一个选项,并显示其所有选择的内容 如果用户给一个错误的选项,则提醒用户选项错误,请其重新选择 #!/bin/bash # echo "* * * * * * * * * * * * *" read -p "Please enter your user name: " US until [ $US == 'quit' ];do if id -u $US &> /dev/null;then echo "$US is OK!Please select" echo "=======options=======" cat << EOF U|u) show UID G|g) show GID S|s) show SHELL q|Q) quit EOF echo "=====================" read -p "Please select options: " SH echo "=====================" while : ;do case $SH in U|u) echo "$US uid=`grep "^$US" /etc/passwd | cut -d: -f4`" ;; G|g) echo "$US gid=`grep "^$US" /etc/passwd | cut -d: -f3`" ;; S|s) echo "$US shell=`grep "^$US" /etc/passwd | cut -d: -f7`" ;; Q|q) echo "******quiting...******" exit ;; *) echo "Wrong option.Please again" echo "=======options=======" cat << EOF U|u) show UID G|g) show GID S|s) show SHELL q|Q) quit EOF echo "=====================" ;; esac read -p "Please choose again: " SH done else echo "-------------------------------------" echo "The user name wrong.." echo "* * * * * * * * * * * * *" read -p "Please enter the username again : " US fi done shell编程until循环 until CONDITION; 进入循环,条件不满足 退出循环,条件满足 for循环 for ((expr1 ; expr2 ; expr3)); do 循环体 done 示例: 100以内的正整数相加 #!/bin/bash # declare -i SUM2=0 for ((J=1;J<=100;J++));do let SUM2+=$J done echo $SUM2 until循环示例: 示例: #!/bin/bash # read -p "input something:" ST until [ $ST== 'quit' ];do echo $ST | tr 'a-z' 'A-Z' read -p "input something:" ST done 示例: 练习: 每隔5秒就来查看hadoop是否已经登陆,如登陆,显示其已经登陆,就退出 第一种方法 #!/bin/bash # who | grep "hadoop" &> /dev/null RETVAL=$? until [ $RETVAL -eq 0 ];do echo "hadoop is not come." sleep 5 who | grep "hadoop" &> /dev/null RETVAL=$? done echo "hadoop is logged in." 第二种方法 #!/bin/bash # until who | grep "hadoop" &> /dev/null;do echo "hadoop is not come." sleep 5 done echo "hadoop is logged in." 测试: 通过ping命令测试192.168.0.151到192.168.0.254直接所有主机是否在线 如果在线,就显示ip is up,其ip要换为真正的IP动作,且显示为绿色 如果不在线,就显示“ip is down”,其中的IP换为真正的IP地址,且红色显示 分别用while,until for(两种形式)循环实现 for循环第一种方法: for ((i=99;i<=120;i++));do if ping -c 1 -W 1 192.168.0.$i &> /dev/null;then echo "192.168.0.$i 在线" else echo "192.168.0.$i 不在线" fi done for循环第二种方法: for i in {99..120};do if ping -c 1 -W 1 192.168.0.$i &> /dev/null;then echo "192.168.0.$i 在线" else echo "192.168.0.$i 不在线" fi done while循环 #!/bin/bash # declare -i I=151 while [ $I -le 254 ];do let I++ if ping -c 1 -W 1 192.168.3.$I &> /dev/null;then echo "192.168.3.$I 在线" else echo "192.168.3.$I 不在线" fi done until循环 #!/bin/bash # declare -i I=191 until [ $I -gt 254 ];do let I++ if ping -c 1 -W 1 192.168.3.$I &> /dev/null;then echo "192.168.3.$I 在线" else echo "192.168.3.$I 不在线" fi done shell编程之:函数、功能 function 代码重用,结构化编程,不能独立运行,需要调用时执行,可以多次被调用 定义函数方法一 function FUNCNAME { command } 定义函数方法二 FUNCNAME() { command } 自定义执行状态返回值 return # #的值:0-255 接受参数的函数 FUNCNAM n1 n2 $1 n1 $2 n2 示例: 多次显示菜单 #!/bin/bash # function SHOWM {#定义函数SHOWM cat << EOF d|D) show disk usages m|M) show menory usages s|S) show swap usages *) quit EOF } SHOWM#调用函数 return示例 添加用户test #!/bin/bash # ADDUSER() { USERNAME=test if ! id -u $USERNAME &> /dev/null;then useradd $USERNAME echo $USERNAME | passwd --stdin $USERNAME &> /dev/null return 0 else return 1 fi } ADDUSER echo $? if [ $? -eq 0 ];then echo "add user finished." else echo "Failuer." fi 扩展: 添加多个用户 #!/bin/bash # ADDUSER() { USERNAME=$1 if ! id -u $USERNAME &> /dev/null;then useradd $USERNAME echo $USERNAME | passwd --stdin $USERNAME &> /dev/null return 0 else return 1 fi } for I in {1..10};do ADDUSER user$I if [ $? -eq 0 ];then echo "add user$I finished." else echo "add user$I Failuer." fi done 函数接受参数示例 #!/bin/bash # TWOSUM() { echo $[$1+$2] } TWOSUM 5 6 SUM=`TWOSUM 5 6`#保存函数的执行结果至一个变量,可做进一步操作 echo $SUM 示例: 10以内相邻两个数相加 #!/bin/bash # TWOSUM() { echo $[$1+$2] } for I in {1..10};do let J=$[$I+1] TWOSUM $I $J echo "$I + $J = `TWOSUM $I $J`" done 示例: 写一个脚本,判定192.168.0.200-192.168.0.254之间的主机哪些在线。要求: 1、使用函数来实现一台主机的判定过程 2、在主程序中来调用此函数判定指定范围内的所有主机的在线情况 第一种方法: #!/bin/bash # PING() { if ping -c 1 -W 1 $1 &> /dev/null;then echo "$1 在线" else echo "$1 不在线" fi } for I in {200..254};do PING 192.168.0.$I done #for I in{200..254};do#ping另一个网段 # PING 192.168.2.$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 在线" else echo "192.168.0.$I 不在线" fi done 写一个脚本 1、函数接受一个参数,参数为用户名 判定一个用户是否存在 如果存在,就返回此用户的shell和UID,并返回正常状态值 如果不存在,就说此用户不存在,并返回错误状态值 2、在主程序中调用函数 扩展1:在主程序中,让用户自己输入用户名后,传递给函数来进行判断 扩展2:在主程序中输入用户名判断后不退出脚本,而是提示用户继续输入下一个用户名,但如果用户输入的是q或Q就退出 #!/bin/bash # ADDUSER() { USERNAME=$1 if id -u $USERNAME &> /dev/null;then return 0 else return 1 fi } read -p "input : " U echo "===================================" until [ $U == q -o $U == Q ];do ADDUSER $U if [ $? == 0 ];then # echo "$U 存在" sh=`grep "^$U" /etc/passwd | awk -F : '{print $7}'` ui=`grep "^$U" /etc/passwd | awk -F : '{print $4}'` echo "$U 的 shell = $sh, UID = $ui" echo "===================================" read -p "input again: " U echo "===================================" else echo "$U 不存在" echo "===================================" read -p "input again: " U echo "===================================" fi done echo "quit..." echo "==================================="