學習Linux已經有一周半了,在馬哥的強壓下,寫了二十幾個shell指令碼。。。shellRegex,awk語句,程式執行流,test語句,sed語句,函數還有一些其他的小命令,如tr,grep,cut,wc等等。越發覺得shell指令碼的可愛,沒錯,是可愛!因為它的快速上手,迷人的Regex,變換莫測的程式執行流和awk語句,還有強大的功能,很難想象這麼簡單的語言和linux如此完美的結合在一起,好像是linux的可愛的“妻子”。
聽馬哥說,中國的程式員並不是不如印度,國際上很多編程大賽,中國程式員都拿獎,但是軟體外包卻不如印度。並不是他們編的程式好,而是中國的程式員編程有點“豆腐渣程——只把要求實現的功能都實現了,其他的不管了。。。同樣是一個小程式,印度人可能寫幾百行,上前行,而中國人唯寫幾十行。。並不是人家不能寫那麼短,而是為了“使用者體驗”。
廢話不說了,切入正題。
###########################
shell指令碼中的細節:
首先是變數的運用:有時候我們不得不多次輸入一個路徑,這個時候我們就可以把路徑定義成變數,例如:FILE=/etc/passwd,在使用時用$FILE引用即可。這個技巧很好用,但是當一個指令碼有多個路徑或多個變數的時候,變數的名字會容易記混,或者打錯。所以,在我看來變數的使用原則如下:
1. 盡量避免引用過多的變數,不能貪多,否則整個指令碼充滿了變數,反而不易讀懂。
2. 變數是用來使整個指令碼變的方便的,所有應該是出現多次的參數才需要變數來引用。
3. 變數的名字應該易讀,易記,易輸入,盡量避免過於相似的變數。
4. 有些時候,變數需要在一個指令碼中被多次重新賦值,但要注意使用,否則容易出錯。
所有的語句都需要精簡嗎?
以前我一直認為,代碼要短越好,這樣執行效率會更高,但是現在有一個問題,再好的代碼,如果容易“崩潰”的話,再精簡有什麼用?有些時候,不得不在完成程式功能的基礎上考慮程式的可用性。比如當使用者輸入錯誤怎麼辦,使用者中突退出怎麼辦,使用者輸入的資料怎麼是否需要驗證。比如,你一個不懂網路知識的人誤將IP地址和GATEWAY設為不同的網段,那麼這個操作就會造成無法接入互連網。舉個例子
寫一個指令碼:
1、提示使用者選擇所要設定的網卡;
2、提示使用者使用dhcp或者static作為選定網卡的BOOTPROTO
a、如果使用者選擇dhcp,則將其設定檔中的BOOTPROTO的值設為dhcp,而後重啟此網卡;
b、如果使用者選擇static,則將其設定檔中的BOOTPROTO的值設為static,並提示使用者輸入IP地址,子網路遮罩和網關;其中網關可以為空白,但IP地址或子網路遮罩不可為空;設定完成後重啟此網卡;
3、無論上述動態或靜態設定,設定完成後將網卡IP地址設定後資訊再次顯示給使用者;
我們來分析:這個程式的功能其實很簡單,只要求能夠識別使用者的輸入資訊是dhcp還是static,然後進行相應的設定,但是我來考慮:
考慮:1、如果使用者沒有做出任何修改之前就不想設定了,如何退出?
2、如果使用者已經設定了一些資訊,如IP地址等卻又不想設定了,而使用了Ctrl+c,如何處置?
3、如果使用者輸入的是錯誤的IP資訊怎麼辦?
4、如果使用者輸入的是錯誤的NETMASK怎麼辦?
5、如果使用者輸入的是不匹配的IP和GATEWAY怎麼辦?
6、如果使用者輸入的資訊已經存在怎麼辦?
7、使用者輸入的網卡是否存在?
8、萬一網卡重啟發生錯誤怎麼辦?
整個代碼如下
#!/bin/bash#建立臨時檔案和標識FLAG=0TMPFILE=`mktemp /tmp/eth.XXXXXXXX`#讀取使用者輸入read -p "Interface: " ETHCARD#判定使用者輸入的網卡是否存在ALLECARD=`ifconfig -a | awk '/^[^[:space:]l]/{print $1}'`until echo $ALLECARD | grep "$ETHCARD" &> /dev/null; do echo -e "\033[31mWrong Card name.\033[0m" read -p "Interface: " ETHCARDdone#網卡路徑的變數,以後要多次應用ETHFILE=/etc/sysconfig/network-scripts/ifcfg-$ETHCARD#判定使用者輸入的協議是否正確read -p "Boot Protocol: " MYBOOTPROTOuntil echo $MYBOOTPROTO | grep -E "dhcp|static" &> /dev/null ; do echo -e "\033[31mWrong BOOTPROTO.\033[0m" read -p "Boot Protocol: " MYBOOTPROTOdone#判定DHCP和staticif [ "$MYBOOTPROTO" == "dhcp" ]; then sed -i "s/^BOOTPROTO=.*/BOOTPROTO=dhcp/g" $ETHFILE if [ $? -eq 0 ]; then ifdown $ETHCARD && ifup $ETHCARD [ $? -eq 0 ] && echo "Set $ETHCARD done." fielif [ "$MYBOOTPROTO" == "static" ]; then cat $ETHFILE > $TMPFILE read -p "Ip Address: " MYIP#判定IP的正確性 until [[ $MYIP =~ ^([1-9]|[1-9][0-9]|1[0-9]{1,2}|2[01][0-9]|22[0-3])(\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])){2}(\.([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4]))$ ]];do echo -e "\033[31mWrong IP.\033[0m" read -p "Ip Address: " MYIP done#判定NETMASK的正確性 read -p "Netmask: " MYNM until [[ $MYNM =~ ^255(\.(0|255)){3}$ ]]; do echo -e "\033[31mWrong NetMask.\033[0m" read -p "Netmask: " MYNM done read -p "Gateway: " MYGW#判定IP與GATEWAY的匹配 for I in {1..4}; do [ $[`echo $MYIP | cut -d. -f $I`&`echo $MYNM | cut -d. -f $I`] -ne $[`echo $MYGW | cut -d. -f $I`&`echo $MYNM | cut -d. -f $I`] ] && FLAG=1 && break done until [[ $MYGW =~ ^([1-9]|[1-9][0-9]|1[0-9]{1,2}|2[01][0-9]|22[0-3])(\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])){2}(\.([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4]))$ ]] && [ $FLAG -eq 0 ];do echo -e "\033[31mWrong GateWay.\033[0m" read -p "Gateway: " MYGW for I in {1..4}; do [ $[`echo $MYIP | cut -d. -f $I`&`echo $MYNM | cut -d. -f $I`] -ne $[`echo $MYGW | cut -d. -f $I`&`echo $MYNM | cut -d. -f $I`] ] && FLAG=1 && break || FLAG=0 done done#檔案裡資訊是否存在,調用臨時檔案 sed -i "s/^BOOTPROTO=.*/BOOTPROTO=static/g" $TMPFILE grep "^IPADDR=" $TMPFILE &> /dev/null && sed -i "s/IPADDR=.*/IPADDR=$MYIP/" $TMPFILE || echo "IPADDR=$MYIP" >> $TMPFILE grep "^NETMASK=" $TMPFILE &> /dev/null && sed -i "s/NETMASK=.*/NETMASK=$MYNM/" $TMPFILE || echo "NETMASK=$MYNM" >> $TMPFILE if [ -z $MYGW ]; then sed -i '/^GATEWAY=.*/d' $TMPFILE else grep "^GATEWAY=" $TMPFILE &> /dev/null && sed -i "s/GATEWAY=.*/GATEWAY=$MYGW/" $TMPFILE || echo "GATEWAY=$MYGW" >> $TMPFILE fi cp -f $TMPFILE $ETHFILE ifdown $ETHCARD && ifup $ETHCARD [ $? -eq 0 ] && echo "Set $ETHCARD done."else echo "No such options." exit 1fi#刪除臨時檔案,避免臨時檔案過多 rm -f $TMPFILE