shell学习

我的自学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 "==================================="

文章标题:shell学习
网址分享:http://myzitong.com/article/pgssoc.html