熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> 游戲開發 >> 正文

一個不錯的shell 腳本教程 入門級

2022-06-13   來源: 游戲開發 
建立一個腳本

  Linux中有好多中不同的shell但是通常我們使用bash (bourne again shell) 進行shell編程因為bash是免費的並且很容易使用所以在本文中筆者所提供的腳本都是使用bash(但是在大多數情況下這些腳本同樣可以在 bash的大姐bourne shell中運行)
  如同其他語言一樣通過我們使用任意一種文字編輯器比如neditkeditemacsvi
  等來編寫我們的shell程序
  程序必須以下面的行開始(必須方在文件的第一行)
#!/bin/sh
  符號#!用來告訴系統它後面的參數是用來執行該文件的程序在這個例子中我們使用/bin/sh來執行程序
  當編輯好腳本時如果要執行該腳本還必須使其可執行
  要使腳本可執行
chmod +x filename
  然後您可以通過輸入 /filename 來執行您的腳本
注釋
  在進行shell編程時以#開頭的句子表示注釋直到這一行的結束我們真誠地建議您在程序中使用注釋如果您使用了注釋那麼即使相當長的時間內沒有使用該腳本您也能在很短的時間內明白該腳本的作用及工作原理
變量
  在其他編程語言中您必須使用變量在shell編程中所有的變量都由字符串組成並且您不需要對變量進行聲明要賦值給一個變量您可以這樣寫
變量名=值
  取出變量值可以加一個美元符號($)在變量前面
#!/bin/sh
#對變量賦值
a=hello world
# 現在打印變量a的內容
echo A is:
echo $a
  在您的編輯器中輸入以上內容然後將其保存為一個文件first之後執行chmod +x first
  使其可執行最後輸入/first執行該腳本
  這個腳本將會輸出
A is:
hello world
  有時候變量名很容易與其他文字混淆比如
num=
echo this is the $numnd
  這並不會打印出this is the nd而僅僅打印this is the 因為shell會去搜索變量numnd的值但是這個變量時沒有值的可以使用花括號來告訴shell我們要打印的是num變量
num=
echo this is the ${num}nd
  這將打印 this is the nd
  有許多變量是系統自動設定的這將在後面使用這些變量時進行討論
  如果您需要處理數學表達式那麼您需要使用諸如expr等程序(見下面)
  除了一般的僅在程序內有效的shell變量以外還有環境變量由export關鍵字處理過的變量叫做環境變量我們不對環境變量進行討論因為通常情況下僅僅在登錄腳本中使用環境變量
Shell命令和流程控制
  在shell腳本中可以使用三類命令
)Unix 命令:
  雖然在shell腳本中可以使用任意的unix命令但是還是由一些相對更常用的命令這些命令通常是用來進行文件和文字操作的
常用命令語法及功能
  echo some text: 將文字內容打印在屏幕上
  ls: 文件列表
  wc –l filewc w filewc c file: 計算文件行數計算文件中的單詞數計算文件中的字符數
  cp sourcefile destfile: 文件拷貝
  mv oldname newname : 重命名文件或移動文件
  rm file: 刪除文件
  grep pattern file: 在文件內搜索字符串比如grep searchstring filetxt
  cut b colnum file: 指定欲顯示的文件內容范圍並將它們輸出到標准輸出設備比如輸出每行第個到第個字符cut b filetxt千萬不要和cat命令混淆這是兩個完全不同的命令
  cat filetxt: 輸出文件內容到標准輸出設備(屏幕)上
  file somefile: 得到文件類型
  read var: 提示用戶輸入並將輸入賦值給變量
  sort filetxt: 對filetxt文件中的行進行排序
  uniq: 刪除文本文件中出現的行列比如 sort filetxt | uniq
  expr: 進行數學運算Example: add and expr +
  find: 搜索文件比如根據文件名搜索find name filename print
  tee: 將數據輸出到標准輸出設備(屏幕) 和文件比如somecommand | tee outfile
  basename file: 返回不包含路徑的文件名比如 basename /bin/tux將返回 tux
  dirname file: 返回文件所在路徑比如dirname /bin/tux將返回 /bin
  head file: 打印文本文件開頭幾行
  tail file : 打印文本文件末尾幾行
  sed: Sed是一個基本的查找替換程序可以從標准輸入(比如命令管道)讀入文本並將結果輸出到標准輸出(屏幕)該命令采用正則表達式(見參考)進行搜索不要和shell中的通配符相混淆比如將linuxfocus 替換為 LinuxFocus cat textfile | sed s/linuxfocus/LinuxFocus/ > newtextfile
  awk: awk 用來從文本文件中提取字段缺省地字段分割符是空格可以使用F指定其他分割符cat filetxt | awk F {print $ $ }這裡我們使用作為字段分割符同時打印第一個和第三個字段如果該文件內容如下 Adam Bor IndiaKerry Miller USA命令輸出結果為Adam Bor IndiaKerry Miller USA
) 概念: 管道 重定向和 backtick
  這些不是系統命令但是他們真的很重要
  管道 (|) 將一個命令的輸出作為另外一個命令的輸入
grep hello filetxt | wc l
  在filetxt中搜索包含有hello的行並計算其行數
  在這裡grep命令的輸出作為wc命令的輸入當然您可以使用多個命令
  重定向將命令的結果輸出到文件而不是標准輸出(屏幕)
  > 寫入文件並覆蓋舊文件
  >> 加到文件的尾部保留舊文件內容
反短斜線
 使用反短斜線可以將一個命令的輸出作為另外一個命令的一個命令行參數
  命令
find mtime type f print
  用來查找過去小時(mtime –則表示過去小時)內修改過的文件如果您想將所有查找到的文件打一個包則可以使用以下腳本
#!/bin/sh
# The ticks are backticks (`) not normal quotes ():
tar zcvf lastmodtargz `find mtime type f print`
  ) 流程控制
  if 表達式 如果條件為真則執行then後面的部分
if ; then
 
elif ; then
 
else
 
fi
  大多數情況下可以使用測試命令來對條件進行測試比如可以比較字符串判斷文件是否存在及是否可讀等等…
  通常用 [ ] 來表示條件測試注意這裡的空格很重要要確保方括號的空格
[ f somefile ] 判斷是否是一個文件
[ x /bin/ls ] 判斷/bin/ls是否存在並有可執行權限
[ n $var ] 判斷$var變量是否有值
[ $a = $b ] 判斷$a和$b是否相等
  執行man test可以查看所有測試表達式可以比較和判斷的類型
  直接執行以下腳本
#!/bin/sh
if [ $SHELL = /bin/bash ]; then
 echo your login shell is the bash (bourne again shell)
else
 echo your login shell is not bash but $SHELL
fi
  變量$SHELL包含了登錄shell的名稱我們和/bin/bash進行了比較
快捷操作符
  熟悉C語言的朋友可能會很喜歡下面的表達式
[ f /etc/shadow ] && echo This computer uses shadow passwors
  這裡 && 就是一個快捷操作符如果左邊的表達式為真則執行右邊的語句您也可以認為是邏輯運算中的與操作上例中表示如果/etc/shadow文件存在則打印 This computer uses shadow passwors同樣或操作(||)在shell編程中也是可用的這裡有個例子
#!/bin/sh
mailfolder=/var/spool/mail/james
[ r $mailfolder ] { echo Can not read $mailfolder ; exit ; }
echo $mailfolder has mail from:
grep ^From $mailfolder
  該腳本首先判斷mailfolder是否可讀如果可讀則打印該文件中的From 一行如果不可讀則或操作生效打印錯誤信息後腳本退出這裡有個問題那就是我們必須有兩個命令
  打印錯誤信息
  退出程序
  我們使用花括號以匿名函數的形式將兩個命令放到一起作為一個命令使用一般函數將在下文提及
  不用與和或操作符我們也可以用if表達式作任何事情但是使用與或操作符會更便利很多
  case表達式可以用來匹配一個給定的字符串而不是數字
case in
) do something here ;;
esac
  讓我們看一個例子 file命令可以辨別出一個給定文件的文件類型比如
file lfgz
  這將返回
lfgz: gzip compressed data deflated original filename
last modified: Mon Aug :: os: Unix
 我們利用這一點寫了一個叫做smartzip的腳本該腳本可以自動解壓bzip gzip 和zip 類型的壓縮文件
#!/bin/sh
ftype=`file $`
case $ftype in
$: Zip archive*)
  unzip $ ;;
$: gzip compressed*)
  gunzip $ ;;
$: bzip compressed*)
  bunzip $ ;;
*) error File $ can not be uncompressed with smartzip;;
esac
  您可能注意到我們在這裡使用了一個特殊的變量$該變量包含了傳遞給該程序的第一個參數值也就是說當我們運行
smartzip articleszip
$ 就是字符串 articleszip
  select 表達式是一種bash的擴展應用尤其擅長於交互式使用用戶可以從一組不同的值中進行選擇
select var in ; do
 break
done
now $var can be used
下面是一個例子
#!/bin/sh
echo What is your favourite OS?
select var in Linux Gnu Hurd Free BSD Other; do
    break
done
echo You have selected $var
  下面是該腳本運行的結果
What is your favourite OS?
) Linux
) Gnu Hurd
) Free BSD
) Other
#?
You have selected Linux
  您也可以在shell中使用如下的loop表達式
while ; do

done
  whileloop 將運行直到表達式測試為真will run while the expression that we test for is true 關鍵字break 用來跳出循環而關鍵字continue用來不執行余下的部分而直接跳到下一個循環
  forloop表達式查看一個字符串列表 (字符串用空格分隔) 然後將其賦給一個變量
for var in ; do
 
done
  在下面的例子中將分別打印ABC到屏幕上

  復制代碼 代碼如下:

  #!/bin/sh
for var in A B C ; do
 echo var is $var
done


  下面是一個更為有用的腳本showrpm其功能是打印一些RPM包的統計信息

  復制代碼 代碼如下:

  #!/bin/sh
# list a content summary of a number of RPM packages
# USAGE: showrpm rpmfile rpmfile
# EXAMPLE: showrpm /cdrom/RedHat/RPMS/*rpm
for rpmpackage in $*; do
 if [ r $rpmpackage ];then
  echo =============== $rpmpackage ==============
  rpm qi p $rpmpackage
 else
  echo ERROR: cannot read file $rpmpackage
 fi
done


  這裡出現了第二個特殊的變量$*該變量包含了所有輸入的命令行參數值如果您運行showrpm opensshrpm wmrpm webgreprpm
  此時 $* 包含了 個字符串即opensshrpm wmrpm and webgreprpm
引號
  在向程序傳遞任何參數之前程序會擴展通配符和變量這裡所謂擴展的意思是程序會把通配符(比如*)替換成合適的文件名它變量替換成變量值為了防 止程序作這種替換您可以使用引號讓我們來看一個例子假設在當前目錄下有一些文件兩個jpg文件 mailjpg 和tuxjpg

#!/bin/sh
echo *jpg
  這將打印出mailjpg tuxjpg的結果
  引號 (單引號和雙引號) 將防止這種通配符擴展
#!/bin/sh
echo *jpg
echo *jpg
  這將打印*jpg 兩次
  單引號更嚴格一些它可以防止任何變量擴展雙引號可以防止通配符擴展但允許變量擴展
#!/bin/sh
echo $SHELL
echo $SHELL
echo $SHELL
  運行結果為
/bin/bash
/bin/bash
$SHELL
  最後還有一種防止這種擴展的方法那就是使用轉義字符——反斜桿
echo *jpg
echo $SHELL
  這將輸出
*jpg
$SHELL
Here documents
  當要將幾行文字傳遞給一個命令時here documents(譯者注目前還沒有見到過對該詞適合的翻譯)一種不錯的方法對每個腳本寫一段幫助性的文字是很有用的此時如果我們四有那個 here documents就不必用echo函數一行行輸出 一個 Here document 以 << 開頭後面接上一個字符串這個字符串還必須出現在here document的末尾下面是一個例子在該例子中我們對多個文件進行重命名並且使用here documents打印幫助

  復制代碼 代碼如下:

  #!/bin/sh
# we have less than arguments Print the help text:
if [ $# lt ] ; then
cat <
ren renames a number of files using sed regular expressions
USAGE: ren regexp replacement files
EXAMPLE: rename all *HTM files in l:
 ren HTM$ html *HTM
HELP
 exit
fi
OLD=$
NEW=$
# The shift command removes one argument from the list of
# command line arguments
shift
shift
# $* contains now all the files:
for file in $*; do
  if [ f $file ] ; then
   newfile=`echo $file | sed s/${OLD}/${NEW}/g`
   if [ f $newfile ]; then
    echo ERROR: $newfile exists already
   else
    echo renaming $file to $newfile
    mv $file $newfile
   fi
  fi
done


  這是一個復雜一些的例子讓我們詳細討論一下第一個if表達式判斷輸入命令行參數是否小於個 (特殊變量$# 表示包含參數的個數) 如果輸入參數小於則將幫助文字傳遞給cat命令然後由cat命令將其打印在屏幕上打印幫助文字後程序退出如果輸入參數等於或大於我們就將第一個參數賦值給變量OLD第二個參數賦值給變量NEW下一步我們使用shift命令將第一個和第二個參數從參數列表中刪除這樣原來的第三個參數就成為參數列表$*的第一個參數然後我們開始循環命令行參數列表被一個接一個地被賦值給變量$file接著我們判斷該文件是否存在如果存在則通過sed命令搜索和替換來產生新的文件名然後將反短斜線內命令結果賦值給newfile這樣我們就達到了我們的目的得到了舊文件名和新文件名然後使用mv命令進行重命名
函數
  如果您寫了一些稍微復雜一些的程序您就會發現在程序中可能在幾個地方使用了相同的代碼並且您也會發現如果我們使用了函數會方便很多一個函數是這個樣子的

  復制代碼 代碼如下:

  functionname()
{
# inside the body $ is the first argument given to the function
# $ the second
body
}


  您需要在每個程序的開始對函數進行聲明

  下面是一個叫做xtitlebar的腳本使用這個腳本您可以改變終端窗口的名稱這裡使用了一個叫做help的函數正如您可以看到的那樣這個定義的函數被使用了兩次

  復制代碼 代碼如下:

  #!/bin/sh
# vim: set sw= ts= et:
help()
{
  cat <
xtitlebar change the name of an xterm gnometerminal or kde konsole
USAGE: xtitlebar [h] string_for_titelbar
OPTIONS: h help text
EXAMPLE: xtitlebar cvs
HELP
  exit
}
# in case of error or if h is given we call the function help:
[ z $ ] && help
[ $ = h ] && help
# send the escape sequence to change the xterm titelbar:
echo e ];$


#
  在腳本中提供幫助是一種很好的編程習慣這樣方便其他用戶(和您)使用和理解腳本
命令行參數
  我們已經見過$* 和 $ $ $ 等特殊變量這些特殊變量包含了用戶從命令行輸入的參數迄今為止我們僅僅了解了一些簡單的命令行語法(比如一些強制性的參數和查看幫助的h選項)但是在編寫更復雜的程序時您可能會發現您需要更多的自定義的選項通常的慣例是在所有可選的參數之前加一個減號後面再加上參數值 (比如文件名)
  有好多方法可以實現對輸入參數的分析但是下面的使用case表達式的例子無遺是一個不錯的方法

  復制代碼 代碼如下:

  #!/bin/sh
help()
{
 cat <
This is a generic command line parser demo
USAGE EXAMPLE: cmdparser l hello f somefile somefile
HELP
 exit
}
while [ n $ ]; do
case $ in
  h) help;shift ;; # function help is called
  f) opt_f=;shift ;; # variable opt_f is set
  l) opt_l=$;shift ;; # l takes an argument > shift by
  ) shift;break;; # end of options
  *) echo error: no such option $ h for help;exit ;;
  *) break;;
esac
done

echo opt_f is $opt_f
echo opt_l is $opt_l
echo first arg is $
echo nd arg is $


  您可以這樣運行該腳本
cmdparser l hello f somefile somefile
  返回的結果是
opt_f is
opt_l is hello
first arg is somefile
nd arg is somefile
  這個腳本是如何工作的呢?腳本首先在所有輸入命令行參數中進行循環將輸入參數與case表達式進行比較如果匹配則設置一個變量並且移除該參數根據unix系統的慣例首先輸入的應該是包含減號的參數
實例
  一般編程步驟
  現在我們來討論編寫一個腳本的一般步驟任何優秀的腳本都應該具有幫助和輸入參數並且寫一個偽腳本(frameworksh)該腳本包含了大多數腳本都需要的框架結構是一個非常不錯的主意這時候在寫一個新的腳本時我們只需要執行一下copy命令
cp frameworksh myscript
 然後再插入自己的函數
  讓我們再看兩個例子
  二進制到十進制的轉換
  腳本 bd 將二進制數 (比如 ) 轉換為相應的十進制數這也是一個用expr命令進行數學運算的例子

  復制代碼 代碼如下:

  #!/bin/sh
# vim: set sw= ts= et:
help()
{
 cat <
bh convert binary to decimal
USAGE: bh [h] binarynum
OPTIONS: h help text
EXAMPLE: bh
will return
HELP
 exit
}
error()
{
  # print an error and exit
  echo $
  exit
}
lastchar()
{
  # return the last character of a string in $rval
  if [ z $ ]; then
    # empty string
    rval=
    return
  fi
  # wc puts some space behind the output this is why we need sed:
  numofchar=`echo n $ | wc c | sed s/ //g `
  # now cut out the last char
  rval=`echo n $ | cut b $numofchar`
}

chop()
{
  # remove the last character in string and return it in $rval
  if [ z $ ]; then
    # empty string
    rval=
    return
  fi
  # wc puts some space behind the output this is why we need sed:
  numofchar=`echo n $ | wc c | sed s/ //g `
  if [ $numofchar = ]; then
    # only one char in string
    rval=
    return
  fi
  numofcharminus=`expr $numofchar `
  # now cut all but the last char:
  rval=`echo n $ | cut b ${numofcharminus}`
}
while [ n $ ]; do
case $ in
  h) help;shift ;; # function help is called
  ) shift;break;; # end of options
  *) error error: no such option $ h for help;;
  *) break;;
esac
done
# The main program
sum=
weight=
# one arg must be given:
[ z $ ] && help
binnum=$
binnumorig=$

while [ n $binnum ]; do
  lastchar $binnum
  if [ $rval = ]; then
    sum=`expr $weight + $sum`
  fi
  # remove the last position in $binnum
  chop $binnum
  binnum=$rval
  weight=`expr $weight * `
done
echo binary $binnumorig is decimal $sum
#


  該腳本使用的算法是利用十進制和二進制數權值 ()比如二進制可以這樣轉換成十進制
* + * =
  為了得到單個的二進制數我們是用了lastchar 函數該函數使用wc –c計算字符個數然後使用cut命令取出末尾一個字符Chop函數的功能則是移除最後一個字符
  文件循環程序
  或許您是想將所有發出的郵件保存到一個文件中的人們中的一員但是在過了幾個月以後這個文件可能會變得很大以至於使對該文件的訪問速度變慢下面的腳本rotatefile 可以解決這個問題這個腳本可以重命名郵件保存文件(假設為outmail)為outmail而對於outmail就變成了outmail 等等等等

  復制代碼 代碼如下:

  #!/bin/sh
# vim: set sw= ts= et:
ver=
help()
{
  cat <
rotatefile rotate the file name

USAGE: rotatefile [h] filename

OPTIONS: h help text
EXAMPLE: rotatefile out
This will eg rename out to out out to out out to out
and create an empty outfile
The max number is
version $ver
HELP
  exit
}

error()
{
  echo $
  exit
}
while [ n $ ]; do
case $ in
  h) help;shift ;;
  ) break;;
  *) echo error: no such option $ h for help;exit ;;
  *) break;;
esac
done
# input check:
if [ z $ ] ; then
error ERROR: you must specify a file use h for help
fi
filen=$
# rename any etc file:
for n in ; do
  if [ f $filen$n ]; then
    p=`expr $n + `
    echo mv $filen$n $filen$p
    mv $filen$n $filen$p
  fi
done
# rename the original file:
if [ f $filen ]; then
  echo mv $filen $filen
  mv $filen $filen
fi
echo touch $filen
touch $filen


  這個腳本是如何工作的呢?在檢測用戶提供了一個文件名以後我們進行一個的循環文件被命名為文件重命名為等等循環完成之後我們將原始文件命名為文件同時建立一個與原始文件同名的空文件
調試
  最簡單的調試命令當然是使用echo命令您可以使用echo在任何懷疑出錯的地方打印任何變量值這也是絕大多數的shell程序員要花費%的時間來調試程序的原因Shell程序的好處在於不需要重新編譯插入一個echo命令也不需要多少時間
  shell也有一個真實的調試模式如果在腳本strangescript 中有錯誤您可以這樣來進行調試
sh x strangescript
  這將執行該腳本並顯示所有變量的值
  shell還有一個不需要執行腳本只是檢查語法的模式可以這樣使用
sh n your_script
  這將返回所有語法錯誤
  我們希望您現在可以開始寫您自己的shell腳本希望您玩得開心
From:http://tw.wingwit.com/Article/program/yxkf/201404/30421.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.