GNU/Linux實戰手記之Emacs篇 中--Bash程式設計 (轉)

gugu99發表於2007-08-15
GNU/Linux實戰手記之Emacs篇 中--Bash程式設計 (轉)[@more@]

【/實戰手記之Emacs篇 中--Bash 】
作者:葉魏彬 to::fritz_yea@.com">MSN:fritz_yea@hotmail.com
Copyright(C)Free Software Library,Org()
本文依照GNU Free Document Lience釋出,任何人都可以將本文原封不動的複製、轉載,但請務必保留此宣告。作者不對本文所導致的任何結果負責。

七、Bash語法
  在看過上一次的那個簡單的之後,我們來深入研究一下shell強大的能力。Shell是一種很容易學習的程式設計語言,至少因為它能夠在把各個小程式組合成一個大程式之前很容易的對它們分別進行互動式的測試。利用現代操作的shell,我們可以編寫出相當龐大的結構化程式。在接下來的幾小節裡,我們將學習:
  ·變數:字串、數字、環境和引數
  ·條件:shell中的布林值
  ·程式控制:if、elif、for、while、until、case
  ·
  ·註釋

  為了確保Bash程式設計的嚴謹性和趣味性,我直接引用了WROX出版社的《Linux程式設計》一書第二章的部分內容和例程。我想以學習的名義,我這裡的引用應該不算,至少它的原始碼是基於GPL的。

1、變數
  在shell裡,使用變數之前並不需要事先對他們做出宣告。我們可以在任何需要的時候直接建立並使用變數。預設情況下,變數型別為字串,即使它所儲存的是數值。Shell和其他的一些工具會自動識別“數值”型字串,並按正確的方法對其進行操作。變數名區分大小寫,這與Unix系統保持一致。因此變數var和Var以及VAR分別指不同的變數。變數命名原則與Unix命名原則相同,但是不允許有空格,更不能和現有系統命令重名。
  在shell裡,變數名前面加一個“$”字元,就可以獲得它的內容。只要用到變數,我們就必須在它前面加上“$”,除非是對它進行賦值。賦值變數可以直接使用“=”,也可以使用read命令,將的輸入賦給變數。請看下面的例子:
$string=Hello
$echo $string
Hello
$string="Guten Tag"
$echo $string
Guten Tag
$string=1+2+3
$echo $string
1+2+3
$read string
I love you  /*使用者輸入,回車結束*/
$echo $string
I love you  /*讀取變數內容*/

*注意,如果字串裡包含空格,就必須用引號把它們括起來。還要注意的是等號兩邊不能有空格。
**我說過,數字也被儲存為字串,因此“string=1+2+3”的結果仍是“1+2+3”,而不是“6”。
***read讀取使用者輸入的字串,以回車結束。
1.1、引號的用法
  一般情況下,引數之間是用空白字元分隔的,比如一個空格、一個製表符或一個換行符,如果想在一個一個引數裡面包含一個或多個這樣的空白字元,就必須給引數加上引號。
  引號也有不同。如果你在雙引號裡包含變數,則會引起“名-值替換”,而在單引號裡就不會。我們還可以在“$”號前加上“”來取消它的特殊含義。
  讓我們來看看引號在變數輸出中的作用:
#!/bin/sh

myvar="Hi there"

echo $myvar
echo "$myvar"
echo '$myvar'
echo $myvar

echo Enter some text
read myvar

echo '$myvar' now equals $myvar

exit 0

輸出結果是:

Hi there
Hi there
$myvar
$myvar
Enter some text
Hello world
$myvar now equals Hello world

1.2、環境變數
  指令碼在的時候,某些變數會根據系統環境設定而進行初始化。這些環境變數通常使用大寫,以便和使用者自定義的變數區分,後者通常使用小寫。下面是一些常用到的環境變數:

環境變數  說明
$HOME  當前使用者的登入子目錄
$PATH  以冒號分隔的用來分隔搜尋命令的子目錄清單
$PS1  命令列提示符,通常是“$”字元
$PS2  輔助提示符,用來提示後續輸入,通常是“>”字元
$IFS  輸入區的分隔符。當shell讀取輸入資料的時候會把一組字元看做是單詞之間的分隔字元,它們通常是空格、製表符和換行符
$0  shell指令碼程式的名字
$#  傳遞到指令碼程式的引數個數
$$  該shell指令碼程式的程式ID,指令碼程式一般會使用它來建立獨一無二的臨時檔案,比如/tmp/tmpfile_$$

1.3、引數變數
  如果你的指令碼程式在的時候還帶有引數,就會產生額外的一些變數。即使你什麼引數也沒傳,上面的“$#”依然存在,只不過值是0罷了。

引數變數 說明
$1,$2... 指令碼程式的引數
$* 一個全體引數組成的清單,這是一個單獨的變數,各個引數之間用環境變數IFS中的第一個字元分隔開
$@ “$*”的一種變數,它不使用IFS環境變數

下面是使用環境變數和引數變數的一個例子:

#!/bin/sh
 
salutation="Hello"
echo $salutation
echo "The program $0 is now running"
echo "The second parameter was $2"
echo "The first parameter was $1"
echo "The parameter list was $*"
echo "The user's home directory is $HOME"

echo "Please enter a new greeting"
read salutation

echo $salutation
echo "The script is now complete"

exit 0

輸出結果是:

Hello
The program ./try_var is now running
The second parameter was
The first parameter was
The parameter list was
The user's home directory is /home/yea
Please enter a new greeting
Sire
Sire
The script is now complete

2、條件測試
  在實際工作中,大多數指令碼程式都會大量使用“[ ]”或“test”命令——即shell的布林判斷命令。注意,“[ ]”和要被檢查的條件之間留出空格。因為“[”與“test”實際上是一樣的,而“test”命令後面要空格,所以“[”後面自然也得有空格了。有關“test”命令的使用,請參考“test”的手冊頁。我不在此贅述了。

3、控制結構——if、elif、for、while、until、case
  shell有一系列控制結構,而且它們同樣與其他程式設計語言很相似。就某些結構而言(比如case語句),shell提供了更強大的功能。
  為了減小篇幅,並且讓大家看起來一目瞭然,我直接列出各控制結構的語法結構和例程,好在這樣寫並不會增加理解的難度。
3.1、if語句

if condition
then
  statements
else
  statements
fi

if語句的例子

#!/bin/sh

echo "Is it morning? Please answer yes or no"
read timeofday

if [ "$timeofday" = "yes" ]; then
  echo "Good morning"
else
  echo "Good afternoon"
fi

exit 0

3.2、elif語句

if condition
then
  statements
elif condition
then
  statements
else
  statements
fi

elif語句的例子

#!/bin/sh

echo "Is it morning? Please answer yes or no"
read timeofday

if [ $timeofday = "yes" ]
then
  echo "Good morning"
elif [ $timeofday = "no" ]; then
  echo "Good afternoon"
else
  echo "Sorry, $timeofday not recognized. Enter yes or no"
  exit 1
fi

exit 0

3.3、for語句

for variable in values
do
  statements
done

for語句的例子

#!/bin/sh

for foo in bar fud 43
do
  echo $foo
done

exit 0

3.4、while語句
  假若我們要迴圈100次,用for的話就得從1一直寫到100,這樣太累了。它確實沒有BASIC裡的for方便——FOR I=1 TO 100 STEP 1,但是它有它的優勢,這裡暫且不談。
  對於上面的情況,我們可以使用while結構和數值替換結合在一起。while的語法結構是
while condition
do
  statements
done

  看下面的例子
#!/bin/sh

foo=1
while [ "$foo" -le 20 ]
do
  echo "Here we go again"
  foo=$(($foo+1))
done

exit 0

  這裡展示了$(command)結構的用法。

3.5、until語句
  until和while很類似,只是把條件測試倒過來了。換句話說,就是迴圈將反覆執行直到條件為真是停止,而不是當條件為真時執行。
  until的語法為
until condition
do
  statements
done

until語句的例子
#!/bin/sh

until who | grep "$1" > /dev/null
do
  sleep 60
done

# Now ring the bell and announce the unexpected user.

echo -e
echo "***** $1 has just logged in *****"

exit 0

3.6、case語句
  case結構比我們前面見過的其他語句都稍微複雜些。它的語法如下所示:
case variable in
  patten [| patten] ...) statements;;
  patten [| patten] ...) statements;;
  ...
esac

  其實這種語法結構要比我們一般所見到的case結構簡潔(比如C/C++的switch~case結構),它可以將多個選項寫在一起(就是[]中的可選部分)。需要注意的是,語句結尾要用兩個分號“;;”,而不是一個分號。在statements裡即可以是一條語句,又可以是數條語句。下面是數條語句的例子:
#!/bin/sh

echo "Is it morning? Please answer yes or no"
read timeofday

case "$timeofday" in
  yes | y | Yes | YES )
  echo "Good Morning"
  echo "Up bright and early this morning?"
  ;;
  [nN]* ) 
  echo "Good Afternoon"
  ;; 
  * ) 
  echo "Sorry, answer not recognised"
  echo "Please answer yes or no"
  exit 1
  ;;
esac

exit 0

4、函式
  shell允許使用者定義函式,以包含某些系統命令,形成執行模組。在shell裡定義函式很簡單,寫出它的名字,加上一對空的“()”,在把有關的語句包含在一對花括號“{}”裡,如下所示:
function_name(){
  statements
}
  shell指令碼的執行順序是自頂向下,因此所有的函式宣告都要出現在他執行之前,否則shell將找不到函式。

5、註釋
  shell指令碼用“#”符號註釋它之後的語句,直至行尾。這有點像C++裡的“//”註釋符。但是所有的指令碼程式,第一行都由“#!”開頭,並指定執行此指令碼的程式。這裡是“#”另一種功能。僅此而已。

八、例項——Mini Music Jukebox
  使用上面的基本元素,我們就可以構件Bash指令碼了。理論上,Bash指令碼同樣可以寫出大型、複雜的程式。但是,這樣肯定不如用C/C++、等編譯型語言寫的執行高。我們學習Bash程式設計的目的也是為了透過構造shell指令碼來減小的負擔,提高管理員的工作效率。所以我們的目標不是大型的程式,而是短小精幹的小應用。我用Bash寫下了下面的東西,用來我的庫。
#!/bin/bash
# This is very simple Bash script.It just help us enjoy music.
# Copyright (C) , Free Software Library

# filename: play_music
# To run this script, simply type follow command.
# chmod +x play_music
# ./play_music

# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.

# This program is distributed in the hopes that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.

# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.
# 675 Mass Ave, Cambridge, MA 02139, USA.

# The first thing to do is to ensure that some global variables that we'll be using
# throughout the script are set up. We set the title and track files and a temporary file.
# We also trap Ctrl-C, so our temporary file is removed if the user interrupts the script.

# First,define some globle variables.
choice=""
menu_choice=""
quit=n

# Second,define some functions.
add_(){
  echo "Add MP3 files from $HOME/music/mp3 to playlist file "mp3list"."
  find $HOME/music/mp3/ -iname *.mp3 >> $HOME/music/mp3list
}

add_ogg(){
  echo "Add Ogg files from $HOME/music/ogg to playlist file "ogglist"."
  find $HOME/music/ogg/ -iname *.ogg >> $HOME/music/ogglist
}

play_mp3(){
  clear
  echo "Playing MP3 files with mpg123."
  echo "Control key:"
  echo "s=>Stop, p=>Pause, f=>Forward, b=>Backward, q=Quit(Directly)"
  echo "Also"
  echo "Press Ctrl-C for next song, and press Ctrl-C twice within a short while to quit."

  mpg123 -C --list $HOME/music/mp3list
  return
}

play_ogg(){
  clear
  echo "Playing Ogg files with ogg123."
  echo "Control key:"
  echo "Press Ctrl-C for next song, and press Ctrl-C twice within a short while to quit."
  echo

  ogg123 $HOME/music/ogg  # As the ogg123 do not support playlist, we never use the ogglist file.
  return
}

welcome_msg(){
  clear
  echo
  echo "Mini Music Jukwbox--A very simple program written in Bash script."
  echo
  echo "Before using it, you should at least have the following two program on your system:"
  echo "ogg123 - needed for playing Ogg files."
  echo "mpg123 - needed for playing MP3 files."
  echo
  echo "Do you have these software?(y/n):"
  read choice
}

set_menu(){
  clear
  echo "Mini Music Jukwbox."
  echo
  echo "Options :"
  echo
  echo "  1) Add MP3 files to playlist"
  echo "  2) Add Ogg files to playlist"
  echo "  3) Play MP3"
  echo "  4) Play Ogg"
  echo "  q) Quit"
  echo
  echo "Please enter your choice and then press return"
  read menu_choice
}

# Final,the application proper
welcome_msg
if [ "$choice" = "y" ]
then
  while [ "$quit" != "y" ]
  do
  set_menu
  case "$menu_choice" in
  1) add_mp3;;
  2) add_ogg;;
  3) play_mp3;;
  4) play_ogg;;
  q|Q) quit=y;;
  *) echo "Sorry, choice not recognized";;
  esac
  done
else
  exit 0
fi

echo "Thanks for using. Bye! :)"
exit 0

  在shell下執行這個指令碼。我在這裡只使用了Bash的部分特性,你可以自行修改上面的程式,作為學習Bash的實驗。

【GNU/Linux實戰手記之Emacs篇 中】到此就結束了。這一篇僅涉及Bash,並未涉及Emacs,所以你完全可以將本篇看做是介紹Bash程式設計的獨立的文章。但是由於我們一直是在Emacs這個環境下編寫和指令碼的,所以我仍將他歸到Emacs篇中。在下一篇【GNU/Linux實戰手記之Emacs篇 下】中我將介紹如何定製Emacs的環境,使它更好用。我們下篇再見。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-959408/,如需轉載,請註明出處,否則將追究法律責任。

相關文章