脚本编程进阶

冷暖自知 提交于 2020-04-07 14:33:59

1、chmod -rw /tmp/file1,编写脚本/root/bin/per.sh,判断当前用户对/tmp/fiile1文件 是否不可读且不可写
#!/bin/bash
[ ! -r /tmp/file1 ] && [ ! -w /tmp/file1 ] && echo "不可读写" || echo "可读写"

[root@centos7 shell]# chmod -rw /tmp/file1
[root@centos7 shell]# ll /tmp/file1
----------. 1 root root 0 Aug 10 16:22 /tmp/file1
[root@centos7 shell]# bash per.sh
可读写
[root@centos7 shell]# su cent
[cent@centos7 shell]$ bash per.sh
不可读写

2、编写脚本/root/bin/nologin.sh和login.sh,实现禁止和充许普通用户登录系统

思路:当/etc/目录下存在 nologin 文件时,普通用户会无法登陆,因此,我们只需要通过删除或增加该文件来限制普通用户是否可登陆
[root@centos7 shell]# cat login.sh nologin.sh
#!/bin/bash
[ -e /etc/nologin ] && echo "rm -f /etc/nologin enable user login "
#!/bin/bash
[ -a /etc/nologin ] || touch /etc/nologin
echo "disable user login "

执行 bash nologin.sh 脚本时,登陆普通用户会提示
Connecting to 172.18.16.152:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.
Connection closed by foreign host.
Disconnected from remote host(centos7) at 20:11:18.

然后执行bash login.sh 脚本时,就可以直接登陆了
Connecting to 172.18.16.152:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.
Last failed login: Fri Aug 12 20:11:09 CST 2016 from 172.18.16.171 on ssh:notty
There was 1 failed login attempt since the last successful login.
Last login: Fri Aug 12 20:10:29 2016 from 172.18.16.171


五,流程控制

5.1 使用read命令来接受输入

使用read来把输入值分配给一个或多个shell变量:
-p :指定要显示的提示
-t :TIMEOUT
比如:
read -p "print a filename:" file

注意:read 从标准输入中读取值,给每一个单词分配一个变量,所有剩余单词都被分配给最后一个变量

5.2 条件选择if语句

if语句是选择执行,并且可以嵌套执行
单分支:
if 判断条件 ; then
条件为真的分支代码
fi
if [ $1 -gt 60 ];then
echo "the grade is pass"
fi

双分支:
if 判断条件 ; then
条件为真的分支代码
else
条件为假的分支代码
fi
if [ $1 -gt 60 ];then
echo "the grade is pass"
else
echo "the grade is not pass"
fi

多分支:
逐条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if语句
if CONDITION1; then
if-true
elif CONDITION2; then
if-ture
elif CONDITION3; then
if-ture
...
else
all-false
fi

5.3 条件判断case语句

case 变量引用 in
PAT1)
分支1
;;
PAT2)
分支2
;;
...
*)
默认分支
;;
esac

case支持glob风格的通配符:
*: 任意长度任意字符
?: 任意单个字符
[]:指定范围内的任意单个字符
a|b: a或b


实战训练5

1、写一个脚本/root/bin/createuser.sh,实现如下功能: 使用一个用户名做为参数,如果指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id号等信息
##方法一
[root@centos7 test]# cat createuser.sh
#!/bin/bash
id $1 &>/dev/null && (echo '该用户已存在,信息为:' ; id $1) || ( useradd $1 ; echo '添加成功,信息为:' ; id $1)
[root@centos7 test]# bash createuser.sh user01
添加成功,信息为:
uid=1005(user01) gid=1005(user01) groups=1005(user01)
[root@centos7 test]# bash createuser.sh user01
该用户已存在,信息为:
uid=1005(user01) gid=1005(user01) groups=1005(user01)

##方法二
#!/bin/bash
if id $1 &> /dev/null ; then
echo "$1 is exsit,the info is id $1"
else
useradd $1 && echo "useradd is successful ,the info is id $1"
fi

2、写一个脚本/root/bin/yesorno.sh,提示用户输入yes或 no,并判断用户输入的是yes还是no,或是其它信息

#!/bin/bash
read -p "please input 'yes' or 'no' : " string
case $string in
[Yy][Ee][sS]|Y|y)
echo "you input is yes"
;;
[Nn][oO]|N|n)
echo "you input is no"
;;
*)
echo "you input is other info"
;;
esac

3、写一个脚本/root/bin/filetype.sh,判断用户输入文件路径,显示其文件类型(普通,目录,链接,其它文件类型)
#!/bin/bash
read -p "please input a path of the file :" files
if [ -b $files ];then
echo "该文件是块设备"
elif [ -c $files ] ;then
echo "该文件是字符设备"
elif [ -f $files ];then
echo "该文件是普通文件"
elif [ -h $files ];then
echo "该文件是符号链接文件"
elif [ -p $files ];then
echo "该文件是管道文件"
elif [ -S $files ];then
echo "该文件是套接字文件"
elif [ -d $files ];then
echo "该文件是目录文件"
else
echo "文件或目录不存在"
fi

4、写一个脚本/root/bin/checkint.sh,判断用户输入的参数是否为正整数
#!/bin/bash
read -p "please input :" arg
if [[ $arg =~ ^[[:digit:]]+$ ]] && [ $(expr $arg + 0) != 0 ] ;then
echo "是正整数"
else
echo "不是正整数"
fi


六,循环

循环执行:
将某代码重复运行多次
重复运行多次
循环次数事先已知
循环次数事先未知
有进入条件和退出条件

for,while,until

6.1
for循环
for 变量名 in 列表;do
循环体
done
执行机制:依次将列表中的元素赋值给"变量名";每次赋值后即执行一次循环体,直到类表中的元素耗尽,循环结束
列表生成方式:
(1) 直接给出列表
(2) 整数列表:
(a) {start..end}
(b) $(seq [start [step]] end)
(3) 返回列表的命令 $(COMMAND)
(4) 使用glob,如:.sh
(5) 变量引用: $@, $


实战训练6
要求:用for实现
1、判断/var/目录下所有文件的类型
#!/bin/bash
for i in /var/* ;do
if [ -b $i ];then
echo "$i是块设备"
elif [ -c $i ] ;then
echo "$i是字符设备"
elif [ -f $i ];then
echo "$i是普通文件"
elif [ -h $i ];then
echo "$i是符号链接文件"
elif [ -p $i ];then
echo "$i是管道文件"
elif [ -S $i ];then
echo "$i是套接字文件"
elif [ -d $i ];then
echo "$i是目录文件"
else
echo "文件或目录不存在"
fi
done

2、添加10个用户user1-user10,密码同用户名
#!/bin/bash
#添加10个用户
for i in user{1..10} ;do
id $i &> /dev/null && echo "$i 用户已存在"|| (adduser $i ;echo "$i 用户添加成功")
echo $i:$i | chpasswd
done

#!/bin/bash
#删除10个用户
for i in user{1..10} ;do
id $i &> /dev/null && (userdel -fr $i ;echo "$i 删除成功") || echo "$i 删除失败,该用户肯不存在"
done

3、/etc/rc.d/rc3.d目录下分别有多个以K开头和以S开头的 文件;分别读取每个文件,以K开头的文件输出为文件加stop ,以S开头的文件输出为文件名加start; “K34filename stop” “S66filename start”
#!/bin/bash
for i in /etc/rc.d/rc3.d/[SK]* ;do
if [ $(basename $i | cut -c1) == "K" ] ;then
echo "basename $i stop"
else
echo "basename $i start"
fi
done

4、写一个脚本,提示输入正整数n的值,计算1+2+3+…n的 总和
#!/bin/bash
read -p "please input a number:" n
sum=0
for i in $(seq 1 $n);do
let sum+=$i
done
echo "the sum is $sum"

5、写一个脚本,提示请输入网络地址,如192.168.0.0,判 断输入的网段中主机在线状态

#!/bin/bash
file=mktemp /tmp/pingip.XXXXXX
read -p "请输入网络地址 :" ip
i=echo $ip | cut -d'.' -f1-3
for z in {1..255};do
{
ip=$i.$z
ping -c1 -W1 $ip &> /dev/null && (echo "$ip is up" ) && echo ip >> $file
}&
done

sleep 1
echo "cat $file | wc -l在线"
rm -f $file &> /dev/null

6、打印九九乘法表
#!/bin/bash
for i in {1..9};do
for j in $(seq 1 $i) ;do
echo -ne "${j}x${i}=$[i*j]\t"
done
echo
done


6.2
while 循环
语法:
while CONDITION; do
循环体
done
CONDITION:循环控制条件;进入循环之前,先做一次判 断;每一次循环之后会再次做判断;条件为“true”,则执行 一次循环;直到条件测试状态为“false”终止循环
因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正
进入条件:CONDITION为true
退出条件:CONDITION为false

实战训练7
要求:用while实现

1、求100以内所有正整数之和
#!/bin/bash
sum=0
i=0
while [ $i -le 100 ] ;do
let sum+=$i
let i++
done
echo $sum

2、通过ping命令探测172.16.250.1-254范围内的所有主机的在线状态,统计在线主机和离线主机各多少。
#!/bin/bash
ip=10.1.250.
i=1
sum=0
while [ $i -lt 255 ] ;do
if ping -c1 -W1 $ip$i &> /dev/null ;then
let sum+=1
echo "$ip$i is up"
else
echo "$ip$i is down"
fi
let i+=1
done
echo "在线主机$sum台,离线$[255-sum]主机台"

3、打印九九乘法表
#!/bin/bash
i=1
j=1
while [ $i -le 9 ] ;do
while [ $j -le $i ] ;do
echo -ne "${j}x${i}=$[i*j]\t"
let j+=1
done
let i+=1
j=1
echo
done

4、利用变量RANDOM生成10个随机数字,输出这个10数字 ,并显示其中的最大者和最小者
#!/bin/bash
let i=0,min=max=$RANDOM
echo "$min "
while [ $i -lt 9 ];do
ran=$RANDOM
echo "$ran "
if [ $ran -ge $max ];then
let max=ran
fi
if [ $ran -le $min ];then
let min=ran
fi
let i+=1
done
echo "最大值是 $max ,最小值是 $min"

5、打印国际象棋棋盘
#!/bin/bash
let x=y=1
h=8
while [ $x -le $h ];do
while [ $y -le $h ];do
if [ $[(x+y)%2] -eq 0 ] ;then
echo -en "\033[47m \033[0m"
else
echo -en "\033[40m \033[0m"
fi
let y+=1
done
echo
let x+=1,y=1
done

#!/bin/bash
num=8
for((i=1;i<=$num;i++)){
for ((j=1;j<=$num;j++))
{
if [ $[(i+j)%2] -eq 0 ];then
echo -en "\033[47m \033[0m"
else
echo -en "\033[42m \033[0m"
fi
}
echo
}


6.3
until循环 (和while循环执行条件相反)
until CONDITION; do
循环体
done
进入条件: CONDITION 为false
退出条件: CONDITION 为true

6.4
循环控制语句continue,break

用于循环体中
continue [N]:提前结束第N层的本轮循环,而直接进入下一 轮判断;最内层为第1层
while CONDTIITON1; do
CMD1
...
if CONDITION2; then
continue
fi
CMDn
...
done

break [N]:提前结束第N层循环,最内层为第1层
while CONDTIITON1; do
CMD1
...
if CONDITION2; then
break
fi
CMDn
...
done

比如无限循环:
while true; do
循环体
done
until false; do
循环体
Done


实战训练8

1、每隔3秒钟到系统上获取已经登录的用户的信息;如果发 现用户hacker登录,则将登录时间和主机记录于日志 /var/log/login.log中,并提示该用户退出系统
#!/bin/bash
username=cent
{
while true ;do
if who | egrep "^\b$username\b" &> /dev/null ;then
who | egrep "^\b$username\b" >> /var/log/login.log
echo "$username 已经登录"
echo "fuck ,go out my system" | write $username
else
echo "$username 已经下线"
fi
sleep 3
done
}

#!/bin/bash
username=hacker
exituser()
{
echo "fuck you,you will exit,haha" | write $username
sleep 2
pidlist=$(ps -f h -u $username | tr -s ' '|cut -d' ' -f2)
for i in $pidlist ;do
kill -9 $i

echo "正在结束进程"

done

}
while true ;do
if w | egrep "^\b$username\b" &> /dev/null ;then
w | egrep "^\b$username\b" >> /var/login.log
echo "$username 已经登录"
exituser
else
echo "$username 已经下线"
fi
sleep 3
done

2、随机生成10以内的数字,实现猜字游戏,提示比较大或小 ,相等则退出
#!bin/bash
lim=10
let key=$RANDOM%lim
read -p "please input a number less than $lim: " num
until false;do
if [ $num -le $lim &> /dev/null ] && [ $num -ge 0 &> /dev/null ] ;then
if [ $num -lt $key ];then
read -p "is small,please input again: " num
elif [ $num -gt $key ];then
read -p "is big,please input again: " num
else
echo "you are right,you are very clever"
break
fi
else
read -p "error,please input a number less than ten: " num
fi
done


6.5 一些特殊用法

while循环的特殊用法(遍历文件的每一行):
while read line; do
循环体
done < /PATH/FROM/SOMEFILE
依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line

练习 扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填充用户名和单位电话为62985600,并提示该用户的GECOS信息修改成功。
#!/bin/bash
phone=" phone number is 62985600"
pathname=/etc/passwd
while read line;do
name=echo $line|cut -d: -f1
b=echo $line | cut -d: -f5|wc -c
if [ $b -eq 1 ] ;then
chfn -f $name -p $phone $name &>/dev/null && echo "$name信息修改成功" || echo "$name信息修改失败"
fi
done < $pathname

双小括号方法,即((…))格式,也可以用于算术运算
双小括号方法也可以使bash Shell实现C语言风格的变量操作 #I=10 #((I++))

for循环的特殊格式:
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)) do
循环体
done
控制变量初始化:仅在运行到循环代码段时执行一次
控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算 ,而后再做条件判断

6.6 select 循环与菜单
select variable in list
do
循环体命令
done
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3提示符等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量REPLY中
select是个无限循环,因此要记住用break命令退出循环,或用exit命令终止脚本,也可以按Ctrl+c退出循环
select经常和case联合使用
与for循环类似,可以省略in list,此时使用位置参数

比如
#!/bin/bash
PS3="please input your chose:"
list="start stop restart status exit"
select k in $list
do
case $k in
start)
echo start
;;
stop)
echo stop
;;
restart)
echo restart
;;
status)
echo status
;;
exit)
echo exit
;;
*)
break
;;
esac
done

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!