適合系統管理新手的 bash 腳本編程

UNIX shell 實質上是用戶、內核和系統硬件之間的接口。在任何 UNIX 或 Linux 系統上,shell 都是很是重要的,是學習正確的系統管理和安全保護最關鍵的方面之一。shell 一般由 CLI 驅動,能夠直接控制或破壞系統。本文討論的開放源碼的 bash shell 是最強大、最實用、可擴展性最好的 shell 之一。在本文中,您將學習 bash 腳本編程的基本技術、平常使用方法以及用它建立可靠的 shell 腳本的方法。
經常使用縮略詞
API:應用程序編程接口
CLI:命令行接口
SNMP:簡單網絡管理協議
bash shell 的歷史
Bourne Again Shell (bash) 誕生於 1987 年,是做爲 GNU 項目開發的,許多 Linux 發行版很快就採用了它。當前,有許多不一樣的 bash 版本可無償使用。
bash 的優勢之一是它具備內置的安全特性。bash 會準確地記錄用戶輸入的命令,並把記錄寫到用戶主目錄中的隱藏文件 .bash_history 中。所以,若是實現 bash,就很容易更緊密地跟蹤系統用戶。實際上,對於許多 Linux 系統,bash 經常是預安裝的默認 shell 環境。
bash 的命令語法和關鍵詞源於 Korn shell (ksh) 和 C shell (csh) 的架構和技術細節並作了改進。另外,bash 的語法具備其餘 shell 所沒有的許多擴展。與其餘 shell 相比,bash 中的整數計算更高效,並且 bash 能夠更方便地重定向標準輸出(stdout)和標準錯誤(stderr)。
bash 還很是適合於安全性要求高的環境,它具備受限制的啓動模式,能夠把 shell 中的用戶限制爲只能執行一組肯定的命令。能夠經過編輯本身的 bash shell 登陸控制文件(即 .bashrc、.bash_profile、.bash_logout 和 .profile 等隱藏文件)定製登陸 shell。
回頁首
bash shell 的用法和功能
要想編寫有效的 bash shell 腳本,就必須掌握在 shell 中執行導航和平常任務的基本 bash 命令集。
bash 登陸過程
在登陸時,用戶一般執行一個全局概要文件和兩個我的文件(.bash_profile 和 .bashrc)。圖 1 顯示一般的過程。
圖 1. bash shell 登陸過程
bash shell 登陸過程
如今,看看 Linux 用戶典型的 .bash_profile(清單 1)和 .bashrc(清單 2)腳本。這些腳本是從用戶的主目錄裝載的。
清單 1. 典型的 .bash_profile 文件html

[fred.smythe@server01 ~]$ cat .bash_profile
  # .bash_profile

  # Get the aliases and functions
  if [ -f ~/.bashrc ]; then
          . ~/.bashrc
  fi

  # User specific environment and startup programs
  export JAVA_HOME=/usr/java/default
  export PATH=$JAVA_HOME/bin:$PATH

  PATH=$PATH:$HOME/bin

  export PATH

在 清單 2 中的 .bashrc 文件中,配置了一些用戶別名並裝載了全局 bashrc 文件(若是存在的話)。
清單 2. 典型的 .bashrc 文件java

[fred.smythe@server01 ~]$ cat .bashrc
  # .bashrc

  # User specific aliases and functions

  alias rm='rm -i'
  alias cp='cp -i'
  alias mv='mv -i'
  alias tc6='cd /opt/tomcat/6.0.13'
  alias conf6='cd /opt/tomcat/6.0.13/conf'
  alias bin6='cd /opt/tomcat/6.0.13/bin'
  alias scr='cd /opt/tomcat/scripts'
  alias reports='cd /opt/tomcat/reports'
  alias temp6='cd /opt/tomcat/6.0.13/template'

  # Source global definitions
  if [ -f /etc/bashrc ]; then
          . /etc/bashrc
  fi

在 圖 2 中能夠看到登陸過程的細節。
圖 2. bash shell 登陸過程細節
bash shell 登陸過程細節
在此以後,用戶就可使用 bash shell 環境變量 $PATH 中指定的標準命令集。若是某個命令不在用戶的 $PATH 中,可是該用戶有執行此命令的權限,那麼必須使用完整的路徑,見 清單 3。
清單 3. bash shell 中的 $PATH 問題示例git

[fred.smythe@server01 ~]$ ifconfig -a
  -bash: ifconfig: command not found
  [fred.smythe@server01 ~]$ which ifconfig
  /usr/bin/which: no ifconfig in (/usr/local/bin:/bin:/usr/bin:/home/fred.smythe/bin)

出現此問題的緣由是二進制程序 ifconfig 不在用戶定義的 PATH 變量中。可是,若是知道此命令的完整路徑,就能夠像 清單 4 這樣執行它。
清單 4. 使用命令的完整路徑解決 bash shell 中的 $PATH 問題web

[fred.smythe@server01 ~]$ /sbin/ifconfig -a
  eth0      Link encap:Ethernet  HWaddr 00:50:56:96:2E:B3
            inet addr:10.14.33.60  Bcast:10.14.33.255  Mask:255.255.255.0

清單 5 演示一種使用別名解決此問題的方法。在 bash 腳本中,可能但願用完整路徑運行命令,這取決於誰將運行腳本。
清單 5. 經過設置別名解決 bash shell 中的 $PATH 問題
[fred.smythe@server01 ~]$ alias ifconfig='/sbin/ifconfig'
[fred.smythe@server01 ~]$ ifconfig
eth0 Link encap:Ethernet HWaddr 00:50:56:96:2E:B3
inet addr:10.14.33.60 Bcast:10.14.33.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
forking
命令或 bash shell 自己可能啓動(或生成)新的 shell 子進程以執行某一任務,這稱爲 forking。當這個新進程(子進程)正在執行時,父進程仍然在運行。若是父進程先於子進程死亡,那麼子進程就成了死進程(也稱爲殭屍進程 ),這經常會致使進程或應用程序掛起。所以,必須以很是規方法殺死或終止掛起的進程。儘管父進程能夠訪問其子進程的進程 ID 並向它傳遞參數,可是反過來不行。當 shell 腳本進程退出或返回到父進程時,退出碼應該是 0。若是是其餘值,那麼進程極可能出現了錯誤或問題。
執行的最後一個命令的退出碼(echo $?)見 清單 6。
清單 6. 退出碼示例shell

# ls -ld /tmp
  drwxrwxrwt 5 root root 4096 Aug 19 19:45 /tmp
  [root@server01 ~]# echo $?
  0     // Good command return of 0.
  [root@server01 ~]# ls -l /junk
  ls: /junk: No such file or directory
  [root@server01 ~]# echo $?

2 // Something went wrong, there was an error, so return 2.
清單 7 演示 bash 環境中的父進程和子進程。
清單 7. bash 環境中的父進程和子進程示例apache

[root@server02 htdocs]# ps -ef | grep httpd
  UID       PID   PPID  C STIME TTY      TIME      CMD
  root      8495     1  0 Jul26 ?        00:00:03 /usr/sbin/httpd -k start 
  apache    9254  8495  0 Aug15 ?        00:00:00 /usr/sbin/httpd -k start

瞭解本身的環境
若是輸入命令 env,就會看到 bash shell 默認環境變量當前設置的值,包括您的用戶名和 tty(終端)信息、$PATH 值和當前工做目錄($PWD)。請看一下 清單 8。
清單 8. bash 環境的示例編程

[fred.smythe@server01 ~]$ env
HOSTNAME=server01
TERM=screen
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=10.12.132.3 56513 22
SSH_TTY=/dev/pts/0
USER=fred.smythe
LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05
;37;41:mi=01;05;37;41:ex=01;32:.cmd=01;32:.exe=01;32:.com=01;32:.btm=01;32:.bat=01;32
:
.sh=01;32:.csh=01;32:.tar=01;31:.tgz=01;31:.arj=01;31:.taz=01;31:.lzh=01;31:.zip=
01;31:
.z=01;31:.Z=01;31:.gz=01;31:.bz2=01;31:.bz=01;31:.tz=01;31:.rpm=01;31:.cpio=
01;31:
.jpg=01;35:.gif=01;35:.bmp=01;35:.xbm=01;35:.xpm=01;35:.png=01;35:.tif=01;35:
MAIL=/var/spool/mail/fred.smythe
PATH=/usr/local/bin:/bin:/usr/bin:/home/fred.smythe/bin
INPUTRC=/etc/inputrc
PWD=/home/fred.smythe
LANG=en_US.UTF-8
SHLVL=1
HOME=/home/fred.smythe
LOGNAME=fred.smythe
SSH_CONNECTION=10.14.43.183 56513 10.14.43.43 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
文件系統導航
可使用 清單 9 所示的 bash 命令導航 Linux 文件系統。
清單 9. 在 bash 環境中導航
[fred.smythe@server01 ~]$ ls -l
total 0
[fred.smythe@server01 ~]$ cd /tmp
[fred.smythe@server01 tmp]$ df -ha .
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg_root-lv_tmp
2.0G 68M 1.8G 4% /tmp
在此清單中,每次只執行一個命令。可是,也可使用分號(;)分隔符一塊兒運行它們,見 清單 10。
清單 10. 在 bash 中連續執行命令
[fred.smythe@server01 tmp]$ ls -l ;cd /tmp;df -ha .
total 40
-rw-r----- 1 root root 1748 May 22 2009 index.html
-rw-r----- 1 root root 786 Aug 17 04:59 index.jsp
drwx------ 2 root root 16384 Jul 15 2009 lost+found
drwx------ 2 root root 4096 Aug 9 21:04 vmware-root
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg_root-lv_tmp
2.0G 68M 1.8G 4% /tmp
[fred.smythe@server01 tmp]$
在 bash 命令行上,命令補全特性能夠減小平常任務所需的輸入量。只需輸入命令的開頭,而後按 Tab 鍵。注意,若是因爲權限限制沒法訪問某個命令或文件,那麼命令補全也無效。
回頁首
在 bash 中得到幫助
bash 提供幾種形式的幫助:
man(見 清單 11):
清單 11. bash 中的手冊頁示例
[fred.smythe@server01 tmp]$ man perl
PERL(1) Perl Programmers Reference Guide PERL(1)數組

NAME
perl - Practical Extraction and Report Languagetomcat

SYNOPSIS
perl [ -sTtuUWX ] [ -hv ] [ -V[:configvar] ] -cw ] [ -d[t][:debugger] ] [ -D
[num- ber/list] ] [ -pna ] [ -Fpattern ] [ -l[octal] ] [ -0[octal/hexadecimal] ]
[ -Idir ] [ -m[-]module ] [ -M[-] module... ] [ -f ] [ -C [number/list] ]
[ -P ] [ -S ] [ -x[dir] ] [ -i[extension] ] [ -e command ] [ -- ]
[ program- file ] [ argument ]...
whatis(見 清單 12):
清單 12. bash 中的 whatis 命令示例
[fred.smythe@server01 tmp]$ whatis perl
perl (1) - Practical Extraction and Report Language
perl (rpm) - The Perl programming language
apropos(見 清單 13):
清單 13. bash 中的 apropos 示例
[root@server01 ~]# apropos perl | more
B (3pm) - The Perl Compiler
B::Asmdata (3pm) - Autogenerated data about Perl ops,
used to generate bytecode
B::Assembler (3pm) - Assemble Perl bytecode
which(見 清單 14):
清單 14. bash 中的 which 命令
[root@server01 ~]# which perl
/usr/bin/perl
bash shell 包含兩類命令:內部的內置命令 和外部程序(或外部篩選器和命令,它們一般是自含的二進制程序文件)。清單 15 說明如何使用 alias 命令在 bash 中尋找內置命令。
清單 15. 在 bash 中尋找內置命令
[root@server01 ~]# man -k builtins| more
. [builtins] (1) - bash built-in commands, see bash(1)
: [builtins] (1) - bash built-in commands, see bash(1)
[ [builtins] (1) - bash built-in commands, see bash(1)
alias [builtins] (1) - bash built-in commands, see bash(1)
bash [builtins] (1) - bash built-in commands, see bash(1)
bg [builtins] (1) - bash built-in commands, see bash(1)
bind [builtins] (1) - bash built-in commands, see bash(1)
break [builtins] (1) - bash built-in commands, see bash(1)
builtin [builtins] (1) - bash built-in commands, see bash(1)
可使用 type 命令在 bash 中尋找特定的命令,見 清單 16。
清單 16. 使用 type 命令尋找內置命令
[root@apache-02 htdocs]# type lsof
lsof is /usr/sbin/lsof
[root@apache-02 htdocs]# type alias
alias is a shell builtin
清單 17 給出外部命令 lsof 的示例。此命令其實是駐留在 Linux 文件系統中的二進制文件;它是經過同名的包安裝的。
清單 17. 在 bash 中尋找外部命令詳細信息
[root@server01 ~]# which lsof
/usr/sbin/lsof
[root@server01 ~]# rpm -qa lsof-4.78-3.i386
[root@server01 ~]# rpm -qa lsof
lsof-4.78-3.i386
即時 bash 腳本編程
bash shell 最強大的特性之一是容許即時命令行腳本編程。好比 清單 18 中的示例,它設置一個 shell 變量,檢查變量的值,若是值大於零,就自動地執行另外一個命令。
清單 18. 用 bash 進行即時腳本編程
[fred.smythe@server01 ~]$ DEBUG=1
[fred.smythe@server01 ~]$ test $DEBUG -gt 0 && echo "Debug turned on"
Debug turned on
下面是即時編寫的 for 循環示例(見 清單 19)。注意,這裏在 shell 提示下交互地輸入;在每一個 > 後面,輸入交互式 shell 腳本的下一行。
清單 19. 在 bash 中即時編寫的 for 循環
$ for SVR in 1 2 3安全

do
echo server0$SVR.example.com
done
server01.example.com
server02.example.com
server03.example.com
注意,也能夠將此代碼做爲分號分隔的連續命令予以運行。
使用關鍵詞
for 命令並非程序,而是稱爲關鍵詞 的特殊內置命令。Linux 上通常 bash 版本的關鍵詞列表見 清單 20。
清單 20. bash 中的關鍵詞
true, false, test, case, esac, break, continue, eval, exec, exit, export, readonly,
return, set, shift, source, time, trap, unset, time, date, do, done, if, fi, else, elif,
function, for, in, then, until, while, select
在爲 shell 變量選擇名稱時,應該避免使用這些關鍵詞(也稱爲 bash shell 保留字)。
在 bash 中用管道輸送命令
bash shell 容許重定向 Linux 或 UNIX 系統上的標準輸入、標準輸出和標準錯誤。請看 清單 21 中的示例。
清單 21. 在 bash 中用管道輸送命令
$ USER="fred.smythe"
$ echo -n "User $USER home is: " && cat /etc/passwd | grep $USER | awk -F: '{print $6}'
User fred.smythe home is: /home/fred.smythe
$

Re-direction of standard output (>) of the date command to a file :

[root@server01 ~]# date > /tmp/today.txt
[root@server01 ~]# cat /tmp/today.txt
Thu Aug 19 19:38:33 UTC 2010

Re-direction of standard input (<) to standard output (>) …

[root@server01 ~]# cat < /tmp/today.txt > /tmp/today.txt.backup
[root@server01 ~]# cat /tmp/today.txt.backup
Thu Aug 19 19:38:33 UTC 2010
複合命令行
複合命令行可使用和組合標準輸入、標準輸出和標準錯誤重定向和/或管道的多個實例,從而執行具備較高準確性的複雜操做。清單 22 提供一個示例。
清單 22. 在 bash 中執行重定向的示例

command1 < input_file1.txt > output_file1.txt

command1 | command2 | command3 > output_file.log

例如,經過使用複雜的組合命令行,能夠搜索找到的全部壓縮的錯誤日誌並統計錯誤數量,由此查明 Apache 拒絕權限錯誤的數量。
$ find ./ -name 'error_log.*.gz' | xargs zcat | grep 'Permission denied'| wc -l
3
回頁首
編寫高質量的 bash 腳本
要想完成生產質量或企業級的腳本編程,必須記住如下幾個要點:
必定要用簡短的標題註釋腳本。
要加上足夠的註釋,這樣之後就能夠輕鬆地想起原來編寫代碼的緣由。請記住,腳本的第一行必須是 #!/bin/bash 行。
應該把腳本的操做記錄在日誌文件中並加上日期和時間戳,以便往後檢查。輸出應該很詳細,應該記錄成功消息並清楚地表述錯誤消息或條件。記錄腳本的啓動和中止時間也可能有意義。可使用 tee 命令把消息同時寫到日誌和標準輸出:
DATEFMT=date "+%m/%d/%Y %H:%M:%S"
echo "$DATEFMT: My message" | tee -a /tmp/myscript.log
若是腳本要寫入日誌文件,那麼應該建立新的日誌文件,並在日誌文件名中包含日期、小時、分鐘甚至秒。這樣的話,在每次運行腳本時,可使用簡單的 find 命令循環和壓縮腳本的日誌:
DATELOG=date "+%m%d%y"
LOGFILE="/data/maillog/mail_stats.log.$DATELOG"

gzip the old mail_stats logs, older than 7 days

find /logs -type f -name "mail_stats.log.????????????" -mtime +7 | xargs gzip -9

# remove the old gzipped mail_stats logs after 30 days 
        find /logs -type f -name "mail_stats.log.*.gz" -mtime +30 -exec rm {} \;
    
        # mail_log utility log resets

echo "" > /var/log/mail_stats.log.$DATELOG
應該在腳本中加入錯誤檢查邏輯,不要假設任何東西是正確的。這樣作會減小往後的不少麻煩和挫折。
儘量在腳本中使用函數和 shell 腳本庫(經過導入另外一個腳本)。這樣作能夠重用通過測試的可靠的代碼,避免重複編寫腳本代碼並減小錯誤。
要對用戶提供的輸入參數進行篩選:
NUMPARAMETERS="$#"
if [ $NUMPARAMETERS != 3 ];then
echo "Insufficient number of parameter passed!」
echo 「Please run script in format ./myscript.sh $1 $2 $3」
exit 2
fi
考慮在腳本中增長調試模式或功能 — 好比使用 set –x 命令。
在腳本中添加對某些事件發出警報的功能。可使用 SNMP 命令或聽獲得的鈴聲(echo x)發出警報,而後用 mail 命令發送電子郵件。
若是用戶將像使用交互式菜單那樣使用您編寫的腳本,那麼要考慮用戶的環境 shell 和他們有權訪問的命令。若是不肯定,那麼腳本中的全部命令都應該使用完整路徑。
在 bash shell 腳本中添加獨特的返回碼。這樣的話,在編寫大腳本時,能夠根據返回碼輕鬆地找到發生錯誤或問題的準確位置:
if [ 「$ERRCHECK」 != 「」 ];then
echo 「Error Detected : $ERRCHECK ! Cannot continue, exit $EXITVAL value」
exit $EXITVAL
fi
在試驗室環境中,針對可能出現的全部狀況全面測試腳本。還應該讓其餘用戶對腳本執行測試,讓他們故意嘗試 「破壞」 腳本。
若是腳本操做來自用戶或數據輸入文件的輸入數據,那麼必定要全面篩選、檢查和檢驗輸入數據。操做數據列表的腳本應該能夠處理多個不一樣的數據列表集。
對於長時間運行的腳本,考慮在腳本中添加超時功能,以便在 n 分鐘以後終止或中止腳本:
stty –icannon min 0 time 1800
在代碼中適當地進行縮進,增長代碼的可讀性。
對於用於特殊用途的腳本,可能但願添加交互式警告提示消息,從而向用戶說明腳本的用途。例如,清單 23 中的腳本獲取遠程日誌並建立一個報告電子郵件。
清單 23. 獲取並報告日誌的簡單 bash 腳本

!/bin/bash

cd /data01/maillog

MAILSVRS=$(/bin/cat /data01/maillog/mail_servers)
DATELOG=date "+%m%d%y"
ALLMAILLOGS="/data01/maillog/all_svr_maillogs.$DATELOG"
MAILREPORT="/data01/maillog/all_svr_maillogs.report.$DATELOG"
MAILADDRESSES=$(/bin/cat /data01/maillog/addresses)
MAILADMINS="admin1@example.com, admin2@example.com"
MAILSTATSLOGALL="/data01/maillog/mailstats.log.all.$DATELOG"
DELDAYSLOGS=10

echo 「Mail Report to $ MAILADMINS」

1 - Get some logs …

for svr in $MAILSVRS
do
if [ -e "/data01/maillog/$svr.maillog.$DATELOG.gz" ]; then
/bin/rm -f /data01/maillog/$svr.maillog.$DATELOG.gz
fi
done

2 - Combine all maillogs from all servers to onefile ($ALLMAILLOGS) ...

/bin/zcat server16.maillog.$DATELOG.gz server17.maillog.$DATELOG.gz
server18.maillog.$DATELOG.gz server19.maillog.$DATELOG.gz >>
$ALLMAILLOGS

3 - Run another script

/bin/cat $ALLMAILLOGS | /data01/maillog/mymailstats.pl | tee -a $MAILREPORT

4 - Get all of the mailstats logs to one log file to send by Email

/bin/cat /data01/maillog/mailstats.log.server*.$DATELOG > $MAILSTATSLOGALL

Send the $MAILADMINS the mail reports

/bin/cat $MAILSTATSLOGALL | mail -s "ACME Servers Outbound Mail Servers
mailstats:$DATELOG" $MAILADMINS
下載 本文的源代碼能夠獲得此腳本的改進版,其中包含更健全的特性。
回頁首
bash 腳本編程中的變量、語法格式和結構
在 bash 中,能夠經過幾種方法定義和設置變量。清單 24 中的腳本給出這些 shell 變量聲明方法的示例。
清單 24. 定義 bash 變量
$ cat a.sh

!/bin/bash

A="String Value 1"
B='String Value 2'
C=9675
D=96.75
export E="String Value 3"

if the variable $F is not ALREADY set to a value, assign "String Value 4" ...

F=${F:="String Value 4"}

echo "A=$A"
echo "B=$B"
echo "C=$C"
echo "D=$D"
echo "E=$E"
echo "F=$F"

exit 0

$ ./a.sh
A=String Value 1
B=String Value 2
C=9675
D=96.75
E=String Value 3
F=String Value 4
收集用戶輸入
要想收集用戶輸入,應該使用 read 語句並向用戶輸入分配一個變量,見 清單 25。
清單 25. 在 bash 腳本中獲取用戶輸入
$ cat prompt.sh

!/bin/bash

echo "Please enter your first and last name:"
read ans
echo "Hellow $ans , welcome to bash scripting ...!"
exit 0

$ ./prompt.sh
Please enter your first and last name:
Joe Jackson
Hello Joe Jackson , welcome to bash scripting ...!
要想在 bash shell 腳本中使用函數,可使用 清單 26 所示的方法。
清單 26. 在 bash 中實現函數
$ cat function.sh

!/bin/bash

funcOne() {
echo "Running function 1, with parameter $1"
date
echo "Current listing /tmp directory, last 3 lines"
ls -lrt /tmp | tail -3
}

echo "Hello World"
funcOne "Server01"
exit 0

$ ./function.sh
Hello World
Running function 1, with parameter Server01
Sun Aug 22 22:43:04 UTC 2010
Current listing /tmp directory, last 3 lines
-rw-r- 1 dsmith progdevel 12749743 Aug 16 20:32 files.tar.gz
drwxr-xr-x 2 jjones progdevel 4096 Aug 16 20:42 ff_hosting_files
-rw-r- 1 rhill heng 1440 Aug 22 19:07 myscript.log
也能夠像 清單 27 這樣編寫函數。
清單 27. bash 中的另外一種函數定義

!/bin/bash

function funcTwo () {
echo "Running function 2, with parameter $1"
date
echo "Current listing /var directory, last 3 lines"
ls -lrt /var | tail -3
}

funcTwo "Server02"

exit 0

$ ./function.sh
Running function 2, with parameter Server02
Sun Aug 22 22:53:16 UTC 2010
Current listing /var directory, last 3 lines
drwxrwxrwt 3 root root 4096 Aug 6 18:22 tmp
drwxr-xr-x 6 root root 4096 Aug 22 04:02 log
drwxrwxr-x 4 root lock 4096 Aug 22 04:22 lock
function 關鍵詞是可選的。唯一的規則是必須先定義函數,而後才能在程序中使用它。調用函數的方法是調用它的名稱並傳遞必需的或可選的輸入參數。
循環和決策
假設您須要在幾個服務器上執行某些重複的工做。在 bash 中,可使用 for 循環輕鬆地實現這個目標。清單 28 給出代碼。
清單 28. 簡單 for 循環的 bash 腳本編程示例
$SERVERS=」server01 server02 server03 server04 server05」
for i in $SERVERS
do
echo "Removing file from server: $i"
ssh $i rm -f /tmp/junk1.txt
done
bash 中的 while 循環能夠重複執行語句必定的次數,或者一直執行到知足某一條件爲止。清單 29 給出一個示例。
清單 29. 簡單的 while 循環
LOOPCTR=1
while [ $LOOPCTR -lt 6 ]
do
echo 「Running patch script for server0$LOOPCTR」
/data/patch.sh server0$LOOPCTR
LOOPCTR=expr $LOOPCTR + 1
done
bash 中的 case 語句能夠用來測試多個條件或值並相應地執行操做。有時候,使用這種語句比嵌套的 for 循環或 if 語句更好,能夠減小重複的代碼並且結構更清楚。清單 30 給出一個簡短的 case 語句,它根據變量 $key 的值調用函數。
清單 30. bash 中的 case 語句示例
case $key in

q) logit "Quit";
exit;;
1) echo 「\tChecking Mail Servers」;
check_mail_servers;;
2) echo "\tChecking Web Servers";
check_web_servers;;
3) echo 「\tChecking App Servers;
check_app_servers;;
4) echo 「\tChecking Database Servers」;
check_database_servers;;

b) echo "Go Back to Main menu";
MENUFLAG="main";
main_menu;;
) echo "$key invalid choice"; invalid;; esac 回頁首 bash 腳本編程的優缺點 須要快速地完成某些任務嗎?若是您掌握了 bash,就能夠很是輕鬆地編寫最新的 web 組件,能夠大大減小所需的時間。bash 腳本編程不是編程語言或應用程序。不須要編譯器,也不須要特殊的庫或軟件開發環境。可是,bash shell 腳本的行爲與應用程序類似,甚至可以執行應用程序能夠完成的一些任務和工做。 從好的方面來講: bash 提供快速開發,代碼便於修改。bash 腳本編程的基本方法幾乎不隨時間變更。 一些編程語言的代碼規則或語法的變更可能比較頻繁,與它們相比,bash 的語法至關簡單明瞭。 高級 bash 特性向用戶提供比之前更強的能力(例如,紀元、函數、信號控制、多個擴展、命令歷史、使用一維數組的方法)。 進行 bash shell 腳本編程只須要 nix bash shell。 從壞的方面來講,bash 代碼: 由 shell 執行,而後傳遞給內核,這個過程一般比編譯爲純機器碼的二進制程序慢。所以,bash shell 腳本編程可能不適用於某些應用程序設計或功能。 是明文的,具備讀權限的任何人均可以輕鬆地讀取它們,而編譯的二進制代碼是不可讀的。在對敏感數據進行編碼時,使用明文是很嚴重的安全風險。 沒有特定的標準函數集,而許多現代編程語言有內置的函數,能夠知足各類編程需求。

相關文章
相關標籤/搜索