1、find -name '*.py' -exec grep 'import' {} /; -print 1>data.txt 2>error.txt
data.txt
import findpmark
import struct
import math
./syl_segment/a/findpmark/Release/test.py
import struct
./syl_segment/a/MakeData.py
import MakeData
import struct
./syl_segment/a/make_ch_ph_p.py
error.txt
grep: ./syl_segment/bak/中文處理/LabDataAnalyse/analyse.py: No such file or directory
如不加-print
data.txt
import findpmark
import struct
import math
import struct
import MakeData
import struct
error.txt
grep: ./syl_segment/bak/中文處理/LabDataAnalyse/analyse.py: No such file or directory
2、grep 'import' `find -name '*.py'`
注意包裹find命令的不是單引號,而是ESC鍵上的符號
./syl_segment/a/findpmark/Release/test.py:import findpmark
./syl_segment/a/findpmark/Release/test.py:import struct
./syl_segment/a/findpmark/Release/test.py:import math
./syl_segment/a/MakeData.py:import struct
./syl_segment/a/make_ch_ph_p.py:import MakeData
./syl_segment/a/make_ch_ph_p.py:import struct
grep: ./syl_segment/bak/中文處理/LabDataAnalyse/analyse.py: No such file or directory
第1個命令好像快一些
附:以下是從網上抄的,有空再看
關於重定向的一些信息
最基本的理論基礎
這裏有對於三個文件的重定向定義: stdin(標準輸入), stdout(標準輸出) and
stderr(標準錯誤輸出) (std=standard).
基本上你可以
1. 重定向 stdout 到一個文件
2. 重定向 stderr 到一個文件
3. 重定向 stdout 到stderr
4. 重定向 stderr 到 stdout
5. 重定向 stderr 到 stdout 中並且成爲一個文件
6. 重定向 stderr and stdout to stdout
7. 重定向 stderr and stdout to stderr
在Linux中 1代表 '標準輸出', 2代表’標準錯誤’
標準輸出
這個例子將會使ls的顯示結果重定向到一個文件中.
ls -l > ls-l.txt
標準錯誤
這個例子將會使grep命令在運行過程中出現的錯誤輸出到一個文件中
grep da * 2> grep-errors.txt
管道
這一節我們將解釋一個非常簡單的並且你以後一定會用到的功能,它就是管道。
爲什麼大家都會用到管道?
管道可以使你非常方便的將一個程序的結果轉向到另外一個程序中。
一個sed的例子
這個例子使用了非常簡單的管道功能:
ls -l | sed -e “s/[aeio]/u/g”
當我們執行以下命令後:首先ls –l會先執行並且它會輸出結果信息但是如果它的後面跟
是一個管道符的話,那麼它就會將結果重新定向到sed這個程序中,sed使用了替換功能,
所以這個例子執行完會,會將ls –l結果中所有含有aeio的英文單詞替換成單詞u.
通過另外的方法實現ls –l *.txt
也許這種方法不同於ls –l *.txt,但是它避免了出現一條 No Such file Or Directory這
種信息。
ls -l | grep “.txt”
我們經常會在UNIX系統下的一些腳本中看到類似”2>&1″這樣的用法,例如“/path/to/prog 2>&1 > /dev/null &”,那麼它的具體含義是什麼呢?
UNIX有幾種輸入輸出流,它們分別與幾個數字有如下的對應關係:0-標準輸入流(stdin),1-標準輸出流(stdout),2-標準錯誤流 (stderr)。”2>&1″的意思就是將stderr重定向至stdout,並一起在屏幕上顯示出來。如果不加數字,那麼默認的重定向 動作是針對stdout(1)的,比如”ls -l > result”就等價於”ls -l 1 > result”。這樣便於我們更普遍性的理解重定向過程。
下面舉例說明:
#cat std.sh
#!/bin/sh
echo “stdout”
echo “stderr” >&2
#/bin/sh std.sh 2>&1 > /dev/null
stderr
#/bin/sh std.sh > /dev/null 2>&1
第一條命令的輸出結果是stderr,因爲stdout和stderr合併後一同重定向到/dev/null,但stderr並未被清除,因此仍將在屏 幕中顯示出來;第二條命令無輸出,因爲當stdout重定向至/dev/null後,stderr又重定向到了stdout,這樣stderr也被輸出到 了/dev/null。
使用命令重定向操作符
使用命令重定向操作符
可以使用重定向操作符將命令輸入和輸出數據流從默認位置重定向到其他位置。輸入或輸出數據流的位置稱爲句柄。
下表將列出可用的句柄。
句柄 | 句柄的數字代號 | 描述 |
STDIN |
0 |
鍵盤輸入 |
STDOUT |
1 |
輸出到命令提示符窗口 |
STDERR |
2 |
錯誤輸出到命令提示符窗口 |
UNDEFINED |
3-9 |
句柄由應用程序單獨定義,它們是各個工具特有的 |
數 字 0 到 9 代表前 10 個句柄。可以使用命令 Cmd.exe 運行程序,並對該程序前 10 個句柄中的任何一個句柄進行重定向。要指定要用的句柄,請在重定向操作符之前鍵入該句柄的數字。如果未定義句柄,則默認的 < 重定向輸入操作符是 0,而默認的 > 重定向輸出操作符是 1。鍵入 < 或 > 操作符之後,必須指定數據的讀寫位置。可以指定文件名或其他現有的句柄。
要指定重定向到現有句柄,請使用與 (&) 字符,後面接要重定向的句柄號(即 &句柄號)。例如,下面的命令可以將句柄 2(即 STDERR)重定向到句柄 1(即 STDOUT):
2>&1
下表列出了可用於重定向輸入和輸出數據流的操作符。
重定向操作符 | 描述 |
> |
將命令輸出寫入到文件或設備(如打印機),而不是命令提示符窗口或句柄。 |
< |
從文件而不是從鍵盤或句柄讀入命令輸入。 |
>> |
將命令輸出添加到文件末尾而不刪除文件中已有的信息。 |
>& |
將一個句柄的輸出寫入到另一個句柄的輸入中。 |
<& |
從一個句柄讀取輸入並將其寫入到另一個句柄輸出中。 |
| |
從一個命令中讀取輸出並將其寫入另一個命令的輸入中。也稱作管道。 |
默認情況下,可以從鍵盤將命令輸入(即 STDIN 句柄)發送到 Cmd.exe,然後由 Cmd.exe 將命令輸出(即 STDOUT 句柄)發送到命令提示符窗口。
重定向輸入 (<)
要通過鍵盤將輸入重定向到文件或設備,請使用 < 操作符。例如,要從 File.txt 獲取 sort 命令的輸入,請鍵入:
sort<file.txt
File.txt 的內容將以字母順序列表的方式顯示在命令提示符窗口中。
< 操作符可以打開具有隻讀訪問權限的指定文件名。因此,不能在使用該操作符時向文件中寫入信息。例如,如果以 <&2 啓動程序,則所有試圖讀取句柄 0 的操作都將失敗,因爲句柄 2 最初是以只寫訪問方式打開的。
注意
• |
0 是 < 重定向輸入操作符的默認句柄。 |
重定向輸出 (>)
幾乎所有的命令都將輸出發送到命令提示符窗口。即使將輸出發送到驅動器或打印機的命令也會在命令提示符窗口顯示消息和提示。
要將輸出從命令提示符窗口重定向到文件或設備,請使用 > 操作符。可以在許多命令中使用該操作符。例如,要將 dir 輸出重定向到 Dirlist.txt,請鍵入:
dir>dirlist.txt
如果 Dirlist.txt 不存在,Cmd.exe 將創建該文件。如果 Dirlist.txt 存在,Cmd.exe 將使用 dir 命令的輸出替換文件中的信息。
要運行 netsh routing dump 命令,然後將輸出發送到 Route.cfg,請鍵入:
netsh routing dump>c:/route.cfg
> 操作符可以打開具有隻寫訪問權限的指定文件。因此,不能使用該操作符讀取文件。例如,如果使用重定向操作符 >&0 啓動程序,則寫入句柄 1 的所有嘗試操作都將失敗,因爲句柄 0 最初是以只讀訪問方式打開的。
注意
• |
1 是 > 重定向輸出操作符的默認句柄。 |
複製句柄
重定向操作符 & 可以將輸出或輸入從一個指定句柄複製到另一個指定的句柄。例如,要將 dir 輸出發送到 File.txt 並將錯誤輸出發送到 File.txt,請鍵入:
dir>c:/file.txt 2>&1
複製句柄時,可以複製該句柄原狀態的所有特性。例如,如果一個句柄具有隻讀訪問的屬性,則該句柄的所有副本都具有隻讀訪問屬性。不能將一個具有隻讀訪問屬性的句柄複製到另一個具有隻寫訪問屬性的句柄。
使用 & 操作符重定向輸入和副本
要 將重定向輸入操作符 (<) 與複製操作符 (&) 結合使用,指定的文件必須已經存在。如果輸入文件存在,Cmd.exe 將以只讀方式打開該文件,然後將文件包含的字符作爲輸入發送到此命令(如同從鍵盤輸入一樣)。如果指定了句柄,Cmd.exe 將指定的句柄複製到系統現有的句柄中。
例如,要以句柄 0 輸入讀取(即 STDIN)的方式打開 File.txt,請鍵入:
<file.txt
要打開 File.txt,並在內容排序後將輸出發送到命令提示符窗口(即 STDOUT),請鍵入:
sort<file.txt
要查找 File.txt,然後將句柄 1(即 STDOUT)和句柄 2(即 STDERR)重定向到 Search.txt,請鍵入:
findfile file.txt>search.txt 2<&1
要以句柄 0 輸入讀取(即 STDIN)的方式複製用戶定義的句柄 3,請鍵入:
<&3
使用 & 操作符重定向輸出和複製
如果將輸出重定向到文件且指定了現有的文件名,Cmd.exe 將以只寫方式打開文件並覆蓋該文件內容。如果指定了句柄,Cmd.exe 將文件複製到現有句柄中。
要將用戶定義的句柄 3 複製到句柄 1,請鍵入:
>&3
要將包括句柄 2(即 STDERR)的所有輸出從 ipconfig 命令重定向到句柄 1(即 STDOUT),然後將輸出重定向到 Output.log,請鍵入:
ipconfig.exe>>output.log 2>&1
使用 >> 重定向操作符附加輸出
要從命令中將輸出添加到文件末尾而不丟失文件中已存在的任何信息,請使用兩個連續的大於號(即 >>)。例如,使用下列命令可以將 dir 命令生成的目錄列表附加到 Dirlist.txt 文件:
dir>>dirlist.txt
要將 netstat 命令的輸出附加到 Tcpinfo.txt 的末尾,請鍵入:
netstat>>tcpinfo.txt
使用管道操作符 (|)
管道操作符 (|) 可以提取一個命令的輸出(默認情況下是 STDOUT),然後將其定向到另一個命令的輸入(默認情況下是 STDIN)中。例如,使用下面的命令可以對目錄進行分類:
dir | sort
在本例中,將同時啓動兩個命令,但隨後 sort 命令會暫停,直到它接收到 dir 命令的輸出爲止。sort 命令使用 dir 命令的輸出作爲輸入,然後將輸出發送到句柄 1(即 STDOUT)。
合併帶重定向操作符的命令
通過合併帶有其他命令和文件名的篩選器命令,可以創建自定義命令。例如,可以使用以下命令存儲包含“LOG”字符串的文件名:
dir /b | find "log" loglist.txt
dir 命令的輸出是通過 find 篩選器命令進行發送的。包含字符串“LOG”的文件名作爲文件名列表(例如,NetshConfig.log、Logdat.svd 和 Mylog.bat)存儲在文件 Loglist.txt 中。
要在相同命令中使用多個篩選器,請使用管道 (|) 分隔篩選器。例如,下面的命令將搜索 C 盤上的每個目錄以查找包含“LOG”字符串的文件名,並且在命令提示符窗口中每次顯示一屏:
dir c:/ /s /b | find "log" | more
利用管道 (|) 可以對 Cmd.exe 進行定向,使其通過 find 篩選器命令發送 dir 命令輸出。find 命令只選擇包含字符串“LOG”的文件名。more 命令可以顯示 find 命令選擇的文件名(在命令提示符窗口中每次顯示一屏)。有關篩選器命令的詳細信息,請參閱使用篩選器。
使用篩選器
使用篩選器
命令篩選器與命令重定向豎線 (|) 聯合使用,它實際上是一個命令,包含在可讀取命令的輸入、可轉換輸入並寫入輸出的命令中。篩選器命令可以幫助您排序、查看和選擇部分命令輸出。
篩選器命令可以劃分、重排或提取通過它們的部分信息。下表列出 Windows Server 2003 家族中可用的篩選器命令。
命令 | 描述 |
在一個命令提示符窗口中每次顯示一個文件的內容或一個命令的輸出。 |
|
在文件和命令輸出中搜索您所指定的字符。 |
|
按字母順序排列文件和命令輸出。 |
要將輸入從文件發送到篩選器命令,請使用小於號 (<)。如果要使篩選器命令從其他命令獲得輸入,請使用豎線 (|)。
使用 more 命令
more 命令在一個命令提示符窗口中每次顯示一個文件的內容或一個命令的輸出。例如,要在一個命令提示符窗口中每次顯示一個名爲 List.txt 的文件的內容,請鍵入:
more < list.txt
此時將出現一個包含信息的命令提示符窗口,然後在命令提示符窗口底部出現 -- More -- 提示。要繼續前進到下一個命令提示符窗口,請在鍵盤上按任意鍵(除 Pause 之外)。要停止命令且不查看詳細信息,請按 Ctrl+C。
使用產生多個輸出命令提示符窗口的命令時,可以使用 more 命令。例如,假定要查看硬盤上的目錄樹。如果命令提示符窗口不能將目錄在一屏內全部顯示出來,請使用帶豎線 (|) 和 more 命令的 tree 命令,如下所示:
tree c:/ | more
出現由 tree 命令產生的第一個輸出命令提示符窗口,後面跟着 -- More -- 提示。輸出暫停,直到用戶按鍵盤上的任意鍵爲止(Pause 除外)。
使用 find 命令
find 命令在文件中搜索指定的字符串或文本。Cmd.exe 顯示與在命令提示符窗口中指定的字符串或文本相匹配的所有行。可以把 find 命令用作篩選器命令,也可以用作標準命令。有關如何將 find 用作標準命令的詳細信息,請參閱 Find。
要將 find 命令用作篩選器命令,必須包含小於號 (<) 和要搜索的字符串或文本。默認情況下,find 搜索區分大小寫。例如,下面的命令查找文件 Trade.txt 中所有的“Pacific Rim”字符串:
find "Pacific Rim" < trade.txt
輸出不包括出現“pacific rim”的任何字符串。輸出只包括所有首字母大寫的“Pacific Rim”字符串。
要保存 find 命令的輸出而不是在命令提示符窗口顯示輸出,請鍵入大於號 (>) 和要存儲輸出內容的文件的名稱。例如,下面的命令查找文件 Trade.txt 中存在的“Pacific Rim”字符串,並將結果保存在 Nwtrade.txt 文件中:
find "Pacific Rim" < trade.txt > nwtrade.txt
使用 sort 命令
sort 命令按字母順序排列文本文件或命令的輸出。例如,下列命令對名爲 List.txt 的文件的內容進行排序,並在命令提示符窗口中顯示排序結果:
sort < list.txt
在此示例中,sort 命令對 List.txt 文件的行按字母列表進行排序並顯示結果,但不更改文件。要保存 sort 命令的輸出而不是顯示輸出,請鍵入大於號 (>) 和文件名。例如,以下命令對 List.txt 文件的行按字母順序排序,並將結果存儲到 Alphlist.txt 文件中:
sort < list.txt > alphlist.txt
要對命令輸出進行排序,請鍵入該命令,鍵入豎線 (|),然後鍵入 sort(即,command | sort)。例如,下列命令對包括字符串“Jones”(即,find 命令輸出)的行按字母順序進行排序:
find "Jones" maillst.txt | sort
<script type="text/javascript"> var arrBaiduCproConfig=new Array(); arrBaiduCproConfig['uid'] = 128453; arrBaiduCproConfig['n'] = 'trottercpr'; arrBaiduCproConfig['tm'] = 34; arrBaiduCproConfig['cm'] = 112; arrBaiduCproConfig['um'] = 36; arrBaiduCproConfig['rad'] = 1; arrBaiduCproConfig['w'] = 250; arrBaiduCproConfig['h'] = 250; arrBaiduCproConfig['bd'] = '#CC0000'; arrBaiduCproConfig['bg'] = '#ffffff'; arrBaiduCproConfig['tt'] = '#0000ff'; arrBaiduCproConfig['ct'] = '#000000'; arrBaiduCproConfig['url'] = '#666666'; arrBaiduCproConfig['bdl'] = '#ffffff'; arrBaiduCproConfig['wn'] = 1; arrBaiduCproConfig['hn'] = 3; arrBaiduCproConfig['ta'] = 'center'; arrBaiduCproConfig['tl'] = 'top'; arrBaiduCproConfig['bu'] = 1; </script> <script src="http://cpro.baidu.com/cpro/ui/ui.js" type="text/javascript"> </script> <script type="text/javascript"> </script> <iframe width="250" scrolling="no" height="250" frameborder="0" src="http://cpro.baidu.com/cpro/ui/uijs.php?&uid=128453&n=trottercpr&tm=34&cm=112&um=36&rad=1&rsi0=250&rsi1=250&rss0=%23CC0000&rss1=%23ffffff&rss2=%230000ff&rss3=%23000000&rss4=%23666666&rss5=%23ffffff&wn=1&hn=3&rssl0=center&rssl1=top&rsi2=1&word=http%3A%2F%2Fwww.gbunix.com%2Fhtmldata%2F2005_04%2F14%2F18%2Farticle_1149_1.html" allowtransparency="" marginheight="0" marginwidth="0"></iframe> |
爲什麼要進行shell編程
在Linux系統中,雖然有各種各樣的圖形化接口工具,但是sell仍然是一個非常靈活的工具。Shell不僅僅是命令的收集,而且是一門非常棒的編程 語言。您可以通過使用shell使大量的任務自動化,shell特別擅長系統管理任務,尤其適合那些易用性、可維護性和便攜性比效率更重要的任務。
下面,讓我們一起來看看shell是如何工作的:
建立一個腳本
Linux中有好多中不同的shell,但是通常我們使用bash (bourne again shell) 進行shell編程,因爲bash是免 費的並且很容易使用。所以在本文中筆者所提供的腳本都是使用bash(但是在大多數情況下,這些腳本同樣可以在bash的大姐,bourne shell 中運行)。
如同其他語言一樣,通過我們使用任意一種文字編輯器,比如nedit、kedit、emacs、vi等來編寫我們的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=2
echo "this is the $numnd"
這並不會打印出"this is the 2nd",而僅僅打印"this is the ",因爲shell會去搜索變量numnd的值,但是這個變量時沒有值的。可以使用花括號來告訴shell我們要打印的是num變量:
num=2
echo "this is the ${num}nd"
這將打印: this is the 2nd
有許多變量是系統自動設定的,這將在後面使用這些變量時進行討論。
如果您需要處理數學表達式,那麼您需要使用諸如expr等程序(見下面)。
除了一般的僅在程序內有效的shell變量以外,還有環境變量。由export關鍵字處理過的變量叫做環境變量。我們不對環境變量進行討論,因爲通常情況下僅僅在登錄腳本中使用環境變量。
Shell命令和流程控制
在shell腳本中可以使用三類命令:
1)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' file.txt
cut -b colnum file&: 指定欲顯示的文件內容範圍,並將它們輸出到標準輸出設備比如:輸出每行第5個到第9個字符cut -b5-9 file.txt千萬不要和cat命令混淆,這是兩個完全不同的命令
cat file.txt: 輸出文件內容到標準輸出設備(屏幕)上
file somefile&: 得到文件類型
read var: 提示用戶輸入,並將輸入賦值給變量
sort file.txt: 對file.txt文件中的行進行排序
uniq: 刪除文本文件中出現的行列比如: sort file.txt | uniq
expr: 進行數學運算Example: add 2 and 3expr 2 "+" 3
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 text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file
awk: awk 用來從文本文件中提取字段。缺省地,字段分割符是空格,可以使用-F指定其他分割符。cat file.txt | awk -F, '{print $1 "," $3 }'這裏我們使用,作爲字段分割符,同時打印第一個和第三個字段。如果該文件內容如下: Adam Bor, 34, IndiaKerry Miller, 22, USA命令輸出結果爲:Adam Bor, IndiaKerry Miller, USA
2) 概念: 管道, 重定向和 backtick
這些不是系統命令,但是他們真的很重要。
管道 (|) 將一個命令的輸出作爲另外一個命令的輸入。
grep "hello" file.txt | wc -l
在file.txt中搜索包含有"hello"的行並計算其行數。
在這裏grep命令的輸出作爲wc命令的輸入。當然您可以使用多個命令。
重定向:將命令的結果輸出到文件,而不是標準輸出(屏幕)。
> 寫入文件並覆蓋舊文件
>> 加到文件的尾部,保留舊文件內容。
反短斜線
使用反短斜線可以將一個命令的輸出作爲另外一個命令的一個命令行參數。
命令:
find . -mtime -1 -type f -print
用來查找過去24小時(-mtime -2則表示過去48小時)內修改過的文件。如果您想將所有查找到的文件打一個包,則可以使用以下腳本:
#!/bin/sh
# The ticks are backticks (`) not normal quotes ('):
tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`
3) 流程控制
"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 1; }
echo "$mailfolder has mail from:"
grep "^From " $mailfolder
該腳本首先判斷mailfolder是否可讀。如果可讀則打印該文件中的"From" 一行。如果不可讀則或操作生效,打印錯誤信息後腳本退出。這裏有個問題,那就是我們必須有兩個命令:
-打印錯誤信息
-退出程序
我們使用花括號以匿名函數的形式將兩個命令放到一起作爲一個命令使用。一般函數將在下文提及。
不用與和或操作符,我們也可以用if表達式作任何事情,但是使用與或操作符會更便利很多。
case表達式可以用來匹配一個給定的字符串,而不是數字。
case ... in
...) do something here
esac
讓我們看一個例子。 file命令可以辨別出一個給定文件的文件類型,比如:
file lf.gz
這將返回:
lf.gz: gzip compressed data, deflated, original filename,
last modified: Mon Aug 27 23:09:18 2001, os: Unix
我們利用這一點寫了一個叫做smartzip的腳本,該腳本可以自動解壓bzip2, gzip 和zip 類型的壓縮文件:
#!/bin/sh
ftype=`file "$1"`
case "$ftype" in
"$1: Zip archive"*)
unzip "$1"
"$1: gzip compressed"*)
gunzip "$1"
"$1: bzip2 compressed"*)
bunzip2 "$1"
*) error "File $1 can not be uncompressed with smartzip";;
esac
您可能注意到我們在這裏使用了一個特殊的變量$1。該變量包含了傳遞給該程序的第一個參數值。也就是說,當我們運行:
smartzip articles.zip
$1 就是字符串 articles.zip
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?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1
You have selected Linux
您也可以在shell中使用如下的loop表達式:
while ...; do
....
done
while -loop 將運行直到表達式測試爲真。 will run while the expression that we test for is true. 關鍵字"break" 用來跳出循 環。而關鍵字"continue"用來不執行餘下的部分而直接跳到下一個循環。
for-loop表達式查看一個字符串列表 (字符串用空格分隔) 然後將其賦給一個變量:
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 rpmfile1 rpmfile2 ...
# 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 openssh.rpm w3m.rpm webgrep.rpm
此時 $* 包含了 3 個字符串,即openssh.rpm, w3m.rpm and webgrep.rpm.
引號
在 向程序傳遞任何參數之前,程序會擴展通配符和變量。這裏所謂擴展的意思是程序會把通配符(比如*)替換成合適的文件名,它變量替換成變量值。爲了防止程序 作這種替換,您可以使用引號:讓我們來看一個例子,假設在當前目錄下有一些文件,兩個jpg文件, mail.jpg 和tux.jpg。
#!/bin/sh
echo *.jpg
這將打印出"mail.jpg tux.jpg"的結果。
引號 (單引號和雙引號) 將防止這種通配符擴展:
#!/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 document.
當要將幾行文字傳遞給一個命令時,here document.(譯者注:目前還沒有見到過對該詞適合的翻譯)一種不錯的方法。對每個腳本寫一段幫助性的文字是很有用的,此時如果我們四有那個here document.就不必用echo函數一行行輸出。 一個 "Here document.quot; 以 << 開頭,後面接上一個字符串,這個字符串還必須出現在here document.末尾。下面是一個例子,在該例子中,我們對多個文件進行重命名,並且使用here document.打印幫助:
#!/bin/sh
# we have less than 3 arguments. Print the help text:
if [ $# -lt 3 ] then
cat <<HELP
ren -- renames a number of files using sed regular expressions
USAGE: ren 'regexp' 'replacement' files...
EXAMPLE: rename all *.HTM files in *.html:
ren 'HTM$' 'html' *.HTM
HELP
exit 0
fi
OLD="$1"
NEW="$2"
# 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表達式判斷輸入命令行參數是否小於3個 (特殊變量$# 表示包含參數的個數) 。如果輸入參數小 於3個,則將幫助文字傳遞給cat命令,然後由cat命令將其打印在屏幕上。打印幫助文字後程序退出。 如果輸入參數等於或大於3個,我們就將第一個參數 賦值給變量OLD,第二個參數賦值給變量NEW。下一步,我們使用shift命令將第一個和第二個參數從參數列表中刪除,這樣原來的第三個參數就成爲參數 列表$*的第一個參數。然後我們開始循環,命令行參數列表被一個接一個地被賦值給變量$file。接着我們判斷該文件是否存在,如果存在則通過sed命令 搜索和替換來產生新的文件名。然後將反短斜線內命令結果賦值給newfile。這樣我們就達到了我們的目的:得到了舊文件名和新文件名。然後使用mv命令 進行重命名。
函數
如果您寫了一些稍微複雜一些的程序,您就會發現在程序中可能在幾個地方使用了相同的代碼,並且您也會發現,如果我們使用了函數,會方便很多。一個函數是這個樣子的:
functionname()
{
# inside the body $1 is the first argument given to the function
# $2 the second ...
body
}
您需要在每個程序的開始對函數進行聲明。
下面是一個叫做xtitlebar的腳本,使用這個腳本您可以改變終端窗口的名稱。這裏使用了一個叫做help的函數。正如您可以看到的那樣,這個定義的函數被使用了兩次。
#!/bin/sh
# vim: set sw=4 ts=4 et:
help()
{
cat <<HELP
xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole
USAGE: xtitlebar [-h] "string_for_titelbar"
OPTIONS: -h help text
EXAMPLE: xtitlebar "cvs"
HELP
exit 0
}
# in case of error or if -h is given we call the function help:
[ -z "$1" ] && help
[ "$1" = "-h" ] && help
# send the escape sequence to change the xterm titelbar:
echo -e "33]0;$107"
#
在腳本中提供幫助是一種很好的編程習慣,這樣方便其他用戶(和您)使用和理解腳本。
命令行參數
我們已經見過$* 和 $1, $2 ... $9 等特殊變量,這些特殊變量包含了用戶從命令行輸入的參數。迄今爲止,我們僅僅瞭解了一些簡單的命令 行語法(比如一些強制性的參數和查看幫助的-h選項)。但是在編寫更復雜的程序時,您可能會發現您需要更多的自定義的選項。通常的慣例是在所有可選的參數 之前加一個減號,後面再加上參數值 (比如文件名)。
有好多方法可以實現對輸入參數的分析,但是下面的使用case表達式的例子無遺是一個不錯的方法。
#!/bin/sh
help()
{
cat <<HELP
This is a generic command line parser demo.
USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2
HELP
exit 0
}
while [ -n "$1" ]; do
case $1 in
-h) help;shift 1;; # function help is called
-f) opt_f=1;shift 1;; # variable opt_f is set
-l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2
--) shift;break;; # end of options
-*) echo "error: no such option $1. -h for help";exit 1;;
*) break;;
esac
done
echo "opt_f is $opt_f"
echo "opt_l is $opt_l"
echo "first arg is $1"
echo "2nd arg is $2"
您可以這樣運行該腳本:
cmdparser -l hello -f -- -somefile1 somefile2
返回的結果是:
opt_f is 1
opt_l is hello
first arg is -somefile1
2nd arg is somefile2
這個腳本是如何工作的呢?腳本首先在所有輸入命令行參數中進行循環,將輸入參數與case表達式進行比較,如果匹配則設置一個變量並且移除該參數。根據unix系統的慣例,首先輸入的應該是包含減號的參數。
實例
一般編程步驟
現在我們來討論編寫一個腳本的一般步驟。任何優秀的腳本都應該具有幫助和輸入參數。並且寫一個僞腳本(framework.sh),該腳本包含了大多數腳本都需要的框架結構,是一個非常不錯的主意。這時候,在寫一個新的腳本時我們只需要執行一下copy命令:
cp framework.sh myscript
然後再插入自己的函數。
讓我們再看兩個例子:
二進制到十進制的轉換
腳本 b2d 將二進制數 (比如 1101) 轉換爲相應的十進制數。這也是一個用expr命令進行數學運算的例子:
#!/bin/sh
# vim: set sw=4 ts=4 et:
help()
{
cat <<HELP
b2h -- convert binary to decimal
USAGE: b2h [-h] binarynum
OPTIONS: -h help text
EXAMPLE: b2h 111010
will return 58
HELP
exit 0
}
error()
{
# print an error and exit
echo "$1"
exit 1
}
lastchar()
{
# return the last character of a string in $rval
if [ -z "$1" ]; then
# empty string
rval=""
return
fi
# wc puts some space behind the output this is why we need sed:
numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
# now cut out the last char
rval=`echo -n "$1" | cut -b $numofchar`
}
chop()
{
# remove the last character in string and return it in $rval
if [ -z "$1" ]; then
# empty string
rval=""
return
fi
# wc puts some space behind the output this is why we need sed:
numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
if [ "$numofchar" = "1" ]; then
# only one char in string
rval=""
return
fi
numofcharminus1=`expr $numofchar "-" 1`
# now cut all but the last char:
rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`
}
while [ -n "$1" ]; do
case $1 in
-h) help;shift 1;; # function help is called
--) shift;break;; # end of options
-*) error "error: no such option $1. -h for help";;
*) break;;
esac
done
# The main program
sum=0
weight=1
# one arg must be given:
[ -z "$1" ] && help
binnum="$1"
binnumorig="$1"
while [ -n "$binnum" ]; do
lastchar "$binnum"
if [ "$rval" = "1" ]; then
sum=`expr "$weight" "+" "$sum"`
fi
# remove the last position in $binnum
chop "$binnum"
binnum="$rval"
weight=`expr "$weight" "*" 2`
done
echo "binary $binnumorig is decimal $sum"
#
該腳本使用的算法是利用十進制和二進制數權值 (1,2,4,8,16,..),比如二進制"10"可以這樣轉換成十進制:
0 * 1 + 1 * 2 = 2
爲了得到單個的二進制數我們是用了lastchar 函數。該函數使用wc -c計算字符個數,然後使用cut命令取出末尾一個字符。Chop函數的功能則是移除最後一個字符。
文件循環程序
或許您是想將所有發出的郵件保存到一個文件中的人們中的一員,但是在過了幾個月以後,這個文件可能會變得很大以至於使對該文件的訪問速度變慢。下面的腳 本rotatefile 可以解決這個問題。這個腳本可以重命名郵件保存文件(假設爲outmail)爲outmail.1,而對於outmail.1就 變成了outmail.2 等等等等...
#!/bin/sh
# vim: set sw=4 ts=4 et:
ver="0.1"
help()
{
cat <<HELP
rotatefile -- rotate the file name
USAGE: rotatefile [-h] filename
OPTIONS: -h help text
EXAMPLE: rotatefile out
This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1
and create an empty out-file
The max number is 10
version $ver
HELP
exit 0
}
error()
{
echo "$1"
exit 1
}
while [ -n "$1" ]; do
case $1 in
-h) help;shift 1;;
--) break;;
-*) echo "error: no such option $1. -h for help";exit 1;;
*) break;;
esac
done
# input check:
if [ -z "$1" ] then
error "ERROR: you must specify a file, use -h for help"
fi
filen="$1"
# rename any .1 , .2 etc file&:
for n in 9 8 7 6 5 4 3 2 1; do
if [ -f "$filen.$n" ]; then
p=`expr $n + 1`
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.1"
mv $filen $filen.1
fi
echo touch $filen
touch $filen
這個腳本是如何工作的呢?在檢測用戶提供了一個文件名以後,我們進行一個9到1的循環。文件9被命名爲10,文件8重命名爲9等等。循環完成之後,我們將原始文件命名爲文件1同時建立一個與原始文件同名的空文件。
調試
最簡單的調試命令當然是使用echo命令。您可以使用echo在任何懷疑出錯的地方打印任何變量值。這也是絕大多數的shell程序員要花費80%的時間來調試程序的原因。Shell程序的好處在於不需要重新編譯,插入一個echo命令也不需要多少時間。
shell也有一個真實的調試模式。如果在腳本"strangescript" 中有錯誤,您可以這樣來進行調試:
sh -x strangescript
這將執行該腳本並顯示所有變量的值。
shell還有一個不需要執行腳本只是檢查語法的模式。可以這樣使用:
sh -n your_script
這將返回所有語法錯誤。
我們希望您現在可以開始寫您自己的shell腳本,希望您玩得開心。
$HOME 使用者自己的目錄
$PATH 執行命令時所搜尋的目錄
$TZ 時區
$MAILCHECK 每隔多少秒檢查是否有新的信件
$PS1 在命令列時的提示號
$PS2 當命令尚未打完時,Shell 要求再輸入時的提示號
$MANPATH man 指令的搜尋路徑
二、特殊變量:
$0 這個程序的執行名字
$n 這個程序的第n個參數值,n=1..9
$* 這個程序的所有參數
$# 這個程序的參數個數
$$ 這個程序的PID
$! 執行上一個指令的PID
$? 執行上一個指令的返回值
三、shell中的變元:
* 任意字符串
? 一個任意字符
[abc] a, b, c三者中之一
[a-n] 從a到n的任一字符
四、幾個特殊字符表示
/b 退回
/c 打印一行時沒有換行符 這個我們經常會用到
/f 換頁
/r 回車
/t 製表
/v 垂直製表
// 反斜線本身
五、判斷文件的屬性
格式:-操作符 filename
-e 文件存在返回1, 否則返回0
-r 文件可讀返回1,否則返回0
-w 文件可寫返回1,否則返回0
-x 文件可執行返回1,否則返回0
-o 文件屬於用戶本人返回1, 否則返回0
-z 文件長度爲0返回1, 否則返回0.
-f 文件爲普通文件返回1, 否則返回0
-d 文件爲目錄文件時返回1, 否則返回0
六、測試字符串
字符串1 = 字符串2 當兩個字串相等時爲真
字符串1 != 字符串2 當兩個字串不等時爲真
-n 字符串 當字符串的長度大於0時爲真
-z 字符串 當字符串的長度爲0時爲真
字符串 當串字符串爲非空時爲真
七、測試兩個整數關係
數字1 -eq 數字2 兩數相等爲真
數字1 -ne 數字2 兩數不等爲真
數字1 -gt 數字2 數字1大於數字2爲真
數字1 -ge 數字2 數字1大於等於數字2爲真
數字1 -lt 數字2 數字1小於數字2爲真
數字1 -le 數字2 數字1小於等於數字2爲真
八、邏輯測試
-a 與
-o 或
! 非
今天介紹shell特殊字符的引用
===============================
shell中的特殊字符有
1、$ 美元符
2、/ 反斜槓
3、` 反引號
4、" 雙引號
5、< ,>,*,?,[,]
下面我一一舉列說明
一、$符號
1、echo $? 顯示的是上一條指令退出狀態
2、echo "$?" 效果同上
3、echo '$?' 顯示的是$?
4、echo /$? 顯示的是$?
5、echo "/$?" 顯示的是$?
大家可能已經看出 $符號在雙引號中具有特殊意義 雙引號對$符號不起作用
而單引號可以將特殊字符的的特殊意義屏蔽掉,使其能顯示爲字符本身,反斜
槓也可以將特殊字符的特殊含義屏蔽掉,使特殊字符失去特殊含義。
二、/ 反斜槓
反斜槓的作用是將特殊符號字符的特殊含義屏蔽掉,使其還是原字符
A=1234
echo /$A 顯示爲$A 如果不加/將顯示爲1234
echo /` 顯示爲`
echo /" 顯示爲雙引號
echo // 顯示爲/
三、` 反引號
反引號的功能是命令替換,將反引號中的字符串做爲命令來執行,我們在用shell編程時經常用的到 將系統命令的執行結果賦給一個變量
A=`date`
echo $A 顯示的不是date而是當時的時間串
比如有一文件A的內容如下
ABCDEFG
1234456
abcdefg
B=`cat A|grep 234` # 檢索文件A中含有字符串234的行
echo $B 將顯示爲1234456
echo "$B" 將顯示爲什麼?
echo "/$B" 將顯示爲什麼?讀者自己試試
四、" 雙引號
在系統中有些特殊字符,爲避免引用這些特殊字符 往往用雙引號或單引號將這些特殊字符引起來,使其不具有特殊含義。
但有一部分特殊字符在引號中還是具有特殊含義,用雙引號引起來是不起作用的。本文中所列的前四個特殊字符在雙引號中還是特殊字符。爲了使其不具有特殊含義一是用單引號引進來二是用/反斜線使其失去作用。
比如我們想原樣輸出這些特殊字符
echo """
echo "$"
echo "/"
echo "`"
以上不是你所期望的結果,因爲雙引號對它們不起作用,你只能這樣才能輸出這些特殊字符的原形
echo '"'
echo '$'
echo '/'
echo '`'
或
echo "/""
echo "/$"
echo "//"
echo "/`"
將分別顯示爲 " $ / `
五、其它特殊字符
大家注意到 除了前四個特殊字符外 我將其它的特殊字符都放在一塊,這是因爲前四個特殊字符在雙引號中還是具有特殊含義,所以單獨拿出來講,除此以外的特殊字符如果你要輸出這些特殊字符的原形,你就可以用雙引號或單引號引起來使其失去特殊含義。
< ,>,*,?,[,]對shell有特殊含義 但你可以用雙引號引起來輸入這些原形
講了這麼多大家是不是已經注意到所有的特殊字符在單引號中失去特殊含義,如果你要輸出特殊字符原形但又記不清那些特殊字符在雙引號中不能輸出原形,建議你乾脆用單引號引起來。
今天介紹條件測試語句
一、if 條件語句
格式:
if 條件表達式
then #當條件爲真時執行以下語句
命令列表
else #爲假時執行以下語句
命令列表
fi
if 語句也可以嵌套使用
if 條件表達式1
then
if 條件表達式2
then
命令列表
else
if 條件表達式3
then
命令列表
else
命令列表
fi
fi
else
命令列表
fi
你可以進行多層嵌套 一個if語句一定要跟一個fi 表示該層條件結束 否則會造成語法錯誤
結合前面講的 舉例如下:
這裏先講一個條件語句中用到的命令test 表示測試test後面的條件是否爲真
if test -f "$1"
then
lpr $1
else
if test -d "$1"
then
cd $1
lpr $1
else
echo "$1不是文件或目錄"
fi
fi
以上的例子還可以改成如下所示
if test -f "$1"
then
lpr $1
elif test -d "$1" #elif 同else if
then
(cd $1;lpr $1)
else
echo "$1不是文件或目錄"
fi
以上的例子不知您是否看懂是什麼意思嗎?
假如我們現在將這個例子保存爲prfile
chmod +x prfile
執行剛纔的程序
./prfile aaa
這個例子是檢查你的輸入的參數是否是一個文件 如果是就打印 如果是一個目錄 先轉目錄再打印 如果即不是文件也不是目錄給出提示
二、多重條件測試語句case
格式:
case 字串 in
模式) 命令列表;;
模式) 命令列表;;
....
esac
多重條件語句是以case 開始以esac結束 中間可以有多個條件列表 功能是測試字串和和裏面的模式有沒有匹配的,有就執行裏面的命令列表 模式也可以是*號 表示任意字串,每個模式裏面的最後要心;;雙引號結束,否則會發生語法錯誤。
現舉例如下:
case $1 in
*.c)
cc $1
;;
*.txt)
lpr $1
;;
*)
echo "未知的類型"
esac
假如將以上內容保存在文件abc中
chmod +x abc
執行 ./abc a.c 將會對文件a.c進行編譯
執行 ./abc readme.txt 將會把文件通過打印機
假如我將以上內容改一下,你是否會知道它的執行結果?
case $1 in
*)
cc $1
;;
*.txt)
lpr $1
;;
*.c)
echo "未知的類型"
esac
今天介紹循環語句
一. while 循環
while 命令格式
while 條件表
do
命令表
done
執行過程
shell首先執行條件表,如果條件表的最後一條語句的退出狀態爲零,則執行盾環體內的命令
表,執行完後,再檢查條件表,如果退出狀態爲零將繼續執行,如此循環往復直到條件表的
最後一條語句的退出狀態非零. 退出狀態爲零就是條件爲真True.
舉例說明 假如shell文件的內容如下:
Sum=0
i=0
while true #true是系統的關鍵詞 表示真
do
i=`expr $i + 1`
Sum=`expr $Sum + $i`
if [ $i = "100" ]
then
break;
fi
done
echo $i $Sum
最後這個程序顯示的是 100 5050
這個程序的運算就是將1到100加起來
下面將這個程序再改動一下
Sum=0
i=0
while [ $i != "100" ]
do
i=`expr $i + 1`
Sum=`expr $Sum + $i`
done
echo $i $Sum
改動後的程序運算結果和上面是一樣 但程序比上面的要簡練
在這個循環中還可以以until做爲測試條件 它正好與while測試的條件相反,也就是當條件爲假時將繼續執行循環體內的語句,否則就退出循環體,下面還用這個例子.
Sum=0
i=0
until [ $i = "100" ]
do
i=`expr $i + 1`
Sum=`expr $Sum + $i`
done
echo $i $Sum
當i不等於100時循環 就是當條件爲假時循環,否則就退出,而第一個例子是當i不等於100
時循環,也就是測試條件爲真時循環.
二.for 循環
命令格式:
for 變量 in 名字列表
do
命令列表
done
這裏的名字列表是一個由空格分隔的字符串列表,shell在執行for循環時每次依次從名字表
中取出一個字符串賦給循環變量作爲變量的值.
在寫for語句時,也可以省略in 名字列表部分,這表示用當前的位置參數來代替這時的名
字列表.
下面舉個例子
比如在你的電腦中有兩個目錄,一個是aa,一個是bb在這兩個目錄中有5個相同的文件,但其
中一個目錄中的一個或多個文件剛剛修改過,現在我忘記剛纔改的是那幾個文件 了,那麼我靠梢員冉弦幌掄飭礁瞿柯嫉奈募橢懶?程序如下:
for File in a1 a2 a3 a4 a5
do
diff aa/$File bb/$File
done
下面再舉一個不帶名字列表的例子
for File
do
echo $Filw
done
文件內容保存在a.sh中 並可執行
我們在執行這個shell程序時命令行如下:
a.sh a1 a2 a3 a4 a5
執行結果如下:
a1
a2
a3
a4
a5
大家從這個例子中可以看到命令行的參數被逐一讀入一次
三.循環控制語句
break 命令不執行當前循環體內break下面的語句從當前循環退出.
continue 命令是程序在本循體內忽略下面的語句,從循環頭開始執行.
一,命令組合:圓括號和花括號
shell中有兩種方法將命令組合在一起:圓括號和花括號.圓括號使shell創建一個子shell
來讀取並執行括起來的名命令.左括號和右括號不論出現在命令行中的什麼位置,shell都會
認爲它們具有特殊的組合意義的.只有用雙引號將它們括起來引用,才表示圓括號或花括號
的原義.例如:
echo a(b)
將出現語法上的錯誤,要想輸出a(b)字符串 只能括起來
echo "a(b)"
或echo a"("b")"
這樣才能被shell正確解釋.
利用組合命令有什麼作用呢?
一,用圓括號組合命令
圓括號的組合命令可以創建子進程運行組合程序,建立子進程的功能是很有用的,因爲
子shell在組合命令中的種種操作都不會影響到當前shell的各變量的值.
例如:
子進程在執行組合命令時改變了工作目錄,並在新的工作目錄下執行一系例命令,執行
完後它可以不必返回原工作目錄,因爲子進程工作目錄的改變不會影響到當前工作目錄.
創建子進程後將當前的環境也同樣傳給子shell,當前shell中用export輸出到環境中的
各變量在子shell中同樣有效.
花括號也可以將命令組合在一起.左 右花括號只有作爲一條命令的第一個字出現時,
shell才它們含有特殊含義.
與圓括號不同的是花括號並不創建子shell,只是由當前的shell來讀取並執行括起來的
命令.有時用戶希望使用一組命令的順序輸出作爲另一組命令的輸入,此時用花括號是很方
便的.
不論是用圓括號不是花括號,退出狀態都是等於最後一條括起來的命令的退出狀態.
二,可以在當前shell中執行的命令
用戶在使用shell時一定要了解那些是可以在當前shell中執行的命令 那些不可以
可以在當前shell中執行的命令有:
break case cd continue
echo eval exec exit
export for if read
readonly return set shift
test times trap umask
until wait while
: {}
shell 讀取文件
#!/bin/sh
while read line
do
echo $line
done < file
file是要讀取的文件。
建一文本,內存放需備份文件的路徑.比如:/root/1.ext和/txt/bb.exe兩個文件.現將其路徑:/root/ 和:/txt/分成兩行放入backup.txt中.這樣後.要求從backup.txt文本中讀出這兩個路徑.然後用CP將這兩個路徑中的文件都 BACKUP到一個指定的文件夾中去.而以後如果我需要加入新的備份路徑的話,只要直接到TXT文本中去加一個路徑就成了.
可是我不會.嗚嗚嗚嗚.
backup.txt格式:
:/root/
:/txt/
高人們救我哪~
---------------------------------------------------------------
#!/bin/sh
bkp_to=./bkp/
for d in `cat backup.txt`
do
bkp_from=`echo $d ¦ sed "s/^://g"`
if [ -d $bkp_from ] ; then
cp $bkp_from/* $bkp_to
fi
done