日常shell练习题-03(持续更新…)

时间:2022-05-30
本文章向大家介绍日常shell练习题-03(持续更新…),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
  • 打印乘法口诀
#! /bin/bash

##printing 9*9 list
##written by zhdya_20171004

for m in `seq 1 9`
do
	for n in `seq 1 $m`
		do
			dd=$[$m*$n]
			echo -ne "$n x $m = $dd t"
	done
	echo
done
  • 写脚本,用来实现交换两个文件或目录的名字。
#! /bin/bash

##change the file or dir's name.
##written by zhdya_20171005

while :
do
	read -p "pls type the file or dir's name, it must exist! :" file1 file2
	
	if [ -z $file1 ] && [ -z $file2 ]
	then
		echo "pls inpute file1 and file2"
		continue
	elif [ -d $file1 ] && [ -d $file2 ]
	then	
		mv $file1 tempfile
		mv $file2 $file1
		mv tempfile $file2
		echo "already change the dir each other, pls check it."
		break
	elif [ -f $file1 ] && [ -f $file2 ]
	then
		mv $file1 tempfile
		mv $file2 $file1
		mv tempfile $file2
		echo "already change the file's name each other, pls check it."
		break
	else
		echo "pls check the file, seems not exist!!!"	
		continue
	fi
done
  • 写一个猜数字脚本,当用户输入的数字和预设数字(随机生成一个小于100的数字)一样时,直接退出,否则让用户一直输入,并且提示用户的数字比预设数字大或者小。
#!/ bin/bash

##guess a number, if right the shell script will be end, if not it will end when the guess was right.
##written by zhdya.

r=`echo $RANDOM`
n=$[$r%100]

while :
do
	read -p "pls input a number:" m
	if [ $n == $m ]
	then
		echo "you're so smart!!"
		break
	elif [ $n -gt $m ]
	then
		echo "pls input a bigger number"
	else
		echo "pls input a smaller number"
	fi
done
  • 写一个脚本,让用户输入一个数字,然后判断是否是数字,如果是数字,则打印数字,否则一直让用户输入,直到是数字为止。
#! /bin/bash

##just input a number, if not the program not end.
##written by zhdya_20171004

while :
do
read -p "pls just input a number:" n

ch=`echo "$n"|sed 's/[0-9]//g' |wc -c`

if [ $ch -ne 1 ]
then
	continue
else
	echo "you input the number is $n"
	break
fi
done
  • 第一个参数为URL,即可下载的文件;第二个参数为目录,即下载后保存的位置;
  • 如果用户给的目录不存在,则提示用户是否创建;如果创建就继续执行,否则,函数返回一个51的错误值给调用脚本;
  • 如果给的目录存在,则下载文件;下载命令执行结束后测试文件下载成功与否;如果成功,则返回0给调用脚本,否则,返回52给调用脚本;

第一种:

#!/bin/bash
url=$1
dir=$2
download()
  {
    if [[ ! -d $dir ]];then
        read -p "$dir No such directory,create?(y/n)" answer
        if [[ "$answer" == "y" ]];then
            mkdir -p $dir
        else
            return "51"
        fi
    fi
    cd $dir && wget $url >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        return "52"
    fi
    return 0
}
download $url $dir
echo $?

第二种:

#! /bin/bash

##down a file check the dir and file exist or not.
##written by zhdya_20171003

if [ -z $1 ]
then 
	echo "pls input a download link and dir"
	exit
elif [ $# -gt 2 ]
then
	echo "pls just input two options"
	exit
fi

if [ -z $2 ]
then
	echo "pls input a dir."
	exit
fi

if [ -d $2/ ]
then
	echo "you choose the dir is $2"
	cd $2
	wget $1
else
	echo "we didn't found the dir"
	read -p "do you need create that one?(if yes, pls type "y" if not, pls type "n")" c
	if [ $c == "y" ]
	then
		cd 
		mkdir -p $2
		cd $2
		wget $1
	echo "already created the folder you needs"
	elif [ $c == "n" ]
	then
		echo "the file already download the current folder,pls check it."
		exit
	else
		echo "you typed was wrong, pls check it!"
	fi
fi

if [ -e bpic3534.rar ]
then
	echo "the file already download, pls check it"
else
	echo 52
	exit
fi
  • 用 for 循环列出当前目录的一级子目录,不要用 find 命令。
#! /bin/bash

##input a dir which check the subdir and files
##written by zhdya_20171003

p=`pwd`

for i in $p/*
do
	if [ -d $i ]
	then
		echo "$i is a dir!!!"
	fi
done
  • 根据自己突如其来的想法,看脚本批量增加用户或删除用户,功能是蛮强大的。
#! /bin/bash

##add user with password and del user
##written by zhdya_20170921

m=`mkpasswd -l 10 -c 2 -C 2 -d 2`

echo "=================================================================================================================="
echo "pls type just one user's number, like "2", it will be creating just user_2"
echo "=================================================================================================================="
echo "pls type the user's number when you start, like "2 6",that will be creating user_2 user_3 ... user_6."
echo "=================================================================================================================="
echo "pls use "d" delete the user with user's home folder, such as: "d 2 5", it will delete user_2 user_3 ... user_5"
echo "=================================================================================================================="

##check if input sth or not
if [ -z $1 ]
then
	echo "pls inputer a number when you run this shell script."
	exit
fi

pc=`echo "$1" | sed 's/[0-9d]//g' |wc -m`
if [ $pc -ne "1" ]
then
	echo "pls just input a number!!!"
fi

##check if just input a one PARM

if [ $# -eq "1" ]
then
	if cat /etc/passwd | awk -F ':' '{print $1}' |grep "user_$1"
	then
		echo "the user already exist."
	else
		useradd user_$1
		echo "$m" | passwd --stdin user_$1 >/dev/null 2>&1
		echo "username: user_$1 password: $m" >> /tmp/users.txt
		echo "pls check the user's list file."
	fi 
fi
##delete a user
if [ $# -eq "2" ] && [ $1 == "d" ]
then
	userdel -r user_$2
	echo "the user_$2 already deleted, pls check it."
        echo "username: user_$a" >> /tmp/userdel.txt
	exit
fi
##check if input two PARM
if [ $# -eq "2" ]
then
        for i in `seq $1 $2`
        do
                m1=`mkpasswd -l 10 -c 2 -C 2 -d 2`
                if cat /etc/passwd | awk -F ':' '{print $1}' | grep "user_$i"
                then
                        echo "the user "user_$i" already exist"
                else
                        useradd user_$i
                        echo "$m1" | passwd --stdin user_$i > /dev/null 2>&1
                        echo "username: user_$i password: $m1" >> /tmp/users.txt
                        echo "pls check the user's list file."
                fi
        done
fi
if [ $# -eq "3" ]
then
	if [ $1 == "d" ]
	then
		for a in `seq $2 $3`
		do
			userdel -r user_$a
                        echo "username: user_$a" >> /tmp/userdel.txt
			echo "the user_$a already delete, pls check it."
		done
	fi
	else
		echo "pls input the correct PARM"
fi
  • 写一个实时监控网络流量的脚本。

提示: /proc/net/dev 文件显示的数字就是网络总流量,单位是B(字节)。 可以用当前时刻的数字减去上一秒的数字来求出每秒的网络流量。单位根据实际情况显示为KB或者MB。 而实时显示,只能使用while 做死循环,而且显示结果要一直在屏幕的第一行,可以使用clear实现。

#! /bin/bash

##monitor the network flow per seconds, and use suitable value.
##wrriten by zhdya_20171008

while :
do

rece=`cat /proc/net/dev | tail -1 | awk '{print $2}'`
trans=`cat /proc/net/dev | tail -1 | awk '{print $10}'`

if [ $rece -gt "1024" ] && [ $trans -gt "1024" ]
then
	krece=$(expr $rece / 1024)
	ktans=$(expr $trans / 1024)
	sleep 1
	rece2=`cat /proc/net/dev | tail -1 | awk '{print $2}'`
	trans2=`cat /proc/net/dev | tail -1 | awk '{print $10}'`
	krece2=$(expr $rece2 / 1024)
        ktans2=$(expr $trans2 / 1024)
	frece=$[$krece2-$krece]
	ftans=$[$ktans2-$ktans]
	clear
	echo "the network traffic Rece $frece KB/s"
	echo "the network traffic Trans $ftans KB/s"
	
elif [ $rece -gt "1048576" ] && [ $trans -gt "1048576" ]
then
	krece=$(expr $rece / 1048576)
        ktans=$(expr $trans / 1048576)
        sleep 1
        rece2=`cat /proc/net/dev | tail -1 | awk '{print $2}'`
        trans2=`cat /proc/net/dev | tail -1 | awk '{print $10}'`
        krece2=$(expr $rece2 / 1048576)
        ktans2=$(expr $trans2 / 1048576)
        frece=$[$krece2-$krece]
        ftans=$[$ktans2-$ktans]
        clear
        echo "the network traffic Rece $frece MB/s"
        echo "the network traffic Trans $ftans MB/s"

elif [ $rece -gt "1073741824" ] && [ $trans -gt "1073741824" ]
then
	krece=$(expr $rece / 103741824)
        ktans=$(expr $trans / 103741824)
        sleep 1
        rece2=`cat /proc/net/dev | tail -1 | awk '{print $2}'`
        trans2=`cat /proc/net/dev | tail -1 | awk '{print $10}'`
        krece2=$(expr $rece2 / 103741824)
        ktans2=$(expr $trans2 / 103741824)
        frece=$[$krece2-$krece]
        ftans=$[$ktans2-$ktans]
        clear
        echo "the network traffic Rece $frece GB/s"
        echo "the network traffic Trans $ftans GB/s"
fi
done
  • 写一个shell脚本,把192.168.1.0/24网段在线的ip列出来。
#! /bin/bash

##check all of ip if online or not.
##wrriten by zhdya_20171008

for i in `seq 1 254`
do
online=`ping -c 1 -w 1 192.168.1.$i | awk -F '=' 'NR==2{print $3}' | awk '{print $2}'`
if [ -z $online ]
then
	continue
elif [ $online == "time" ]
then
	echo "the IP 192.168.1.$i are online now."
fi
done
  • rm命令删除的文件放入垃圾箱
#! /bin/bash

##if use "rm" command, the file or dir will be move to another folder.
##written by zhdya_20171010

dir=/home/root/.trash

for i in $*
do
	date=`date "+%y%m%d%H%M%S"`
	mv $i $dir/$date$i
done

-----------------------------------------
修改~/.bashrc, 增加一行

[[email protected] ~]# cat ~/.bashrc
# .bashrc

# User specific aliases and functions

#alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias rm='sh /usr/local/sbin/rm.sh'

用我们自建的rm.sh替代rm命令

source ~/.bashrc 使替换立即生效

设置crontab,定期清空垃圾箱,如:(每月的月底28号将清空垃圾箱内的文件)

0 0 28 * * rm -rf /home/root/.trash/*

或者使用脚本 手动清理:

find /home/root/.trash/ -ctime 7 -type f -name "*" -exec /bin/rm {} ;

测试:(删除了一个文件)

[[email protected] ~]# rm asdd.sh 
[[email protected] ~]# ls /home/root/.trash/
201710100933asdd.sh

升级版:假设有一个大的分区/data/,每次删除文件或者目录之前,都要先在/data/下面创建一个隐藏目录,以日期/时间命名,比如/data/.2017101418 然后把所有删除的文件同步到该目录下面。在删除之前先计算要删除的文件或者目录大小,然后对比系统的磁盘空间,如果够则按照上面的规则创建隐藏目录,并备份,如果没有足够空间,要提醒用户没有足够的空间备份并提示是否放弃备份,如果用户选择y,则直接删除文件或者目录,如果选择n,则提示未删除,然后退出脚本。

#! /bin/bash

##before delete file or dir, first we should total both of file or dir's size then move to another place
##written by zhdya_20171014

deldt=`date +%Y%m%d%H`
bakdir="/data"
trushsize=`df | egrep "/dev/sda3" | awk '{print $4}'`

if [ ! -d $bakdir/.$deldt ]
then
	mkdir -p $bakdir/.$deldt
else 
	for i in $*
	do
		filesize=`du -sh $i | awk '{print $1}'| sed 's/[a-zA-Z]//g'`
		if [ $filesize -gt $trushsize ]
		then
			echo "The File or Dir's size already bigger than TRUSH. two option you can choice!!"
			echo "if you type "y" it will delete the file or dir's directly!!!"
			echo "if you type "n" it will end!!"
			read -p "what's your opinion? [y/n]:" n
			case $n in
			y)
				rm -rf $i
				echo "already delete file and dir's directly"
				exit
			;;
			n)
				echo "the file or dir's not delete."
				exit
			;;
			*)
				echo "you input was wrong!!"
				exit
			;;
			esac
		else
			mv $i $bakdir/.$deldt
			echo "already deleted!!"
		fi
	done
fi
  • 用shell写一段代码,把/msxf目录下所有以ms开头的文件夹取出,保存到dirlist.txt文件中,然后遍历文件中的文件夹路径,在每个文件夹目录中创建一个test.txt文件。
#! /bin/bash

##find all of folders which beging with ms
##written by zhdya_20171011

find /tmp/msxf -name "ms*" > /tmp/dirlist.txt

for i in `cat /tmp/dirlist.txt`
do
	cd $i
	touch test.txt
done
  • 用shell编程,判断一个文件是否为字符设备文件,如果是将其拷贝到/dev 目录下。
#! /bin/bash

##check a file which is c file or not
##written by zhdya_20171011

read -p "pls input a location,like "/tmp/":" l

cd $l
for i in `ls`
do
	if [ -c $i ]
	then
		cp $i /dev/
	fi
done
  • 自动生成shell脚本头注释信息
#! /bin/bash
##when you add a new shell script you can add this one in front of your filename, that's can help you add the discrible
##writen by JustinZh 2017-05-18

if [ ! "$1" ]; then
        ehco "Pls Input A New Filename!"
        exit 1
fi
if [ -f "$1" ]; then
        vim "$1"
        exit 2
fi
touch "$1"
echo "#! /bin/bash" >> "$1"
echo "#Discription:" >> "$1"
echo "#Author:$USER" >> "$1"
echo "#Version:1.0" >> "$1"
echo "#CreateTime:`date +%F' 'H%:M%:S% `" >> "$1"
vim "$1"


当然 创建完成之后,你在哪个目录下运行此命令,它就会在此目录创建下创建你的shell。
但是必须每次都要输入全称,例如此shell 我定义为autoshell.sh  如果想要创建一个test.sh 
如下:#autoshell.sh test.sh 然后我想到了把autoshell.sh直接搞个软链接在/bin/auto目录下,
然后chmod +x autoshell.sh  下次我再次创建一个shell的时候就只需要#auto test2.sh即可!!!
  • 设计一个shell程序,添加一个新组为msxf,然后添加属于这个组的50个用户,用户名的形式为msfinanceXX 其中xx 从 01 到 50。
#! /bin/bash

##add a new user group, and let all of new user join in.
##written by zhdya_20171011

read -p "pls input a user's group name, like msxf:" g
read -p "pls input a number which from XX and end of XX, like 01 05, it will create msfinance01 ... msfinance05:" n m

if [ -z $g ] && [ -z $n ] && [ -z $m ]
then
	echo "pls it must input the PARA."
	exit
fi

groupadd $g

echo "already created the usergroup $g"

for i in `seq $n $m`
do
	useradd msfinance$i -g $g
done

echo "already created the users you needs."
  • 某文件内容如下:
jack  huaxue   90
tom  huaxue	70
jack  shuxue	99
tom  shuxue	80

要求算出jack和tom的2科的平均分。

#! /bin/bash

##get Jack and Tom's average score!
##written by zhdya_20171015

tom=`cat /usr/local/sbin/kb.txt | grep tom | awk 'BEGIN{sum=0}{sum+=$3}END{print sum}'`
jack=`cat /usr/local/sbin/kb.txt | grep jack | awk 'BEGIN{sum=0}{sum+=$3}END{print sum}'`

toma=$[$tom/2]
jacka=$[$jack/2]
echo "Tom's average score is $toma , Jack's average score is $jacka ."
  • 写一个脚本,判断一个指定的脚本是否是语法错误;如果有错误,则提醒用户键入Q或者q无视错误并退出其它任何键可以通过vim打开这个指定的脚本。
#! /bin/bash

##judge a shell running well or not.
##written by zhdya_20171015

read -p "pls input the shell's name, like "test.sh" :" n

if [ -z $n ]
then
	echo "pls input a shell's name!"
	break
else
	sh -n $n >/dev/null 2>&1
	if [ $? -ne "0" ]
	then
		read -p "this shell has a problem, if you wanna exit pls use [q/Q], if you wanna edit pls input anywords :" m
		case $m in
		q|Q)
			exit
		;;
		*)
			vim $n
		;;
		esac
	else
		echo "this shell file without any error!!"
	fi
fi
  • 监控MySQL主从同步是否异常,如果异常,则发送短信或者邮件给管理员。提示:如果没主从同步环境,可以用下面文本放到文件里读取来模拟:
    • 阶段1:开发一个守护进程脚本每30秒实现检测一次。
    • 阶段2:如果同步出现如下错误号(1158,1159,1008,1007,1062),则跳过错误。
    • 阶段3:请使用数组技术实现上述脚本(获取主从判断及错误号部分)
#!/bin/sh

USER=root
PASSWORD=123456
PORT=3306
error=(1158 1159 1008 1007 1062)
MYSQLCMD="mysql -u$USER -p$PASSWORD -S /data/$PORT/mysql.sock"
 
is_run(){
  [ `lsof -i:$PORT|wc -l` -lt 2 ]&&{
    echo "mysql server is stopped"
    exit 1
  }
}
 
status_array(){
 status=($($MYSQLCMD -e "show slave statusG"|egrep "_Running|Last_Errno|Behind_Master"|awk '{print $NF}'))
}
 
status_error(){
for((i=0;i<${#error[*]};i++))
do
  if [ "$1" == "${error[$i]}" ]
    then
      $MYSQLCMD -e "stop slave;set global sql_slave_skip_counter=1;start slave;"
  else 
      echo "MySQL slave is failed, errorno is $1"
  fi
done
}
 
judge_slave(){
  status_array
  if [ "${status[0]}" == "Yes" -a "${status[1]}" == "Yes" -a "${status[3]}" = "0" ]
  then
    echo "MySQL slave is ok"
  else
    status_error ${status[2]}
  fi
}
 
main(){
while true
do
  is_run
  judge_slave
  sleep 60
done
}
main