且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

通过脚本案例学习shell(五) 通过创建DNS脚本一步一步教你将一个普通脚本规范到一个生产环境脚本

更新时间:2022-09-20 15:54:13

为了能够很好的学习shell脚本的规范书写,这里将搭建过程分为四个步骤,其中每个步骤都是上个步骤的延续,直至创建出生产环境下可以使用的脚本,也就是任何一个人在未知此脚本内容的情况下都可以很好的运行此脚本.

步骤1、先通过手动搭建DNS服务,然后将执行的命令复制到脚本文件中,创建一个简单脚本。

1、安装bind、bind-chroot包


  1. yum install bind bind-chroot -y 

2、修改/etc/named.conf文件


  1. sed -i  ‘s/127\.0\.0\.1/any/’ /etc/named.conf  //替换127.0.0.1为any 
  2. sed -i  's/::1/any/' /etc/named.conf  //替换::1为any 
  3. sed -i  's/localhost/any/' /etc/named.conf //替换localhost为any 
  4. #sed -i -e '/listen-on/d' -e '/allow-query/d' -e '/dnssec/d' /etc/named.conf  //将以上sed的三行删掉,dns默认为any,也可以实现。 
  5. sed -i  's/^dnssec/\/\/&/' /etc/named.conf  //将以dnssec开头的所有行前面加\\,其中&是引用前面的替换值,\/是转义 
  6. 注意:使用sed命令的时候,先不要-i参数,可以通过-n和p函数先在屏幕上显示是否正常,例:sed -n ‘s/127\.0\.0\.1/any/p’ /etc/named.conf 

3、在/etc/named.rfc1912.zone中创建区域


  1. cat >> /etc/named.rfc1912.zones << ENDF \\使用cat追加多行信息到文件中 
  2. zone "rsyslog1.com" IN { 
  3.         type master; 
  4.         file "rsyslog1.com.zone"; 
  5.         allow-update { none; }; 
  6. }; 
  7. ENDF 

4、在/var/named/创建zone文件并设置相应权限cp -p 可以继承原有权限


  1. cp -p /var/named/named.localhost /var/named/rsyslog1.com.zone 
  2. sed -i '/127.0.0.1\|AAAA/d' /var/named/rsyslog1.com.zone  //删除不需要的包含127.0.0.1或AAAA的行,其中\|是或的意思 
  3.  
  4. cat >> /var/named/rsyslog1.com.zone << ENDF  //追加A记录 
  5.         A       192.168.100.109 
  6. www     A       192.168.100.109 
  7. ENDF 

5、设置DNS,重启named服务并通过nslookup进行本地解析


  1. sed -i '1inameserver 192.168.100.109' /etc/resolv.conf //在resolv.conf首行添加nameserver语句,其中1i i是变量当前行上插入一行的意思,1i是在第一行前加入一行
  2. /etc/rc.d/init.d/named restart 
  3. nslookup www.rsyslog1.com 

将以上命令统一放到文件当中就形成了一个简单脚本如下解释如上


  1. #!/bin/bash 
  2.  
  3. yum install bind bind-chroot -y 
  4.  
  5. sed -i 's/127\.0\.0\.1/any/' /etc/named.conf 
  6. sed -i 's/::1/any/' /etc/named.conf 
  7. sed -i 's/localhost/any/' /etc/named.conf 
  8. sed -i 's/dnssec/\/\/&/g' /etc/named.conf 
  9. #sed -i -e '/listen-on/d' -e '/allow-query/d' -e '/dnssec/d' /etc/named.conf 
  10.  
  11. cat >> /etc/named.rfc1912.zones << ENDF 
  12. zone "rsyslog1.com" IN { 
  13.         type master; 
  14.         file "rsyslog1.com.zone"; 
  15.         allow-update { none; }; 
  16. }; 
  17. ENDF 
  18.  
  19. cp -p /var/named/named.localhost /var/named/rsyslog1.com.zone 
  20.  
  21. sed -i '/127.0.0.1\|AAAA/d' /var/named/rsyslog1.com.zone 
  22.  
  23. cat >> /var/named/rsyslog1.com.zone << ENDF 
  24.         A       192.168.100.109 
  25. www     A       192.168.100.109 
  26. ENDF 
  27.  
  28. sed -i '1inameserver 192.168.100.109' /etc/resolv.conf 
  29. /etc/rc.d/init.d/named restart 
  30. nslookup www.rsyslog1.com 

脚本运行结果如下


  1. [root@RHEL6U3-9 named.sh]# ./named1.sh  
  2. ......//省略 
  3. Server:     192.168.100.109 
  4. Address:    192.168.100.109#53 
  5.  
  6. Name:   www.rsyslog1.com    
  7. Address: 192.168.100.109 

以上正确解析,说明脚本运行OK

 

步骤2、将一些常用到的路径以及会变的内容通过变量引用

脚本使用过程中很多部分内容都会在不同的环境下有所变动,为了修改方便,引入变量,每次只需要修改变量的值,脚本中所有引用变量的地方都会自动取定义的变量。(可在vim下使用 :.,$%A%B%g 将光标以下内容中的A全部替换成B)

修改部分:

1、定义安装包变量、配置文件路径变量、域名变量、IP地址变量

脚本修改后如下:


  1. #!/bin/bash 
  2. PKG="bind bind-chroot"  //定义安装的包,不同版本包可能不一样 
  3. M_CONF="/etc/named.conf" //定义主配置文件named.conf路径 
  4. R_CONF="/etc/named.rfc1912.zones" //定义named.rfc1912.zones文件路径 
  5. DOMAIN_N="rsyslog2.com" //定义域名 
  6.  
  7. MYIP="$(ifconfig eth0 | grep "inet addr:" | awk -F[:" "]+ '{print $4}')"  //取eth0的IP地址 –F[:” ”]+表示以:或者空格分隔,’{print $4}’表示打印第四列 
  8. #MYIP="$(ifconfig eth0 | sed –n   's/.*addr:\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/p')" //也是取eth0的IP地址,解析如下: 
  9. sed –n ‘s///p’  sed标准写法 
  10. \(\) 保存被匹配的字符          \1 引用第一个保存匹配的字符 
  11. .* 表示所有 
  12. [0-9]\{1,3\} 表示至少1个最多3个数字组合 
  13. \. 表示转义 
  14. #MYIP="$(ifconfig eth0 | grep "inet addr:" | cut -d":" -f2 | cut -d " " -f1)"  //取eth0的IP地址,-d: 以:分隔,-d” “ 以空格分隔,-f1 打印:分隔的第一部分 
  15. #MYIP="$(ifconfig eth0 | grep "inet addr" |sed -e 's/.*addr://' -e 's/Bcast.*//') //将IP地址两边的多余部分替换成空即可。
  16. #MYIP="$("ifconfig eth0 | grep "inet addr" |awk -F: '{print $2}' |awk '{print $1}') //先以:分割过滤,然后以空格分割过滤
  17. yum install $PKG -y 
  18.  
  19. sed -i 's/127\.0\.0\.1/any/' $M_CONF   
  20. sed -i 's/::1/any/' $M_CONF 
  21. sed -i 's/localhost/any/' $M_CONF 
  22. sed -i 's/dnssec/\/\/&/' $M_CONF 
  23.  
  24. cat >> $R_CONF << ENDF 
  25. zone "$DOMAIN_N" IN { 
  26.         type master; 
  27.         file "$DOMAIN_N.zone"; 
  28.         allow-update { none; }; 
  29. }; 
  30. ENDF 
  31.  
  32. cp -p /var/named/named.localhost /var/named/$DOMAIN_N.zone 
  33.  
  34. sed -i '/127.0.0.1\|AAAA/d' /var/named/$DOMAIN_N.zone 
  35.  
  36. cat >> /var/named/$DOMAIN_N.zone << ENDF 
  37.         A       $MYIP 
  38. www     A       $MYIP 
  39. ENDF 
  40.  
  41. sed -i "1inameserver $MYIP" /etc/resolv.conf 
  42. service named restart 
  43. nslookup www.$DOMAIN_N 

脚本运行结果


  1. [root@RHEL6U3-9 named.sh]# ./named2.sh 
  2. ...... 
  3. Server:     192.168.100.109 
  4. Address:    192.168.100.109#53 
  5.  
  6. Name:   www.rsyslog2.com 
  7. Address: 192.168.100.109 
  8. 脚本运行正常 

步骤3、将各个部分模块化函数化

修改部分:

1、  各模块函数化,后面调用函数即可

2、  安装包函数定义for循环判断是否安装过

3、  创建的域名通过在脚本后面跟上域名进行传递到脚本里面$1里

4、  多行sed命令写入文件中,然后通过-f参数进行引用

5、  函数部分如果比较大可以单独写一个文件,然后在脚本中通过source或者.进行调用。例:source /etc/install.sh或 . /etc/install.sh  (以下脚本未举例可自行测试)

脚本修改后如下


  1. #!/bin/bash 
  2.  
  3. PKG="bind bind-chroot" 
  4. M_CONF="/etc/named.conf" 
  5. R_CONF="/etc/named.rfc1912.zones" 
  6. DOMAIN_N="$1" 
  7. MYIP="$(ifconfig eth0 | grep "inet addr:" | awk -F[:" "]+ '{print $4}')" 
  8.  
  9. INSTALL_PKG() //安装包定义一个函数 
  10. #       yum install $PKG -y 
  11.         for i in $PKG 
  12.         do 
  13.                 rpm -q $i &> /dev/null 
  14.                 [ $? -ne 0 ] && UNPKG="$UNPKG $i" //将所有检测出来未安装的包保存到变量UPPKG中,也可以保存到文件中,不过变量是临时存储在内存中的,速度要比文件快的多,其次可以减少磁盘I/O性能。 
  15.         done 
  16.         [ -n "$UNPKG" ] && yum install $UNPKG –y //判断变量UNPKG是否为空,如果不为空就安装里面包含的包 
  17.  
  18. MAIN_CONF() 
  19. sed -i -f /root/shell/sed.txt $M_CONF  //将之前那四行sed内容写到一个文件中,然后通过-f参数进行调用即可,其实四行命令也可以通过-e命令连接,不建议这么操作。 
  20.  
  21.         cat >> $R_CONF << ENDF 
  22. zone "$DOMAIN_N" IN { 
  23.         type master; 
  24.         file "$DOMAIN_N.zone"; 
  25.         allow-update { none; }; 
  26. }; 
  27. ENDF 
  28.  
  29.         cp -p /var/named/named.localhost /var/named/$DOMAIN_N.zone 
  30.  
  31.         sed -i '/127.0.0.1\|AAAA/d' /var/named/$DOMAIN_N.zone 
  32.  
  33.         cat >> /var/named/$DOMAIN_N.zone << ENDF 
  34.         A       $MYIP 
  35. www     A       $MYIP 
  36. ENDF 
  37.  
  38. MYTEST() 
  39.         sed -i "1inameserver $MYIP" /etc/resolv.conf 
  40.         service named restart 
  41.         nslookup www.$DOMAIN_N 
  42.  
  43. INSTALL_PKG 
  44. MAIN_CONF 
  45. MYTEST 
  46.  
  47. [root@RHEL6U3-9 shell]# cat /root/shell/sed.txt  //引用的四条sed写入的文件格式如下。注意没有’’符号。 
  48. s/127\.0\.0\.1/any 
  49. s/::1/any/ 
  50. s/localhost/any/ 
  51. s/dnssec/\/\/&/ 

脚本运行结果如下


  1. [root@RHEL6U3-9 named.sh]# ./named3.sh rsyslog3.org 
  2. Stopping named: .                                          [  OK  ] 
  3. Starting named:                                            [  OK  ] 
  4. Server:     192.168.100.109 
  5. Address:    192.168.100.109#53 
  6.  
  7. Name:   www.rsyslog3.org 
  8. Address: 192.168.100.109 

步骤4、完善脚本中存在的各种情况,初步达到生产环境基本要求

修改部分:

1、定义错误函数,方便他人传递参数错误报错。

2、传递参数加上-d 增强书写规范

4、定义测试函数,测试传递参数是否有效

5、定义case语句,内含测试函数,将传递参数一一验证,如果正确报错所有域名参数为后面所用,如果不正确,调用错误函数输出结束。

脚本修改后如下


  1. #!/bin/bash 
  2.  
  3. PKG="bind bind-chroot" 
  4. M_CONF="/etc/named.conf" 
  5. R_CONF="/etc/named.rfc1912.zones" 
  6. MYIP="$(ifconfig eth0 | grep "inet addr:" | awk -F[:" "]+ '{print $4}')" 
  7.  
  8. MYHELP() //定义输出错误方便他人尤其是开发人员正确运行脚本,这也能体现出来一个大牛写脚本是否规范地方,同时也能体现出来团队协作精神,方便他人使用。 
  9. cat << ENDF 
  10. usage: $0 [option] // $0 表示第一个参数 也就是脚本名称 
  11. option: 
  12. -d dn1 dn2 ...  :input your domain names 
  13. ENDF 
  14. exit 1 
  15.  
  16. TEST_D() //定义测试函数,测试输入域名格式是否有效,以下只列出了两种域名格式有效,分别为***.***或者***.***.*** 
  17.         echo $1 | grep '.\..\|.*\..*\..*' &>/dev/null  // \|或的意思 
  18.         [ $? -ne 0 ] && MYHELP \\如果执行没有结果或者报错,则显示错误帮助 
  19.  
  20. INSTALL_PKG() 
  21. #       yum install $PKG -y 
  22.         for i in $PKG 
  23.         do 
  24.                 rpm -q $i &> /dev/null 
  25.                 [ $? -ne 0 ] && UNPKG="$UNPKG $i" 
  26.         done 
  27.         [ -n "$UNPKG" ] && yum install $UNPKG -y 
  28.  
  29. MAIN_CONF() 
  30.         sed -i -f /root/shell/sed.txt $M_CONF 
  31.         cat >> $R_CONF << ENDF 
  32.         zone "$DOMAIN_N" IN { 
  33.                 type master; 
  34.                 file "$DOMAIN_N.zone"; 
  35.                 allow-update { none; }; 
  36.         }; 
  37. ENDF 
  38.  
  39.         cp -p /var/named/named.localhost /var/named/$DOMAIN_N.zone 
  40.  
  41.         sed -i '/127.0.0.1\|AAAA/d' /var/named/$DOMAIN_N.zone 
  42.  
  43.         cat >> /var/named/$DOMAIN_N.zone << ENDF 
  44.         A       $MYIP 
  45. www     A       $MYIP 
  46. ENDF 
  47.  
  48. MYTEST() //由于是可以传递多个域名参数,使用for循环将多个域名进行解析 
  49.         sed -i "1inameserver $MYIP" /etc/resolv.conf 
  50.         service named restart 
  51.         for i in $DOMAIN_N_ALL 
  52.         do 
  53.                 nslookup $i 
  54.         done 
  55.  
  56. [ -z "$1" ] && MYHELP  //如果脚本不跟任何传递参数,则退出显示帮助信息 
  57.  
  58. case $1 in  //定义case语句,判断脚本后所有域名是否有效,如果有效全部写入变量DOMAIN_N_ALL中,后面再通过for循环读取变量获取的值,如果无效则退出显示帮助错误, 
  59.         -d)  //加入 –d 参数后,域名部分从$2开始 
  60.                 shift  向左移动一位,将$2的值传递给$1,后面依次类推 
  61.                 TEST_D $1 //判断第一个域名是否有效 
  62.                 DOMAIN_N_ALL="$1" 将域名保存到变量DOMAIN_N_ALL变量中 
  63.                 shift 继续左移动,将第二个域名传递给$1 
  64.                 while [ $# -gt 0 ] //判断位置参数个数是否为0,也就是是否还有域名存在 
  65.                 do 
  66.                         TEST_D $1 //如果有继续判断是否有效 
  67.                         DOMAIN_N_ALL="$DOMAIN_N_ALL $1" //如果有效,将域名追加到DOMAIN_N_ALL变量中,注意中间是有空格的 
  68.                         shift \\传递之后,位置参数继续左移 
  69.                 done 
  70.         ;; 
  71.         *) 
  72.                 MYHELP 
  73.         ;; 
  74. esac 
  75.  
  76.  
  77.  
  78.  
  79. INSTALL_PKG 
  80. for DOMAIN_N in $DOMAIN_N_ALL  //使用for循环添加传递的所有域名 
  81. do 
  82.         MAIN_CONF 
  83. done 
  84. MYTEST 

脚本执行结果如下


  1. [root@RHEL6U3-9 named.sh]# ./named4.sh  //不传递任何参数报错 
  2. usage: ./named4.sh [option] 
  3. option: 
  4. -d dn1 dn2 ...  :input your domain names 
  5. [root@RHEL6U3-9 named.sh]# ./named4.sh –d  //传递参数有问题报错 
  6. usage: ./named4.sh [option] 
  7. option: 
  8. -d dn1 dn2 ...  :input your domain names 
  9. [root@RHEL6U3-9 named.sh]# ./named4.sh -d rsyslog1 //传递的参数不符合域名格式报错 
  10. usage: ./named4.sh [option] 
  11. option: 
  12. -d dn1 dn2 ...  :input your domain names 
  13. [root@RHEL6U3-9 named.sh]# ./named4.sh -d rsyslog1.net rsyslog2  //传递的第二个域名不符合格式报错 
  14. usage: ./named4.sh [option] 
  15. option: 
  16. -d dn1 dn2 ...  :input your domain names 
  17. [root@RHEL6U3-9 named.sh]# ./named4.sh -d rsyslog1.net rsyslog2.net  //正确传递两个域名,后面还可以跟域名 
  18. Stopping named: .                                          [  OK  ] 
  19. Starting named:                                            [  OK  ] 
  20. Server:     192.168.100.109 
  21. Address:    192.168.100.109#53 
  22.  
  23. Name:   rsyslog1.net 
  24. Address: 192.168.100.109 
  25.  
  26. Server:     192.168.100.109 
  27. Address:    192.168.100.109#53 
  28.  
  29. Name:   rsyslog2.net 
  30. Address: 192.168.100.109 

 

步骤5、继续完善脚本中存在的各种情况,最终达到生产环境要求

1、   加复杂文件锁,防止脚本被重复执行或者系统宕机再次被执行

2、   ……………..

待续.......................

 


本文转自凌激冰51CTO博客,原文链接:http://blog.51cto.com/dreamfire/1156189,如需转载请自行联系原作者