Bourne shell?(/bin/sh) 存在于所有的 Unix 系統上,并且用她寫的腳本是(完全)可移植的;?`man 1 sh`?是一個好的參考。
## 基礎
### 變量和參數
使用?`variable=value`?的命令格式設置變量,其中 variable 是變量名稱,value是打算賦給該變量的值。使用 $variable 獲取變量值。
MESSAGE="Hello?World"????????????????????????#?賦予一個字符串
PI=3.1415????????????????????????????????????#?賦予一個十進制小數N=8
TWON=`expr?$N?*?2`???????????????????????????#?算術表達式(只限整數)
TWON=$(($N?*?2))?????????????????????????????#?另一種語法
TWOPI=`echo?"$PI?*?2"?|?bc?-l`???????????????#?使用?bc?進行浮點運算
ZERO=`echo?"c($PI/4)-sqrt(2)/2"?|?bc?-l`
命令行參數:
$0,?$1,?$2,?...??????????????????????????????#?$0?命令本身?
$#???????????????????????????????????????????#?命令參數個數
$*???????????????????????????????????????????#?所有參數(也可以是?$@)
### 一些特殊的變量
$$???????????????????????????????????????????#?當前進程?ID
$????????????????????????????????????????????#?最后命令退出狀態碼
??command??if?[?$??!=?0?];?then
????echo?"command?failed"??fimypath=`pwd`mypath=${mypath}/file.txt
echo?${mypath##*/}???????????????????????????#?只顯示文件名
echo?${mypath%%.*}???????????????????????????#?除了擴展名的全路徑
var2=${var:=string}??????????????????????????#?如果var沒有被賦值,則string值先賦值給var,
?????????????????????????????????????????????#?然后再賦值給var2
### 結構控制
for?file?in?`ls`
do
????echo?$file
done
count=0
while?[?$count?-lt?5?];?do
????echo?$count
????sleep?1????
????count=$(($count?+?1))
done
myfunction()?{
????find?.?-type?f?-name?"*.$1"?-print???????#?$1?為方法的第一個參數
}
myfunction?"txt"
#### 產生一個文件
MYHOME=/home/colin
cat?>?testhome.sh?<<?_EOF#?所有_EOF前的代碼都會進入到?testhome.sh?文件中去
if?[?-d?"$MYHOME"?]?;?then
????echo?$MYHOME?exists
else
????echo?$MYHOME?does?not?exist
fi
_EOF
sh?testhome.sh
## Bourne 腳本實例
來一個小實例,此腳本從本 xhtml 文檔創建一個 PDF 小冊子:
#!/bin/sh#?此腳本可以創建一份供雙面打印機打印的?PDF?格式的書
if?[?$#?-ne?1?];?then????????????????????????#?檢查參數是否等于?1
??echo?1>&2?"Usage:?$0?HtmlFile"??
??exit?1?????????????????????????????????????#?如果不等于1,非0退出
fi
file=$1??????????????????????????????????????#?文件變量
fname=${file%.*}?????????????????????????????#?文件名變量
fext=${file#*.}??????????????????????????????#?文件擴展名變量
prince?$file?-o?$fname.pdf???????????????????#?www.princexml.com
pdftops?-paper?A4?-noshrink?$fname.pdf?$fname.ps?#?創建?postscript?小冊子
cat?$fname.ps?|psbook|psnup?-Pa4?-2?|pstops?-b?"2:0,1U(21cm,29.7cm)"?>?$fname.book.ps
ps2pdf13?-sPAPERSIZE=a4?-sAutoRotatePages=None?$fname.book.ps?$fname.book.pdf????????????????????????????????????????????????????????????????????????????????????#?在?Windows?上使用?#a4?和?#None!
exit?0???????????????????????????????????????#?exit?0?意為成功
## 一些 sed 命令
這里是[單行 sed 命令的金礦](http://student.northpark.edu/pemente/sed/sed1line.txt)。還有一個很好的?[sed 介紹及教程](http://www.grymoire.com/Unix/Sed.html)。
sed?'s/string1/string2/g'????????????????????#?替換?string1?為?string2
sed?-i?'s/wroong/wrong/g'?*.txt??????????????#?用?g?替換所有返回的單詞
sed?'s/\(.*\)1/\12/g'????????????????????????#?修改?anystring1?為?anystring2
sed?'/<p>/,/<\/p>/d'?t.xhtml?????????????????#?刪除以?<p>?開始,以?</p>?結尾的行
sed?'/?*#/d;?/^?*$/d'????????????????????????#?刪除注釋和空行
sed?'s/[?\t]*$//'????????????????????????????#?刪除行尾空格?(使用?tab?代替?\t)
sed?'s/^[?\t]*//;s/[?\t]*$//'????????????????#?刪除行頭尾空格
sed?'s/[^*]/[&]/'????????????????????????????#?括住首字符?[]?top?->?[t]op
sed?=?file?|?sed?'N;s/\n/\t/'?>?file.num?????#?為文件添加行號
## 正則表達式
一些基本的正則表達式同樣可用于 sed。作為一個良好的啟蒙,可看?[基本正則語法](http://www.regular-expressions.info/reference.html)。
[\^$.|?*+()??????????????????????????#?特殊字符,其他字符將匹配自身
\????????????????????????????????????#?轉義特殊字符,當成普通字符對待
*????????????????????????????????????#?重復前項?0?次或多次
.????????????????????????????????????#?單個字符除換行符
.*???????????????????????????????????#?匹配?0?個或多個字符
^????????????????????????????????????#?匹配字符串行開始處
$????????????????????????????????????#?匹配字符串行結尾處
.$???????????????????????????????????#?匹配字符串行最后一個字符
^?$??????????????????????????????????#?匹配單個空格的行
[^A-Z]???????????????????????????????#?匹配任何以?A-Z?字符開始的行
### 一些實用命令
下列命令對于包含于一個腳本或者單行命令來說很有用。
sort?-t.?-k1,1n?-k2,2n?-k3,3n?-k4,4n?????????#?排序?IPv4?格式的?IP?地址
echo?'Test'?|?tr?'[:lower:]'?'[:upper:]'?????#?轉換成大寫
echo?foo.bar?|?cut?-d?.?-f?1?????????????????#?返回?foo
PID=$(ps?|?grep?script.sh?|?grep?bin?|?awk?'{print?$1}')??????????#?正在運行名為?script?腳本的?
PIDPID=$(ps?axww?|?grep?[p]ing?|?awk?'{print?$1}')???????????????????#?ping?的?PID?(w/o?grep?pid)
IP=$(ifconfig?$INTERFACE?|?sed?'/.*inet?addr:/!d;s///;s/?.*//')???#?Linux
IP=$(ifconfig?$INTERFACE?|?sed?'/.*inet?/!d;s///;s/?.*//')????????#?FreeBSD
if?[?`diff?file1?file2?|?wc?-l`?!=?0?];?then?[...]?fi?????????????#?文件改變了?
cat?/etc/master.passwd?|?grep?-v?root?|?grep?-v?\*:?|?awk?-F":"?\?#?創建?http?passwd
'{?printf("%s:%s\n",?$1,?$2)?}'?>?/usr/local/etc/apache2/passwd
testuser=$(cat?/usr/local/etc/apache2/passwd?|?grep?-v?\????#?查看?passwd?中的用戶
root?|?grep?-v?\*:?|?awk?-F":"?'{?printf("%s\n",?$1)?}'?|?grep?^user$)
:(){?:|:&?};:????????????????????????????????#?bash?fork?炸彈。會干掉你的機器
tail?+2?file?>?file2?????????????????????????#?刪除文件的第一行
我使用一種小伎倆來一次更改許多文件的擴展名。舉個例子,從 .cxx 到 .cpp。排除最后的?`| sh`?先測試一下。你同樣可以使用命令?`rename`?來做這些,如果安裝了的話。或者使用 bash 內建命令。
#?ls?*.cxx?|?awk?-F.?'{print?"mv?"$0"?"$1".cpp"}'?|?sh
#?ls?*.c?|?sed?"s/.*/cp?&?&.$(date?"+%Y%m%d")/"?|?sh?#?如?拷貝?*.c?成?*.c.20080401
#?rename?.cxx?.cpp?*.cxx?????????????????????????????#?重命名所有?.cxx?成?.cpp
#?for?i?in?*.cxx;?do?mv?$i?${i%%.cxx}.cpp;?done??????#?bash?內建的