Shell Script 学习笔记

Shell Script 学习笔记

1、什么是Shell Script

shell是命令行界面下让我们与操作系统沟通的一个工具接口,script是就是‘"脚本"的意思。

shell script是利用shell的功能所写的一个"程序",这个"程序"是使用纯文本文件,将一些shell的语法与命令(含外部命令)写在文件中,搭配正则表达式、管道命令与数据流重定向等功能,以达到我们想要的处理目的。

shell script可以被简单的看成批处理文件,也可以当做一种程序语言,由于是利用shell的相关工具命令,所以不需要编译即可执行。

1.1、为什么学shell script

①自动化管理
②追踪与管理系统的重要工作
③简单的入侵检测功能
④连续命令整合处理
⑤简易的数据处理
⑥跨平台支持与学习历程较短

1.2、编写并执行第一个shell script

[root@localhost ~]# mkdir scripts 
[root@localhost ~]# cd scripts 
[root@localhost scripts]# vi sh01.sh
#!/bin/bash 
# It's my first script 
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin 
export PATH 
echo -e "hello world \a \n" 
exit 0 
~

①首先,创建~/scripts目录,编写sh01.sh

②脚本的第一行 #!/bin/bash 声明了这个script使用的shell名称

我们使用的是bash,所以以"#!/bin/bash"来声明这个文件的内容使用的是bash的语法,当脚本被执行时,他能够自动加载bash的相关环境配置文件(一般来说就是non-login shell 的~/.bashrc),并用bash来执行这个脚本

③第二行的#是对script内容的注释

④第三行及第四行是主要环境变量的声明,PATH与LANG一般是最重要的

⑤第五行为程序的主要内容

⑥第六行是返回的执行结果,执行脚本结束后可以输入scho $?可以得到0的值

[root@localhost scripts]# sh sh01.sh
hello world  
①直接命令执行:shell.sh文件必须要具备可读与可执行(rx)的权限

[root@localhost scripts]# ls -l
total 4
-rw-r--r--. 1 root root 166 Nov  4 18:16 sh01.sh
[root@localhost scripts]# chmod 755 sh01.sh
[root@localhost scripts]# ls -l
total 4
-rwxr-xr-x. 1 root root 166 Nov  4 18:16 sh01.sh

绝对路径:使用 /root/scripts/sh01.sh 来执行

[root@localhost scripts]# /root/scripts/sh01.sh
hello world 
相对路径:当前目录为/root/scripts/时,使用 ./sh01.sh执行

[root@localhost scripts]# ./sh01.sh
hello world
变量PATH功能,将sh01.sh放在PATH指定目录内,例如:~/bin/ 中

②以bash进程来执行:

[root@localhost scripts]# bash sh01.sh
hello world 
[root@localhost scripts]# sh sh01.sh
hello world 

2、简单的shell scripts练习

2.1、简单范例

①交互式脚本:变量内容由用户决定
以read命令的功能,编写一个script,他可让用户输入first name和last name,最后在屏幕上显示"Your full name is:"的内容:
[root@localhost scripts]# vi sh02.sh
[root@localhost scripts]# ls
sh01.sh  sh02.sh
[root@localhost scripts]# chmod 755 sh02.sh
[root@localhost scripts]# ls
sh01.sh  sh02.sh
#!/bin/bash
# Program:
#       User input first name and last name.Program shows his full name
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

read -p "Input your first name:" firstname
read -p "Input your last name:" lastname
echo -e "\nYour full name is : $firstname $lastname"
~ 
[root@localhost scripts]# ./sh02.sh
Input your first name:张
Input your last name:三

Your full name is : 张 三
②随日期变化:利用日期进行文件的创建
我们希望每天的数据都备份成不同的文件名,假设我想创建三个空文件(通过touch命令),文件名开头由用户输入决定,假设用户输入filename,今天的日期是2016-11-04,我想以前天、昨天、今天的日期来创建文件,即filename_20141102,filename_20141103,filename_20141104:
[root@localhost scripts]# vi sh03.sh
[root@localhost scripts]# ls
sh01.sh  sh02.sh  sh03.sh
[root@localhost scripts]# chmod 755 sh03.sh
[root@localhost scripts]# 
[root@localhost scripts]# vi sh03.sh
#!/bin/bash
# Program:
#       Program creat three file ,which named by user'input
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

# 1.让用户输入文件名,取得fileuser变量
echo -e "I will use ‘touch’ command to creat 3 files."
read -p "Input your filename: " fileuser

# 2.为了避免用户随意按[enter],利用变量功能分析文件名是否已存在
filename=${fileuser:-"filename"} #判断是否有配置文件名

# 3.使用date命令取得所需的日期作为文件名的一部分
date1=$(date --date='2 days ago' +%Y%m%d) #前两天的日期
date2=$(date --date='1 days ago' +%Y%m%d) #前一天的日期
date3=$(date +%Y%m%d) #今天的日期

# 4.下面三行配置文件名
file1=${filename}${date1}
file2=${filename}${date2}
file3=${filename}${date3}

# 5.创建文件
touch "$file1"
touch "$file2"
touch "$file3"
[root@localhost scripts]# ./sh03.sh
I will use ‘touch’ command to creat 3 files.
Input your filename: my
[root@localhost scripts]# ls
my20161102  my20161103  my20161104  sh01.sh  sh02.sh  sh03.sh
[root@localhost scripts]# 
③数值运算:简单的加减乘除
我们可以使用declare来定义变量的类型,当变量定义为整数时才能进行加减运算。此外也可以使用$((计算表达式))来进行数值运算,不过bashshell仅支持到整数的数据
现在用户要输入两个变量,将两个变量内容相乘,输出结果

[root@localhost scripts]# vi sh04.sh 
#!/bin/bash # Program: 
#       user input two integer numbers ,program will cross these two numbers # History: 
#       2016-11-04  ...  ... 
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin 
export PATH  
echo -e "you should input 2 numbers,and i will cross them \n" 
read -p "first number: " num1 
read -p "second number: " num2 
total=$(($num1*$num2)) 
echo -e "\nThe result of $num1 X $num2 is ==> $total"
[root@localhost scripts]# chmod 755 sh04.sh
[root@localhost scripts]# ./sh04.sh
you should input 2 numbers,and i will cross them 

first number: 6
second number: 7

The result of 6 X 7 is ==> 42

2.2、script的执行方式的区别(source,shscript,./script)

①利用直接执行的方式来执行script
当使用直接命令执行(不论是在 绝对路径/相对路径 还是 PATH 内),或者利用bash或sh来执行脚本时,
该script都会使用一个新的bash环境来执行脚本内的命令。 这种方式script是在子进程的bash内执行的。
重点在于:当子进程完成后,子进程内的各项变量或操作将会结束而不会传回到父进程中。
[root@localhost scripts]# echo $firstname $lastname

[root@localhost scripts]# ./sh02.sh
Input your first name:张
Input your last name:三

Your full name is : 张 三
[root@localhost scripts]# echo $firstname $lastname

[root@localhost scripts]# 
上面的firstname和lastname两个变量并不存在
②利用source来执行脚本,会在父进程中执行
[root@localhost scripts]# source sh02.sh
Input your first name:张
Input your last name:三

Your full name is : 张 三
[root@localhost scripts]# echo $firstname $lastname
张 三
[root@localhost scripts]# 
firstname和lastname两个变量存在当前bash中

以上也是我们不注销系统而要让某些写入~./bashrc 的设置生效时,需要使用 "source ~./bashrc" 而不能使用 "bash ~./bashrc "。

3、善用判断式

3.1、利用test命令的测试功能

当要检测系统上面某些文件或者相关属性是,利用test命令

举个栗子,现在检查/abc是否存在时:

[root@localhost scripts]# test -e /abc
[root@localhost scripts]# 
执行结果没有显示任何信息
但是我们可以通过$?或&&及 || 来显示结果
[root@localhost scripts]# test -e /abc && "exist" || echo "not exist"
not exist
[root@localhost scripts]# 

文章末尾粘贴了来自《鸟哥的linux私房菜》的一张表test相关命令的参数,以供参考

现在我们利用test写个简单例子:

首先让用户输入一个文件名,判断:
1. 这个文件是否存在,不存在输出"Filename does not exist",并中断程序
2. 若存在,判断是文件还是目录,结果输出"Filename is regular file"或"Filename is directory"
3. 判断,一下执行者的身份对对这个文件或目录所拥有的权限,并输出详情

[root@localhost scripts]# vi sh05.sh
#!/bin/bash
# Program:
#       user input a filename ,program will check the flowing
#       1)exist?        2)file/directory?       3)file permissions
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

# 1)
read -p "input a filename,i will check it :"  filename
test -z $filename && echo "You must input a filename" && exit 0
# 2)
test ! -e  $filename && echo "The filename '$filename' NOT exist" && exit 0
# 3)
test -f $filename && filetype="regulare file"
test -d $filename && filetype="directory"
test -r $filename && perm="readable"
test -w $filename && perm="$perm writable"
test -x $filename && perm="$perm executable"
# 输出信息
echo "The filename :$filename is a $filetype"
echo "And the permissions are :$perm"
[root@localhost scripts]# chmod 755 sh05.sh
[root@localhost scripts]# ./sh05.sh
input a filename,i will check it :sh01.sh
The filename :sh01.sh is a regulare file
And the permissions are :readable writable executable

3.2、利用判断符号[]

举个栗子:

1、当执行一个程序时,让用户选择Y或N
2、如果用户输入Y或y,是显示"OK,continue"
3、如果用户输入N或n,就显示"O,interrupt"
4、如果不是Y/y/N/n,就显示"I don not know what your choice is"
[root@localhost scripts]# vi sh06.sh
#!/bin/bash
# Program:
#       show the user choice
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

read -p "input (Y/N):" yn
[ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK,continue" && exit 0
[ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh,interrupt" && exit 0
echo "I do not konw what your choice is" && exit 0
[root@localhost scripts]# chmod 755  sh06.sh
[root@localhost scripts]# ./sh06.sh
input (Y/N):y
OK,continue
[root@localhost scripts]# ./sh06.sh
input (Y/N):n
Oh,interrupt

3.3、shell script的默认变量($0,$1...)

script针对参数默认设置了一些变量名称

/path/to/scriptname  opt1  opt2  opt3  opt4 
$0     $1      $2    $3 $4   
还有一些特殊的参数变量可以在scrip中调用
$#:代表后接的参数个数
$@:代表"$1"、"$2"、"$3"、"$4",每个变量都是独立的(用双引号括起来,用空格连接)
$*:代表"$1c$2c$3c$4",其中c是分隔符,默认为空格键
假设我们执行一个可带参数的script,执行脚本后显示如下数据:
程序文件名
共有几个参数
若参数小于2则输出参数数量太少
全部的参数内容
第一个参数
第二个参数
[root@localhost scripts]# vi sh07.sh
#!/bin/bash
# Program:
#       show the script name ,parameters...
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

echo "The script name is  ==> $0"
echo "Total parameter number is  ==> $#"
[ "$#" -lt 2 ] && echo "The number of parameter is less than 2.Stop here" && exit 0
echo "whole parameters is  ==> $@"
echo "The 1st parameter is  ==> $1"
echo "The 2st parameter is  ==> $2"
[root@localhost scripts]# chmod 755  sh07.sh
The script name is  ==> ./sh07.sh
Total parameter number is  ==> 3
whole parameters is  ==> one two three
The 1st parameter is  ==> one
The 2st parameter is  ==> two

shift:造成参数变量的号码偏移

#!/bin/bash
# Program:
#       show the effect of shift function
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

echo "Total parameter number is  ==> $#"
echo "whole parameters is  ==> $@"
shift   #第一次一个变量shift
echo "Total parameter number is  ==> $#"
echo "whole parameters is  ==> $@"
shift 3 #第二次,三个变量shift
echo "Total parameter number is  ==> $#"
echo "whole parameters is  ==> $@"
[root@localhost scripts]# chmod 755 sh08.sh
[root@localhost scripts]# ./sh08.sh 1 2 3 4 5 6
Total parameter number is  ==> 6
whole parameters is  ==> 1 2 3 4 5 6
Total parameter number is  ==> 5
whole parameters is  ==> 2 3 4 5 6
Total parameter number is  ==> 2
whole parameters is  ==> 5 6

4、条件判断式

4.1、利用if...then

①单层、简单条件判断式:

if [ 条件判断式 ]; then
	#当条件判断式成立时,可进行的命令语句内容
fi	#将if反过来写,用来结束if语句
	#其中&&代表and	|| 代表or
可以将sh06.sh改为if...then的样式:
[root@localhost scripts]# cp sh06.sh sh06-2.sh
[root@localhost scripts]# vi sh06-2.sh
#!/bin/bash
# Program:
#       show the user choice
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

read -p "input (Y/N):" yn

if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then 
        echo "OK,continue"
        exit 0
fi
if [ "$yn" == "N" ] || [ "$yn" == "n" ]; then 
        echo "Oh,interrupt"
        exit 0
fi

echo "I do not konw what your choice is" && exit 0

②多重、复杂条件判断式:

多种不同的判断:

# 一个条件判断
if [ 条件判断式 ]; then
	#当条件判断成立时,进行的命令内容
else
	#当条件判断不成立时,进行的命令内容
fi

更加复杂的情况可以:

# 多个条件判断(if...elif...else)
if [ 条件判断式1 ]; then
	#当条件判断1成立时,进行的命令内容
elif [ 条件判断式2 ]; then
	#当条件判断2成立时,进行的命令内容
else
	#当条件判断全不成立时,进行的命令内容
fi
可以将sh06-2.sh修改成下面这样:
[root@localhost scripts]# cp sh06-2.sh sh06-3.sh
[root@localhost scripts]# vi sh06-3.sh
#!/bin/bash
# Program:
#       show the user choice
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

read -p "input (Y/N):" yn

if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then
        echo "OK,continue"
elif [ "$yn" == "N" ] || [ "$yn" == "n" ]; then
        echo "Oh,interrupt"
else 
        echo "I do not konw what your choice is"
fi
exit 0

现在我们想让用户输入"hello"这个关键字时,利用参数的方法可以这样设计:

1、判断$!是否为hello,是就显示"hello ,how are you?"
2、若没有任何参数,就提示用户必须要使用的参数
3、若参数不是hello,就提示仅能使用hello作为参数
[root@localhost scripts]# vi sh09.sh
#!/bin/bash
# Program:
#       check $1 is equal to "hello"
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

if [ "$1" == "hello" ]; then
        echo "Hello,how are you?"
elif [ "$1"=="" ]; then
        echo "You must input parameter, ex>{$0 someword}"
else
        echo "The parameter is 'hello',ex->{$0 hello}"
fi
[root@localhost scripts]# chmod 755 sh09.sh
[root@localhost scripts]# vi sh09.sh
[root@localhost scripts]# ./sh09.sh
You must input parameter, ex>{./sh09.sh someword}
[root@localhost scripts]# 
[root@localhost scripts]# ./sh09.sh hello
Hello,how are you?

netstat命令可以查询到目前主机打开的网络服务端口,可以利用netstat -tuln 获取目前主机有启动的服务:

[root@localhost scripts]# netstat -tuln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State      
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      
tcp        0      0 127.0.0.1:631               0.0.0.0:*                   LISTEN      
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      
tcp        0      0 :::22                       :::*                        LISTEN      
tcp        0      0 ::1:631                     :::*                        LISTEN      
tcp        0      0 ::1:25                      :::*                        LISTEN      
udp        0      0 0.0.0.0:68                  0.0.0.0:*                               
udp        0      0 0.0.0.0:631                 0.0.0.0:*    
#封包格式	         #本地ip:端口		     #远程IP:端口		     #是否监听
重点关注[本地ip:端口]的那个字段,它代表本机所启动的网络服务,若为127.0.0.1是仅对本机开放,若是0.0.0.0或:::代表对整个Internet开放,几个常见的端口与相关网络服务的关系是:
80:WWW
22:ssh
21:ftp
25:mail
111:RPC(远程过程调用)
631:CUPS(打印服务功能)

假设我的主机要检测比较常见的端口21,22,25 及80时

那我如何通过netstat去检查主机是否开机这四个主要的网络服务端口呢?由于每个服务的关键字都在冒号‘:’后面,所以我们可以:

[root@localhost scripts]# vi sh10.sh

#!/bin/bash
# Program:
#       Using netstat and grep to detect WWW,SSH,FTP and Mail services.
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

# 1.说明
echo "Now,I will detect your Linux server's services"
echo -e "The WWW,SSH,FTP and Mail will be detect! \n"

# 2.开始测试并输出
testing=$(netstat -tuln | grep ":80")  #检测 port 80
if [ "$testing" != "" ]; then
        echo "WWW is running in your system."
fi
testing=$(netstat -tuln | grep ":22")  #检测 port 22
if [ "$testing" != "" ]; then
        echo "SSH is running in your system."
fi
testing=$(netstat -tuln | grep ":21")  #检测 port 21
if [ "$testing" != "" ]; then
        echo "FTP is running in your system."
fi
testing=$(netstat -tuln | grep ":25")  #检测 port 25
if [ "$testing" != "" ]; then
        echo "Mail is running in your system."
fi
exit 0
[root@localhost scripts]# chmod 755 sh10.sh
[root@localhost scripts]# ./sh10.sh
Now,I will detect your Linux server's services
The WWW,SSH,FTP and Mail will be detect! 

SSH is running in your system.
Mail is running in your system.

4.2、利用case...esac判断

语法:

case $变量名称 in		#关键字为case,变量前有$
	"第一个变量内容")	#每个变量内容用双引号括起来,关键字为小括号
		程序段
		;;		#每个类型结尾使用两个分号处理
	"第二个变量内容")
		程序段
		;;
	*)			#最后一个变量内容用* 代表所有其他值
		exit 1
		;;
esac				#结束case
修改一下sh09.sh:
#!/bin/bash
# Program:
#       check $1 is equal to "hello"
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

case $1 in
  "hello")
        echo "Hello,how are you?"
        ;;
  "")
        echo "You must input parameter, ex>{$0 someword}"
        ;;
  *)
        echo "Usage $0 {hello}"
        ;;
esac
~     
[root@localhost scripts]# cp sh09.sh sh09-2.sh
[root@localhost scripts]# vi sh09-2.sh
[root@localhost scripts]# ./sh09-2.sh
You must input parameter, ex>{./sh09-2.sh someword}
[root@localhost scripts]# ./sh09-2.sh hello
Hello,how are you?

一般来说,使用"case $变量 in"这个语法中,"$变量"有两种获取方式:
直接执行式:
利用"script.sh bariable "的方式来直接给$1赋值,这也是在/etc/init.d 目录下大多数程序的设计方式
交互式:
通过read这个命令来让用户输入

练习:

让用户能够输入one,two,three,并且将用户的变量显示到屏幕上,如果不是one,two,three时,就告知用户仅有这三种选择
</pre><pre name="code" class="plain">#!/bin/bash
# Program:
#       this only sccepts the flowing parameters:one,two,three.
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

echo "This program will print your selection !"
case $1 in
  "one")
        echo "Your choice is one"
        ;;
  "two")
        echo "Your choice is two"
        ;;
  "three")
        echo "Your choice is three"
        ;;
  *)
        echo "Usage $0 {one|two|three}"
        ;;
esac
[root@localhost scripts]# vi sh12.sh
[root@localhost scripts]# chmod 755  sh12.sh
[root@localhost scripts]# ./sh12.sh one
This program will print your selection !
Your choice is one

4.3、利用function功能

语法:

function fname(){
<span style="white-space:pre">	</span>程序段  
}

例子1:

因为shell script 的执行方式是由上而下、由左及右,因此在脚本中的 function 的设置一定要在程序的最前面

我们将sh12.sh改写一下:

[root@localhost scripts]# cp sh12.sh sh12-2.sh
[root@localhost scripts]# vi sh12-2.sh
#!/bin/bash
# Program:
#       Use function to repeat information.
# History:
#       2016-11-04  ...  ...
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

[root@localhost scripts]# ./sh12-2.sh two
This program will print your selection !
Your choice is TWO

例子2:

function同样拥有内置变量参数,函数名称表示$0,后续变量也是以$1,$2,$3替代

我们可以在改写一下sh12-2.sh:

[root@localhost scripts]# vi sh12-3.sh

#!/bin/bash
# Program:
#       Use function to repeat information.
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

function printit(){
        echo "Your choice is $1"
}
echo "This program will print your selection !"
case $1 in
  "one")
        printit 1
        ;;
  "two")
        printit 2
        ;;
  "three")
        printit 3
        ;;
  *)
        echo "Usage $0 {one|two|three}"
        ;;
esac

[root@localhost scripts]# ./sh12-3.sh one
This program will print your selection !
Your choice is 1

5、循环(loop)

5.1、while do done,util do done(不定循环)

语法:

while [ condition ] <span style="white-space:pre">	</span># 中括号内的为判断式
do		<span style="white-space:pre">	</span># do是循环的开始
	#程序段
done		<span style="white-space:pre">	</span># done循环结束
或者

until [ condition ]
do
	#程序段
done

练习1:

假设我要让用户输入yes或者YES才结束程序执行,否则就一直提示用户输入字符串:

[root@localhost scripts]# vi sh13.sh

#!/bin/bash
# Program:
#       Repeat question until user input correct answer.
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

while [ "$yn" != "yes" -a "$yn" != "YES" ]
do
        read -p "input yes/YES to stop this program:" yn
done
acho "OK,you input the correct answer."
exit 0
[root@localhost scripts]# vi sh13.sh
[root@localhost scripts]# chmod 755 sh13.sh
[root@localhost scripts]# ./sh13.sh
input yes/YES to stop this program:no
input yes/YES to stop this program:yes
OK,you input the correct answer.
如果用until则:
[root@localhost scripts]# vi sh13-2.sh

#!/bin/bash
# Program:
#       Repeat question until user input correct answer.
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

until [ "$yn" == "yes" -o "$yn" == "YES" ]
do
        read -p "input yes/YES to stop this program:" yn
done
echo "OK,you input the correct answer."
exit 0

练习2:

计算1+2+3+...+100:

[root@localhost scripts]# vi sh14.sh

#!/bin/bash
# Program:
#       use loop to calculate "1+2+3+...+100" result.
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

s=0
i=0
while [ "$i" != "100" ]
do
        i=$(($i+1))     # 每次i+1
        s=$(($s+$i))    # 和的累加
done
echo "the result of " 1+2+3+...+100 " is $s"
exit 0
[root@localhost scripts]# chmod 755 sh14.sh
[root@localhost scripts]# ./sh14.sh
the result of  1+2+3+...+100  is 5050

5.2、for...do...done(固定循环)

语法:

for var in cin1 con2 con3 ...
do
	#程序段
done

练习1:

假设我有三只宠物,分别是dog cat elephant,我想每一行都输出"There are dogs"这样的话:

[root@localhost scripts]# vi sh15.sh

#!/bin/bash
# Program:
#       using for...loop to print 3 animals
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

for animal in "dog" "cat" "elephant"
do
        echo "I'm a ${animal}"
done
exit 0
[root@localhost scripts]# ./sh15.sh
I'm a dog
I'm a cat
I'm a elephant


练习2:

由于系统上面各种账号都是写在 /etc/passwd 内的第一个字段,我们可以通过管道命令 cut 找出单纯的账号名称后,以 id 及 finger 分别检查用户的标识符与特殊参数。

由于不同的linux系统上面账号都不一样,此时获取 /etc/passwd 并使用循环处理是一个可行的方案:

#!/bin/bash
# Program:
#       use id ,finger command to check system account's information.
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

users=$(cut -d ':' -f 1 /etc/passwd)    #获取账号名称
for username in $users
do
        id $username
        finger $username
done
exit 0<span style="font-size:14px;">
</span>

这个操作还可以用在每个账号的删除、更改

练习3:

我要利用ping 这个判断网络状态的命令,来进行网络状态的实时检测时,我要检测的域是本机所在的192.168.1.1~192.168.1.100 由于有100台主机所以:

[root@localhost scripts]# vi sh17.sh

#!/bin/bash
# Program:
#       use ping command to check the network's PC state
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

network="192.168.1"             # 先定义一个域的一部分
for sitenu in $(seq 1 100)      # seq为sequence(连续)的缩写
do
        # 取得ping 的回传值,正确or失败
        ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1
        # 开始显示结果是正确的启动(up)还是错误的没有连通(DOWN)
        if [ "$result" == 0 ]; then
                echo "Server ${network}.${sitenu} is UP."
        else
                echo "Server ${network}.${sitenu} is DOWN"
        fi
done

[root@localhost scripts]# vi sh17.sh
[root@localhost scripts]# chmod 755  sh17.sh
[root@localhost scripts]# ./sh17.sh
Server 192.168.1.1 is UP
Server 192.168.1.2 is UP

练习4:

我想让某个用户输入某个目录文件名,然后找出某目录内的文件名的权限:

[root@localhost scripts]# vi sh18.sh

#!/bin/bash
# Program:
#       user input dir name,I will find the permission of file
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

# 1.先看目录是否存在
read -p "input a directory name :" dir
if [ "$dir" == "" -o ! -d "$dir" ]; then
        echo "The $dir is NOT exist in your system."
        exit 1
fi

# 2.开始测试文件
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

[root@localhost scripts]# cd
[root@localhost ~]# scripts/sh18.sh
input a directory name :scripts
The file scripts/my20161102's permission is  readable writable 
The file scripts/my20161103's permission is  readable writable 
The file scripts/my20161104's permission is  readable writable 
The file scripts/sh01.sh's permission is  readable writable executable 
The file scripts/sh02.sh's permission is  readable writable executable 
The file scripts/sh03.sh's permission is  readable writable executable 
The file scripts/sh04.sh's permission is  readable writable executable 
The file scripts/sh05.sh's permission is  readable writable executable 
The file scripts/sh06-2.sh's permission is  readable writable executable 
The file scripts/sh06-3.sh's permission is  readable writable executable 
The file scripts/sh06.sh's permission is  readable writable executable 
The file scripts/sh07.sh's permission is  readable writable executable 
The file scripts/sh08.sh's permission is  readable writable executable 
The file scripts/sh09-2.sh's permission is  readable writable executable 
The file scripts/sh09.sh's permission is  readable writable executable 
The file scripts/sh10.sh's permission is  readable writable executable 
The file scripts/sh12-2.sh's permission is  readable writable executable 
The file scripts/sh12-3.sh's permission is  readable writable executable 
The file scripts/sh12.sh's permission is  readable writable executable 
The file scripts/sh13-2.sh's permission is  readable writable executable 
The file scripts/sh13.sh's permission is  readable writable executable 
The file scripts/sh14.sh's permission is  readable writable executable 
The file scripts/sh15.sh's permission is  readable writable executable 
The file scripts/sh16.sh's permission is  readable writable executable 
The file scripts/sh17.sh's permission is  readable writable executable 
The file scripts/sh18.sh's permission is  readable writable executable

5.3、for...do...done 的数值处理

语法:

for((初始值;限制值;执行步长))
do
	#程序段
done

练习:

我们以累加1的方式计算1+2+3+...+input_number

[root@localhost scripts]# vi sh19.sh

#!/bin/bash
# Program:
#       Try to calculate "1+2+3+..+your_input_number"
# History:
#       2016-11-04  ...  ...
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr.local/sbin:~/bin
export PATH

read -p "input a number, I will count for 1+2+3+...+your_input: " num
s=0
for((i=1;i<=$num;i=i+1))
do
        s=$(($s+$i))
done
echo "The result of 1+2+...+$num is ==> $s"
[root@localhost scripts]# vi sh19.sh
[root@localhost scripts]# chmod 755  sh19.sh
[root@localhost scripts]# ./sh19.sh
input a number, I will count for 1+2+3+...+your_input: 50
The result of 1+2+...+50 is ==> 1275

6、sell script的追踪与调试

语法:

[root@localhost scripts]# sh [-nvx] scripts.sh
参数:
-n	:	不执行script,仅查询语法问题
-v	:	在执行script前
-x	:	将使用到的script内容显示到屏幕上

范例一:

#测试sh19.sh的语法
[root@localhost scripts]# sh -n sh19.sh
#若语法无错误,则不会显示任何信息
范例二:

#将执行过程列出来
[root@localhost scripts]# sh -x sh19.sh
+ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr.local/sbin:/root/bin
+ export PATH
+ read -p 'input a number, I will count for 1+2+3+...+your_input: ' num
input a number, I will count for 1+2+3+...+your_input: 4
+ s=0
+ (( i=1 ))
+ (( i<=4 ))
+ s=1
+ (( i=i+1 ))
+ (( i<=4 ))
+ s=3
+ (( i=i+1 ))
+ (( i<=4 ))
+ s=6
+ (( i=i+1 ))
+ (( i<=4 ))
+ s=10
+ (( i=i+1 ))
+ (( i<=4 ))
+ echo 'The result of 1+2+...+4 is ==> 10'
The result of 1+2+...+4 is ==> 10

7、附录

測試的標誌代表意義
1. 關於某個檔名的『檔案類型』判斷,如 test -e filename 表示存在否
-e該『檔名』是否存在?(常用)
-f該『檔名』是否存在且為檔案(file)?(常用)
-d該『檔名』是否存在且為目錄(directory)?(常用)
-b該『檔名』是否存在且為一個 block device 裝置?
-c該『檔名』是否存在且為一個 character device 裝置?
-S該『檔名』是否存在且為一個 Socket 檔案?
-p該『檔名』是否存在且為一個 FIFO (pipe) 檔案?
-L該『檔名』是否存在且為一個連結檔?
2. 關於檔案的權限偵測,如 test -r filename 表示可讀否 (但 root 權限常有例外)
-r偵測該檔名是否存在且具有『可讀』的權限?
-w偵測該檔名是否存在且具有『可寫』的權限?
-x偵測該檔名是否存在且具有『可執行』的權限?
-u偵測該檔名是否存在且具有『SUID』的屬性?
-g偵測該檔名是否存在且具有『SGID』的屬性?
-k偵測該檔名是否存在且具有『Sticky bit』的屬性?
-s偵測該檔名是否存在且為『非空白檔案』?
3. 兩個檔案之間的比較,如: test file1 -nt file2
-nt(newer than)判斷 file1 是否比 file2 新
-ot(older than)判斷 file1 是否比 file2 舊
-ef判斷 file1 與 file2 是否為同一檔案,可用在判斷 hard link 的判定上。 主要意義在判定,兩個檔案是否均指向同一個 inode 哩!
4. 關於兩個整數之間的判定,例如 test n1 -eq n2
-eq兩數值相等 (equal)
-ne兩數值不等 (not equal)
-gtn1 大於 n2 (greater than)
-ltn1 小於 n2 (less than)
-gen1 大於等於 n2 (greater than or equal)
-len1 小於等於 n2 (less than or equal)
5. 判定字串的資料
test -z string判定字串是否為 0 ?若 string 為空字串,則為 true
test -n string判定字串是否非為 0 ?若 string 為空字串,則為 false。
註: -n 亦可省略
test str1 == str2判定 str1 是否等於 str2 ,若相等,則回傳 true
test str1 != str2判定 str1 是否不等於 str2 ,若相等,則回傳 false
6. 多重條件判定,例如: test -r filename -a -x filename
-a(and)兩狀況同時成立!例如 test -r file -a -x file,則 file 同時具有 r 與 x 權限時,才回傳 true。
-o(or)兩狀況任何一個成立!例如 test -r file -o -x file,則 file 具有 r 或 x 權限時,就可回傳 true。
!反相狀態,如 test ! -x file ,當 file 不具有 x 時,回傳 true

学习书籍请参考:《鸟哥的linux私房菜》

  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值