Shell腳本編程的常識

(這些每每是常常用到,可是各類網絡上的材料都語焉不詳的東西,我的認爲比較有用)html

七種文件類型

d            目錄                                                       l             符號連接python

s             套接字文件                                           b            塊設備文件linux

c            字符設備文件                                       p            命名管道文件git

-             普通文件正則表達式

正則表達式

從一個文件或命令輸出中抽取或過濾文本時。可以使用正則表達式(RE),正則表達式是一些特殊或不很特殊的字符串模式的集合。shell

       基本的元字符集:數據庫

       ^                   只匹配行首。編程

       $                   只匹配行尾。數組

       *                   一個單字符後緊跟*,匹配0個或多個此單字符。安全

       []                   匹配[]內字符,能夠是一個單字符,也能夠是字符序列。能夠使

              用-來表示[]內範圍,如[1-5]等價於[1,2,3,4,5]。

\                    屏蔽一個元字符的特殊含義,如\$表示字符$,而不表示匹配行

                    尾。

       .                 匹配任意單字符。

       pattern\{n\}   匹配pattern出現的次數n

       pattern\{n,\}m匹配pattern出現的次數,但表示次數最少爲n

       pattern\{n,m\} 匹配pattern出現的次數在n與m之間(n,m爲0-255)

幾個常見的例子:

       顯示可執行的文件:ls –l | grep …x...x..x

       只顯示文件夾:ls –l | grep  ^d

       匹配全部的空行:^$

       匹配全部的單詞:[A-Z a-z]*

       匹配任一非字母型字符:[^A-Z a-z]

       包含八個字符的行:^……..$(8個.)

字符類描述

如下是可用字符類的至關完整的列表:

[:alnum:] 字母數字 [a-z A-Z 0-9]

[:alpha:] 字母 [a-z A-Z]

[:blank:] 空格或製表鍵

[:cntrl:] 任何控制字符

[:digit:] 數字 [0-9]

[:graph:] 任何可視字符(無空格)

[:lower:] 小寫 [a-z]

[:print:] 非控制字符

[:punct:] 標點字符

[:space:] 空格

[:upper:] 大寫 [A-Z]

[:xdigit:] 十六進制數字 [0-9 a-f A-F]

儘量使用字符類是頗有利的,由於它們能夠更好地適應非英語 locale(包括某些必需的重音字符等等).

shell的引號類型

shell共有四種引用類型:

       「 」          雙引號

       ‘ ’           單引號

` `         反引號

\            反斜線

l        「 」 可引用除$、` 、\ 、外的任意字符或字符串,「 」中的變量可以正常顯示變量值。

l        ‘ ’與「 」相似,不一樣在於shell會忽略任何的引用值。

              例如: GIRL=‘girl’

                        echo 「The ‘$GIRL’ did well」

              則打印:The ‘girl’ did well

l        ` `用於設置系統命令的輸出到變量,shell會將` `中的內容做爲一個系統命令並執行質。

              例如:echo `date` 則打印當前的系統時間。

l        \ 用來屏蔽特殊含義的字符:&  *  +  ^  $  `  「  |  ?

例如:expr 12 \* 12 將輸出144

變量設置時的不一樣模式:

valiable_name=value           設置實際值到 variable_name中

valiable_name+value           若是設置了variable_name,則重設其值

valiable_name:?value           若是未設置variable_name,則先顯示未定義用戶錯誤信息

valiable_name?value           若是未設置variable_name,則顯示系統錯誤信息

valiable_name:=value   若是未設置variable_name,則設置其值

valiable_name-value            同上,但取值並不設置到variable_name

條件測試

test命令用於測試字符串、文件狀態和數字,expr測試和執行數值輸出。

Test格式:test condition 或 [ condition ](須要特別注意的是condition的兩邊都要有一個空格,不然會報錯),test命令返回0表示成功。

l        下面將分別描述test的三種測試:

n        文件狀態測試(經常使用的)

-d           測試是否文件夾

-f            測試是否通常文件

-L          測試是否連接文件

-r           測試文件是否可讀

-w         測試文件是否可寫

-x           測試文件是否可執行

-s           測試文件是否非空

n        字符串測試

五種格式: test  「string」

                            test  string_operator  「string」

                            test  「string」  string_operator  「string」

                            [ string_operator  「string」 ]

                            [ 「string」  string_operator  「string」 ]

其中string_operator能夠爲:       =     兩字符串相等

                                                               !=    兩字符串不等

                                                               -z   空串

                                                               -n   非空串

n        數值測試

兩種格式: 「number」  number_operator  「number」

                            [ 「number」  number_operator  「number」 ]

其中:number_operator 能夠爲:-eq  、-ne、-gt、-lt、-ge

例如:  NUMBER=130

                     [ 「990」  –le  「995」  –a  「NUMBER」  -gt  「133」 ]

                     (其中-a表示先後結果相「與」)

l        expr命令通常用於整數值,但也能夠用於字符串。

n        格式:  expr srgument operator operator argument

例如:  expr 10 + 10

              expr 10 ^ 2 (10的平方)

              expr $value + 10

n        增量計數――expr在循環中最基本的用法

例如:  LOOP=0

              LOOP=`expr $LOOP + 1`

n        模式匹配:經過指定的冒號選項計算字符串中的字符數

例如:  value=account.doc

              expr $value : `\(.*\).doc`

              輸出 account

命令執行順序

&&               成功執行一個命令後再執行下一個

||                    一個命令執行失敗後再執行另外一個命令

( )                  在當前shell中執行一組命令(格式:(命令1;命令2; ……))

{ }                同( )

       例如:  comet mouth_end || ( echo 「hello」 | mail dave ;exit )

             若是沒有( ),則shell將直接執行最後一個命令(exit)

腳本調試

最有用的調試腳本的工具是echo命令,能夠隨時打印有關變量或操做的信息,以幫助定位錯誤。也可以使用打印最後狀態($?) 命令來判斷命令是否成功,這時要注意的是要在執行完要測試的命令後當即輸出$?,不然$?將會改變。

Set命令也能夠用來輔助腳本測試:

Set –n           讀命令可是不執行

Set –v           顯示讀取的全部的行

Set –x           顯示全部的命令及其參數

(要關閉set選項,只要把-換成+就能夠了,這裏有點特殊,要注意一下)

一些經常使用的小trick

打印一些頭信息

command  <<  dilimiter

……

……

dilimiter

以分界符號dilimiter中的內容做爲命令的標準輸入

       經常使用在echo命令中,這樣就避免了沒輸出一行就要使用一個echo命令,同時,輸出格式的調整也相應變得簡單了。

       例如:  echo << something_message

************************************************

                                         hello, welcome to use my shell script

************************************************

                something_message

將在屏幕上輸出:

************************************************

                                         hello, welcome to use my shell script

************************************************

1、利用<<的分解符號性質還能夠自動選擇菜單或實現自動的ftp傳輸

也就是利用分解符號的性質自動選擇菜單。

例如: ./menu_choose >>output_file 2>&1 <<Choose

             2

             3

             Y

             Choose

             則自動在執行腳本的過程當中一步步做出選擇:2,3,Y

<<這種性質決定了它是理想的訪問數據庫的有用工具,能夠用它來輸入面對數據庫提示時所做的各類選擇。

建立一個長度爲0的空文件

執行 > file_name 命令或 touch file_name 命令。

一些經常使用的shell變量

$#          傳遞到腳本的參數個數

$*          以一個單字符串顯示全部向腳本傳遞的參數(可大於9個)

$$          腳本運行的當前進程的ID號

$!           後臺運行的最後一個進程的ID號

$@        與$#相同,但使用時加引號,並在引號中返回每一個參數

$-           顯示shell使用的當前選項

$?                 顯示最後命令的退出狀態,0表示無錯誤(這個變量也經常用來打印輸出,在腳本調試時標記某個shell命令或某個函數是否正確執行,可是要注意,$?記載的是最近的函數或命令的退出狀態,所以打印時應該當即打印以得到正確的信息)

$0的使用

在變量中有一種位置變量$n,用來存放函數調用或腳本執行時傳入的參數,其中$0表示函數名或腳本名,須要注意的是,這時的腳本名傳遞的是包含全路徑的腳本名。從$1-$9表示傳入的第一到第九個參數,這樣的參數表示不能多於九個,若是多於九個,能夠使用下面將要提到的shift指令來讀取。

由於$0存放函數名或腳本名,所以咱們能夠經過echo $0來輸出調用信息,可是,因爲存放的是全路徑名,咱們能夠利用一個shell命令來獲得腳本名,basename $0 將獲得$0中名字的部分,而與之相反的,dirname $0將獲得$0中路徑的部分。

Shift的運用

用head或tail指令指定查閱的行數

例如:查閱文件前20行:  head –20 file_name

             查閱文件後10行: tail –10 file_name

awk使用規則

awk 是一種很棒的語言。awk 適合於文本處理和報表生成,它還有許多精心設計的特性,容許進行須要特殊技巧程序設計。與某些語言不一樣,awk 的語法較爲常見。它借鑑了某些語言的一些精華部分,如 C 語言、python 和 bash(雖然在技術上,awk 比 python 和 bash 早建立)。awk 是那種一旦學會了就會成爲您戰略編碼庫的主要部分的語言。

第一個 awk

讓咱們繼續,開始使用 awk,以瞭解其工做原理。在命令行中輸入如下命令:

$ awk '{ print }' /etc/passwd

您將會見到 /etc/passwd 文件的內容出如今眼前。如今,解釋 awk 作了些什麼。調用 awk 時,咱們指定 /etc/passwd 做爲輸入文件。執行 awk 時,它依次對 /etc/passwd 中的每一行執行 print 命令。全部輸出都發送到 stdout,所獲得的結果與與執行catting /etc/passwd徹底相同。

如今,解釋 { print } 代碼塊。在 awk 中,花括號用於將幾塊代碼組合到一塊兒,這一點相似於 C 語言。在代碼塊中只有一條 print 命令。在 awk 中,若是隻出現 print 命令,那麼將打印當前行的所有內容。

       這裏是另外一個 awk 示例,它的做用與上例徹底相同:

              $ awk '{ print $0 }' /etc/passwd

在 awk 中,$0 變量表示整個當前行,因此 print 和 print $0 的做用徹底同樣。

若是您願意,能夠建立一個 awk 程序,讓它輸出與輸入數據徹底無關的數據。如下是一個示例:

$ awk '{ print "" }' /etc/passwd

只要將 "" 字符串傳遞給 print 命令,它就會打印空白行。若是測試該腳本,將會發現對於 /etc/passwd 文件中的每一行,awk 都輸出一個空白行。再次說明, awk 對輸入文件中的每一行都執行這個腳本。如下是另外一個示例:

$ awk '{ print "hiya" }' /etc/passwd

運行這個腳本將在您的屏幕上寫滿 hiya。:)

多個字段

awk 很是善於處理分紅多個邏輯字段的文本,並且讓您能夠絕不費力地引用 awk 腳本中每一個獨立的字段。如下腳本將打印出您的系統上全部用戶賬戶的列表:

$ awk -F":" '{ print $1 }' /etc/passwd

上例中,在調用 awk 時,使用 -F 選項來指定 ":" 做爲字段分隔符。awk 處理 print $1 命令時,它會打印出在輸入文件中每一行中出現的第一個字段。如下是另外一個示例:

$ awk -F":" '{ print $1 $3 }' /etc/passwd

如下是該腳本輸出的摘錄:

halt7

operator11

root0

shutdown6

sync5

bin1

....etc.

如您所見,awk 打印出 /etc/passwd 文件的第一和第三個字段,它們正好分別是用戶名和用戶標識字段。如今,當腳本運行時,它並不理想 -- 在兩個輸出字段之間沒有空格!若是習慣於使用 bash 或 python 進行編程,那麼您會期望 print $1 $3 命令在兩個字段之間插入空格。然而,當兩個字符串在 awk 程序中彼此相鄰時,awk 會鏈接它們但不在它們之間添加空格。如下命令會在這兩個字段中插入空格:

$ awk -F":" '{ print $1 " " $3 }' /etc/passwd

以這種方式調用 print 時,它將鏈接 $一、" " 和 $3,建立可讀的輸出。固然,若是須要的話,咱們還能夠插入一些文本標籤:

$ awk -F":" '{ print "username: " $1 "\t\tuid:" $3" }' /etc/passwd

這將產生如下輸出:

username: halt          uid:7

username: operator      uid:11

username: root          uid:0

username: shutdown      uid:6

username: sync          uid:5

username: bin           uid:1

....etc.

外部腳本

將腳本做爲命令行自變量傳遞給 awk 對於小的單行程序來講是很是簡單的,而對於多行程序,它就比較複雜。您確定想要在外部文件中撰寫腳本。而後能夠向 awk 傳遞 -f 選項,以向它提供此腳本文件:

$ awk -f myscript.awk myfile.in

將腳本放入文本文件還可讓您使用附加 awk 功能。例如,這個多行腳本與前面的單行腳本的做用相同,它們都打印出 /etc/passwd 中每一行的第一個字段:

BEGIN {

                 FS=":"

}

{ print $1 }

這兩個方法的差異在於如何設置字段分隔符。在這個腳本中,字段分隔符在代碼自身中指定(經過設置 FS 變量),而在前一個示例中,經過在命令行上向 awk 傳遞 -F":" 選項來設置 FS。一般,最好在腳本自身中設置字段分隔符,只是由於這表示您能夠少輸入一個命令行自變量。咱們將在本文的後面詳細討論 FS 變量。

BEGIN 和 END 塊

一般,對於每一個輸入行,awk 都會執行每一個腳本代碼塊一次。然而,在許多編程狀況中,可能須要在 awk 開始處理輸入文件中的文本以前執行初始化代碼。對於這種狀況,awk 容許您定義一個 BEGIN 塊。咱們在前一個示例中使用了 BEGIN 塊。由於 awk 在開始處理輸入文件以前會執行 BEGIN 塊,所以它是初始化 FS(字段分隔符)變量、打印頁眉或初始化其它在程序中之後會引用的全局變量的極佳位置。

awk 還提供了另外一個特殊塊,叫做 END 塊。awk 在處理了輸入文件中的全部行以後執行這個塊。一般,END 塊用於執行最終計算或打印應該出如今輸出流結尾的摘要信息。

規則表達式和塊

awk 容許使用規則表達式,根據規則表達式是否匹配當前行來選擇執行獨立代碼塊。如下示例腳本只輸出包含字符序列 foo 的那些行:

/foo/ { print }

固然,能夠使用更復雜的規則表達式。如下腳本將只打印包含浮點數的行:

/[0-9]+\.[0-9]*/ { print }

還有許多其它方法能夠選擇執行代碼塊。咱們能夠將任意一種布爾表達式放在一個代碼塊以前,以控制什麼時候執行某特定塊。僅當對前面的布爾表達式求值爲真時,awk 才執行代碼塊。如下示例腳本輸出將輸出其第一個字段等於 fred 的全部行中的第三個字段。若是當前行的第一個字段不等於 fred,awk 將繼續處理文件而不對當前行執行 print 語句:

$1 == "fred" { print $3 }

awk 提供了完整的比較運算符集合,包括 "=="、"<"、">"、"<="、">=" 和 "!="。另外,awk 還提供了 "~" 和 "!~" 運算符,它們分別表示「匹配」和「不匹配」。它們的用法是在運算符左邊指定變量,在右邊指定規則表達式。若是某一行的第五個字段包含字符序列 root,那麼如下示例將只打印這一行中的第三個字段:

$5 ~ /root/ { print $3 }

條件語句

awk 還提供了很是好的相似於 C 語言的 if 語句。若是您願意,能夠使用 if 語句重寫前一個腳本:

{

                 if ( $5 ~ /root/ ) {

                    print $3

                 }

}

這兩個腳本的功能徹底同樣。第一個示例中,布爾表達式放在代碼塊外面。而在第二個示例中,將對每個輸入行執行代碼塊,並且咱們使用 if 語句來選擇執行 print 命令。這兩個方法均可以使用,能夠選擇最適合腳本其它部分的一種方法。

如下是更復雜的 awk if 語句示例。能夠看到,儘管使用了複雜、嵌套的條件語句,if 語句看上去仍與相應的 C 語言 if 語句同樣:

{

                 if ( $1 == "foo" ) {

                    if ( $2 == "foo" ) {

                       print "uno"

                    } else {

                       print "one"

                    }

                 } else if ($1 == "bar" ) {

                    print "two"

                 } else {

                    print "three"

                 }

}

使用 if 語句還能夠將代碼:

! /matchme/ { print $1 $3 $4 }

轉換成:

{  

                 if ( $0 !~ /matchme/ ) {

                    print $1 $3 $4

                 }

}

這兩個腳本都只輸出不包含 matchme 字符序列的那些行。此外,還能夠選擇最適合您的代碼的方法。它們的功能徹底相同。

awk 還容許使用布爾運算符 "||"(邏輯與)和 "&&"(邏輯或),以便建立更復雜的布爾表達式:

( $1 == "foo" ) && ( $2 == "bar" ) { print }

這個示例只打印第一個字段等於 foo 且第二個字段等於 bar 的那些行。

數值變量

至今,咱們不是打印字符串、整行就是特定字段。然而,awk 還容許咱們執行整數和浮點運算。經過使用數學表達式,能夠很方便地編寫計算文件中空白行數量的腳本。如下就是這樣一個腳本:

              BEGIN   { x=0 }

/^$/    { x=x+1 }

END     { print "I found " x " blank lines. :}" }

在 BEGIN 塊中,將整數變量 x 初始化成零。而後,awk 每次遇到空白行時,awk 將執行 x=x+1 語句,遞增 x。處理完全部行以後,執行 END 塊,awk 將打印出最終摘要,指出它找到的空白行數量。

字符串化變量

awk 的優勢之一就是「簡單和字符串化」。我認爲 awk 變量「字符串化」是由於全部 awk 變量在內部都是按字符串形式存儲的。同時,awk 變量是「簡單的」,由於能夠對它執行數學操做,且只要變量包含有效數字字符串,awk 會自動處理字符串到數字的轉換步驟。要理解個人觀點,請研究如下這個示例:

x="1.01"

# We just set x to contain the *string* "1.01"

x=x+1

# We just added one to a *string*

print x

# Incidentally, these are comments :)

awk 將輸出:

              2.01

有趣吧!雖然將字符串值 1.01 賦值給變量 x,咱們仍然能夠對它加一。但在 bash 和 python 中卻不能這樣作。首先,bash 不支持浮點運算。並且,若是 bash 有「字符串化」變量,它們並不「簡單」;要執行任何數學操做,bash 要求咱們將數字放到醜陋的 $( ) ) 結構中。若是使用 python,則必須在對 1.01 字符串執行任何數學運算以前,將它轉換成浮點值。雖然這並不困難,但它還是附加的步驟。若是使用 awk,它是全自動的,而那會使咱們的代碼又好又整潔。若是想要對每一個輸入行的第一個字段乘方並加一,能夠使用如下腳本:

{ print ($1^2)+1 }

若是作一個小實驗,就能夠發現若是某個特定變量不包含有效數字,awk 在對數學表達式求值時會將該變量看成數字零處理。

衆多運算符

awk 的另外一個優勢是它有完整的數學運算符集合。除了標準的加、減、乘、除,awk 還容許使用前面演示過的指數運算符 "^"、模(餘數)運算符 "%" 和其它許多從 C 語言中借入的易於使用的賦值操做符。

這些運算符包括先後加減(i++、--foo)、加/減/乘/除賦值運算符( a+=三、b*=二、c/=2.二、d-=6.2)。不只如此 -- 咱們還有易於使用的模/指數賦值運算符(a^=二、b%=4)。

字段分隔符

awk 有它本身的特殊變量集合。其中一些容許調整 awk 的運行方式,而其它變量能夠被讀取以收集關於輸入的有用信息。咱們已經接觸過這些特殊變量中的一個,FS。前面已經提到過,這個變量讓您能夠設置 awk 要查找的字段之間的字符序列。咱們使用 /etc/passwd 做爲輸入時,將 FS 設置成 ":"。當這樣作有問題時,咱們還能夠更靈活地使用 FS。

FS 值並無被限制爲單一字符;能夠經過指定任意長度的字符模式,將它設置成規則表達式。若是正在處理由一個或多個 tab 分隔的字段,您可能但願按如下方式設置 FS:

FS="\t+"

以上示例中,咱們使用特殊 "+" 規則表達式字符,它表示「一個或多個前一字符」。

若是字段由空格分隔(一個或多個空格或 tab),您可能想要將 FS 設置成如下規則表達式:

FS="[[:space:]+]"

這個賦值表達式也有問題,它並不是必要。爲何?由於缺省狀況下,FS 設置成單一空格字符,awk 將這解釋成表示「一個或多個空格或 tab」。在這個特殊示例中,缺省 FS 設置偏偏是您最想要的!

複雜的規則表達式也不成問題。即便您的記錄由單詞 "foo" 分隔,後面跟着三個數字,如下規則表達式仍容許對數據進行正確的分析:

FS="foo[0-9][0-9][0-9]"

字段數量

接着咱們要討論的兩個變量一般並非須要賦值的,而是用來讀取以獲取關於輸入的有用信息。第一個是 NF 變量,也叫作「字段數量」變量。awk 會自動將該變量設置成當前記錄中的字段數量。能夠使用 NF 變量來只顯示某些輸入行:

NF == 3 { print "this particular record has three fields: " $0 }

固然,也能夠在條件語句中使用 NF 變量,以下:

{  

                 if ( NF > 2 ) {

                    print $1 " " $2 ":" $3

                 }

}

記錄號

記錄號 (NR) 是另外一個方便的變量。它始終包含當前記錄的編號(awk 將第一個記錄算做記錄號 1)。迄今爲止,咱們已經處理了每一行包含一個記錄的輸入文件。對於這些狀況,NR 還會告訴您當前行號。然而,當咱們在本系列之後部分中開始處理多行記錄時,就不會再有這種狀況,因此要注意!能夠象使用 NF 變量同樣使用 NR 來只打印某些輸入行:

(NR < 10 ) || (NR > 100) { print "We are on record number 1-9 or 101+" }

另外一個示例:

{

                 #skip header

                 if ( NR > 10 ) {

                    print "ok, now for the real information!"

                 }

}

awk 提供了適合各類用途的附加變量。咱們將在之後的文章中討論這些變量。

多行記錄

awk 是一種用於讀取和處理結構化數據(如系統的 /etc/passwd 文件)的極佳工具。/etc/passwd 是 UNIX 用戶數據庫,而且是用冒號定界的文本文件,它包含許多重要信息,包括全部現有用戶賬戶和用戶標識,以及其它信息。在個人前一篇文章中,我演示了 awk 如何輕鬆地分析這個文件。咱們只須將 FS(字段分隔符)變量設置成 ":"。

正確設置了 FS 變量以後,就能夠將 awk 配置成分析幾乎任何類型的結構化數據,只要這些數據是每行一個記錄。然而,若是要分析佔據多行的記錄,僅僅依靠設置 FS 是不夠的。在這些狀況下,咱們還須要修改 RS 記錄分隔符變量。RS 變量告訴 awk 當前記錄何時結束,新記錄何時開始。

譬如,讓咱們討論一下如何完成處理「聯邦證人保護計劃」所涉及人員的地址列表的任務:

Jimmy the Weasel

100 Pleasant Drive

San Francisco, CA 12345

Big Tony

200 Incognito Ave.

Suburbia, WA 67890

理論上,咱們但願 awk 將每 3 行看做是一個獨立的記錄,而不是三個獨立的記錄。若是 awk 將地址的第一行看做是第一個字段 ($1),街道地址看做是第二個字段 ($2),城市、州和郵政編碼看做是第三個字段 $3,那麼這個代碼就會變得很簡單。如下就是咱們想要獲得的代碼:

BEGIN {

                     FS="\n"

                     RS=""

}

在上面這段代碼中,將 FS 設置成 "\n" 告訴 awk 每一個字段都佔據一行。經過將 RS 設置成 "",還會告訴 awk 每一個地址記錄都由空白行分隔。一旦 awk 知道是如何格式化輸入的,它就能夠爲咱們執行全部分析工做,腳本的其他部分很簡單。讓咱們研究一個完整的腳本,它將分析這個地址列表,並將每一個記錄打印在一行上,用逗號分隔每一個字段。

address.awk BEGIN {

                     FS="\n"

                     RS=""

}

{

                     print $1 ", " $2 ", " $3

}

若是這個腳本保存爲 address.awk,地址數據存儲在文件 address.txt 中,能夠經過輸入 "awk -f address.awk address.txt" 來執行這個腳本。此代碼將產生如下輸出:

Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345

Big Tony, 200 Incognito Ave., Suburbia, WA 67890

OFS 和 ORS

在 address.awk 的 print 語句中,能夠看到 awk 會鏈接(合併)一行中彼此相鄰的字符串。咱們使用此功能在同一行上的三個字段之間插入一個逗號和空格 (", ")。這個方法雖然有用,但比較難看。與其在字段間插入 ", " 字符串,倒不如讓經過設置一個特殊 awk 變量 OFS,讓 awk 完成這件事。請參考下面這個代碼片段。

print "Hello", "there", "Jim!"

這行代碼中的逗號並非實際文字字符串的一部分。事實上,它們告訴 awk "Hello"、"there" 和 "Jim!" 是單獨的字段,而且應該在每一個字符串之間打印 OFS 變量。缺省狀況下,awk 產生如下輸出:

Hello there Jim!

這是缺省狀況下的輸出結果,OFS 被設置成 " ",單個空格。不過,咱們能夠方便地從新定義 OFS,這樣 awk 將插入咱們中意的字段分隔符。如下是原始 address.awk 程序的修訂版,它使用 OFS 來輸出那些中間的 ", " 字符串:

address.awk 的修訂版 BEGIN {

                     FS="\n"

                     RS=""

                     OFS=", "

}

{

                     print $1, $2, $3

}

       awk 還有一個特殊變量 ORS,全稱是「輸出記錄分隔符」。經過設置缺省爲換行 ("\n") 的 OFS,咱們能夠控制在 print 語句結尾自動打印的字符。缺省 ORS 值會使 awk 在新行中輸出每一個新的 print 語句。若是想使輸出的間隔翻倍,能夠將 ORS 設置成 "\n\n"。或者,若是想要用單個空格分隔記錄(而不換行),將 ORS 設置成 " "。

將多行轉換成用 tab 分隔的格式

假設咱們編寫了一個腳本,它將地址列表轉換成每一個記錄一行,且用 tab 定界的格式,以便導入電子表格。使用稍加修改的 address.awk 以後,就能夠清楚地看到這個程序只適合於三行的地址。若是 awk 遇到如下地址,將丟掉第四行,而且不打印該行:

Cousin Vinnie

Vinnie's Auto Shop

300 City Alley

Sosueme, OR 76543

要處理這種狀況,代碼最好考慮每一個字段的記錄數量,並依次打印每一個記錄。如今,代碼只打印地址的前三個字段。如下就是咱們想要的一些代碼:

適合具備任意多字段的地址的 address.awk 版本 BEGIN {

                 FS="\n"

                 RS=""

                 ORS=""

}

             { 

             x=1

             while ( x<NF ) {

print $x "\t"

              x++

             }

             print $NF "\n"

}

首先,將字段分隔符 FS 設置成 "\n",將記錄分隔符 RS 設置成 "",這樣 awk 能夠象之前同樣正確分析多行地址。而後,將輸出記錄分隔符 ORS 設置成 "",它將使 print 語句在每一個調用結尾不輸出新行。這意味着若是但願任何文本重新的一行開始,那麼須要明確寫入 print "\n"。

在主代碼塊中,建立了一個變量 x 來存儲正在處理的當前字段的編號。起初,它被設置成 1。而後,咱們使用 while 循環(一種 awk 循環結構,等同於 C 語言中的 while 循環),對於全部記錄(最後一個記錄除外)重複打印記錄和 tab 字符。最後,打印最後一個記錄和換行;此外,因爲將 ORS 設置成 "",print 將不輸出換行。程序輸出以下,這正是咱們所指望的(不算漂亮,但用 tab 定界,以便於導入電子表格):

Jimmy the Weasel        100 Pleasant Drive      San Francisco, CA 12345

Big Tony        200 Incognito Ave.      Suburbia, WA 67890

Cousin Vinnie   Vinnie's Auto Shop      300 City Alley  Sosueme, OR 76543

循環結構

咱們已經看到了 awk 的 while 循環結構,它等同於相應的 C 語言 while 循環。awk 還有 "do...while" 循環,它在代碼塊結尾處對條件求值,而不象標準 while 循環那樣在開始處求值。它相似於其它語言中的 "repeat...until" 循環。如下是一個示例:

do...while 示例 {

                     count=1

                     do {

                            print "I get printed at least once no matter what"

                     } while ( count != 1 )

}

與通常的 while 循環不一樣,因爲在代碼塊以後對條件求值,"do...while" 循環永遠都至少執行一次。換句話說,當第一次遇到普通 while 循環時,若是條件爲假,將永遠不執行該循環。

for 循環

awk 容許建立 for 循環,它就象 while 循環,也等同於 C 語言的 for 循環:

for ( initial assignment; comparison; increment ) {

                     code block

}

如下是一個簡短示例:

for ( x = 1; x <= 4; x++ ) {

                     print "iteration",x

}

此段代碼將打印:

iteration 1

iteration 2

iteration 3

iteration 4

break 和 continue

此外,如同 C 語言同樣,awk 提供了 break 和 continue 語句。使用這些語句能夠更好地控制 awk 的循環結構。如下是迫切須要 break 語句的代碼片段:

while 死循環 while (1) {

                     print "forever and ever..."

}

由於 1 永遠表明是真,這個 while 循環將永遠運行下去。如下是一個只執行十次的循環:

break 語句示例 x=1

while(1) {

                     print "iteration",x

                     if ( x == 10 ) {

                     break

                     }

                     x++

}

這裏,break 語句用於「逃出」最深層的循環。"break" 使循環當即終止,並繼續執行循環代碼塊後面的語句。

continue 語句補充了 break,其做用以下:

x=1

while (1) {

                     if ( x == 4 ) {

                            x++

                            continue

                     }

                     print "iteration",x

                     if ( x > 20 ) {

                            break

                     }

                     x++

}

這段代碼打印 "iteration 1" 到 "iteration 21","iteration 4" 除外。若是迭代等於 4,則增長 x 並調用 continue 語句,該語句當即使 awk 開始執行下一個循環迭代,而不執行代碼塊的其他部分。如同 break 同樣,continue 語句適合各類 awk 迭代循環。在 for 循環主體中使用時,continue 將使循環控制變量自動增長。如下是一個等價循環:

for ( x=1; x<=21; x++ ) {

                     if ( x == 4 ) {

                            continue

                     }

                     print "iteration",x

}

在 while 循環中時,在調用 continue 以前沒有必要增長 x,由於 for 循環會自動增長 x。

數組

若是您知道 awk 能夠使用數組,您必定會感到高興。然而,在 awk 中,數組下標一般從 1 開始,而不是 0:

myarray[1]="jim"

myarray[2]=456

awk 遇到第一個賦值語句時,它將建立 myarray,並將元素 myarray[1] 設置成 "jim"。執行了第二個賦值語句後,數組就有兩個元素了。

數組迭代

定義以後,awk 有一個便利的機制來迭代數組元素,以下所示:

for ( x in myarray ) {

                     print myarray[x]

}

這段代碼將打印數組 myarray 中的每個元素。當對於 for 使用這種特殊的 "in" 形式時,awk 將 myarray 的每一個現有下標依次賦值給 x(循環控制變量),每次賦值之後都循環一次循環代碼。雖然這是一個很是方便的 awk 功能,但它有一個缺點 -- 當 awk 在數組下標之間輪轉時,它不會依照任何特定的順序。那就意味着咱們不能知道以上代碼的輸出是:

jim

456

仍是:

456

jim

套用 Forrest Gump 的話來講,迭代數組內容就像一盒巧克力 -- 您永遠不知道將會獲得什麼。所以有必要使 awk 數組「字符串化」,咱們如今就來研究這個問題。

數組下標字符串化

在個人前一篇文章中,我演示了 awk 實際上以字符串格式來存儲數字值。雖然 awk 要執行必要的轉換來完成這項工做,但它卻能夠使用某些看起來很奇怪的代碼:

a="1"

b="2"

c=a+b+3

執行了這段代碼後,c 等於 6。因爲 awk 是「字符串化」的,添加字符串 "1" 和 "2" 在功能上並不比添加數字 1 和 2 難。這兩種狀況下,awk 均可以成功執行運算。awk 的「字符串化」性質很是可愛 -- 您可能想要知道若是使用數組的字符串下標會發生什麼狀況。例如,使用如下代碼:

myarr["1"]="Mr. Whipple"

print myarr["1"]

能夠預料,這段代碼將打印 "Mr. Whipple"。但若是去掉第二個 "1" 下標中的引號,狀況又會怎樣呢?

myarr["1"]="Mr. Whipple"

print myarr[1]

猜測這個代碼片段的結果比較難。awk 將 myarr["1"] 和 myarr[1] 看做數組的兩個獨立元素,仍是它們是指同一個元素?答案是它們指的是同一個元素,awk 將打印 "Mr. Whipple",如同第一個代碼片段同樣。雖然看上去可能有點怪,但 awk 在幕後卻一直使用數組的字符串下標!

瞭解了這個奇怪的真相以後,咱們中的一些人可能想要執行相似於如下的古怪代碼:

myarr["name"]="Mr. Whipple"

print myarr["name"]

這段代碼不只不會產生錯誤,並且它的功能與前面的示例徹底相同,也將打印 "Mr. Whipple"!能夠看到,awk 並無限制咱們使用純整數下標;若是咱們願意,能夠使用字符串下標,並且不會產生任何問題。只要咱們使用非整數數組下標,如 myarr["name"],那麼咱們就在使用關聯數組。從技術上講,若是咱們使用字符串下標,awk 的後臺操做並無什麼不一樣(由於即使使用「整數」下標,awk 仍是會將它看做是字符串)。可是,應該將它們稱做關聯數組 -- 它聽起來很酷,並且會給您的上司留下印象。字符串化下標是咱們的小祕密。;)

數組工具

談到數組時,awk 給予咱們許多靈活性。能夠使用字符串下標,並且不須要連續的數字序列下標(例如,能夠定義 myarr[1] 和 myarr[1000],但不定義其它全部元素)。雖然這些都頗有用,但在某些狀況下,會產生混淆。幸虧,awk 提供了一些實用功能有助於使數組變得更易於管理。

首先,能夠刪除數組元素。若是想要刪除數組 fooarray 的元素 1,輸入:

delete fooarray[1]

並且,若是想要查看是否存在某個特定數組元素,能夠使用特殊的 "in" 布爾運算符,以下所示:

if ( 1 in fooarray ) {

                     print "Ayep!  It's there."

} else {

                     print "Nope!  Can't find it."

}

格式化輸出

雖然大多數狀況下 awk 的 print 語句能夠完成任務,但有時咱們還須要更多。在那些狀況下,awk 提供了兩個咱們熟知的老朋友 printf() 和 sprintf()。是的,如同其它許多 awk 部件同樣,這些函數等同於相應的 C 語言函數。printf() 會將格式化字符串打印到 stdout,而 sprintf() 則返回能夠賦值給變量的格式化字符串。若是不熟悉 printf() 和 sprintf(),介紹 C 語言的文章可讓您迅速瞭解這兩個基本打印函數。在 Linux 系統上,能夠輸入 "man 3 printf" 來查看 printf() 幫助頁面。

如下是一些 awk sprintf() 和 printf() 的樣本代碼。能夠看到,它們幾乎與 C 語言徹底相同。

x=1

b="foo"

printf("%s got a %d on the last test\n","Jim",83)

myout=("%s-%d",b,x)

print myout

      此代碼將打印:

              Jim got a 83 on the last test

foo-1

字符串函數

awk 有許多字符串函數,這是件好事。在 awk 中,確實須要字符串函數,由於不能象在其它語言(如 C、C++ 和 Python)中那樣將字符串看做是字符數組。例如,若是執行如下代碼:

mystring="How are you doing today?"

print mystring[3]

將會接收到一個錯誤,以下所示:

awk: string.gawk:59: fatal: attempt to use scalar as array

噢,好吧。雖然不象 Python 的序列類型那樣方便,但 awk 的字符串函數仍是能夠完成任務。讓咱們來看一下。

首先,有一個基本 length() 函數,它返回字符串的長度。如下是它的使用方法:

print length(mystring)

此代碼將打印值:

24

好,繼續。下一個字符串函數叫做 index,它將返回子字符串在另外一個字符串中出現的位置,若是沒有找到該字符串則返回 0。使用 mystring,能夠按如下方法調用它:

print index(mystring,"you")

awk 會打印:

9

讓咱們繼續討論另外兩個簡單的函數,tolower() 和 toupper()。與您猜測的同樣,這兩個函數將返回字符串而且將全部字符分別轉換成小寫或大寫。請注意,tolower() 和 toupper() 返回新的字符串,不會修改原來的字符串。這段代碼:

print tolower(mystring)

print toupper(mystring)

print mystring

……將產生如下輸出:

how are you doing today?

HOW ARE YOU DOING TODAY?

How are you doing today?

到如今爲止一切不錯,但咱們究竟如何從字符串中選擇子串,甚至單個字符?那就是使用 substr() 的緣由。如下是 substr() 的調用方法:

mysub=substr(mystring,startpos,maxlen)

mystring 應該是要從中抽取子串的字符串變量或文字字符串。startpos 應該設置成起始字符位置,maxlen 應該包含要抽取的字符串的最大長度。請注意,我說的是最大長度;若是 length(mystring) 比 startpos+maxlen 短,那麼獲得的結果就會被截斷。substr() 不會修改原始字符串,而是返回子串。如下是一個示例:

print substr(mystring,9,3)

awk 將打印:

you

若是您一般用於編程的語言使用數組下標訪問部分字符串(以及不使用這種語言的人),請記住 substr() 是 awk 代替方法。須要使用它來抽取單個字符和子串;由於 awk 是基於字符串的語言,因此會常常用到它。

一些更回味無窮的函數

首先是 match()。match() 與 index() 很是類似,它與 index() 的區別在於它並不搜索子串,它搜索的是規則表達式。match() 函數將返回匹配的起始位置,若是沒有找到匹配,則返回 0。此外,match() 還將設置兩個變量,叫做 RSTART 和 RLENGTH。RSTART 包含返回值(第一個匹配的位置),RLENGTH 指定它佔據的字符跨度(若是沒有找到匹配,則返回 -1)。經過使用 RSTART、RLENGTH、substr() 和一個小循環,能夠輕鬆地迭代字符串中的每一個匹配。如下是一個 match() 調用示例:

print match(mystring,/you/), RSTART, RLENGTH

awk 將打印:

9 9 3

字符串替換

如今,咱們將研究兩個字符串替換函數,sub() 和 gsub()。這些函數與目前已經討論過的函數略有不一樣,由於它們確實修改原始字符串。如下是一個模板,顯示瞭如何調用 sub():

sub(regexp,replstring,mystring)

調用 sub() 時,它將在 mystring 中匹配 regexp 的第一個字符序列,而且用 replstring 替換該序列。sub() 和 gsub() 用相同的自變量;惟一的區別是 sub() 將替換第一個 regexp 匹配(若是有的話),gsub() 將執行全局替換,換出字符串中的全部匹配。如下是一個 sub() 和 gsub() 調用示例:

sub(/o/,"O",mystring)

print mystring

mystring="How are you doing today?"

gsub(/o/,"O",mystring)

print mystring

必須將 mystring 復位成其初始值,由於第一個 sub() 調用直接修改了 mystring。在執行時,此代碼將使 awk 輸出:

HOw are you doing today?

HOw are yOu dOing tOday?

固然,也能夠是更復雜的規則表達式。我把測試一些複雜規則表達式的任務留給您來完成。

經過介紹函數 split(),咱們來彙總一下已討論過的函數。split() 的任務是「切開」字符串,並將各部分放到使用整數下標的數組中。如下是一個 split() 調用示例:

numelements=split("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",mymonths,",")

調用 split() 時,第一個自變量包含要切開文字字符串或字符串變量。在第二個自變量中,應該指定 split() 將填入片斷部分的數組名稱。在第三個元素中,指定用於切開字符串的分隔符。split() 返回時,它將返回分割的字符串元素的數量。split() 將每個片斷賦值給下標從 1 開始的數組,所以如下代碼:

print mymonths[1],mymonths[numelements]

……將打印:

Jan Dec

特殊字符串形式

簡短註釋 -- 調用 length()、sub() 或 gsub() 時,能夠去掉最後一個自變量,這樣 awk 將對 $0(整個當前行)應用函數調用。要打印文件中每一行的長度,使用如下 awk 腳本:

{

                 print length()

}

sed使用規則

       sed 是頗有用(但常被遺忘)的 UNIX 流編輯器。sed是十分強大和小巧的文本流編輯器。使用sed 能夠執行字符串替換、建立更大的 sed 腳本以及使用 sed 的附加、插入和更改行命令。在以批處理方式編輯文件或以有效方式建立 shell 腳原本修改現有文件方面,它是十分理想的工具。

sed 示例

sed 經過對輸入數據執行任意數量用戶指定的編輯操做(「命令」)來工做。sed 是基於行的,所以按順序對每一行執行命令。而後,sed 將其結果寫入標準輸出 (stdout),它不修改任何輸入文件。

讓咱們看一些示例。頭幾個會有些奇怪,由於我要用它們演示 sed 如何工做,而不是執行任何有用的任務。然而,若是您是 sed 新手,那麼理解它們是十分重要的。下面是第一個示例:

$ sed -e 'd' /etc/services

若是輸入該命令,將得不到任何輸出。那麼,發生了什麼?在該例中,用一個編輯命令 'd' 調用 sed。sed 打開 /etc/services 文件,將一行讀入其模式緩衝區,執行編輯命令(「刪除行」),而後打印模式緩衝區(緩衝區已爲空)。而後,它對後面的每一行重複這些步驟。這不會產生輸出,由於 "d" 命令除去了模式緩衝區中的每一行!

在該例中,還有幾件事要注意。首先,根本沒有修改 /etc/services。這仍是由於 sed 只讀取在命令行指定的文件,將其用做輸入 -- 它不試圖修改該文件。第二件要注意的事是 sed 是面向行的。'd' 命令不是簡單地告訴 sed 一會兒刪除全部輸入數據。相反,sed 逐行將 /etc/services 的每一行讀入其稱爲模式緩衝區的內部緩衝區。一旦將一行讀入模式緩衝區,它就執行 'd' 命令,而後打印模式緩衝區的內容(在本例中沒有內容)。我將在後面爲您演示如何使用地址範圍來控制將命令應用到哪些行 -- 可是,若是不使用地址,命令將應用到全部行。第三件要注意的事是括起 'd' 命令的單引號的用法。養成使用單引號來括起 sed 命令的習慣是個好注意,這樣能夠禁用 shell 擴展。

另外一個 sed 示例

下面是使用 sed 從輸出流除去 /etc/services 文件第一行的示例:

$ sed -e '1d' /etc/services | more

如您所見,除了前面有 '1' 以外,該命令與第一個 'd' 命令十分相似。若是您猜到 '1' 指的是第一行,那您就猜對了。與第一個示例中只使用 'd' 不一樣的是,這一次使用的 'd' 前面有一個可選的數字地址。經過使用地址,能夠告訴 sed 只對某一或某些特定行進行編輯。

地址範圍

如今,讓咱們看一下如何指定地址範圍。在本例中,sed 將刪除輸出的第 1 到 10 行:

$ sed -e '1,10d' /etc/services | more

當用逗號將兩個地址分開時,sed 將把後面的命令應用到從第一個地址開始、到第二個地址結束的範圍。在本例中,將 'd' 命令應用到第 1 到 10 行(包括這兩行)。全部其它行都被忽略。

帶規則表達式的地址

如今演示一個更有用的示例。假設要查看 /etc/services 文件的內容,可是對查看其中包括的註釋部分不感興趣。如您所知,能夠經過以 '#' 字符開頭的行在 /etc/services 文件中放置註釋。爲了不註釋,咱們但願 sed 刪除以 '#' 開始的行。如下是具體作法:

$ sed -e '/^#/d' /etc/services | more

試一下該例,看看發生了什麼。您將注意到,sed 成功完成了預期任務。如今,讓咱們分析發生的狀況:

要理解 '/^#/d' 命令,首先須要對其剖析。首先,讓咱們除去 'd' -- 這是咱們前面所使用的同一個刪除行命令。新增長的是 '/^#/' 部分,它是一種新的規則表達式地址。規則表達式地址老是由斜槓括起。它們指定一種 模式,緊跟在規則表達式地址以後的命令將僅適用於正好與該特定模式匹配的行。所以,'/^#/' 是一個規則表達式。(規則表達式的有關規定能夠參見本文前面的內容)

例如:

$ sed -e '/regexp/d' /path/to/my/test/file | more

這將致使 sed 刪除任何匹配的行。

對好比下的命令:

$ sed -n -e '/regexp/p' /path/to/my/test/file | more

請注意新的 '-n' 選項,該選項告訴 sed 除非明確要求打印模式空間,不然不這樣作。您還會注意到,咱們用 'p' 命令替換了 'd' 命令,如您所猜測的那樣,這明確要求 sed 打印模式空間。就這樣,將只打印匹配部分。

有關地址的更多內容

目前爲止,咱們已經看到了行地址、行範圍地址和 regexp 地址。可是,還有更多的可能。咱們能夠指定兩個用逗號分開的規則表達式,sed 將與全部從匹配第一個規則表達式的第一行開始,到匹配第二個規則表達式的行結束(包括該行)的全部行匹配。

例如,如下命令將打印從包含 "BEGIN" 的行開始,而且以包含 "END" 的行結束的文本塊:

$ sed -n -e '/BEGIN/,/END/p' /my/test/file | more

若是沒發現 "BEGIN",那麼將不打印數據。若是發現了 "BEGIN",可是在這以後的全部行中都沒發現 "END",那麼將打印全部後續行。發生這種狀況是由於 sed 面向流的特性 -- 它不知道是否會出現 "END"。

C 源代碼示例

若是隻要打印 C 源文件中的 main() 函數,可輸入:

$ sed -n -e '/main[[:space:]]*(/,/^)/p' sourcefile.c | more

該命令有兩個規則表達式 '/main[[:space:]]*(/' 和 '/^}/',以及一個命令 'p'。第一個規則表達式將與後面依次跟有任意數量的空格或製表鍵以及開始圓括號的字符串 "main" 匹配。這應該與通常 ANSI C main() 聲明的開始匹配。

在這個特別的規則表達式中,出現了 '[[:space:]]' 字符類。這只是一個特殊的關鍵字,它告訴 sed 與 TAB 或空格匹配。若是願意的話,能夠不輸入 '[[:space:]]',而輸入 '[',而後是空格字母,而後是 -V,而後再輸入製表鍵字母和 ']' -- Control-V 告訴 bash 要插入「真正」的製表鍵,而不是執行命令擴展。使用 '[[:space:]]' 命令類(特別是在腳本中)會更清楚。

如今看一下第二個 regexp。'/^}' 將與任何出如今新行行首的 '}' 字符匹配。若是代碼的格式很好,那麼這將與 main() 函數的結束花括號匹配。若是格式很差,則不會正確匹配 -- 這是執行模式匹配任務的一件棘手之事。由於是處於 '-n' 安靜方式,因此 'p' 命令仍是完成其慣有任務,即明確告訴 sed 打印該行。試着對 C 源文件運行該命令 -- 它應該輸出整個 main() { } 塊,包括開始的 "main()" 和結束的 '}'。

替換

讓咱們看一下 sed 最有用的命令之一,替換命令。使用該命令,能夠將特定字符串或匹配的規則表達式用另外一個字符串替換。

下面是該命令最基本用法的示例:

$ sed -e 's/foo/bar/' myfile.txt

上面的命令將 myfile.txt 中每行第一次出現的 'foo'(若是有的話)用字符串 'bar' 替換,而後將該文件內容輸出到標準輸出。請注意,我說的是每行第一次出現,儘管這一般不是您想要的。在進行字符串替換時,一般想執行全局替換。也就是說,要替換每行中的全部出現,以下所示:

$ sed -e 's/foo/bar/g' myfile.txt

在最後一個斜槓以後附加的 'g' 選項告訴 sed 執行全局替換。

關於 's///' 替換命令,還有其它幾件要了解的事。首先,它是一個命令,而且只是一個命令,在全部上例中都沒有指定地址。這意味着,'s///' 還能夠與地址一塊兒使用來控制要將命令應用到哪些行,以下所示:

$ sed -e '1,10s/enchantment/entrapment/g' myfile2.txt

上例將致使用短語 'entrapment' 替換全部出現的短語 'enchantment',可是隻在第一到第十行(包括這兩行)上這樣作。

$ sed -e '/^$/,/^END/s/hills/mountains/g' myfile3.txt

該例將用 'mountains' 替換 'hills',可是,只從空行開始,到以三個字符 'END' 開始的行結束(包括這兩行)的文本塊上這樣作。

關於 's///' 命令的另外一個妙處是 '/' 分隔符有許多替換選項。若是正在執行字符串替換,而且規則表達式或替換字符串中有許多斜槓,則能夠經過在 's' 以後指定一個不一樣的字符來更改分隔符。例如,下例將把全部出現的 /usr/local 替換成 /usr:

$ sed -e 's:/usr/local:/usr:g' mylist.txt

在該例中,使用冒號做爲分隔符。若是須要在規則表達式中指定分隔符字符,能夠在它前面加入反斜槓。

規則表達式混亂

目前爲止,咱們只執行了簡單的字符串替換。雖然這很方便,可是咱們還能夠匹配規則表達式。例如,如下 sed 命令將匹配從 '<' 開始、到 '>' 結束、而且在其中包含任意數量字符的短語。下例將刪除該短語(用空字符串替換):

$ sed -e 's/<.*>//g' myfile.html

這是要從文件除去 HTML 標記的第一個很好的 sed 腳本嘗試,可是因爲規則表達式的特有規則,它不會很好地工做。緣由何在?當 sed 試圖在行中匹配規則表達式時,它要在行中查找最長的匹配。在個人前一篇 sed 文章中,這不成問題,由於咱們使用的是 'd' 和 'p' 命令,這些命令總要刪除或打印整行。可是,在使用 's///' 命令時,確實有很大不一樣,由於規則表達式匹配的整個部分將被目標字符串替換,或者,在本例中,被刪除。這意味着,上例將把下行:

<b>This</b> is what <b>I</b> meant.

變成:meant.

咱們要的不是這個,而是:This is what I meant.

幸運的是,有一種簡便方法來糾正該問題。咱們不輸入「'<' 字符後面跟有一些字符並以 '>' 字符結束」的規則表達式,而只需輸入一個「'<' 字符後面跟有任意數量非 '>' 字符並以 '>' 字符結束」的規則表達式。這將與最短、而不是最長的可能性匹配。新命令以下:

             $ sed -e 's/<[^>]*>//g' myfile.html

在上例中,'[^>]' 指定「非 '>'」字符,其後的 '*' 完成該表達式以表示「零或多個非 '>' 字符」。對幾個 html 文件測試該命令,將它們管道輸出到 "more",而後仔細查看其結果。

更多字符匹配

'[ ]' 規則表達式語法還有一些附加選項。要指定字符範圍,只要字符不在第一個或最後一個位置,就能夠使用 '-',以下所示:

             '[a-x]*'

這將匹配零或多個所有爲 'a'、'b'、'c'...'v'、'w'、'x' 的字符。另外,能夠使用 '[:space:]' 字符類來匹配空格(字符類的相關信息能夠參見本文前面部份內容)。

高級替換功能

咱們已經看到如何執行簡單甚至有些複雜的直接替換,可是 sed 還能夠作更多的事。實際上能夠引用匹配規則表達式的部分或所有,並使用這些部分來構造替換字符串。做爲示例,假設您正在回覆一條消息。下例將在每一行前面加上短語 "ralph said: ":

$ sed -e 's/.*/ralph said: &/' origmsg.txt

輸出以下:

ralph said: Hiya Jim, ralph said: ralph said:

I sure like this sed stuff! ralph said:

該例的替換字符串中使用了 '&' 字符,該字符告訴 sed 插入整個匹配的規則表達式。所以,能夠將與 '.*' 匹配的任何內容(行中的零或多個字符的最大組或整行)插入到替換字符串中的任何位置,甚至屢次插入。這很是好,但 sed 甚至更強大。

那些極好的帶反斜槓的圓括號

's///' 命令甚至比 '&' 更好,它容許咱們在規則表達式中定義區域,而後能夠在替換字符串中引用這些特定區域。做爲示例,假設有一個包含如下文本的文件:

bar oni eeny meeny miny larry curly moe jimmy the weasel

如今假設要編寫一個 sed 腳本,該腳本將把 "eeny meeny miny" 替換成 "Victor eeny-meeny Von miny" 等等。要這樣作,首先要編寫一個由空格分隔並與三個字符串匹配的規則表達式:

'.* .* .*'

如今,將在其中每一個感興趣的區域兩邊插入帶反斜槓的圓括號來定義區域:

'\(.*\) \(.*\) \(.*\)'

除了要定義三個可在替換字符串中引用的邏輯區域之外,該規則表達式的工做原理將與第一個規則表達式相同。下面是最終腳本:

$ sed -e 's/\(.*\) \(.*\) \(.*\)/Victor \1-\2 Von \3/' myfile.txt

如您所見,經過輸入 '\x'(其中,x 是從 1 開始的區域號)來引用每一個由圓括號定界的區域。輸入以下:

Victor foo-bar Von oni Victor eeny-meeny Von miny Victor larry-curly Von moe Victor jimmy-the Von weasel

隨着對 sed 愈來愈熟悉,您能夠花最小力氣來進行至關強大的文本處理。您可能想如何使用熟悉的腳本語言來處理這種問題 -- 能用一行代碼輕易實現這樣的解決方案嗎?

組合使用

在開始建立更復雜的 sed 腳本時,須要有輸入多個命令的能力。有幾種方法這樣作。首先,能夠在命令之間使用分號。例如,如下命令系列使用 '=' 命令和 'p' 命令,'=' 命令告訴 sed 打印行號,'p' 命令明確告訴 sed 打印該行(由於處於 '-n' 模式)。

$ sed -n -e '=;p' myfile.txt

不管何時指定了兩個或更多命令,都按順序將每一個命令應用到文件的每一行。在上例中,首先將 '=' 命令應用到第 1 行,而後應用 'p' 命令。接着,sed 繼續處理第 2 行,並重復該過程。雖然分號很方便,可是在某些場合下,它不能正常工做。另外一種替換方法是使用兩個 -e 選項來指定兩個不一樣的命令:

$ sed -n -e '=' -e 'p' myfile.txt

然而,在使用更爲複雜的附加和插入命令時,甚至多個 '-e' 選項也不能幫咱們的忙。對於複雜的多行腳本,最好的方法是將命令放入一個單獨的文件中。而後,用 -f 選項引用該腳本文件:

$ sed -n -f mycommands.sed myfile.txt

這種方法雖然可能不太方便,但老是管用。

一個地址的多個命令

有時,可能要指定應用到一個地址的多個命令。這在執行許多 's///' 以變換源文件中的字和語法時特別方便。要對一個地址執行多個命令,可在文件中輸入 sed 命令,而後使用 '{ }' 字符將這些命令分組,以下所示:

1,20{    s/[Ll]inux/GNU\/Linux/g     s/samba/Samba/g        s/posix/POSIX/g }

上例將把三個替換命令應用到第 1 行到第 20 行(包括這兩行)。還能夠使用規則表達式地址或者兩者的組合:

1,/^END/{         s/[Ll]inux/GNU\/Linux/g         s/samba/Samba/g         s/posix/POSIX/g        p }

該例將把 '{ }' 之間的全部命令應用到從第 1 行開始,到以字母 "END" 開始的行結束(若是在源文件中沒發現 "END",則到文件結束)的全部行。

附加、插入和更改行

既然在單獨的文件中編寫 sed 腳本,咱們能夠利用附加、插入和更改行命令。這些命令將在當前行以後插入一行,在當前行以前插入一行,或者替換模式空間中的當前行。它們也能夠用來將多行插入到輸出。插入行命令用法以下:

i\ This line will be inserted before each line

若是不爲該命令指定地址,那麼它將應用到每一行,併產生以下的輸出:

             This line will be inserted before each line line 1 here

             This line will be inserted before each line line 2 here

             This line will be inserted before each line line 3 here

             This line will be inserted before each line line 4 here

若是要在當前行以前插入多行,能夠經過在前一行以後附加一個反斜槓來添加附加行,以下所示:

             i\ insert this line\ and this one\ and this one\ and, uh, this one too.

附加命令的用法與之相似,可是它將把一行或多行插入到模式空間中的當前行以後。其用法以下:

             a\ insert this line after each line.  Thanks! :)

另外一方面,「更改行」命令將實際替換模式空間中的當前行,其用法以下:

             c\ You're history, original line! Muhahaha!

由於附加、插入和更改行命令須要在多行輸入,因此將把它們輸入到一個文本 sed 腳本中,而後經過使用 '-f' 選項告訴 sed 執行它們。使用其它方法將命令傳遞給 sed 會出現問題。

使用 sed 的幾個示例

這些示例不只演示 sed 的能力,並且還作一些真正巧妙(和方便)的事。例如,在本文的後半部,將爲您演示如何設計一個 sed 腳原本將 .QIF 文件從 Intuit 的 Quicken 金融程序轉換成具備良好格式的文本文件。在那樣作以前,咱們將看一下不怎麼複雜但卻頗有用的 sed 腳本。

l        文本轉換

第一個實際腳本將 UNIX 風格的文本轉換成 DOS/Windows 格式。您可能知道,基於 DOS/Windows 的文本文件在每一行末尾有一個 CR(回車)和 LF(換行),而 UNIX 文本只有一個換行。有時可能須要將某些 UNIX 文本移至 Windows 系統,該腳本將爲您執行必需的格式轉換。

             $ sed -e 's/$/\r/' myunix.txt > mydos.txt

      在該腳本中,'$' 規則表達式將與行的末尾匹配,而 '\r' 告訴 sed 在其以前插入一個回車。在換行以前插入回車,當即,每一行就以 CR/LF 結束。請注意,僅當使用 GNU sed 3.02.80 或之後的版本時,纔會用 CR 替換 '\r'。若是尚未安裝 GNU sed 3.02.80,請在個人第一篇 sed 文章中查看如何這樣作的說明。

我已記不清有多少次在下載一些示例腳本或 C 代碼以後,卻發現它是 DOS/Windows 格式。雖然不少程序不在意 DOS/Windows 格式的 CR/LF 文本文件,可是有幾個程序卻在意 -- 最著名的是 bash,只要一遇到回車,它就會出問題。如下 sed 調用將把 DOS/Windows 格式的文本轉換成可信賴的 UNIX 格式:

             $ sed -e 's/.$//' mydos.txt > myunix.txt

      該腳本的工做原理很簡單:替代規則表達式與一行的最末字符匹配,而該字符剛好就是回車。咱們用空字符替換它,從而將其從輸出中完全刪除。若是使用該腳本並注意到已經刪除了輸出中每行的最末字符,那麼,您就指定了已是 UNIX 格式的文本文件。也就不必那樣作了!

l        反轉行

下面是另外一個方便的小腳本。與大多數 Linux 發行版中包括的 "tac" 命令同樣,該腳本將反轉文件中行的次序。"tac" 這個名稱可能會給人以誤導,由於 "tac" 不反轉行中字符的位置(左和右),而是反轉文件中行的位置(上和下)。用 "tac" 處理如下文件:

             foo bar oni

      ....將產生如下輸出:

oni bar foo

      能夠用如下 sed 腳本達到相同目的:

             $ sed -e '1!G;h;$!d' forward.txt > backward.txt

      若是登陸到恰巧沒有 "tac" 命令的 FreeBSD 系統,將發現該 sed 腳本頗有用。雖然方便,但最好仍是知道該腳本爲何那樣作。讓咱們對它進行討論。

反轉解釋:首先,該腳本包含三個由分號隔開的單獨 sed 命令:'1!G'、'h' 和 '$!d'。如今,須要好好理解用於第一個和第三個命令的地址。若是第一個命令是 '1G',則 'G' 命令將只應用第一行。然而,還有一個 '!' 字符 -- 該 '!' 字符忽略該地址,即,'G' 命令將應用到除第一行以外的全部行。'$!d' 命令與之相似。若是命令是 '$d',則將只把 'd' 命令應用到文件中的最後一行('$' 地址是指定最後一行的簡單方式)。然而,有了 '!' 以後,'$!d' 將把 'd' 命令應用到除最後一行以外的全部行。如今,咱們所要理解的是這些命令自己作什麼。

當對上面的文本文件執行反轉腳本時,首先執行的命令是 'h'。該命令告訴 sed 將模式空間(保存正在處理的當前行的緩衝區)的內容複製到保留空間(臨時緩衝區)。而後,執行 'd' 命令,該命令從模式空間中刪除 "foo",以便在對這一行執行完全部命令以後不打印它。

如今,第二行。在將 "bar" 讀入模式空間以後,執行 'G' 命令,該命令將保留空間的內容 ("foo\n") 附加到模式空間 ("bar\n"),使模式空間的內容爲 "bar\n\foo\n"。'h' 命令將該內容放回保留空間保護起來,而後,'d' 從模式空間刪除該行,以便不打印它。

對於最後的 "oni" 行,除了不刪除模式空間的內容(因爲 'd' 以前的 '$!')以及將模式空間的內容(三行)打印到標準輸出以外,重複一樣的步驟。

linux經常使用腳本和函數

l        #查找當前目錄中是否存在指定目錄,若不存在,則建立之

function mkdir_1

{

                     if test ! -d $1

                     then

                            mkdir $1

                     fi

}

l        #將指定文件中的"prefix = .*"串替換爲"prefix=\/home\/gnome-unicore-install2\/usr/"

#能夠用來做爲sed用法的參考

function modify_prefix

{

             chmod +w $1

             cp $1 $1.bak

             sed 's/prefix = .*/prefix=\/home\/gnome-unicore-install2\/usr/g' $1.bak > $1

             rm $1.bak

}

l        #將指定文件中的"^LDFLAGS =.*"串替換爲"LDFLAGS = -rdynamic -lgdk_pixbuf -lgtk -lgdk -lgmodule -lglib -ldl -lXext -lX11 -lm"

#change_gnome-config FILENAME

function change_gnome-config

{

                     cp $1 $1.bak

                    sed 's/^LDFLAGS =.*/LDFLAGS = -rdynamic -lgdk_pixbuf -lgtk -lgdk -lgmodule -lglib -ldl -lXext -lX11 -lm /g' $1.bak> $1    

                    rm $1.bak

}

l        #刪除指定文件的含有指定字符的行

#格式:delete_line filename "word_contain"

function delete_line

{

                     chmod +w $1

                     cp $1 $1.bak

                     cat $1.bak | grep -v -e "$2" >$1      

}

l        #用途:刪除文件中包含line1或(和?)line2的行

#格式:delete_line filename line1 line2

function delete_line_no

{

             chmod +w $1

             cp $1 $1.bak

             sed  $2,$3'd' $1.bak>$1

             rm $1.bak

}

l        #用途:在LINE_NO指定的行插入字符串CONTENT

#能夠用來做爲sed用法的參考

#格式: add_line FILENAME LINE_NO CONTENT

function add_line

{

                     chmod +w $1

             cp $1 $1.bak

             sed -e $2 'i\' "$3" '' $1.bak > $1

             rm $1.bak

}

l        #用途:檢查含有"PC24"代碼的程序並打印出來

#格式: check_PC24 //after installation 

function check_PC24

{

                   echo "now comes the PC24 checking..."

                   . $COMMAND_UNICORE/shell/shell_PC24 >& /dev/null

                   if test -s $COMMAND_UNICORE/PC24_result

                 then :

               echo "The following file contains PC24 problems: $COMMAND_UNICORE/PC24_result "

                 else

                      echo "No PC24 problem found"

                   fi

}

l        #打印標題

displayheader() {

                   echo "   *****************************************"

                   echo "   *         IeeeCC754 testing tool           *"

                   echo "   *****************************************"

                   echo " "

}

l        #打印一個菜單的作法

displayplatformmenu() {

            #clear the screen

            clear

            displayheader

            echo "   a) SunSparc "

            echo "   b) IntelPentium "

            echo "   c) AMD "

            echo "   d) Unicore32 "

            echo "   e) Unicore32(with FP2001) "

            echo " "

            echo  -n "   select a Platform > "

}

l        #接收一個菜單輸入

displayplatformmenu

read answer

case ${answer} in

            a) TARGET="BasicOp";;

            b) TARGET="Conversion";;

            *) badchoice;;

esac

l        #查找當前目錄下是否存在file_name文件

#能夠用來做爲if用法的參考

detectfile_name() {

                   if [ ! -f file_name ]

                   then

                        echo "Error: file_name does not exist.  Please check"

                 exit 1;

                   else

                        echo "OK,the directy is exist"

                   fi

}

l        #將參數指定的一個或多個目錄項以及其下的多級子目錄下的全部文件名和目錄名轉換爲小寫。

cvitem()

{

echo "mv $1 `dirname $1`/`basename $1 | tr \

'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`"

}

[ $# = 0 ] && { echo "Usage: lcdir item1 item2 ..."; exit; }

for item in $*     #能夠用來做爲for用法的參考

do

[ "`dirname $item`" != "`basename $item`" ] && {

[ -d $item ] &&

{

for subitem in `ls $item`

do

cvlc $item/$subitem

done

}

cvitem $item

}

done

l        #一個login的例子

if ($?path) then

set path=($HOME/bin $path)

else

set path=($HOME/bin /usr/bin .)

endif

if ( ! $ {?DT} ); then

stty dec new

tset -I -Q

endif

set mail=/usr/spool/mail/$USER

l        #關於if使用的幾個例子

n        #執行一個命令或程序以前,先檢查該命令是否存在,然後才執行

if [ -x /sbin/quotaon ] ; then

echo "Turning on Quota for root filesystem"

/sbin/quotaon /

fi

n        #獲得Hostname

#!/bin/sh

if [ -f /etc/HOSTNAME ] ; then

HOSTNAME=`cat /etc/HOSTNAME`

else

HOSTNAME=localhost

fi

n        #若是某個設定檔容許有好幾個位置的話,例如crontab,可利用if then elif fi來找尋

if [ -f /etc/crontab ] ; then  #[ -f /etc/crontab ]等價於test -f /etc/crontab

CRONTAB="/etc/crontab"

elif [ -f /var/spool/cron/crontabs/root ] ; then

CRONTAB="/var/spool/cron/crontabs/root"

elif [ -f /var/cron/tabs/root ] ; then

CRONTAB="/var/cron/tabs/root"

fi

export CRONTAB

n        #利用uname來判斷目前系統,並分別作各系統情況不一樣的事。

SYSTEM=`uname -s`

if [ $SYSTEM = "Linux" ] ; then

echo "Linux"

elif [ $SYSTEM = "FreeBSD" ] ; then

echo "FreeBSD"

elif [ $SYSTEM = "Solaris" ] ; then

echo "Solaris"

else

echo "What?"

fi

l        #關於while使用的幾個例子

n        #無條件循環

while : ; do

echo "do something forever here"

sleep 5

done

linux經常使用命令

如下只說明各指令的基本用法, 若需詳細說明, 請用 man 去讀詳細的 manual.

關於文件/目錄處理的指令:

1. ls

這是最基本的文件指令。 ls 的意義爲 "list",也就是將某一個目錄或是某一個文件的內容顯示出來。

若是你在下 ls 指令後面沒有跟任何的文件名,它將會顯示出目前目錄中全部文件。

也能夠在 ls 後面加上所要察看的目錄名稱或文件的名稱,如:

% ls /home2/X11R5

% ls first

ls 有一些特別的參數,能夠給予使用者更多有關的信息,以下:

-a : 在 UNIX 中若一個目錄或文件名字的第一個字符爲 "." , 則使用 ls

將不會顯示出這個文件的名字,咱們稱此類文件爲隱藏文件。若是咱們要察看這類文件,則必須加上參數 -a 。

-l : 這個參數表明使用 ls 的長( long )格式,能夠顯示更多的信息,如文件存取權,文件擁有者( owner ),文件大小,文件最後更新日期,甚而 symbolic link 的文件是 link 到那一個文件等等。例如:

% ls -l

drwx--x--x 2 jjtseng 512 Aug 8 05:08 18

drwx--x--x 2 jjtseng 512 Aug 8 22:00 19

-rw------- 1 jjtseng 566 Aug 8 05:28 makefile

2. cp     

cp 這個指令的意義是複製("COPY") , 也就是將一個或多個文件複製成另外一個文件或者是將其複製到另外一個目錄去。

cp 的用法以下:

cp f1 f2 : 將文件名爲 f1 的文件複製一份爲文件名爲 f2 的文件。

cp f1 f2 f3 ... dir : 將文件 f1 f2 f3 ... 都以相同的文件名複製一份放到目錄 dir 裏面。

cp -r dir1 dir2 : 將 dir1 的所有內容所有複製到 dir2 裏面。

cp 也有一些參數,以下:

-i : 此參數是當已經有文件名爲 f2 的文件時,若逕自使用 cp 將會將原來 f2的內容覆蓋,所以在要覆蓋以前先詢問使用者。如使用者的回答是y(yes)才執行復制的動做。

-r : 此參數是用來作遞迴複製用,可遞歸的將整個目錄都複製到另外一個目錄中。

3. mv

mv 的意義爲 move , 主要是將一文件更名或移動到另外一個目錄。與cp相似,它也有三種格式:

mv f1 f2 : 將文件名爲 f1 的文件變動成文件名爲 f2 的文件。

mv dir1 dir2 : 將文件名爲 dir1 的目錄變動成文件名爲 dir2 的目錄。

mv f1 f2 f3 ... dir : 將文件 f1 f2 f3 ... 都移至目錄 dir 裏面。

mv 的參數有兩個,-f 和 -i , 其中 -i 的意義與 cp 中的相同,均是 interactive的意思。而 -f 爲強迫( force ) , 就是無論有沒有同名的文件,反正就是要執行,全部其餘的參數遇到 -f 均會失效。

4. rm

rm 的意義是 remove ,也就是用來刪除一個文件的指令。須要注意的是,在 UNIX 中一個被刪除的文件除非是系統剛好作了備份,不然是沒法像 DOS 裏面同樣還可以恢復的。因此在作 rm 動做的時候使用者應該要特別當心。

rm 的格式以下:

rm f1 f2 f3 .....

rm 的參數比較經常使用的有幾個: -f , -i , 與 -r

-f : 將會使得系統在刪除時,不提出任何警告訊息。

-i : 在刪除文件以前均會詢問是否真要刪除。

-r : 遞歸的刪除,可用於刪除目錄。

5. mkdir

mkdir 是一個讓使用者創建一個目錄的指令。你能夠在一個目錄底下使用 mkdir 創建一個子目錄,使用的方法以下:

mkdir dirname1 [ dirname2 ... ]

8. pwd

pwd 會將當前目錄的路徑( path )顯示出來

9. cat/more/less

以上三個指令均爲察看文件內容的指令。cat 的意義是concatenate,實際就是把文件的內容顯示出來的意思。

cat 有許多奇怪的參數,較常爲人所使用的是 -n 參數,也就是把顯示出來的內容加上行號。

cat 的用法以下:

cat [-n] :自標準輸入讀取內容,能夠用 pipe 將別的指令的輸出轉向給 cat 。

cat [-n] filename : 將 filename 的內容讀進來,顯示在標準輸出上。

問題在於 cat 它是不會停下來的,所以並很差用( 試想若是一個螢幕二十四行,而一個文件四百行,cat 一出來將會噼裏啪啦不斷的捲上去,使用者很難據此獲得他們所需的信息。) 因此經常麼使用 more 和less來幫助。

more 可讓文件根據控制檯的模式一頁頁的顯示出來,再根據使用者的要求換頁或者換行。若是使用者要在某一個文件中搜尋一個特定的字符串,則按 / 而後跟着打所要搜尋的單字便可進行搜尋。

more 的使用法以下:

more filename

若是你在使用中以爲已經看到了所要看的部份,能夠按'q'離開 more 的使用。

less 的用法與 more 極相似,原先它就是爲了彌補 more 只能往前方卷頁的缺點而設計。

Less 的用法以下:

less filename

它與 more 不一樣的是它能夠按 y 來往上卷一行,而且能夠用"?"來往回搜尋你所要找的字符。

10. chmod

chmod用來改變文件存取模式( change mode ) 。在linux中,一個文件有可讀(r)可寫(w)可執行(x)三種模式,分別針對該文件的擁有者( onwer )、同組用戶( group member )(能夠 ls -lg來觀看某一文件的所屬的 group ),以及其餘人( other )。

一個文件若是改爲可執行模式則系統就將其視爲一個可執行文件,而一個目錄的可執行模式表明使用者有進入該目錄之權利。

chmod使用方式以下:

chmod [ -fR ] mode filename ...

其參數的意義以下:

-f Force. chmod 不會理會失敗的動做。

-R Recurive. 會將目錄下全部子目錄及文件改成你所要改爲的模式。

關於 Process 處理的指令:

1. ps

ps 是用來顯示目前你的 process 或系統 processes 的情況。

其選項說明以下:

-a 列出包括其餘 users 的 process 情況。

-u 顯示 user - oriented 的 process 情況 。

-x 顯示包括沒有 terminal 控制的 process 情況 。

-w 使用較寬的顯示模式來顯示 process 情況 。

咱們能夠經由 ps 取得目前 processes 的情況,如 pid , running state 等。

2. kill

kill 指令的用途是送一個 signal 給某一個 process 。由於大部份送的都是用來殺掉 process 的 SIGKILL 或 SIGHUP,所以稱爲kill 。

kill 的用法爲:

kill [ -SIGNAL ] pid ...

kill -l

SIGNAL 爲一個 singal 的數字,從 0 到 31 ,其中 9 是 SIGKILL ,也就是通常用來殺掉一些沒法正常 terminate 的信號。

也能夠用 kill -l 來察看可代替 signal 號碼的數字。

關於字符串處理的指令:

1. echo

echo 是用來顯示一字符串在標準輸出上。echo -n 則表示當顯示完以後不執行換行操做。

2. grep

grep 爲一過濾器,它可自一個或多個文件中過濾出具備某個字符串的行,或是從標準輸入過濾出具備某個字符串的行。

 grep的用法以下:

grep [-nv] match_pattern file1 file2 ....

-n 把所找到的行在行前加上行號列出

-v 把不包含 match_pattern 的行列出

match_pattern 所要搜尋的字符串

-f 以 pattern_file 存放所要搜尋的字符串

聯機查詢的指令:

1. man

man 是手冊 ( manual ) 的意思。 UNIX 提供線上輔助( on-line help )的功能,man 就是用來讓使用者在使用時查詢指令、系統調用、標準庫函數、各類表格等的使用所用的。

man 的用法以下:

man [-M path] [[section] title ] .....

man [-M path] -k keyword ...

-M path man 所須要的 manual database 的路徑。咱們也能夠用設定環境變數 MANPATH 的方式來取代 -M 選項。

title 這是所要查詢的目標。

section 用一個數字表示 manual 的分類,一般 1 表明可執行指令,2 表明系統調用( system call ) ,3 表明標準庫函數,等等。

 man 在 UNIX 上是一項很是重要的指令,咱們在這裏所描述的用法僅僅只是一個你們比較經常使用的用法以及簡單的說明,真正詳細的用法與說明仍是要經過使用 man 來獲得。

2. who

who 指令是用來查詢目前有那些人在線上。

3. info

       info的查詢與man相似。

網絡運用指令:

1. telnet

telnet 是一個提供 user 經過網絡連到 remote host。

telnet 的 格式以下:

telnet [ hostname | ip-address ] [ port ]

hostname 爲一個像 ccsun1 或是 ccsun1.cc.nctu.edu.tw 的 name address,ip-address 則爲一個由四個小於 255 的數字組成的 ip address ,

2. ftp

ftp 的意義是 File Transfer Program ,是一個很經常使用的在網路文件傳輸的軟件。

ftp 的格式以下:

ftp [ hostname | ip-address ]

其中 hostname | ip-address 的意義跟 telnet 中的相同。

在進入 ftp 以後,若是與 remote host 鏈接上了,它將會詢問你 username 與密碼,若是輸入對了就能夠開始進行文件傳輸。

在 ftp 中有許多的命令,這裏僅列出較經常使用的 cd , lcd , mkdir , put , mput , get , mget , binary , ascii , prompt , help 與 quit 的使用方式。

ascii 將傳輸模式設爲 ascii 模式。一般用於傳送文字文件。

binary 將傳輸模式設爲 binary 模式,一般用於傳送執行文件,壓縮文件與影像文件等。

cd remote-directory 將 remote host 上的工做目錄改變。

lcd [ directory ] 更改 local host 的工做目錄。

ls [ remote-directory ] [ local-file ] 列出 remote host 上的文件。

get remote-file [ local-file ] 取得登錄機的文件。

mget remote-files 可以使用通用字符一次取得多個文件。

put local-file [ remote-file] 將 local host 的文件送到 remote host。

mput local-files 可以使用通用字符一次將多個文件放到 remote host 上。

help [ command ] 線上輔助指令。

mkdir directory-name 在 remote host 新建一個目錄。

prompt 更改交談模式,若爲 on 則在 mput 與 mget 時每作一個文件傳輸時均會詢問。

Exit/quit離開ftp

3.rlogin命令

rlogin 是「remote login」(遠程登陸)的縮寫。該命令與telnet命令很類似,容許用戶啓動遠程系統上的交互命令會話。

rlogin 的通常格式是:

rlogin [ -8EKLdx ] [ -e char ] [-k realm ] [ - l username ] host

通常最經常使用的格式是:

rlogin host

該命令中各選項的含義爲:

   -8 此選項始終容許8位輸入數據通道。該選項容許發送格式化的ANSI字符和其餘的特殊代碼。若是不用這個選項,除非遠端的終止和啓動字符不是或,不然就去掉奇偶校驗位。

-E 中止把任何字符看成轉義字符。當和-8選項一塊兒使用時,它提供一個徹底的透明鏈接。

-K 關閉全部的Kerberos確認。只有與使用Kerberos 確認協議的主機鏈接時才使用這個選項。

-L 容許rlogin會話在litout模式中運行。要了解更多信息,請查閱tty聯機幫助。

-d 打開與遠程主機進行通訊的TCP sockets的socket調試。要了解更多信息,請查閱setsockopt的聯機幫助。

-e 爲rlogin會話設置轉義字符,默認的轉義字符是「~」,用戶能夠指定一個文字字符或一個\\nnn形式的八進制數。

-k 請求rlogin得到在指定區域內的遠程主機的Kerberos許可,而不是得到由krb_realmofhost(3)肯定的遠程主機區域內的遠程主機的Kerberos 許可。

-x 爲全部經過rlogin會話傳送的數據打開DES加密。這會影響響應時間和CPU利用率,可是能夠提升安全性。

4.rsh命令

rsh是「remote shell」(遠程 shell)的縮寫。 該命令在指定的遠程主機上啓動一個shell並執行用戶在rsh命令行中指定的命令。若是用戶沒有給出要執行的命令,rsh就用rlogin命令使用戶登陸到遠程機上。

rsh命令的通常格式是:

          rsh [-Kdnx] [-k realm] [-l username] host [command]

通常經常使用的格式是:

         rsh host [command ]

         command能夠是從shell提示符下鍵人的任何Linux命令。

      rsh命令中各選項的含義以下:

    -K 關閉全部的Kerbero確認。該選項只在與使用Kerbero確認的主機鏈接時才使用。

    -d 打開與遠程主機進行通訊的TCP sockets的socket調試。要了解更多的信息,請查閱setsockopt的聯機幫助。

    -k 請求rsh得到在指定區域內的遠程主機的Kerberos許可,而不是得到由krb_relmofhost(3)肯定的遠程主機區域內的遠程主機的Kerberos許可。

    -l 缺省狀況下,遠程用戶名與本地用戶名相同。本選項容許指定遠程用戶名,若是指定了遠程用戶名,則使用Kerberos 確認,與在rlogin命令中同樣。

    -n 重定向來自特殊設備/dev/null的輸入。

-x 爲傳送的全部數據打開DES加密。這會影響響應時間和CPU利用率,可是能夠提升安全性。

Linux把標準輸入放入rsh命令中,並把它拷貝到要遠程執行的命令的標準輸入中。它把遠程命令的標準輸出拷貝到rsh的標準輸出中。它還把遠程標準錯誤拷貝到本地標準錯誤文件中。任何退出、停止和中斷信號都被送到遠程命令中。當遠程命令終止了,rsh也就終止了。

5.rcp命令

rcp表明「remote file copy」(遠程文件拷貝)。該命令用於在計算機之間拷貝文件。

rcp命令有兩種格式。第一種格式用於文件到文件的拷貝;第二種格式用於把文件或目錄拷貝到另外一個目錄中。

   rcp命令的通常格式是:

            rcp [-px] [-k realm] file1 file2 rcp [-px] [-r] [-k realm] file

   directory 每一個文件或目錄參數既能夠是遠程文件名也能夠是本地文件名。遠程文件名具備以下形式:rname@rhost:path,其中rname是遠程用戶名,rhost是遠程計算機名,path是這個文件的路徑。

   rcp命令的各選項含義以下:

   -r 遞歸地把源目錄中的全部內容拷貝到目的目錄中。要使用這個選項,目的必須是一個目錄。

     -p 試圖保留源文件的修改時間和模式,忽略umask。

   -k 請求rcp得到在指定區域內的遠程主機的Kerberos 許可,而不是得到由krb_relmofhost(3)肯定的遠程主機區域內的遠程主機的Kerberos許可。

     -x 爲傳送的全部數據打開DES加密。這會影響響應時間和CPU利用率,可是能夠提升安全性。 若是在文件名中指定的路徑不是完整的路徑名,那麼這個路徑被解釋爲相對遠程機上同名用戶的主目錄。若是沒有給出遠程用戶名,就使用當前用戶名。若是遠程機上的路徑包含特殊shell字符,須要用反斜線(\\)、雙引號(」)或單引號(’)括起來,使全部的shell元字符都能被遠程地解釋。 須要說明的是,rcp不提示輸入口令,它經過rsh命令來執行拷貝。

Vi經常使用技巧

l        取消命令

在vi中,只要沒有把修改結果存入磁盤文件中,那麼就能夠經過「取消」來撤銷最近的操做或對緩衝區的修改。

假設你無心刪除了一行文本、改變了一些你不該該改變的內容或增長了一些不正確的文本,能夠按<Esc>改變到命令模式中,而後按<u>,則文件內容恢復到修改前的樣子。

l        保存到文件名爲filename的文件中

發出寫命令格式:   :w filename

l        不使用小鍵盤來定位光標

vi用<h>、<j>、<k>、<l>鍵來定位光標。其中<h>、<l>鍵表示光標的左右移動,<j>、<k>鍵表示光標的上下移動,在某些沒有或不能使用小鍵盤的狀況下這四個鍵是頗有用的。

下面是其餘一些用於移動光標的鍵:

n        按空格鍵或<l>向右移動光標一個位置

n        按<Return>將光標移動到下一行的行首

n        使用<j>鍵將光標移動到下一行的當前位置或行末

n        按<->將光標移動到上一行行首

n        使用<k>鍵將光標移動到上一行的當前位置或行末

n        按<h>將光標向左移動一個字符

n        按<0>(零)將光標移動到一行的行首

n        按<$>將光標移動到一行的行末

l        大範圍移動鍵

可快速定位光標到屏幕的頂部、中部和底部:

n        按<Shift-h>將光標移到屏幕的第一行,有時稱爲home位置

n        按<Shift-m>將光標移到如今屏幕顯示的各行的中間一行

n        按<Shift-l>將光標移到屏幕的最後一行

n        按<Ctrl-f>向前移動一屏

n        按<Ctrl-b>向後移動一屏

n        要移動到緩衝區中指定的行中,在按<Shift-g>前鍵入行號(注意,這裏的行號不是當前屏幕中的相對行號,而是絕對行號)

l        刪除文本

n        <x>刪除光標處的字符

n        <d> <w> 刪除從當前字的光標處到下一個字的開始處之間的內容

n        <d> <$> 刪除從光標處到行尾之間的內容

n        <Shift-d> 同<d> <$>,刪除當前行的剩餘部分

n        <d> <d> 刪除整行,無論光標在該行的位置

n        經過在上述命令以前鍵入一個整數,可將這些命令應用到幾個對象中,例如:<4> <x>刪除4個字符;<8> <d> <d> 刪除8行

l        添加文本

n        使用<i>在光標位置前插入文本

n        使用<Shift-i>使你進入輸入模式而且在當前行行首插入文本

n        使用<a>在光標位置後插入文本

n        使用<Shift-a>使你進入輸入模式而且在當前行末尾插入文本

n        使用<o>在當前行的下面打開一行以添加文本

n        使用<Shift-o>在當前行的上面打開一行以添加文本

l        使vi顯示行號

按<Esc>鍵以確保你在命令模式中,而後輸入:se number。要關閉行號,輸入:se nonumber

l        查找

n        /string     在緩衝區中向前查找字符串string

n        ?string    在緩衝區中向後查找字符串string

n        <n>        以當前的方向再次查找

n        <Shift-n>以相反的方向再次查找

n        注意,查找的字符串中若含有特殊字符的,要使用\來進行轉意

l        修改和替換文本

n        <r> 替換單個字符

n        <Shift-r>替換一個字符序列

n        <c> <w>修改當前字,從光標處到這個字的字尾

n        <c> <e>修改當前字,從光標處到這個字的字尾(與<c> <w>相同)

n        <c> <b>修改當前字,從該字的字頭到光標之前的那些字符

n        <c> <$>修改一行,從光標處到該行的行尾

n        <Shift-c>修改一行,從光標處到該行的行尾(與<c> <$>相同)

n        <c> <c>修改整行

n        注意,這些命令的每一個命令都使之進入了輸入模式。除使用<r>來替換單個字符外,必須按<Esc>鍵來完成所做的修改並返回命令模式

n        要修改幾個字,在按<c> <w>以前使用一個整數

l        拷貝、剪切和粘貼

n        <y> <w>拷貝從當前字的光標處到下一個字的開始處之間的內容

n        <y> <$>拷貝從光標處到行尾之間的內容

n        <Shift-y>拷貝當前行的剩餘部分(與<y> <$>相同)

n        <y> <y>拷貝整個當前行

n        經過在這些命令前鍵入整數,全部這些命令均可以用於多個對象。

n        當刪除或剪切或拷貝時,刪除或拷貝的對象被保存在通用緩衝區中,能夠使用<p>或<Shift-p>命令將這個緩衝區中的內容粘貼到光標位置。

n        <p>命令將對象粘貼到光標位置右邊或光標位置後面

n        <Shift-p>命令將對象粘貼到光標位置左邊或光標位置前面

l        重複命令

能夠按< . >來重複改變緩衝區的最後一個命令。

相關文章
相關標籤/搜索