前言 本文主要总结编写shelll脚本时会遇到的一些坑,另外总结shell编程中如何实现外部传参。
shell编程 注意事项 .sh文件头部需要添加如下信息,笔者曾因为漏写了bin前面的/,执行时出现各种未知问题。
注意.sh文件的编码格式,打开.sh文件
不进入.sh文件的编辑模式,输入如下命令然后回车查看文件格式
文件编码的格式必须如下所示,为unix类型。如果是dos类型,执行脚本时可能会报错。
注意重定向和追加的区别
1 2 3 4 # 将输出内容重定向至test.log,此时test.log内容被覆盖为新内容。 $ echo "This is a Test." > /var/test.log # 追加到test.log文件的内容后,不覆盖原有内容 $ echo "Test for >>" >> /var/test.log
常用函数理解 shift函数 主要用来左移位置参数。比如执行shift 2命令表示将原来的外部参数\$3变成\$1,原来的\$1和\$2被丢弃。而不带参数的shift命令相当于shift 1。创建test_shift.sh文件,内容如下所示。
1 2 3 4 5 6 #!/bin/sh until [$# -eq 0] do echo "第一个参数为:$1 ,参数个数为:$# " shift done
执行脚本
getopt函数 这里讲的getopt函数其实就是Linux系统的getopt命令,它主要用来传递参数,支持长参数和短参数。
在Linux命令中,给命令附上不同的参数,命令能够实现不同的功能,比如下面的例子。
有时候我们需要在自己写的shell脚本上实现外部传参时,就需要用到getopt这个函数。执行如下命令查看帮助信息。比较常用的的是-a,-l,-o等选项。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ getopt -h Usage: getopt <optstring> <parameters> getopt [options] [--] <optstring> <parameters> getopt [options] -o|--options <optstring> [options] [--] <parameters> Parse command options. Options: -a, --alternative allow long options starting with single - -l, --longoptions <longopts> the long options to be recognized -n, --name <progname> the name under which errors are reported -o, --options <optstring> the short options to be recognized -q, --quiet disable error reporting by getopt(3) -Q, --quiet-output no normal output -s, --shell <shell> set quoting conventions to those of <shell> -T, --test test for getopt(1) version -u, --unquoted do not quote the output -h, --help display this help -V, --version display version
-o后面为短参数,-l后面为长参数。具体这两者没什么区别。不过按照约定俗称,-后面接单个字母不带参数值,–后面接单词,带参数值。例如下面内容所示,其中短参数t后面可以带参数值,而长参数help,version不能带参数值。
1 2 argv=`getopt -a -o hv,t: -l name:,age:,help,version -- $@` eval set -- $argv
创建test_getopt.sh文件,内容如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #!/bin/sh argv=`getopt -a -o hv -l name:,age:,help ,version -- $@ ` eval set -- $argv help (){ Usage="Usage: $0 \n\ options:\n\ [--name] \t ---your name\n \ [--age] \t ---your age\n \" } #函数,打印此shell脚本的版本 show_version() { echo " Version1.0" } #给定参数默认参数值 Name=" " Age=0 #解析外部传参数,将外部传入的参数值赋给内部变量 while true do case $i in: --name) Name=$2 shift 2 ;; --age) Age=$2 shift 2 ;; -h | --help) help shift ;; -v | --version) show_version shitf ;; --) break ;; esac done if [-n $Name -a $Age -eq 0] then echo " Hello,My Name is $Name ." elif [-n $Name -a $Age -nq 0] then echo " Hello,My Name is $Name .I am $Age " fi
外部传参并执行test_getopt.sh文件
1 2 3 $ chmod +x test_getopt.sh $ ./test_getopt.sh -h $ ./test_getopt.sh --name Alan --age 19
代码实例 实例一 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 #!/bin/sh help (){ Usage="Usage: $0 \n\ Options:\n\ [--intf if_name] \t-- W522U接口名称,默认为ra0\n \ [--scan 2.4/5] \t-- 扫描无线列表信息(扫描2.4G或5G无线列表)\n \ [--ssid ssid] \t\t-- 连接SSID\n \ [--workhz 2.4/5] \t-- 连接无线的频段,默认2.4G\n \ [--channel 信道] \t-- 设置信道\n \ [--authmode mode] \t-- 认证模式 取值范围\"OPEN, SHARED, WPAPSK, WPA2PSK\"\n \ [--encryptype type] \t-- 加密类型 取值范围\"NONE, TKIP, AES, WEP\"\n \ [--wpapsk wpa密码] \t-- WPA密码\n \ [--defkeyid num] \t-- wep默认密码\n \ [--key1 wep密码1] \t-- wep密码1\n \ [--key2 wep密码2] \t-- wep密码2\n \ [--key3 wep密码3] \t-- wep密码3\n \ [--key4 wep密码4] \t-- wep密码4\n \ [-h | --help] \t\t-- 显示此帮助信息\n \ " echo -e $Usage } normal='\033[0m' ;red='\033[31m' ;green='\033[32m' ;yellow='\033[33m' Intf="ra0" Scan="0" WorkHz="2.4" SSID="" Channel="" AuthMode="OPEN" EncrypType="NONE" WpaPsk="" DefKeyId="1" Key1="12345" Key2="12345" Key3="12345" Key4="12345" OPTIND=1 argv=`getopt -a -o h -l intf:,scan:,ssid:,channel:,workhz:,authmode:,encryptype:,wpapsk:,defkeyid:,key1:,key2:,key3:,key4:,help -- $@ ` if [ "$?" != "0" ]then help exit 127 fi eval set -- $argv while true do case "$1 " in --intf) Intf=$2 shift 2 ;; --scan) if [ "$2 " == "2.4" -o "$2 " == "5" ] then Scan=$2 else help exit 0 fi shift 2 ;; --ssid) SSID=$2 shift 2 ;; --channel) Channel=$2 shift 2 ;; --workhz) WorkHz=$2 shift 2 ;; --authmode) AuthMode=$2 shift 2 ;; --encryptype) EncrypType=$2 shift 2 ;; --wpapsk) WpaPsk=$2 shift 2 ;; --defkeyid) DefKeyId=$2 shift 2 ;; --key1) Key1=$2 shift 2 ;; --key2) Key2=$2 shift 2 ;; --key3) Key3=$2 shift 2 ;; --key4) Key4=$2 shift 2 ;; -h | --help ) help exit 0 shift ;; --) break ;; esac done :<<BLOCK echo -e ${green} echo Scan=$Scan echo SSID=$SSID echo WorkHz=$WorkHz echo AuthMode=$AuthMode echo EncrypType=$EncrypType echo WpaPsk=$WpaPsk echo DefKeyId=$DefKeyId echo Key1=$Key1 echo Key2=$Key2 echo Key3=$Key3 echo Key4=$Key4 echo -e ${normal} BLOCK ifconfig $Intf up if [ "$Scan " != "0" ]then WirelessMode=`iwpriv $Intf show WirelessMode |awk '{print $3}' ` case $WirelessMode in "11B" ) WirelessMode="1" ;; "11A" ) WirelessMode="2" ;; "11A/B/G" ) WirelessMode="3" ;; "11G" ) WirelessMode="4" ;; "11A/B/G/N" ) WirelessMode="5" ;; "11N" ) WirelessMode="6" ;; "11G/N" ) WirelessMode="7" ;; "11A/N" ) WirelessMode="8" ;; "11B/G/N" ) WirelessMode="9" ;; "11A/G/N" ) WirelessMode="10" ;; esac SSID=`iwpriv $Intf show SSID |awk '{print $3}' ` AuthMode=`iwpriv $Intf show AuthMode |awk '{print $3}' ` EncrypType=`iwpriv $Intf show EncrypType |awk '{print $3}' ` WpaPsk=`iwpriv $Intf show WPAPSK |awk '{print $5}' ` DefKeyId=`iwpriv $Intf show DefaultKeyID |awk '{print $3}' ` Key1=`iwpriv $Intf show Key1 |awk '{print $3}' ` Key2=`iwpriv $Intf show Key2 |awk '{print $3}' ` Key3=`iwpriv $Intf show Key3 |awk '{print $3}' ` Key4=`iwpriv $Intf show Key4 |awk '{print $3}' ` iwpriv $Intf set SSID="" :<<BLOCK echo -e ${yellow} echo WirelessMode=$WirelessMode echo SSID=$SSID echo AuthMode=$AuthMode echo EncrypType=$EncrypType echo WpaPsk=$WpaPsk echo DefKeyId=$DefKeyId echo Key1=$Key1 echo Key2=$Key2 echo Key3=$Key3 echo Key4=$Key4 echo -e ${normal} BLOCK if [ "$Scan " == "2.4" ] then iwpriv $Intf set WirelessMode="9" iwpriv $Intf set CountryRegion="5" else iwpriv $Intf set WirelessMode="8" iwpriv $Intf set CountryRegion="7" fi echo -e ${green} "正在使用W522U扫描${Scan} G无线信号..." ${normal} sleep 4 iwpriv $Intf get_site_survey iwpriv $Intf set WirelessMode="${WirelessMode} " &>/dev/null iwpriv $Intf set SSID="${SSID} " &>/dev/null iwpriv $Intf set CountryRegionABand="7" &>/dev/null iwpriv $Intf set CountryRegion="5" &>/dev/null iwpriv $Intf set AuthMode="${AuthMode} " &>/dev/null iwpriv $Intf set EncrypType="${EncrypType} " &>/dev/null iwpriv $Intf set WPAPSK="${WpaPsk} " &>/dev/null iwpriv $Intf set DefaultKeyID="${DefKeyId} " &>/dev/null iwpriv $Intf set Key1="${Key1} " &>/dev/null iwpriv $Intf set Key2="${Key2} " &>/dev/null iwpriv $Intf set Key3="${Key3} " &>/dev/null iwpriv $Intf set Key4="${Key4} " &>/dev/null exit 0 fi if [ "$WorkHz " == "2.4" ]then iwpriv $Intf set WirelessMode="9" else iwpriv $Intf set WirelessMode="8" fi if [ "$Channel " != "" ]then iwpriv $Intf set Channel="${Channel} " &>/dev/null fi iwpriv $Intf set SSID="${SSID} " &>/dev/null iwpriv $Intf set CountryRegionABand="7" &>/dev/null iwpriv $Intf set CountryRegion="5" &>/dev/null iwpriv $Intf set AuthMode="${AuthMode} " &>/dev/null iwpriv $Intf set EncrypType="${EncrypType} " &>/dev/null iwpriv $Intf set WPAPSK="${WpaPsk} " &>/dev/null iwpriv $Intf set DefaultKeyID="${DefKeyId} " &>/dev/null iwpriv $Intf set Key1="${Key1} " &>/dev/null iwpriv $Intf set Key2="${Key2} " &>/dev/null iwpriv $Intf set Key3="${Key3} " &>/dev/null iwpriv $Intf set Key4="${Key4} " &>/dev/null echo -e ${green} "正在使用W522U ${WorkHz} G连接SSID:${SSID} " ${normal} suctime=0 for ((i=1;i<=45;i++))do result=`iwpriv $Intf connStatus |grep Disconnected |wc -m` if [ "$result " == "0" ] then suctime=`expr $suctime + 1` if [ "$suctime " -ge "3" ] then break fi fi sleep 1 done iwpriv $Intf connStatus if [ "$i " -ge "46" ]then echo Link Fail else echo Link Suc fi exit 0
实例二 主要实现配置PPPoE server的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 # !/bin/sh # config_PppoeSerCfg.sh # --------------------------------------------------------------------- # FileName: config_PppoeSerCfg.sh # Version: V1.0 # Description: 编辑PPPoE服务器配置文件 # # History: # <author> <time> <version > <desc> # --------------------------------------------------------------------- help() { Usage="Usage: config_PppoeSerCfg.sh\n\ Options:\n\ [--auth pap|chap|mschap|mschap-v2] \t-- 配置认证方式,默认为chap加密\n \ [--mppe type] \t\t\t\t-- MPPE加密要求,type[40,128,both],若开启此选项,认证协议将自动使用mschap-v2协议\n \ [--mtu num] \t\t\t\t-- 配置MTU值选项\n \ [--mru num] \t\t\t\t-- 配置MRU值选项,0为拒绝协商\n \ [--echointerval num] \t\t\t-- 配置维链次数选项,默认12\n \ [--echofailure num] \t\t\t-- 配置维链失败次数选项,默认8s\n \ [--dns dnsip] \t\t\t\t-- 配置下发的DNS地址\n \ [--wins winsip] \t\t\t-- 配置下发的WINS地址\n \ [--custom args] \t\t\t-- 添加自定义参数,按pppoe-server配置文件格式即可\n \ [-o options file] \t\t\t-- 输出到配置文件(默认:/etc/ppp/pppoe-options\n \ [-h | --help] \t\t\t\t-- 显示此帮助信息\n \ " echo -e $Usage } # 定义公共变量 normal='\033[0m';red='\033[31m';green='\033[32m';yellow='\033[33m' tmp=0 AUTH=chap MPPE="" MRU="" MTU="" EchoInterval=12 EchoFailure=8 DNS="" dnsnum=0 WINS="" winsnum=0 CUSTOM="" #自定义参数 customnum=0 OPTDIR="" # 定义配置文件 PPPOESEROPT=/etc/ppp/pppoe-server-options # 定义选项变量 OPTIND=1 argv=`getopt -a -o o:,h -l auth:,mppe:,mtu:,mru:,echointerval:,echofailure:,dns:,wins:,custom:,help -- $@` # [ $? -ne 0 ] && (help ;exit 127) if [ "$?" != "0" ] then help exit 127 fi eval set -- $argv while true do case "$1" in --auth) if [ $2 == pap -o $2 == chap -o $2 == mschap -o $2 == mschap-v2 ] then AUTH=$2 else help exit 0 fi shift 2 ;; --mppe) if [ $2 == 40 -o $2 == 128 -o $2 == both ] then MPPE=$2 else help exit 0 fi shift 2 ;; --mtu | --mru | --echointerval | --echofailure) expr $2 + 1 &>/dev/null if [ $? -eq 0 ] # if [ `echo $2 |grep [0-9]` ] then case "$1" in --mtu) MTU=$2 ;; --mru) MRU=$2 ;; --echointerval) EchoInterval=$2 ;; --echofailure) EchoFailure=$2 ;; --) break ;; esac else help exit 0 fi shift 2 ;; --dns) DNS[$dnsnum]=$2 dnsnum=`expr $dnsnum + 1` shift 2 ;; --wins) WINS[$ winsnum]=$2 winsnum=`expr $winsnum + 1` shift 2 ;; --custom) CUSTOM[customnum]=$2 customnum=`expr $customnum + 1` shift 2 ;; -o) PPPOESEROPT=$2 shift 2 ;; -h | --help) help exit 0 shift ;; --) break ;; esac done echo -e ${green}auth=$AUTH echo MPPE=$MPPE echo MTU=$MTU echo MRU=$MRU echo EchoInterval=$EchoInterval echo EchoFailure=$EchoFailure for((i=0;i<$dnsnum;i++)) do echo DNS[$i]=${DNS[$i]} done for((i=0;i<$winsnum;i++)) do echo WINS[$i]=${WINS[$i]} done for((i=0;i<customnum;i++)) do echo CUSTOM[$i]=${CUSTOM[$i]} done echo PPPOESEROPT=$PPPOESEROPT echo -e ${normal} # 重新创建配置文件 OPTDIR=`expr ${PPPOESEROPT%/*}` mkdir -p ${OPTDIR} rm -rf $PPPOESEROPT echo "# PPP options for the PPPoE server" > $PPPOESEROPT echo "# LIC: GPL" >> $PPPOESEROPT if [ $MPPE ] then echo "refuse-pap" >> $PPPOESEROPT echo "refuse-chap" >> $PPPOESEROPT echo "refuse-mschap" >> $PPPOESEROPT echo "require-mschap-v2" >> $PPPOESEROPT if [ $MPPE == "both" ] then echo "require-mppe" >> $PPPOESEROPT else echo "require-mppe-${MPPE}" >> $PPPOESEROPT fi else case "$AUTH" in pap) echo "require-pap" >> $PPPOESEROPT echo "refuse-chap" >> $PPPOESEROPT echo "refuse-mschap" >> $PPPOESEROPT echo "refuse-mschap-v2" >> $PPPOESEROPT ;; chap) echo "refuse-pap" >> $PPPOESEROPT echo "require-chap" >> $PPPOESEROPT echo "refuse-mschap" >> $PPPOESEROPT echo "refuse-mschap-v2" >> $PPPOESEROPT ;; mschap) echo "refuse-pap" >> $PPPOESEROPT echo "refuse-chap" >> $PPPOESEROPT echo "require-mschap" >> $PPPOESEROPT echo "refuse-mschap-v2" >> $PPPOESEROPT ;; mschap-v2) echo "refuse-pap" >> $PPPOESEROPT echo "refuse-chap" >> $PPPOESEROPT echo "refuse-mschap" >> $PPPOESEROPT echo "require-mschap-v2" >> $PPPOESEROPT ;; *) echo "refuse-pap" >> $PPPOESEROPT echo "require-chap" >> $PPPOESEROPT echo "refuse-mschap" >> $PPPOESEROPT echo "refuse-mschap-v2" >> $PPPOESEROPT ;; esac fi if [ $MRU ] then if [ $MRU == 0 ] then echo "-mru" >> $PPPOESEROPT else echo "mru $MRU" >> $PPPOESEROPT fi fi if [ $MTU ] then echo "mtu $MTU" >> $PPPOESEROPT fi echo "lcp-echo-interval $EchoInterval" >> $PPPOESEROPT echo "lcp-echo-failure $EchoFailure" >> $PPPOESEROPT for((i=0;i<$dnsnum;i++)) do echo "ms-dns ${DNS[$i]}" >> $PPPOESEROPT done for((i=0;i<$winsnum;i++)) do echo "ms-wins ${WINS[$i]}" >> $PPPOESEROPT done for((i=0;i<$customnum;i++)) do echo "${CUSTOM[$i]}" >> $PPPOESEROPT done exit 0