文章目录
前言
学习linux笔记小实践三
shell 示例
一、Linux shell命令
当一个用户登录Linux系统之后,系统初始化程序init就为每一个用户运行一个称为shell(外壳)的程序。
那么,shell是什么呢?确切一点说,shell就是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用shell来启动、挂起、停止甚至是编写一些程序。当用户使用Linux Shell命令时是通过命令来完成所需工作的。一个命令就是用户和shell之间对话的一个基本单位,它是由多个字符组成并以换行结束的字符串。shell解释用户输入的命令,就象DOS里的command.com所做的一样,所不同的是,在DOS中,command.com只有一个,而在Linux下比较流行的shell有好几个,每个shell都各有千秋。一般的Linux系统都将bash作为默认的shell。
二、shell练习
1.login界面
[root@student100 ~]# cat h1.sh
#! /bin/bash
#
#登录界面
#
clear
grep "PRETTY_NAME" /etc/os-release | cut -d'=' -f2 | tr -d '"'
echo -n "Kernel $(uname -r) on an $(uname -p)"
echo
read -p "$(hostname -s) login: " uname
read -p "Password: " -s pas
echo
echo "$uname $pas" >> /tmp/.userinfo
exit 0
2.创建用户
(1)编写脚本创建用户rhel,密码为123456,主组为group文件中第10个组,要求登陆强制修改密码,密码有效期30天,提前5天告警,失效3天允许更改密码。
[root@student100 ~]# cat h2.sh
#! /bin/bash
#
#创建用户,强制改密码
#
clear
gname=$(head -n 10 /etc/group | tail -n 1 | cut -d':' -f1)
useradd -g ${gname} rhel
echo "123456" | passwd --stdin rhel
chage -d0 -M30 -W5 -I3 rhel
exit 0
(2)编写脚本:提示用户输入用户名和密码,脚本自动创建相应的账户及配置密码。如果用户不输入账户名,则提示必须输入账户名并退出脚本;如果用户不输入密码,则统一使用默认的 123456 作为默认密码(密码输入时不应该被看见)
#! /bin/bash
#
read -p "输入用户名:" name
if test -z "$name"
then
echo "user name cant't empty."
exit 1
fi
useradd ${name}
read -p "输入密码:" -s pas
#判断是否输入了密码
if [ -z "$pas" ]
then
echo "123456" | passwd --stdin ${name}
else
echo "${pas}" | passwd --stdin ${name}
fi
exit 0
(3)创建cw0n的10个账号,要求默认密码为 8位置的随机字符,将用户和密码记录到 /tmp/user.txt文件中
#! /bin/bash
#
for i in {1..10}
do
useradd cw$i
num=$(date +%N|md5sum|cut -c 5-12)
echo "$num" | passwd --stdin cw$i
echo "cw$i : $num" >> /tmp/user.txt
done
3.nginx安装
编写脚本 检查系统nginx安装是否有配置,如果没有配置,已知nginx的源url为http://nginx.org/packages/centos/ r e l e a s e v e r / releasever/ releasever/basearch/
[root@student100 ~]# cat h3.sh
#! /bin/bash
#
#检查nginx是否有配置,没有则安装
#
function show()
{
while :
do
echo -n "."
usleep 500000
done
}
##########################
#清缓存
yum clean all &> /dev/null
# 在后台显示动态效果
echo -n "正则检查系统yum源"
show &
#列出当前系统下所有仓库源,检查是否包含nginx
yum repolist | grep "nginx" &> /dev/null
#结束后台show进程
kill -9 $!
#打印空行
echo
#如果源存在则直接退出
if test $? -eq 0
then
echo "nginx yum is exist."
exit 0
fi
echo -e "\033[32mcreating nginx yum.....\033[0m"
#不存在,建立nginx源
cat > /etc/yum.repos.d/nginx.repo << EOF
[nginx]
name="nginx install"
enabled=1
gpgchek=0
baseurl=http://nginx.org/packages/centos/\$releasever/\$basearch/
EOF
exit 0
4.判断冒险位
判断 /usr/bin/passwd文件是否有 set-user-id冒险位权限
[root@student100 ~]# cat h4.sh
#! /bin/bash
#
#判断冒险位
#
clear
if [ -u /usr/bin/passwd ]
then
echo "有冒险位"
else
echo "没有冒险位"
fi
exit 0
5.判断文件
(1)判断 /tmp/a.txt是否存在且是否为空普通文件,如果是空的普通文件则删除
[root@student100 ~]# cat h5.sh
#! /bin/bash
#
#判断文件
#
clear
# 是否存在
if ! test -e /tmp/a.txt
then
echo "'/tmp/a.txt' is not exist."
exit 0
fi
#判断是否为普通文件 且是否为空
#if [ -f /tmp/a.txt ] && [ ! -s /tmp/a.txt ]
if [ -f /tmp/a.txt -a ! -s /tmp/a.txt ]
then
echo "'/tmp/a.txt' 是一个普通空文件,删除."
rm -rf /tmp/a.txt
else
echo "'/tmp/a.txt' 它不是普通文件或者它不为空."
fi
exit 0
(2)以位置参数的用法,判断某个文件的类型
例如 ./xxx.sh /etc/passwd
#! /bin/bash
#
#检查是否传参正确
if [ $# -ne 1 ]
then
echo "use error. use : $0 file"
exit 1
fi
file=$1
#判断是否存在
if test ! -e ${file}
then
echo "'${file}' is not exist."
exit 2
fi
# 鉴定 file 类型
#方法一:直接使用 file命令鉴定
#file ${file}
# 方法二: 使用 test测试 鉴定文件类型
#ps : -f -d -p -s -b -c 判断文件类型时,如果是链接文件它会跟随链接,因此 -L 判断链接放在最前面
#if test -L ${file}
#then
# echo "a symbolic link"
#elif test -f ${file}
#then
# echo "a regular file"
#elif test -d ${file}
#then
# echo "a directory"
#elif test -S ${file}
#then
# echo "a socket"
#elif test -p ${file}
#then
# echo "a named pipe"
#elif test -b ${file}
#then
# echo "block special"
#elif test -c ${file}
#then
# echo "character special"
#else
# echo "unknow."
#fi
#方法三:ls -l 查看详细属性,然后截取 第一个字符,则为类型标识 - d s l p b c
key=$(ls -ld ${file} | cut -c1)
case $key in
'-')
echo "a regular file"
;;
'd')
echo "a directory"
;;
'l')
echo "a symbolic link"
;;
'p')
echo "a named pipe"
;;
's')
echo "a socket."
;;
'b')
echo "block special"
;;
'c')
echo "character special"
;;
*)
echo "unknow."
;;
esac
exit 0
(3)遍历 /tmp目录下是否有空文件,如果有则删除,并统计删除的数量
#! /bin/bash
#
#遍历 /tmp目录下是否有空文件,如果有则删除,并统计删除的数量
#
for i in $(ls /tmp)
do
if [ "-" = "$(ls -ld /tmp/$file | cut -c1)" ]
then
echo "文件$i为空,删除"
rm -rf /tmp/$i
if [ $? -eq 0 ] #如果删除成功,计数
then
let "count++"
fi
fi
done
echo $sum
6.判断超级管理员
检测本机当前用户是否为超级管理员,如果是管理员root,则使用 yum 安装 vsftpd,如果不是,则提示您非管理员.
[root@student100 ~]# cat h6.sh
#! /bin/bash
#
#判断超级管理员
#
clear
if [ "$(whoami)" = "root" ]
then
echo "当前用户为超级管理员"
yum install -y vsftpd
else
echo "非超级管理员"
fi
exit 0
7.计算
公鸡5元一只,母鸡3元一只,小鸡1元3只,求100元刚好买100只鸡的买法.
#! /bin/bash
#
read -p "公鸡价格(默认5):" gjp
read -p "母鸡价格(默认3):" mjp
read -p "小鸡价格一块多少只(默认3只):" xjp
[ -z "$gjp" ] && gjp=5
[ -z "$mjp" ] && mjp=3
[ -z "$xjp" ] && xjp=3
[ $[$gjp+$mjp+$xjp] -eq 0 ] && echo "错误输入!" && exit 1
for x in $(seq 0 $[100/$gjp])
do
for y in $(seq 0 $[100/$mjp])
do
xj=$[100-$x-$y]
if [ $[$gjp*$x+$mjp*$y+$xj/$xjp] -eq 100 ] && [ $xj -ge $xjp ]
then
echo "公鸡:$x,母鸡:$y,小鸡:$xj"
fi
done
done
8.降序排序输出
输入三个数并进行降序排序输出
#! /bin/bash
#
read -p "input 3 int number:" a b c
#检查输入是否合法`
ret=$(expr $a + $b + $c 2> /dev/null)
if test -z "${ret}"
then
echo "输入非法."
exit 1
fi
######排序
#假设a is max
if [ $a -ge $b -a $a -ge $c ]
then
if [ $b -ge $c ]
then
echo "$a $b $c"
else
echo "$a $c $b"
fi
#假设b is max
elif test $b -ge $a -a $b -ge $c
then
if test $a -ge $c
then
echo "$b $a $c"
else
echo "$b $c $a"
fi
else
if [ $a -ge $b ]
then
echo "$c $a $b"
else
echo "$c $b $a"
fi
fi
#取消变量
unset a
unset b
unset c
exit 0
9.判断用户类型
任意输入一个用户名,判断通过uid值用户的类型 (0:管理 1–999程序用户 1000+ 普通用户 不存在)
#! /bin/bash
#
read -p "input user name:" name
#检查输入
if test -z "$name"
then
echo "name can't empty."
exit 1
fi
uid=$(id -u ${name})
#用户不存在
if test -z "${uid}"
then
exit 2
fi
if [ $uid -eq 0 ]
then
echo "管理员用户"
elif [ $uid -gt 0 -a $uid -lt 999 ]
then
echo "程序用户"
else
echo "普通用户"
fi
unset name
unset uid
exit 0
10.备份分区
编写脚本备份/boot分区,完全备份文件名为 boot-fully.bak,要求编脚本备份时如果完全备份不存在则实现完全备份,如果完全备份已经存在则实现差异备份,差异备份文件为 “mmddHHMM-boot.bak”; 并配置计划任务在每周五 凌晨3点执行备份脚本。
#! /bin/bash
#
#判断完全备份是否则
if test -e /opt/boot-fully.bak
then
#差异备份
xfsdump -f /opt/$(date +"%m%d%H%M")-boot.bak -l1 -L "boot分区完差异备份" -M " " /boot
else
#完全备份
xfsdump -f /opt/boot-fully.bak -l0 -L "boot分区完全备份" -M " " /boot
fi
exit 0
11.测试网段是否被使用
编写脚本测试网段 192.168.3.0/24下有哪些IP正则被使用,将正则被使用的IP记录到/tmp/yes.txt,没有被使用的记录到 /tmp/no.txt (分别实现for循环版本 和 while循环版本的 2个版本)
#! /bin/bash
#
IP=1
while [ $IP -le 5 ]
do
ping -c 2 -w 2 192.168.3.$IP &> /dev/null
if [ $? -eq 0 ]
then
echo "192.168.3.$IP正在使用"
echo "192.168.3.$IP" >> /tmp/yes.txt
else
echo "192.168.3.$IP没有在使用"
echo "192.168.3.$IP" >> /tmp/no.txt
fi
let "IP=IP+1"
done
#! /bin/bash
#
for IP in {1..5}
do
#{ }& 可做多进程运行,但不可控
ping -c 2 -w 2 192.168.3.$IP &> /dev/null
if [ $? -eq 0 ]
then
echo "192.168.3.$IP正在使用"
echo "192.168.3.$IP" >> /tmp/yes.txt
else
echo "192.168.3.$IP没有在使用"
echo "192.168.3.$IP" >> /tmp/no.txt
fi
done
12.统计
(1)用for…in循环统计系统下哪些用户是不可登陆的,总数为多少?
#! /bin/bash
#
#grep -v /etc/passwd | cut -d':' -f1 grep -v /etc/passwd
for i in $(grep nologin /etc/passwd | cut -d':' -f1)
do
echo $i
let "sum=sum+1"
done
echo $sum
(2)统计系统下所有的tcp状态的数量 ?
#netstat -nat | grep “^tcp” | awk ‘{print $6}’ 列出系统下所有的TCP状态命令
#! /bin/bash
#
declare -A tcps
for t in $(netstat -nat | grep "^tcp" | awk '{print $6}' ) 或 netstat -nat | awk '/^tcp/{print $NF}'
do
let "tcps[$t]++"
done
for i in ${!tcps[*]}
do
echo "$i : ${tcps[$i]}"
done
(3)写脚本 统计/etc/passwd文件中 数字、字母、标点符号的数量, 并统计 其中统计字母分别出现多少次(例如 a多少次 b多少次…字母不区分大小写)
#!/bin/bash
#
#定义字母数组,统计对应的字母出现的次数
declare -A alphas
#grep -o "[[:print:]]" /etc/passwd 获取到文件中每个字符,用于for in 遍历
for c in $(grep -o "[[:print:]]" /etc/passwd)
do
case $c in
[[:digit:]]) #数字
let "d++"
;;
[[:punct:]]) #标点符号
let "p++"
;;
[[:alpha:]]) #字母
let "a++"
#如果是大写转换为小写
ch=$(echo "$c" | tr "[:upper:]" "[:lower:]")
let "alphas[$ch]++"
esac
done
#打印结果
echo "数字总计 :$d个"
echo "标点符号总计:$p个"
echo "字母总计 :$a个"
echo "对应的字母出现的次数"
for idx in ${!alphas[@]}
do
echo "$idx : ${alphas[$idx]}"
done
13.判断是否对称
任意输入一个内容,判断它是否为对称的输出yes/no(例如: a b 1 2 3 11 aa 121 aba 123321 abccba)
#! /bin/bash
#
read -p "任意输入:" str
if test -z "$str"
then
echo "input can't empty."
exit 1
fi
#################################
#方法一: 通过rev命令将 str 逆置
#t=$(echo "$str"|rev)
#方法二:通过循环逐个去str中字符,再组合为逆置
#for idx in $(seq 1 $(expr length "$str"))
#do
# t=$(expr substr "$str" $idx 1)$t
#done
#方法三:通过普通变量特殊引用 进行逆置
for idx in $(seq 0 $[${#str}-1])
do
t=${str:$idx:1}$t
done
if [ "$str" = "$t" ]
then
echo "'$str' yes."
else
echo "'$str' no ."
fi
(4)写一个while死循环,从0 开始打印数字,每隔半秒打印一个,当打印到10的时候结束。
#! /bin/bash
#
num=0
while :
do
if [ $num -le 10 ]
then
echo "$num"
let "num++"
fi
sleep 0.5
done
14.打印
(1)打印99乘法表
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
#! /bin/bash
#
#打印99乘法表
#
for i in {1..9}
do
for j in $(seq 1 $i)
do
x=$[i*j]
echo -n "$j*$i=$x "
done
echo
done
(2)打印以下图形(边长为8的空正方形)
* * * * * * * * * * * **
* *
* *
* *
* * * * * * * * * * * **
#! /bin/bash
#
#打印边长为8的空正方形
#
for i in {1..8}
do
for j in {1..8}
do
if [ $j -eq 1 -o $j -eq 8 -o $i -eq 1 -o $i -eq 8 ]
then
echo -n "* "
else
echo -n " "
fi
done
echo
done
(3)for循环 打印100以内所有包含数字’7’的数据 且求所有数据和。
#! /bin/bash
#
for i in {1..100}
do
if echo $i | grep "7"
then
echo $i
let "sum=sum+i"
fi
done
echo $sum
15.猜数字
RANDOM 变量可以产生一个0–32767的随机正整数,利用该变量产生一个 0–1000范围的随机数,然后编写一个猜数字的小游戏,猜错提示 太大或太小,直到猜对为止,统计猜的次数。
#! /bin/bash
#
count=0
#产生0--1000的随机值
echo "=====seed:$seed"
while :
do
read -p "猜一个1000以内的数字:" num
#判断num是否输入为数字
if [[ ! "$num" =~ ^[0-9]+$ ]]
then
continue
fi
#累加次数
let "count++"
#如果输入时数字,则判断
if [ $num -eq $seed ]
then
echo "恭喜你,猜对了.总计猜测次数为:$count"
#打破(结束)循环
break
elif [ $num -gt $seed ]
then
echo "太大了."
else
echo "太小了."
fi
done
16.监控程序
写一个监控程序,监控系统下 1分钟内是否有新的登陆失败的用户记录到 /tmp/failed.txt下,并统计如果某个用户在1分钟内登陆失败3次及以上则 通过 wall 广播警告提示 “xxxx 用户正在被爆破.”
#! /bin/bash
#
#统计当前登陆失败的用户信息
lastb > /tmp/lastb_old.txt
while :
do
sleep 60
lastb > /tmp/lastb_new.txt
#对比上一次的差异
diff /tmp/lastb_old.txt /tmp/lastb_new.txt | grep "^>"|cut -d' ' -f2| sort | uniq | tee /tmp/failed.txt
#并统计用户在1分钟内登陆失败的次数记录到txt临时文件中
diff /tmp/lastb_old.txt /tmp/lastb_new.txt | grep "^>"|cut -d' ' -f2|tee /tmp/failed.txt|sort|uniq -c > ./txt
for nu in $(grep -woE "[0-9]+" ./txt)
do
#检索出失败次数大于等于3次的
if [ $nu -ge 3 ]
then
name=$(grep -wE "$nu" ./txt | awk '{print $2}')
wall "$name 登陆失败 ${nu} 次......"
fi
done
#将本次的处理过的新结果作为 老结果数据,为下一次检查做准备
cat /tmp/lastb_new.txt > /tmp/lastb_old.txt
done
17.判断组是否存在
编写脚本判断itgrp组是否存在,如果存在将 root 加入该组,不存在输出 “‘itgrp’ group is not exist.”
#! /bin/bash
#
grep -w "itgrp" /etc/group &> /dev/null
if [ $? -eq 0 ]
then
echo "存在"
gpasswd -a root itgrp
else
echo "'itgrp' group is not exist."
fi
18.菜单
(1)用while+echo+case实现菜单 且根据对应的选择执行对应的动作 1.打印A 2.打印# 3.打印B 4.退出
#! /bin/bash
#
echo "##############"
echo "# 1. 打印A #"
echo "# 2. 打印# #"
echo "# 3. 打印B #"
echo "# 4. 退出 #"
echo "##############"
while :
do
read -p "请输入请求:" n
case $n in
1)
echo "A"
;;
2)
echo "#"
;;
3)
echo "B"
;;
4)
break
;;
esac
done
(2)用select将某个目录底下的所有普通空文件实现菜单选择 可以删除某个文件,并包含菜单项 all删除所有,quit退出
PS:某个目录通过 位置参数传入
#! /bin/bash
#
#如果有传路径则 遍历对应的路径,如果没有则遍历当前目录
path="./"
if test -n "$1"
then
path=$1
fi
if test $(ls -ld ${path}|cut -c1) != "d"
then
echo "参数必须是一个目录路径." > /dev/fd/2
exit 1
fi
###########
PS3=">># "
select fname in $(find ${path} -mount -empty) all quit
do
case $fname in
all)
#find ${path} -mount -empty -exec rm -rf {} \;
find ${path} -mount -empty -delete
;;
quit)
break
;;
*)
rm -rf $fname
esac
done
(3)编写一个脚本提供菜单选择收集系统以下信息:
当前登陆的用户名
主机名
当前的IP地址、掩码地址、DNS、缺省网关
当前是否可以通信外网
内存及交换内存信息
挂载的文件系统信息(除tmpfs devtmpfs)
CPU负载状况
所有可登陆的系统账号 并统计个数
最近登陆失败的账号(仅打印出用户名,要求去重)
#! /bin/bash
#
function showNetworkInfo()
{
echo "IP :$(ifconfig ens33|awk '/netmask/{print $2}')"
echo "NETMASK :$(ifconfig ens33|awk '/netmask/{print $4}')"
echo "DNS :$(awk '/^nameserver/{print $2}' /etc/resolv.conf | tr '\n' ' ' )"
echo "DefRoute:$(ip route list | awk '/^default/{print $3}')"
}
echo "#############################################"
echo "# 1. 当前登陆的用户名 #"
echo "# 2. 主机名 #"
echo "# 3. 当前的IP地址、掩码地址、DNS、缺省网关 #"
echo "# 4. 当前是否可以通信外网 #"
echo "# 5. 内存及交换内存信息 #"
echo "# 6. 挂载的文件系统信息 #"
echo "# 7. CPU负载状况 #"
echo "# 8. 所有可登陆的系统账号 并统计个数 #"
echo "# 9. 最近登陆失败的账号 #"
echo "# 10.退出 #"
echo "#############################################"
while :
do
read -p "请输入选项:" n
echo -e "\033[34m"
case $n in
1)
whoami
;;
2)
hostname
;;
3)
showNetworkInfo
;;
4)
if ping -c 2 14.119.104.189 或 www.baidu.com
then
echo "可以通信外网"
else
echo "不可以通信外网"
fi
;;
5)
free -m
;;
6)
df -TH | grep "^/"
;;
7)
top -n 1 | awk 'FNR==1{print $10,$11,$12,$13,$14}'
;;
8)
grep "bash$" /etc/passwd | cut -d':' -f1 或 awk -F':' '/bash$/{print $1;count++}END{print "总计:" count "个"}' /~/
echo "总计$(grep "bash$" /etc/passwd | wc -l)个"
;;
9)
lastb | cut -d' ' -f1 | uniq | grep -v "btmp" 或 awk '$1 !~ /btmp/{print $1}' | sort | uniq
;;
10)
break
;;
esac
echo -e "\033[0m"
read -p "[any key continue]" -n1
done
总结
本文总结了shell的一些实例,用于学习笔记。