简单的Shell脚本

shell脚本的基本结构以及如何执行

[root@localhost script]# cat 1.sh 
#!/bin/bash
#The first shell script
#Writen by Justin 2015-01-07
date
echo "Hello World"
[root@localhost script]# ./1.sh
-bash: ./1.sh: Permission denied
[root@localhost script]# sh 1.sh 
Wed Jan  7 05:15:38 CST 2015
Hello World
[root@localhost script]# chmod +x 1.sh 
[root@localhost script]# ./1.sh
Wed Jan  7 05:15:50 CST 2015
Hello World
[root@localhost script]# sh -x 1.sh 
+ date
Wed Jan  7 07:29:29 CST 2015
+ echo 'Hello World'
Hello World
[root@localhost script]#

以上为一个简单的shell脚本和执行,Shell脚本通常都是以.sh 为后缀名,不是说不带.sh就不是脚本,“#! /bin/bash” 它代表的意思是,该文件使用的是bash语法,其中#表示该行是注释,叹号“!”告诉shell运行叹号之后的命令并用文件的其余部分作为输入,也就是运行/bin/bash并让/bin/bash去执行shell程序的内容。后面跟一些该脚本的相关注释内容以及作者和创建日期或者版本等等,这些注释并非必须的,可以省略掉,但是不建议省略。因为随着你工作时间的增加,你写的shell脚本也会越来越多,如果有一天你回头查看你写的某个脚本时,很有可能忘记该脚本是用来干什么的以及什么时候写的,所以写上注释是有必要的。Shell脚本的执行很简单,直接”sh filename “ 即可,也可以加一个执行权限,直接使用’./filename’ 执行这个脚本。

另外使用sh命令去执行一个shell脚本的时候是可以加-x选项来查看这个脚本执行过程,也可以在脚本里写上set -x或者set -xv,这样只执行脚本时候就会显示执行的每条命令,这样有利于我们调试这个脚本哪里出了问题。

使用-n可以检查是否有错误

[root@localhost src]# sh -n install-tomcat.sh 
install-tomcat.sh: line 72: syntax error: unexpected end of file
[root@localhost src]#

syntax error: unexpected end of file:

如果是在windows环境下编写的shell脚本上传到linux下需要把dos文件转换成unix文件格式,否则会出现报错:syntax error: unexpected end of file:

dos格式文件传输到unix系统时,会在每行的结尾多一个^M,当然也有可能看不到,但是在vi的时候,会在下面显示此文件的格式,比如 "dos.txt" [dos] 120L, 2532C 字样,表示是一个[dos]格式文件,如果是MAC系统的,会显示[MAC],因为文件格式的原因有时会导致我们的unix程序,或者shell程序出现错误,那么需要把这些dos文件格式转换成unix格式,方法是
 
    vi   dos.txt         
     :set fileformat=unix
 
    :w                  
    这样文件就转换成unix格式文件了

出现中文乱码的问题

此问题是因执行定时任务时没有去获取系统的环境变量,导致了中文乱码。在shell脚本开始的时候加下命令:export LANG="en_US.UTF-8"

#!/bin/sh
export LANG="en_US.UTF-8"

shell脚本中的变量

[root@localhost script]# cat 2.sh 
#!/bin/bash
#This script,we will use variables.
#Write by Justin 2015-01-07
x=`date +%H:%M:%S`
echo "the script begin at $x"
echo "The script end after 2 seconds"
sleep 2
y=`date +%H:%M:%S`
echo "The script end at $y" 
[root@localhost script]# sh 2.sh 
the script begin at 14:22:08
The script end after 2 seconds
The script end at 14:22:10
[root@localhost script]#

脚本中调用了命令date所以使用了反引号,在调用变量时需要加上符号$,这个和在shell中定义变量是一致的。

[root@localhost script]# cat 3.sh 
#!/bin/bash
a=1
b=2
sum=$[$a+$b]
echo "sum is $sum"
[root@localhost script]# sh 3.sh 
sum is 3
[root@localhost script]#

数学计算要用’[ ]’括起来并且外头要带一个’$’。

[root@localhost script]# cat 4.sh 
#!/bin/bash
echo "please input a number:"
read x
echo "please input another number:"
read y
sum=$[$x+$y]
echo "The sum of tow number is:$sum"

[root@localhost script]# sh 4.sh 
please input a number:
3
please input another number:
5
The sum of tow number is:8
[root@localhost script]# sh -x 4.sh 
+ echo 'please input a number:'
please input a number:
+ read x
3   
+ echo 'please input another number:'
please input another number:
+ read y
5
+ sum=8
+ echo 'The sum of tow number is:8'
The sum of tow number is:8
[root@SAMBA1 infa_shared]# echo `date +"%Y-%m-%d %H:%M:%S"` > read-only.txt 
[root@SAMBA1 infa_shared]# cat read-only.txt 
2015-11-25 15:56:56
[root@SAMBA1 infa_shared]# y=`date +"%Y-%m-%d %H:%M:%S"`
[root@SAMBA1 infa_shared]# echo $y
2015-11-25 15:58:27
[root@SAMBA1 infa_shared]#

Shell脚本可以和用户交互。这就用到了read命令了,它可以从标准输入获得变量的值,后跟变量名。”read x”表示x变量的值需要用户通过键盘输入得到。我们可以直接使用read -p 来代替echo的作用

[root@localhost script]# cat 5.sh 
#!/bin/bash
read -p "please input a number:" x     ;x前有个空格
read -p "please input another number:" y
sum=$[$x+$y]
echo "The sum of tow number is:$sum"

[root@localhost script]# sh -x 5.sh 
+ read -p 'please input a number:' x
please input a number:3
+ read -p 'please input another number:' y
please input another number:5
+ sum=8
+ echo 'The sum of tow number is:8'
The sum of tow number is:8
[root@localhost script]#

”/etc/init.d/iptables restart “ 前面的/etc/init.d/iptables 就是一个shell脚本,后面”restart”是了shell脚本的预设变量。上面例子我们可以通过设置预设变量

[root@localhost script]# cat 5.sh 
#!/bin/bash
sum=$[$1+$2]
echo "The sum of tow number is:$sum"
echo "$0"
[root@localhost script]# sh -x 5.sh 3 5
+ sum=8
+ echo 'The sum of tow number is:8'
The sum of tow number is:8
+ echo '5.sh'
5.sh
[root@localhost script]#

$1和$2就是shell脚本的预设变量,其中$1的值就是在执行的时候输入的3,而$2的值就是执行的时候输入的5,一个shell脚本的预设变量是没有限制的,$0代表的是脚本本身的名字。

shell脚本中的逻辑判断

if判断语句:

1)不带else

格式:

if 判断语句; then

command

fi

[root@localhost script]# cat if1.sh 
#! /bin/bash
read -p "please input your score:" a
if ((a<60));then
    echo "You didn't pass the exam.you score is $a"
fi
[root@localhost script]# sh if1.sh 
please input your score:33
You didn't pass the exam.you score is 33
[root@localhost script]#

上面出现了 ((a<60))这样的形式,这是shell脚本中判断数值大小特有的格式,用一个小括号或者不用都会报错,请记住这个格式,在判断数值大小除了可以用”(( ))”的形式外,还可以使用”[ ]”。但是就不能使用>, < , = 这样的符号了,要使用 -lt (小于),-gt (大于),-le (小于等于),-ge (大于等于),-eq (等于),-ne (不等于),这种类型在while循环中使用多

2)带有else

格式:

if 判断语句 ; then

command

else

command

fi

[root@localhost script]# cat if1.sh 
#! /bin/bash
read -p "please input your score:" a
if ((a<60));then
    echo "You didn't pass the exam.you score is $a"
else
    echo "GOOD! You passed the exam,you score is $a."
fi
[root@localhost script]# sh if1.sh 
please input your score:67
GOOD! You passed the exam,you score is 67.
[root@localhost script]# sh if1.sh 
please input your score:33
You didn't pass the exam.you score is 33
[root@localhost script]#
linux-gnv2:/opt/FlashServer/flashserver # cat restart.sh 
#!/bin/bash
x=`ps -ef|grep 'flashserver'|grep -v grep|grep -v nohup|awk -F " " '{print $2}'`
y=`ps -ef|grep 'flashserver'|grep -v grep|grep -v nohup|wc -l`
if [ $y -ge 1 ]
then
        sudo kill -9 $x
        sleep 2
else
        echo "no service exist"
fi
nohup ./flashserver >/dev/null &
y=`ps -ef|grep 'flashserver'|grep -v grep|grep -v nohup|wc -l`
sleep 1
if [ $y -ge 1 ]
then
        echo "start service success"
else
        echo "start service fail"
fi
linux-gnv2:/opt/FlashServer/flashserver #

[root@QuoteService Release]# cat RestartQuoteServer.sh 
#!/bin/bash
x=`pgrep QuotePlatform`
y=`ps -ef|grep 'QuotePlatform'|grep -v grep|wc -l`
z="/usr/local/QuoteService/make/Release"
if [ $y -ge 1 ];then
   kill -9 $x
   sleep 2
   yy=`ps -ef|grep 'QuotePlatform'|grep -v grep|wc -l`   #pgrep QuotePlatform是变量,每次应用都需要重新定义变量,不重新定义就是第一次赋予的值
   if [ $yy -le 0 ];then
      echo "QuotePlatform server is not running!" 
      cd $z
      nohup ./QuotePlatform >/dev/null &
      sleep 3
      yyy=`ps -ef|grep 'QuotePlatform'|grep -v grep|wc -l`
      if [ $yyy -ge 1 ];then
        echo "QuotePlatform service successfully started!"
        else
        echo "QuotePlatform service startup failed! "
      fi
   else
     echo "Kill QuotePlatform service is failed!"
   fi
else
  echo "QuotePlatform server is not running!"
  cd $z
  nohup ./QuotePlatform >/dev/null &
  sleep 3
  yyyy=`ps -ef|grep 'QuotePlatform'|grep -v grep|wc -l`
  if [ $yyyy -ge 1 ];then
    echo "QuotePlatform service successfully started!"
    else
     echo "QuotePlatform service startup failed! "
   fi
fi

多判断条件:同时满足三个文件大小

[root@localhost src]# cat test.sh 
#!/bin/bash
nagiossize=`du -k nagios-plugins-1.4.16.tar.gz|awk '{print $1}'`
nrpesize=`du -k nrpe-2.15.tar.gz|awk '{print $1}'`
zabbixsize=`du -k zabbix-2.2.2.tar.gz|awk '{print $1}'`
if [ $zabbixsize -ge 14200 ] && [ $nagiossize -ge 2000 ] && [ $nrpesize -ge 400 ];then
    echo "download is successful"
else
    echo "download is failed"
fi
[root@localhost src]# sh test.sh 
download is successful
[root@localhost src]#


3)带有elif

格式:

if 判断语句一 ; then

command

elif 判断语句二; then

command

else

command

fi

[root@localhost script]# cat if1.sh 
#! /bin/bash
read -p "please input your score:" a
if ((a<60));then
    echo "You didn't pass the exam.you score is $a"
elif ((a>60)) && ((a<85));then
    echo "GOOD! You passed the exam,you score is $a."
else
    echo "Very Good! You score is $a,it's very hight!"
fi
[root@localhost script]# sh if1.sh 
please input your score:33
You didn't pass the exam.you score is 33
[root@localhost script]# sh if1.sh 
please input your score:77
GOOD! You passed the exam,you score is 77.
[root@localhost script]# sh if1.sh 
please input your score:99
Very Good! You score is 99,it's very hight!
[root@localhost script]#

逻辑运算符&& 表示“并且”, || 表示“或者”。
判断文件(夹)是否存在

注意:单引号和双引号的区别。单引号告诉shell忽略所有特殊字符,而双引号忽略大多数,但不包括$、\、`,即双引号保有变量的内容,但单引号内仅能是 一般字符 ,而不会有特殊符号。

#!/bin/bash  
myPath="/usr/local/src/dir/test"
myFile="/usr/local/src/access.log" 
#这里的-d参数判断$myPath是否存在,注意[]前后空格
if [ -d  "$myPath" ];then
 cd "$myPath"
 tar -cvf myPath.tar *
else
   mkdir -p /usr/local/src/dir/test
   echo "$myPath is created"
   touch /usr/local/src/dir/test/1
   touch /usr/local/src/dir/test/2
   touch /usr/local/src/dir/test/3
fi
#!/bin/bash  
myPath="/usr/local/src/dir/test"
myFile="/usr/local/src/access.log"
#这里的-f参数判断$myPath是否存在  
if [ ! -f  "$myFile" ];then
   touch "$myFile"
   echo "test" > "$myFile"
else
   cat "$myFile"
fi
#!/bin/bash  
#这里的-x参数判断$myPath是否存在并且有可执行权限  
if [ ! -x  '/usr/local/src/' ];then
   chmod +x /usr/local/src/
   ll -d /usr/local/src/
else
   cd "$myPath" && tar -cvf tar.tar /usr/local/src/*
   tar -tvf tar.tar
fi

#!/bin/bash
MyFile=`command -v ntpdate`
if [ ! -x "$MyFile" ];then
yum -y install ntp
cat >> /var/spool/cron/root << EOF
0 */12 * * *  /usr/sbin/ntpdate cn.pool.ntp.org
EOF
/sbin/hwclock --systohc
/etc/init.d/crond restart
else
cat >> /var/spool/cron/root << EOF
0 */12 * * *  /usr/sbin/ntpdate cn.pool.ntp.org
EOF
/sbin/hwclock --systohc
/etc/init.d/crond restart
fi

#!/bin/bash 
#两个变量判断是否相等
if [ "$var1" == "$var2" ]; then
echo '$var1 eq $var2'
else
echo '$var1 not eq $var2'
fi

其他参数:

-a file exists. 
-b file exists and is a block special file. 
-c file exists and is a character special file. 
-d file exists and is a directory. 
-e file exists (just the same as -a). 
-f file exists and is a regular file. 
-g file exists and has its setgid(2) bit set. 
-G file exists and has the same group ID as this process. 
-k file exists and has its sticky bit set. 
-L file exists and is a symbolic link. 
-n string length is not zero. 
-o Named option is set on. 
-O file exists and is owned by the user ID of this process. 
-p file exists and is a first in, first out (FIFO) special file or 
named pipe. 
-r file exists and is readable by the current process. 
-s file exists and has a size greater than zero. 
-S file exists and is a socket. 
-t file descriptor number fildes is open and associated with a 
terminal device. 
-u file exists and has its setuid(2) bit set. 
-w file exists and is writable by the current process. 
-x file exists and is executable by the current process. 
-z string length is zero.


判断文件是否存在特定字符串grep -q 

[root@finchina ~]# cat a.txt 
nihao
nihaooo
hello
[root@finchina ~]# if grep -q hellooooo a.txt ;then echo 'hello is exist';else echo 'hello is not exist';fi
hello is not exist
[root@finchina ~]#

case判断语句

格式:

case 变量 in

value1)

command

;;

value2)

command

;;

value3)

command

;;

*)

command

;;

esac

上面的结构中,不限制value的个数,*则代表除了上面的value外的其他值

[root@localhost script]# cat case.sh 
#!/bin/bash
read -p "please input:" n
case $n in
[0-9]*)
echo "You input a number:$n"
;;
[a-z]*|[A-Z]*)
echo "You input a letter:$n"
;;
*)
echo "You input is not a digital or not characters:$n"
;;
esac
[root@localhost script]# sh case.sh 
please input:111112222
You input a number:111112222
[root@localhost script]# sh case.sh 
please input:afdfdaf
You input a letter:afdfdaf
[root@localhost script]# sh case.sh 
please input:**(*
You input is not a digital or not characters:**(*
[root@localhost script]#

case脚本常用于编写系统服务的启动脚本,例如/etc/init.d/iptables中就用到了

read命令:

主要参数:

-t  等待时间,eg、read -t 5 -p "please enter your name:" name

-p 用户提示

-s 使输入不显示在屏幕上(用于输入密码)

-n 计算输入字符数  eg、read  -n1 -p "please enter your choice(y/n):"

shell脚本中的循环

for循环

结构 :

for 变量名 in 循环的条件; do

command

done

[root@localhost script]# cat for.sh 
#!/bin/bash
#for i in `seq 0 5`
#for i  in {0..5}
for i in 0 1 2 3 4 5
do
echo $i
done
[root@localhost script]# sh for.sh 
0
1
2
3
4
5
[root@localhost script]# cat for.sh 
#!/bin/bash
for i in `tail -1 /etc/passwd`
do
x=`echo $i|awk -F':' '{print $1"\t"$7}'`
echo $x
done
[root@localhost script]# sh for.sh 
tcpdump /sbin/nologin
[root@localhost script]#

seq 0 5 表示从0到5的一个序列,seq默认从0开始,

[root@localhost script]# cat for.sh 
#!/bin/bash
for ((i=1;i<=19;i++))
do
 if((i%3==0));then
echo $i
 fi
done
[root@localhost script]# sh for.sh 
3
6
9
12
15
18
[root@localhost script]#

for语法循环有点像C语法,但记得双括号

while循环

格式:

while 条件; do

command

done

[root@localhost script]# cat while.sh 
#!/bin/bash
min=1
max=20
#while (($min<=$max))
while [ $min -le $max ]    ;[后面、]前面有个空格
do 
echo $min
min=$[$min+1]
done 
[root@localhost script]# sh while.sh 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@localhost script]#


.循环控制语句 
# break 命令不执行当前循环体内break下面的语句从当前循环退出. 
# continue 命令是程序在本循体内忽略下面的语句,从循环头开始执行

Tips:如果脚本你是直接在windows下通过记事本类工具编写传到linux上给了执行权限后使用./来执行发现无法执行,而通过sh就可以

[root@localhost src]# chmod +x linux_nagios_client.sh 
[root@localhost src]# ./linux_nagios_client.sh 
-bash: ./linux_nagios_client.sh: /bin/bash^M: bad interpreter: No such file or directory
[root@localhost src]# sh linux_nagios_client.sh 
Loaded plugins: fastestmirror, product-id, subscription-manager
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Loading mirror speeds from cached hostfile
Setting up Group Process

出现上面错误的原因之一是脚本文件是DOS格式的, 即每一行的行尾以\r\n来标识, 使用vim编辑器打开脚本, 运行:

:set ff?

可以看到DOS或UNIX的字样. 使用set ff=unix把它强制为unix格式的, 然后存盘退出, 即可.


你可能感兴趣的:(shell,while,for,FI)