shell里面的 条件判断式
1、单层,简单的条件判断
if [ 条件判断 ];then
条件成立,进行的指令
fi <==将if反过来写,就成了 fi 结束if之意
或者将多个条件放在一个中括号中
[ "$yn" == "Y" -o "$yn" == "y" ] # -o就是or 或的意思
用&&(and) 或者 ||(or) 隔开
[ $yn" == "Y" ] || [ "$yn" == "y" ]
2、多层、复杂的条件判别
if [条件判断式];then
条件成立
else
条件不成立
fi
更复杂的 多个条件判断 (if … elif … elif … else) 分多种不同情况执行
if [ 条件判断式一 ]; then
当条件判断式一成立时,可以独行的指令工作内容;
elif [ 条件判断式二 ]; then
当条件判断式二成立时,可以独行的指令工作内容;
else
当条件判断式一不二均丌成立时,可以独行的指令工作内容;
fi
案例: 在用户下达指令的时候就把参数带进去!现在让用户输入hello 这个关键字
#!/bin/bash
#Program
# check '$1' is hello
#History
#2019/05/04 zyr first
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
if [ "$1" == "hello" ];then
echo "this 1st parameter is '$1'"
elif [ "$#" == 0 ];then
echo "please input parameter"
exit 0
else
echo "the only parameter is 'hello',ex>{$0 hello} "
fi
结果:
来开始做一些有趣的东西吧
我可以利用『 netstat -tuln 』来取得目前主机有启动的服务, 而且取得的信 息有点像这样
由图中可以知道,一些常见的服务名称都有常用的端口号,比如www服务是80号端口。且在文件中的表现形式总是 :80 所以我们可以用grep来查找是否开启相应服务
1、可以查看服务器中那些服务启动了
#!/bin/bash
#Program
# use netstat and grep to detect www,ssh,ftp,and mail service
#History
#2019/05/04
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "now i will detect your linux server service"
echo -e "the www,ftp,ssh,and mail will be detect!\n"
testing=$(netstat -tuln | grep ":80")
if [ "$testing" != "" ];then
echo "www is running in your system"
fi
testing=$(netstat -tuln | grep ":22")
if [ "$testing" != "" ];then
echo "ssh is running"
fi
testing=$(netstat -tuln | grep ":21")
if [ "$testing" != "" ];then
echo "ftp is running"
fi
testing=$(netstat -tuln | grep ":25")
if [ "$testing" != "" ];then
echo "mail is running"
fi
结果:
2、计算日期,计算退伍时间
利用date来计算两个日期之间的差(把日期转化成秒数来做减法)
date --d "2019-05-04" +%s //获取相对日期 +%s 用秒数来表示
同时date 的用法 date +%Y%m%d 获取年月日
#!/bin/bash
#Program
# you input your demobilization date .i calculate how many days
#History
#2019/05/04
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "this program will try to calculate:"
read -p "please input your demobilization date(YYYYMMDD) ex>20090410:" date2
#test if the input is right
date_d=$(echo $date2 | grep '[0-9]\{8\}') #检查输入日期是否符合规范
if [ "$date_d" == "" ];then
echo "you input the wrong date"
exit 1
fi
declare -i date_demo=`date --date="${date2}" +%s` #把输入日期转化为秒数 记得用`` 引起来
declare -i date_new=`date +%s` #把现在的日期化成秒数
declare -i date_total_s=$(($date_demo - $date_new))
declare -i date_day=$(($date_total_s/60/60/24)) #化成天数
if [ "$date_total_s" -lt "0" ];then #如果秒数小于零 说明已经退伍
echo "you have been demobilization before:"$((-1*$date_day))
else
declare -i date_h=$(($(($date_total_s-$date_day*60*60*24))/60/60)) #小时
echo "you will demo after $(($date_day +1)) day or $date_h hours"
fi
3、第二个分支
case... esac..
case $发量名称 in <==关键词为 case ,还有发数前有钱字号
"第一个发量内容") <==每个发量内容建议用双引号括起来,关键词则为小括号 )程序段
;; <==每个类删结尾使用两个连续的分号来处理!
"第二个发量内容")
程序段
;;
*) <==最后一个发量内容都会用 * 来代表所有其他值不包含第一个发量内容不第二个发量内容的其他程序执行段
exit 1
;;
esac <==最终的 case 结尾!『反过来写』思考一下!
这里 [case $变量 in] 这个语法中,取得变量的方式大概有两种:
1、直接下达式:例如上面提到的,利用『 script.sh variable 』 的方式来直接给予 $1 这个变量的内容,这也是在 /etc/init.d 目录下大多数程序的设计方式。
2、交互式:透过 read 这个指令来让用户输入变量的内容。
实例:
#!/bin/bash
# Program:
# Use function to repeat information.
# History:
# 2005/08/29 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
function printit(){
echo -n "Your choice is " # 加上 -n 可以丌断行继续在同一行显示
}
echo "This program will print your selection !"
case $1 in
"one")
printit; echo $1 | tr 'a-z' 'A-Z' # 将参数做大小写转换!
;;
"two")
printit; echo $1 | tr 'a-z' 'A-Z'
;;
"three")
printit; echo $1 | tr 'a-z' 'A-Z'
;;
*)
echo "Usage $0 {one|two|three}"
;;
esac
结果:
以下是鸟哥的一些建议: 建议读者可以使用类似 vim 的编辑器到 /etc/init.d/ 目录下去查阅一下你所看到的档案, 并且自行追踪一下每个档案的执行情况,相信会更有心得
4、loop循环
while do done ,until do done(不定循环)
//满足条件时 开始循环
while [ condition ] <==中括号内的状态就是判断式
do <==do 是循环的开始!
程序段落
done <==done 是循环的结束
//当条件成立是,终止循环
until [ condition ]
do
程序段落
done
实例:
计算1到100的累加和
#!/bin/bash
#Program
#you input a num and will output from 1 to 100 sum
#History
#2019/05/04 zyr
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "please input a num:"
read -p "number:" number
s=0
i=0
while [ "$i" != "$number" ] #而这里判定的时候一定每一个元素都要空格
do
i=$(($i+1)) #注意这里变量之前一定不要空格
s=$(($s + $i))
done
echo "the result of '1+2+3..+$number' is ==> $s"
结果:
for … do … done (固定循环)
for var in con1 con2 con3 ...
do
程序段
done
第一次循环时, $var 的内容为 con1 ;
第二次循环时, $var 的内容为 con2 ;
第三次循环时, $var 的内容为 con3 ;
…
实例:
#!/bin/bash
# Program:
# Using for .... loop to print 3 animals
# History:
# 2005/08/29 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
for animal in dog cat elephant
do
echo "There are ${animal}s.... "
done
结果:
因为系统上面的各种账号都存储在 /etc/passwd这个文件中的第一个字段,能不能通过线管命令的 cut 捕捉出单纯的账号之后,用id 和finger这个两个命令去检查使用者的标识符和特殊参数呢?
实例:
#!/bin/bash
#Program
# Use id ,finger command to check system account information
#History
#2019/05/05
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bi
export PATH
users=$(cut -d ':' -f1 /etc/passwd) #get username
for username in $users
do
id $username
finger $username
done
结果:每一个账号都检索出来了
如果我现在需要一连串的数字来进行循环呢?举例来说,我想要利用 ping 这个 可以判断网络状态的指令, 来进行网络状态的实际侦测时,我想要侦测的网域是本机所在的 192.168.1.1~192.168.1.10,由于有 10 台主机, 总不会要我在 for 后面输入 1 到 100 吧?此时你 可以这样做喔!
上面这一串指令执行之后就可以显示出 192.168.1.1~192.168.1.100 共 100 部主机目前是否能不你的 机器连通!
#!/bin/bash
#Program
# use ping command to check the network'S PC state.
#History
#2019/05/05 zyr
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
network="192.168.141"
for sitenu in $(seq 1 10)
do
ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1
if [ "$result" == 0 ];then
echo "Server ${network}.${sitenu} is UP."
else
echo "Server ${network}.${sitenu} is DOWN"
fi
done
解释:实这个范例的重点在 $(seq …) 那个位置!那个 seq 是连续 (sequence) 的缩写之意!代表后面接的两个数值是一直连续的! 如此一来,就能够轻松的将连续数字带入程序中啰!
结果:
处理一些文档的特性
让我们来玩判断式加上循环的功能!我想要让用户输入某个目录文件名, 然后我找出某目录内 的文件名的权限,该如何是好
#!/bin/bash
#Program
# user input dir name,I find the permission of files
#History
#2019/05/05
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "please input a directory:" dir
if [ "$dir" == "" -o ! -d "$dir" ];then
echo "the $dir is not exist in your system"
exit 1
fi
filelist=$(ls $dir)
for filename in $filelist
do
perm=""
test -r "$dir/$filename" && perm="$perm readable"
test -w "$dir/$filename" && perm="$perm writable"
test -x "$dir/$filename" && perm="$perm executable"
echo "the file $dir/$filename's permission is $perm"
done
注意:这里输入的文件名或者是文件夹名必须是绝对路径
5、for … do … done 的数值处理的另一种写法
for((初始值;限制值;执行步阶))
do
程序段
done
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
read -p "Please input a number, I will count for 1+2+...+your_input: " nus=0
for (( i=1; i<=$nu; i=i+1 ))
do
s=$(($s+$i))
done
echo "The result of '1+2+3+...+$nu' is ==>$s"
shell script的追踪与debug
script在执行之前,最怕的就是出现语法错误的问题了! 那么我们如何debug呢? 有没有办法不需要透过直接执行该scripts就可以判断是否有问题呢? 当然有
我们就直接以bash 的相关参数来进行判断吧!
sh [-nvx] scripts.sh
选项与参数:
-n :不要执行script ,仅查询语法问题;如果没有语法错误就不输出
-v :在执行script 前,先将script的内容输出到屏幕上;
-x : 将已经执行使用到的script内容显示到屏幕上,很重要
测试一: sh -n sh16.sh
#若没有语法错误,则不会显示任何信息
测试二: sh -x sh15.sh
在知道输出的情况写,查找错误变得比较简单了呢
举个例子:
sh -nvx sh16.sh
三个参数一起带的时候,因为 -n 是不执行shell ,直接检查语法错误,所以相当于 -x 的参数被屏蔽了
以下是鸟哥的一些建议:
1、网络上的一下相当有用的script,拿过来改造成适合自己的样子,学习起来是最快的呢
2、我们linux系统本来就有很多的服务器启动的脚本,如果你想知道每一个script所代表的功能是什么,直接vim进入该script进行查阅,立刻就知道该script的目的了
举例来说,我们之前一直提到的 /etc/init.d/syslog 这个script 是干嘛用的? 利用 vi 去查阅最前面的几行字,他 出现如下信息:
# description: Syslog is the facility by which many daemons use to log \
# messages to various system log files. It is a good idea to always \
# run syslog.
### BEGIN INIT INFO
# Provides: $syslog
### END INIT INFO
这个脚本在启动一个名为 syslog 的常驻程序 (daemon),这个常驻程序可以帮助很多系统 服务记载她们的登录文件 (log file), 我们的 Linux 建议你一直启动 syslog 是个好主意!
参考鸟哥的linux私房菜:http://cn.linux.vbird.org/linux_basic/0340bashshell-scripts_1.php#script_1st
另外两篇博客 :
一起来写Shell Script 02 https://blog.csdn.net/aoxixi/article/details/89855908
一起来写Shell Script 01 https://blog.csdn.net/aoxixi/article/details/89843929