Chinaunix首页 | 论坛 | 博客
  • 博客访问: 308812
  • 博文数量: 84
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 890
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-13 16:46
文章分类

全部博文(84)

文章存档

2017年(2)

2016年(4)

2015年(78)

我的朋友

分类: LINUX

2015-06-10 22:23:30

一、shell script编写注意事项
1、命令的执行时从上而下,从左至右的分析与执行;
2、命令的执行,命令、参数键的多个空白会被忽略掉;
3、空白行也将被忽略掉,并且tab键所得的空白同样视为空格键;
4、如果读取到一个Enter符号(CR),就尝试开始执行该行(或该串)命令;
5、如果一行的内容太多,则可以使用“\Enter”来扩展至下一行;
6、#作为批注

二、shell script如何执行
直接执行:script文件必须具备可读与可执行的权限
1、绝对路径执行:使用/home/root/xxx.sh来执行;(就是在命令行直接敲/home/root/xxx.sh并回车就可执行)
2、相对路径执行:假设script文件在当前目录下,则使用./xxx.sh来执行(“./”代表当前目录,“../”代表上级目录)
3、变量“PATH”功能执行,将xxx.sh放在PATH指定的目录内,例如:~/bin;(这个高级,如果将xxx.sh放到PATH目录中直接在命令行中输入脚本名字就可执行,那么如果执行文件名重复了怎么办?哦,原来PATH变量是有顺序的,哈哈)
以bash进程来执行(以bash来执行脚本,脚本有可读r权限即可执行,上面的执行方法脚本必须有执行权限):通过bash xxx.sh或sh xxx.sh执行脚本文件

三、script执行方式区别
直接命令执行(不论是绝对路径/相对路径还是$PATH内),或者是利用bash(或sh)来执行脚本时,该script都会使用一个新bash环境来执行脚本的命令,也就是使用这种执行方式时,其实script是在子进程的bash内执行的。
利用source来执行脚本(脚本有可读r属性也可执行),是直接在父进程中执行,利用点“.”来执行脚本与source有同样的效果。
 
四、脚本的一般格式
1、第一行#!/bin/bash声明这个script使用的shell名称,因为我们使用的是bash,所以必须要以#!/bin/bash来声明这个文件内的语法使用bash的语法,那么这个程序被执行时,它就能够加载bash的相关环境配置文件(一般来说就是non-login shell的~/.bashrc),并且执行bash来使我们下面的命令能够执行。在很多情况中,如果没有设置好这一行,那么该程序很可能会无法执行,因为系统很可能无法判断该程序需要使用什么shell来执行.
2、程序内容说明:一般说,建议你一定要养成说明该script的内容与功能、版本信息、作者与联系方式、建立日期、历史记录等习惯,这有助于将来程序的修改与调试。
3、主要环境变量声明:建议务必要将一些重要的环境变量设置好,如PATH与LANG(如果有使用到输出相关的信息时)是当中最重要的!如此一来,则我们这个程序在执行时可以直接执行一些外部命令,而不必写绝对路径。
4、主要程序部分:
5、告知执行结果

五、Shell script编写及练习
1、第一个script的编写与执行
脚本1内容
  1. [root@RHEL6 scripts]# more sh01.sh              //查看刚编辑完的脚本内容
  2. #!/bin/bash                                     //声明这个script使用的shell名称
  3. #Program:                                       //程序内容说明
  4. # This program shows "Hello World!" in your screen.
  5. #History:                                       //历史信息
  6. #2015/06/12 Awake release
  7. PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/locale/sbin:~/bin:/root/scripts: //主要环境变量声明
  8. export PATH                                      //将PATH变量转换为环境变量
  9. echo -e "Hello world! \a \n"                     //主要程序部分:在屏幕上输出hello world,并有bb声“\a”,并换行"\n"
  10. exit 0                                  //告知执行结果:利用exit中断程序,并回传一个数值给系统。利用这个exit n的功能,我们可以自定义错误信息,让这个程序更加聪明
脚本1执行情况
  1. [root@RHEL6 scripts]# ll sh01.sh //查看脚本的文件属性为644,没有执行权限
  2. total 4
  3. -rw-r--r--. 1 root root 240 Jun 12 15:41 sh01.sh
  4. [root@RHEL6 scripts]#
  1. [root@RHEL6 scripts]# sh sh01.sh //使用sh命令执行脚本(脚本可以没有执行权限)
  2. Hello
  3.                                       //这是echo \n参数生成的
  4. [root@RHEL6 ~]# echo $PATH //查看PATH变量,发现并未改变
  5. /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
  6. [root@RHEL6 scripts]# source sh01.sh //使用source命令执行脚本(脚本可以没有执行权限)
  7. Hello

  8. [root@RHEL6 scripts]# echo $PATH //查看PATH变量,发现已经改变
  9. /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/locale/sbin:/root/bin:/root/scripts:
  10. [root@RHEL6 scripts]#
2、交互式脚本:变量内容由用户决定
  1. [root@RHEL6 scripts]# more sh02.sh
  2. #!/bin/bash
  3. #program:
  4. # user inputs his first name and last name. program shows his full name.
  5. #history:
  6. #2015/08/23 Awake First release


  7. PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
  8. export PATH


  9. read -p "Please input your first name:" firstname //变量firstname的内容由用户输入,read -p 及后面双引号内容表示用户输入提示符;
  10. read -p "Please input your last name:" lastname //变量lastname的内容由用户输入
  11. echo -e "\n your full name is :$firstname $lastname" //换行\n显示变量内容
  12. [root@RHEL6 scripts]#
脚本2执行情况
  1. [root@awake scripts]# ll
  2. total 8
  3. -rw-r--r--. 1 root root 240 Jun 12 20:09 sh01.sh
  4. -rw-r--r--. 1 root root 374 Jun 12 20:09 sh02.sh
  5. [root@awake scripts]# source sh02.sh
  6. Please input your first name:li
  7. Please input your last name:lo

  8.  your full name is :li lo
  9. [root@awake scripts]#
3、随日期变化:利用日期进行文件的创建
这个脚本可用于数据库的备份或其他数据备份时,希望将每次和面每天的数据都备份成不同的文件名;
  1. [root@awake scripts]# ll //查看当前目录下的文件,及变量名称
  2. total 12
  3. -rw-r--r--. 1 root root 240 Jun 12 20:09 sh01.sh
  4. -rw-r--r--. 1 root root 374 Jun 12 20:09 sh02.sh
  5. -rw-r--r--. 1 root root 589 Jun 13 07:34 sh03.sh
  6. [root@awake scripts]# more sh03.sh //查看脚本内容
  7. #!/bin/bash
  8. #program:
  9. # program creates three files,which named by user's input
  10. # and date command
  11. #History
  12. #2015/08/23 Awake First release
  13. PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
  14. export PATH
  15. echo -e "I will use 'touch' command to create 3 files."
  16. read -p "Please input your filename:" fileuser //变量fileuser的内容由用户输入,
  17. filename=${fileuser:-"filename"} //定义filename的变量内容,取决于fileuser是否存在,如果fileuser是未设置或值为空,那么filename的变量内容等于filename,如果fileuser存在且有变量内容,那么filename的变量内容就等于fileuser的变量内容,(加强学习${})这里面的意思是filename的变量内容是用户输入的fileuser内容。
  18. date1=$(date --date='2 days ago' +%Y%m%d) //定义date1的变量内容为当前时间的两天前
  19. date2=$(date --date='1 days ago' +%Y%m%d) //定义date2的变量内容为当前时间的一天前
  20. date3=$(date +%Y%m%d) //定义date2的变量内容为当前时间,时间的格式是%Y表示年(如1970,1980,2015等),%m表示月份的格式(01-12),%d表示日期(01-31),如果你的备份叫频繁,例如一天备份几次,也可以加上具体时间如+%Y%m%d%H%k%M,程序的最后输出文件名可能是这样sqlback20150613104852
  21. file1=${filename}${date1} //定义file1的变量内容为filename的变量和date1的变量
  22. file2=${filename}${date2}
  23. file3=${filename}${date3}
  24. touch "$file1" //利用touch创建文件
  25. touch "$file2"
  26. touch "$file3"
  27. [root@awake scripts]#
脚本3的一种执行情况(输入文件名)
  1. [root@awake scripts]# source sh03.sh //执行脚本
  2. I will use 'touch' command to create 3 files.
  3. Please input your filename:sqlback //输入的文件名
  4. [root@awake scripts]# ll
  5. total 12
  6. -rw-r--r--. 1 root root 240 Jun 12 20:09 sh01.sh
  7. -rw-r--r--. 1 root root 374 Jun 12 20:09 sh02.sh
  8. -rw-r--r--. 1 root root 589 Jun 13 07:34 sh03.sh
  9. -rw-r--r--. 1 root root 0 Jun 13 10:11 sqlback20150611 //生成的三个文件
  10. -rw-r--r--. 1 root root 0 Jun 13 10:11 sqlback20150612
  11. -rw-r--r--. 1 root root 0 Jun 13 10:11 sqlback20150613
  12. [root@awake scripts]# date //查看一下当前日期,以作对比
  13. Sat Jun 13 10:11:40 CST 2015
脚本3的第二种情执行况(不输入文件名)
  1. [root@awake scripts]# source sh03.sh
  2. I will use 'touch' command to create 3 files.
  3. Please input your filename:
  4. [root@awake scripts]#
  5. [root@awake scripts]# ll
  6. total 12
  7. -rw-r--r--. 1 root root 0 Jun 13 10:55 filename20150611101055 //生成的三个文件,发现文件名的前缀有所变化(这是一个如果用户不输入文件名,脚本默认赋予的文件名),也就是filename=${fileuser:-"filename"}语句的作用;
  8. -rw-r--r--. 1 root root 0 Jun 13 10:55 filename20150612101055
  9. -rw-r--r--. 1 root root 0 Jun 13 10:55 filename20150613101055
  10. -rw-r--r--. 1 root root 240 Jun 12 20:09 sh01.sh
  11. -rw-r--r--. 1 root root 374 Jun 12 20:09 sh02.sh
  12. -rw-r--r--. 1 root root 607 Jun 13 10:52 sh03.sh
  13. [root@awake scripts]#

4、数值运算:简单的加减乘除
我们可以利用“$((计算式))”来进行数值的运算,可惜的是,bash shell默认仅支持整数的数据运算,那么我们来试试,如果我们要用户输入两个变量,然后将连个变量的内容相乘,最后输出相乘的结果,如何实现?
  1. [root@awake scripts]# more sh04.sh
  2. #!/bin/bash
  3. #program:
  4. # user inputs 2 integer numbers;program will cross these two numbers.
  5. #History:
  6. #2015/08/23 Awake First release
  7. PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/~/bin
  8. export PATH
  9. echo -e "You SHOULD input 2 numbers,I will cross them! \n"
  10. read -p "first number:" firstnu
  11. read -p "second number:" secnu
  12. total=$(($firstnu*$secnu)) //这个就是利用$((计算式))来将两个变量相乘运算
  13. echo -e "\nThe result of $firstun * $secun is = $total" //输出变量结果
  14. [root@awake scripts]#
脚本4的执行情况
  1. [root@awake scripts]# source sh04.sh
  2. You SHOULD input 2 numbers,I will cross

  3. first number:5 //输入数值
  4. second number:2 //输入数值

  5. The result of * is = 10 //10就是得到的结果
  6. [root@awake scripts]#
在数值运算上,我们可以使用“declare -i total=$firstnu*$secnu”,也可以使用上面的方式来进行,建议使用$(())这种方式运算,因为两个小括号内可以加上空格。至于数值运算处理,则有+-*/%等,那个%表示取余数了,例如echo $((13%3))结果是13=4*3+1结果是1.

5、利用test命令的判断功能
首先判断一下,让用户输入一个文件名,我们判断
a、这个文件是否存在?若不存在则给予一个“Filename does not exist”的信息,并中断程序;
b、若这个文件存在,则判断它是个文件或目录,结果输出“Filename is regular file”或“Filename is directory”;
c、判断一下,执行者的身份对这个文件或目录所拥有的权限,并输出权限数据;
  1. [root@RHEL6 scripts]# more sh05.sh
  2. #!/bin/bash
  3. #program:
  4. # User input a filename,program will check the flowing;
  5. # 1.)exist? 2.)file/directory? 3.)file permissions
  6. #History:
  7. #2015/06/15 Awake first release
  8. PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
  9. export PATH


  10. #让用户输入文件名,并且判断用户是否真的输入字符串
  11. echo -e "please input a filename, I will check the filename's type and permission. \n\n"
  12. read -p "Input a filename :" filename
  13. test -z $filename && echo "You MUST input a filename." && exit 0 //test -z表示判定字符串($filename)是否为0,若string为空字符串,则为true。此处的意思是,如果用户没有输入文件名,那么输出"You MUST input a filename."因为echo命令一定会执行成功也就是他的$?一定为0,因此执行exit退出,并且告诉系统的返回值为0


  14. #判断文件是否存在(是当前运行脚本的目录吗?还是上面的PATH变量?test命令在查找文件是否存在有点像ls -l命令,因此$filename变量可以是一个文件名称,也可以是路径加文件名,test不能利用PATH变量),若不存在则显示信息并结束脚本
  15. test ! -e $filename && echo "The filename '$filename' Do NOT exist" && exit 0 //test ! -e $filename表示反向状态,如果该文件不存在(若存在者不向下执行该语句,直接进入下面的判断语句)则执行&& echo "The filename '$filename' Do NOT exist" ,接着执行exit 0


  16. #开始判断文件类型与属性
  17. test -f $filename && filetype="regulare file"  //test -f $filename判断这个文件是否为普通文件,如果是普通文件则执行filetype="regulare file"
  18. test -d $filename && filetype="directory"      //test -d $filename判断这个文件是否为目录
  19. test -r $filename && perm="readable"           //test -r $filename判断这个文件权限是否为可读
  20. test -w $filename && perm="$perm writable"     //test -r $filename判断这个文件权限是否为可写
  21. test -x $fllename && perm="$perm executable"   //test -r $filename判断这个文件权限是否为可执行


  22. #开始输出信息
  23. echo "The filename:$filename is a $fileytype" //输入文件的文件类型
  24. echo "And the permissions are : $perm" //输出文件的权限
  25. [root@RHEL6 scripts]#
由于root在很多权限的限制上面都是无效的,所以使用root执行这个脚本时,常常会发现与ls -l 观察到的结果并不同(怎么回事?什么意思?)
sh05.sh的执行结果
执行结果测试1(输入一个当前目录的文件名)
  1. [root@RHEL6 scripts]# ll //查看一下当前目录
  2. total 24
  3. -rw-r--r--. 1 root root 240 Jun 12 16:38 sh01.sh
  4. -rw-r--r--. 1 root root 374 Jun 12 17:00 sh02.sh
  5. -rw-r--r--. 1 root root 607 Jun 13 10:52 sh03.sh
  6. -rw-r--r--. 1 root root 424 Jun 13 11:10 sh04.sh
  7. -rwxr--r--. 1 root root 824 Jun 15 13:10 sh05.sh
  8. [root@RHEL6 scripts]# ./sh05.sh //执行脚本
  9. Please input a filename, I will check the filename's type and permission.


  10. Input a filename :sh02.sh //输入一个当前目录下已经存在的文件
  11. The filename:sh02.sh is a regulare file //输出的结果
  12. And the permissions are : readable writable executable //输出的结果
  13. [root@RHEL6 scripts]#
执行结果测试2(输入路径测试)
  1. [root@RHEL6 scripts]# ll /bin/ls
  2. -rwxr-xr-x. 1 root root 109208 Apr 17 2012 /bin/ls
  3. [root@RHEL6 scripts]# ./sh05.sh
  4. Please input a filename, I will check the filename's type and permission.


  5. Input a filename :/bin/ls
  6. The filename:/bin/ls is a regulare file
  7. And the permissions are : readable writable executable
  8. [root@RHEL6 scripts]#
执行结果测试3(使用普通用户测试)
  1. [root@RHEL6 scripts]# su - li
  2. [li@RHEL6 ~]$ ll /bin/ls
  3. -rwxr-xr-x. 1 root root 109208 Apr 17 2012 /bin/ls
  4. [li@RHEL6 ~]$ ./sh05.sh
  5. Please input a filename, I will check the filename's type and permission.


  6. Input a filename :/bin/ls
  7. The filename:/bin/ls is a regulare file
  8. And the permissions are : readable executable
  9. [li@RHEL6 ~]$
执行结果测试4(没有输入文件名)
  1. [li@RHEL6 ~]$ ./sh05.sh
  2. Please input a filename, I will check the filename's type and permission.


  3. Input a filename :
  4. You MUST input a filename.
  5. [li@RHEL6 ~]$
6、利用判断符号[]
中括号的使用方法与命令test几乎一模一样。只是中括号比较常用在条件判断式if...then...fi的情况中。
使用中括号必须要特别注意,因为中括号用在很多地方,包括通配符与正则表达式等,所以如果要在bash的语法中使用中括号作为shell的判断式时,必须注意中括号的两端需要有空格符来分隔。假设我们空格使用“□”符号来表示,那么这些地方需要有空格键:
[□"$HOME"□==□"MAIL"□]
注意一下上方的==两个等于号,在bash当中使用一个等号与两个等号的结果是一样的。不过在一般惯用程序写法中,一个等号代表“变量的设置”,两个等号则代表“逻辑判断(是否之意)”由于我们在中括号内重点在于“判断”而非“设置变量”,因此建议还是使用两个等号。

中括号的书写注意事项
在中括号[]内的每个组件都需要有空格键来分隔;
在中括号内的变量,最好以双引号括起来
在中括号内的常量,最好以单引号括起来
一个判断式仅能有两个数据的比较

[ -z "$HOME" ] 其实就等于 test -z "$HOME" ,所以 [ ] 里面能用的选项和 test 语句能用的完全一样,所以你可以通过 man test 来查看详细信息。

实例1,简单判断
  1. [root@RHEL6 scripts]# echo -e "$HOME \n$MAIL" //可以事先查看一下系统的环境变量
  2. /root
  3. /var/spool/mail/root
  4. [root@RHEL6 scripts]# [ -z "$HOME" ] ; echo $? //那么使用[ -z "$HOME" ]判断变量是否为空,结果为非空
  5. 1
  6. [root@RHEL6 scripts]# test -z "$HOME" ; echo $? //使用test -z结果是一样的,只是中括号比较常用在条件判断式中,中括号的方式更常用。
  7. 1
  8. [root@RHEL6 scripts]# [ “$HOME” == “$MAIL” ] ; echo $? //用中括号判断一下,结果肯定是否啊
  9. 1
  10. [root@RHEL6 scripts]# [ “$HOME” == '/root' ] ; echo $? //用中括号判断一下,结果肯等是是啊
  11. 0
  12. [ -z "$HOME" ] || echo $? //判定变量$HOME内容的字符串是否为0,若$HOME为空字符串,则为true,正常下$HOME是有内容的,就会继续运行||后面的echo $?
  13. [ -z "$HOME" ] ; echo $? //也可以写成这样,那么就是无论前面的命令是否为空与否,那么都会执行后面的echo $?, 只是这样两个命令就没有依赖关系也就是命令的串连功能(自己起的名字呵呵)
实例2,中括号在脚本中的简单应用
1、当执行一个程序的时候,这个程序会让用户选择Y或N;
2、如果用户输入Y或y时,就显示“OK,continue”
3、如果用户输入N或n时,就显示“Oh,interupt!”
4、如果不是/Y/y/N/n之内的其他字符,就显示“I don't know what your choice is”。
  1. [root@RHEL6 scripts]# more sh06.sh
  2. #!/bin/bash
  3. #program:
  4. # This program shows the user's choice
  5. #History:
  6. #2015/06/16 Awake Fist release
  7. PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
  8. export PATH
  9. read -p "please input (Y/N):" yn //让用户输入yn变量内容
  10. [ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK,continue" && exit 0   //任何一个条件成立(-o表示或)[ "$yn" == "Y" -o "$yn" == "y" ] 即用户输入Y或y那么$?就会为0即为true就会向下执行echo "OK,continue" && exit 0
  11. [ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh,interrupt!" && exit 0 //同上
  12. echo "I dot't know what your choice is" && exit 0 //如果不符合上述两条的输入内容,那么就执行这条。
  13. [root@RHEL6 scripts]#
执行结果测试
  1. [root@RHEL6 scripts]# sh sh06.sh
  2. please input (Y/N):asdf
  3. I dot't know what your choice is
  4. [root@RHEL6 scripts]# sh sh06.sh
  5. please input (Y/N):y
  6. OK,continue
  7. [root@RHEL6 scripts]# sh sh06.sh
  8. please input (Y/N):n
  9. Oh,
  10. [root@RHEL6 scripts]#













 
阅读(787) | 评论(0) | 转发(0) |
0

上一篇:bash环境配置文件

下一篇:lsblk,df -h命令

给主人留下些什么吧!~~