1、编写一个问候程序,它根据当前的时间来执行,假设从夜里到中午为早晨,中午到下午六点为下午,下午六点到半夜为网上;
注释:可以用date +%H 来判断小时; if [ $h -ge 0 ] && [ $h -lt 12 ] 来判读时区;
[root@localhost_002 shell100]# date +%H
22
脚本如下:
[root@localhost_002 shell100]# cat 41.sh
#!/bin/bash
h=`date +%H`
if [ $h -ge 0 ] && [ $h -lt 12 ]
then
echo "gond morning."
elif [ $h -ge 12 ] && [ $h -lt 18 ]
then
echo "good afternoon"
else
echo "good evening"
fi
执行脚本;
[root@localhost_002 shell100]# sh 41.sh
good evening
方法二:当然也可以用如下方法:使用 if 判断tag 打标记的方法;然后通过 case来循环;
[root@localhost_002 shell100]# cat 41.1.sh
#!/bin/bash
h=`date +%H`
if [ $h -ge 0 -a $h -lt 12 ]
then
tag=1
elif [ $h -ge 12 -a $h -lt 18 ]
then
tag=2
elif [ $h -ge 18 -a $h -lt 21 ]
then
tag=3
else
tag=4
fi
case $tag in
1)
echo "good morning"
;;
2)
echo "good afternoon"
;;
3)
echo "good evening"
;;
4)
echo "bash is error"
;;
esac
执行;
[root@localhost_002 shell100]# sh -x 41.1.sh
++ date +%H
+ h=23
+ '[' 23 -ge 0 -a 23 -lt 12 ']'
+ '[' 23 -ge 12 -a 23 -lt 18 ']'
+ '[' 23 -ge 18 -a 23 -lt 21 ']'
+ tag=4
+ case $tag in
+ echo 'bash is error'
bash is error
注释: if 的语句用法: 如下两种格式: 并且 可以用 && 或者 -a 来表示;
if [ $h -ge 0 ] && [ $h -lt 12 ] then tag=1 elif [ 判断 ] then tag=2 elif [ 判断 ] then tag=3 else tag=4
if [ $h -ge 0 -a $h lt 12 ]
然后分别用 case 来循环; case $tag in 1) echo "gond morning" ;; 2) echo "......." ;; 3) echo "......." ;; 4) ".........." ;; esac
2、写一个 shell 脚本,实现弹出菜单功能,用户根据显示的菜单从键盘选择执行对应的命令;
其实这个题可以用 read 和 case 参数来实现的;
首先 echo 显示一下内容要求用户输入: -n 表示换行符 -e 能够识别特殊字符
echo -e "1) w\n2) ls\n3) pwd\4) quit"
然后再使用 read 来使用; read -p "please input your nubmer " c 注释: c 是一个变量;
脚本如下:
[root@localhost_002 shell100]# cat 42.sh
#!/bin/bash
echo -e "1) w\n2) ls\n3) pwd\n4) quit"
read -p "Please input you number: " c
case $c in
1)
w
;;
2)
ls
;;
3)
pwd
;;
4)
exit
;;
*)
echo "bash is error"
;;
esac
执行命令;
[root@localhost_002 shell100]# sh 42.sh
1) w
2) ls
3) pwd
4) quit
Please input you number: 2
16.sh 1.txt 22.1.sh 23.sh 28.1.sh 28.sh 30.sh 41.2.sh 42.sh stu.txt
17.sh 21.sh 22.sh 25.sh 28.2.sh 2.txt 41.1.sh 41.sh ls.tar.gz
注释:由于上面是执行后自动退出,当然也可以写成死循环的方式,一直循环下去;用while : do done
[root@localhost_002 shell100]# cat 42.sh
#!/bin/bash
echo -e "1) w\n2) ls\n3) pwd\n4) quit"
while : # 新加 while 循环语句;
do
read -p "Please input you number: " c
case $c in
1)
w
;;
2)
ls
;;
3)
pwd
;;
4)
exit
;;
*)
echo "bash is error"
;;
esac
done # while 循环语句结束;
执行脚本;
[root@localhost_002 shell100]# sh 42.sh
1) w
2) ls
3) pwd
4) quit
Please input you number: 1
22:30:03 up 9 min, 1 user, load average: 0.02, 0.08, 0.09
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.149.135 22:21 3.00s 0.06s 0.01s w
Please input you number: 2
16.sh 1.txt 22.1.sh 23.sh 28.1.sh 28.sh 30.sh 41.2.sh 42.sh stu.txt
17.sh 21.sh 22.sh 25.sh 28.2.sh 2.txt 41.1.sh 41.sh ls.tar.gz
Please input you number: 3
/root/shell/shell100
注释:如上脚本,也只是新加 while 的语句而已;可以实现不断循环输入;当然要是输入 4 选项,即 exit 还是会退出此脚本;
当然还有一个方法: 可以使用 select 语句,这个语句和for 循环的语法相同,也可以遍历文件;
select 格式如下: select i in w ls pwd exit do case语句 done
注释: select 语句会一直执行下去的,并且左侧以 #? 结尾;用法如下;
[root@localhost_002 shell100]# cat 42.1.sh
#!/bin/bash
select i in w ls pwd exit
do
case $i in
w)
w
;;
ls)
ls
;;
pwd)
pwd
;;
exit)
exit
;;
*)
echo "Please input 1-4."
;;
esac
done
执行命令;
[root@localhost_002 shell100]# sh 42.1.sh
1) w
2) ls
3) pwd
4) exit
#? 2
16.sh 1.txt 22.1.sh 23.sh 28.1.sh 28.sh 30.sh 41.2.sh 42.1.sh ls.tar.gz
17.sh 21.sh 22.sh 25.sh 28.2.sh 2.txt 41.1.sh 41.sh 42.sh stu.txt
#? 1
22:38:43 up 18 min, 1 user, load average: 0.00, 0.03, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.149.135 22:21 3.00s 0.09s 0.00s w
#? 3
/root/shell/shell100
注释:当然 左侧 #? 是可以修改了的,只需要在开头添加如下内容即可;如下;
PS3="Please input you number(1-4): "
[root@localhost_002 shell100]# cat 42.1.sh
#!/bin/bash
PS3="Please input you number(1-4): "
select i in w ls pwd exit
do
case $i in
w)
w
;;
ls)
ls
;;
pwd)
pwd
;;
exit)
exit
;;
*)
echo "Please input 1-4."
;;
esac
done
执行脚本:
[root@localhost_002 shell100]# sh 42.1.sh
1) w
2) ls
3) pwd
4) exit
Please input you number(1-4): 2
16.sh 1.txt 22.1.sh 23.sh 28.1.sh 28.sh 30.sh 41.2.sh 42.1.sh ls.tar.gz
17.sh 21.sh 22.sh 25.sh 28.2.sh 2.txt 41.1.sh 41.sh 42.sh stu.txt
Please input you number(1-4): 1
22:44:12 up 23 min, 1 user, load average: 0.04, 0.03, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.149.135 22:43 4.00s 0.05s 0.01s w
Please input you number(1-4): 3
/root/shell/shell100
Please input you number(1-4):
注释:这个脚本会一直不断的循环下去,不会退出的;
3、写一个 shell 脚本,每隔 5 分钟判断指定的用户是否登录系统; 需要指定用户名;
注释:如果先登录root 用户,然后通过root用户去sudo 到 yuanhh 用户, 那么这种情况是查询不到,也是会显示 root;
分析: 如果要判断用户是否登录,\从命令行输入判断可以有两种方式,
1)、脚本本执行时 传递一个参数;通过用 w 命令查看并打印第一列;
2)、另一种是给它一个用户,通过 read -p 命令;
首先用第一种脚本传递参数的方式:
[root@localhost_002 shell100]# w
22:58:45 up 38 min, 1 user, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.149.135 22:43 5.00s 0.07s 0.02s w
[root@localhost_002 shell100]# w|awk '{print $1}'|sed '1,2'd
root
脚本代码如下:
[root@localhost_002 shell100]# cat 43.sh
#!/bin/bash
while :
do
if w|sed '1,2'd|awk '{print $1}' |grep -qw "$1"
then
echo "用户$1已经登录系统"
exit
fi
sleep 30
done
执行:
[root@localhost_002 shell100]# sh 43.sh root
用户root已经登录系统
方法二: 当然也可以用 read -p 给一个用户,然后来判断;
4、先普及一个小常识,我们用ps aux可以查看到进程的PID,而每个PID都会在/proc内产生。如果查看到的pid在proc内是没有的,则进程被人修改了,这就代表系统很有可能已经被入侵过了。 请用上面知识编写一个shell,定期检查下自己的系统是否被人入侵过;
分析:可以把ps aux 列出来的pid做一个遍历,然后过滤到pid,并打印第二行:如下:
ps aux|grep 'pid'|awk '{print $2}'
然后把列出的行逐一遍历, 使用 while read xxx; do ...... done 这种循环的格式来逐行处理; 赋予变量 pid
echo -e "1\n2\3"|while read n;do echo $n;done
[root@fenye2019 shell]# echo -e "1\n2\n3"|while read n;do echo $n;done
1
2
3
然后在while语句里,使用find 来查找 pid 相关行; 赋予变量 result -maxdepth 1 表示查看的深度为 1;
result=`find /proc -type d -maxdepth 1 -name "$pid"`
然后在通过判断这个变量是否为空,如果在/proc 目录查找不到$pid,则为空; if [ -z $pid ] then echo $pid not exist;
脚本内容:
[root@fenye2019 shell]# cat 44.sh
#!/bin/bash
echo $$
ps aux|sed '1'd|awk '{print $2}'|while read pid
do
result=`find /proc -type d -maxdepth 1 -name "$pid"`
if [ -z $result ]
then
echo "$pid not exist"
fi
done
执行脚本:
[root@fenye2019 shell]# sh 44.sh
21101
21102 not exist
21103 not exist
21104 not exist
注释:如上在执行过程中还是会显示出脚本本身的pid和命令的pid进程号;
那么如何解决:只能在执行时过滤掉脚本本身的进程pid才可以,可以通过追踪到父进程PPID的方式, 然后把变量在传递到awk的脚本参数里;
pp=$$ 表示脚本本身的pid;
ps elf 命令可以追踪到 PPID, 第三列则是PPID , 第四列则是PID;
把shell变量传递awk 脚本里; ps elf |sed '1'd >/tmp/pid.txt
for pid in `awk -v ppn=$pp '$5!=ppn {print $4}'` do if ! [ -d $pid ] then echo "$pid not exist" fi down
脚本内容如下:
[root@fenye2019 shell]# cat 44.2.sh
#!/bin/bash
pp=$$
ps -elf|sed '1'd > /tmp/pid.txt
for pid in `awk -v ppn=$pp '$5!=ppn {print $4}' /tmp/pid.txt`
do
if ! [ -d /proc/$pid ]
then
echo "系统中并没有pid为$pid的目录"
fi
done
[root@fenye2019 shell]# sh 44.2.sh
此时脚本才算正确了;
5、想办法把文本里面每三行内容合并到一行 例如:1.txt内容如下:
1
2
3
4
5
6
7
分析:根据要求每三行变成一行,可以想到的是第3行, 第6行, 第9行后面为换行符,其他行后面为空格;
可以用 while read line 来做一个遍历,然后用 if 判断是否能被 3 整除,如果能则使用 echo -n 换行输出,如果不能,则显示当前行;
[root@fenye2019 shell]# cat 45.sh
#!/bin/bash
n=0
cat $1|while read line
do
n1=$[$n%3]
if [ $n1 -eq 0 ]
then
echo "$line"
else
echo -n "$lne\n"
fi
n=$[$n+1]
done
[root@fenye2019 shell]# sh 45.sh 1.txt
1 2 3
4 5 6
ada 1231