什么是shell?
如上图所示:最底下是计算机硬件,然后硬件被系统核心包住,在系统核心外层的就是shell,然后shell外层的就是我们最容易理解的应用程序,我们平时接触最多的就是应用程序了。
看图可知:shell其实是一个命令解释器,它的作用是解释用户输入的命令和程序,命令和程序可以理解成我们途中的应用程序,我们linux中的那些命令其实也都是一个个的小程序,只不过完成的是系统的应用功能。我们在系统的终端输入一条命令,可以马上看到一条或者几条系统回复我们的信息,其实就是shell在帮我们回复,所以shell可以称之为命令解释器。这种从键盘一输入命令就可以立马得到相应的回复信息,叫做交互方式,相当于我们在和电脑进行相互交流,shell存在于系统的最外层,所以算作操作系统的外壳,他之外的应用程序就不能算作操作系统了。我们从输入系统的账户密码开始,到登录系统以后的所有操作都是shell在帮我们解释执行的。
了解了shell之后,我们再来了解下shell脚本,如果我们的命令或者应用程序不在命令行直接执行,而是通过一个程序文件来执行时,这个程序就称之为shell脚本。shell脚本里面通常内置了多条命令,有的还包含控制语句,比如if和else的条件控制语句,for和select的循环控制语句等。这些内置在shell脚本中的命令通常是一次性执行完成,不会不停的返回信息给用户,这种通过文件执行脚本的方式称之为非交互方式。shell脚本类似于windows下的批处理,但是它比批处理要强大一些。现在的win10系统下有一个功能叫做power shell,它可以和linux下的shell功能相媲美。
我们可以在文本中输入一系列的命令、控制语句和变量,这一切有机的结合起来就形成了功能强大的shell脚本。
在linux中我们一般通过vim来创建shell脚本(后缀名为.sh),创建完成以后保存并退出,当我们运行shell脚本的时候需要通过:chmod +x ./shell.sh 命令使得shell脚本具有执行权限,否则shell.sh只是一个文件;在赋予shell脚本执行权限以后通过:./shell.sh 命令即可执行shell脚本。另外,在shell脚本的第一行需要指定解释器的信息如下所示:#!/bin/bash
常用的shell脚本
打印形状:
#!/bin/bash
# 等腰三角形
read -p "Please input the length: " n
for i in `seq 1 $n`
do
for ((j=$n;j>i;j--))
do
echo -n " "
done
for m in `seq 1 $i`
do
echo -n "* "
done
echo
done
# 倒直角三角形
read -p "Please input the length: " len
for i in `seq 1 $len`
do
for j in `seq $i $len`
do
echo -n "* "
done
echo
done
# 菱形
read -p "Please input the length: " n
for i in `seq 1 $n`
do
for ((j=$n;j>i;j--))
do
echo -n " "
done
for m in `seq 1 $i`
do
echo -n "* "
done
echo
done
for i in `seq 1 $n`
do
for((j=1;j<=$i;j++))
do
echo -n " "
done
for((k=$i;k<=$len-1;k++))
do
echo -n "* "
done
echo
done
截取字符串
http://www.aaa.com/root/123.htm
请根据以下要求截取出字符串中的字符:
1.取出www.aaa.com/root/123.htm
2.取出123.htm
3.取出http://www.aaa.com/root
4.取出http:
5.取出http://
6.取出www.aaa.com/root/123.htm
7.取出123
8.取出123.htm
#!/bin/bash
var="http://www.aaa.com/root/123.htm"
#1.
echo $var |awk -F '//' '{print $2}'
#2.
echo $var |awk -F '/' '{print $5}'
#3.
echo $var |grep -o 'http.*root'
#4.
echo $var |awk -F '/' '{print $1}'
#5.
echo $var |grep -o 'http://'
#6.
echo $var |grep -o 'www.*htm'
#7.
echo $var |grep -o '123'
#8.
echo $var |grep -o '123.htm'
tomcat启动脚本
tomcat没有自带的能够给service开机启动的脚本,该脚本是一个简单的启动的脚本
#!/bin/bash
# chkconfig:2345 64 36
# description: Tomcat start/stop/restart script.
### BEGIN INIT INFO
# Provides: tomcat
# Required-Start:
# Should-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop Tomcat
# Description: Tomcat Service start&restart&stop script
### END INIT INFO
##Written by zero.##
JAVA_HOME=/usr/local/jdk1.8/
JAVA_BIN=/usr/local/jdk1.8/bin
JRE_HOME=/usr/local/jdk1.8/jre
PATH=$PATH:/usr/local/jdk1.8/bin:/usr/local/jdk1.8/jre/bin
CLASSPATH=/usr/local/jdk1.8/jre/lib:/usr/local/jdk1.8/lib:/usr/local/jdk1.8/jre/lib/charsets.jar
TOMCAT_BIN=/usr/local/tomcat/bin
RETVAL=0
prog="Tomcat"
start()
{
echo "Starting $prog......"
/bin/bash $TOMCAT_BIN/startup.sh
RETVAL=$?
return $RETVAL
}
stop()
{
echo "Stopping $prog......"
/bin/bash $TOMCAT_BIN/shutdown.sh
RETVAL=$?
return $RETVAL
}
restart(){
echo "Restarting $prog......"
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
*)
echo $"Usage: $0 {start|stop|restart}"
RETVAL=1
esac
exit $RETVAL
自定义rm命令
linux系统的rm命令太危险,一不小心就会删掉系统文件。写一个shell脚本来替换系统的rm命令,要求删除一个文件或者目录的时候,都要做一个备份,然后再删除。下面分两种情况:
1.简单的实现:
假设有一个大的分区/data/,每次删除文件或目录之前,都要在/data/下面创建一个隐藏目录,以日期/时间命名,比如/data/.201903271012/,然后把所有删除的文件同步到该目录下面,可以使用rsync -R把文件路径一同同步,示例:
#!/bin/bash
fileName=$1
now=`date +%Y%m%d%H%M`
read -p "Are you sure delete the file or directory $1? yes|no: " input
if [ $input == "yes" ] || [ $input == "y" ]
then
mkdir /data/.$now
rsync -aR $1/ /data/.$now/$1/
/bin/rm -rf $1
elif [ $input == "no" ] || [ $input == "n" ]
then
exit 0
else
echo "Only input yes or no"
exit
fi
2.复杂的实现;
不知道那个分区有剩余空间,再删除之前先计算删除的文件或者目录大小,然后对比计算机系统的磁盘空间,如果能够按照上面的规则创建隐藏目录,并备份,如果没有足够空间,要提醒用户没有足够的空间备份并提示是否放弃备份,如果用户输入yes,则直接删除文件或者目录,如果输入no,则提示未删除,然后退出脚本,示例:
#!/bin/bash
fileName=$1
now=`date +%Y%m%d%H%M`
f_size=`du -sk $1 |awk '{print $1}'`
disk_size=`LANG=en; df -k |grep -vi filesystem |awk '{print $4}' |sort -n |tail -n1`
big_filesystem=`LANG=en; df -k |grep -vi filesystem |sort -n -k4 |tail -n1 |awk '{print $NF}'`
if [ $f_size -lt $disk_size ]
then
read -p "Are you sure delete the file or directory: $1 ? yes|no: " input
if [ $input == "yes" ] || [ $input == "y" ]
then
mkdir -p $big_filesystem/.$now && rsync -aR $1 $big_filesystem/.$now/ && /bin/rm -rf $1
elif [ $input == "no" ] || [ $input == "n" ]
then
exit 0
else
echo "Only input 'yes' or 'no'."
fi
else
echo "The disk size is not enough to backup the file: $1."
read -p "Do you want to delete "$1"? yes|no: " input
if [ $input == "yes" ] || [ $input == "y" ]
then
echo "It will delete "$1" after 5 seconds whitout backup."
for i in `seq 1 5`; do echo -ne "."; sleep 1; done
echo
/bin/rm -rf $1
elif [ $input == "no" ] || [ $input == "n" ]
then
echo "It will not delete $1."
exit 0
else
echo "Only input 'yes' or 'no'."
fi
fi
数字求和
编写shell脚本,要求输入一个数字,然后计算出从1到输入数字的和,要求,如果输入的数字小于1 ,则重新输入,直到输入正确的数字为止,示例:
#!/bin/bash
while :
do
read -p "Please enter a positive integer: " n
if [ $n -lt 1 ]
then
echo "It can't be less than 1"
else
break
fi
done
num=1
for i in `seq 2 $n`
do
num=$[$num+$i]
done
echo $num
拷贝目录
编写shell脚本,把/root/目录下的所有目录(只需一级)拷贝到/temp/目录下:
#!/bin/bash
cd /root/
list=(`ls`)
for i in ${list[@]}
do
if [ -d $i ]
then
cp -r $i /tmp/
fi
done
批量建立用户
编写shell脚本,批量建立用户user_00,user_01,....user_100并且所有用户同属于users组;
#!/bin/bash
group=`cat /etc/group |grep -o users`
if [ $group == "users" ]
then
for i in `seq 0 100`
do
if [ $i -lt 10 ]
then
useradd -g users user_0$i
else
useradd -g users user_$i
fi
done
else
echo "users group not found!"
exit 1
fi
删除以上脚本批量田间的用户:
#!/bin/bash
for i in `seq 0 100`
do
if [ $i -lt 10 ]
then
userdel -r user_0$i
else
userdel -r user_$i
fi
done
每日生成一个文件
要求:请按照这样的日期格式(xxxx-xx-xx)每日生成一个文件,例如今天生成的文件为2019-01-31.log,并且把磁盘的使用情况写到这个文件中(不用考虑corn,仅仅写脚本即可)
#!/bin/bash
fileName=`date +%F`
c=`df -h`
echo "$c" > /root/$fileName.log
统计ip
有一个日志文件,日志片段:如下:
112.111.12.248 – [25/Sep/2013:16:08:31 +0800]formula-x.haotui.com “/seccode.php?update=0.5593110133088248″ 200″http://formula-x.haotui.com/registerbbs.php” “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)”
61.147.76.51 – [25/Sep/2013:16:08:31 +0800]xyzdiy.5d6d.com “/attachment.php?aid=4554&k=9ce51e2c376bc861603c7689d97c04a1&t=1334564048&fid=9&sid=zgohwYoLZq2qPW233ZIRsJiUeu22XqE8f49jY9mouRSoE71″ 301″http://xyzdiy.×××thread-1435-1-23.html” “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)”
要求:统计出每个IP的访问量有多少?
awk '{print $1}' 1.log |sort -n |uniq -c |sort -n
解释:sort -n会按照数值而不是ASCII码来排序awk截取出来的ip。然后uniq命令用于报告或者忽略文件中的重复行,
加上-c选项后会在每列旁边显示该行重复出现的次数,在这一步就完成了统计。不过最后还得让
sort -n排序一下uniq -c统计出来的结果
统计内存使用
写一个脚本计算linux系统所有进程占用内存大小的和。脚本如下;
#!/bin/bash
count=0
# 这个循环会遍历出每个进程占用的内存大小
for i in `ps aux |awk