- 論壇徽章:
- 0
|
翻譯自——GNULinux應(yīng)用程序編程(GNU/Linux Application Programming) by M.Tim Jones
第十九章: GNU/Linux命令
在這一章中我們將介紹
標(biāo)準(zhǔn)輸入輸出和錯誤流
調(diào)用Shell腳本
重定向
GNU/Linux重要命令的討論
介紹
在這一章中,我們將學(xué)習(xí)GNU/Linux Shell的基礎(chǔ)知識還有經(jīng)常使用的重要命令。
重定向
讓我們首先來看一個在GNU/Linux Shell使用中一個基本的主題——輸入輸出重定向。
重定向的概念十分的簡單——將我們的輸入輸出重定向到非默認(rèn)的事物上。例如,大多數(shù)命令的標(biāo)準(zhǔn)輸出將被重定向到Shell窗口上。我們可以使用“>”——重定向標(biāo)志符來重新定向一個命令的輸出。
例如:ls -la將會產(chǎn)生一個文件列表并將結(jié)果顯示在Shell窗口上。
我們可以將這個列表重定向到一個文件上:ls -la > ls-out.txt
本來應(yīng)該顯示在Shell窗口上的列表被打印在了文件ls-out.txt上。
除了可以從鍵盤上接收輸入,我們還可以從其它源接受輸入。例如:命令cat簡單地顯示它的標(biāo)準(zhǔn)輸入(或者被命名在命令行上的文件)到它的標(biāo)準(zhǔn)輸出。我們可以用”
在這里,為了簡單化我們?nèi)∮盟鼈兊目s寫名。描述符stdin一般來說是鍵盤,而stdout和stderr則為終端或者是Shell窗口(程序結(jié)果是stdout,程序錯誤、警告和狀態(tài)則為stderr)。輸出描述符被分開是為了追求向用戶顯示信息時的更大的彈性。雖然stdout和stderr共享著相同的默認(rèn)輸出設(shè)備,但是它們可以根據(jù)開發(fā)者的需要而分開。
回想我們先前的討論——我們可以將stdout重新定向到一個文件上。就像:
Prog > out.txt
Prog的輸出將會重新定向到文件out.txt。注意——如果我們要將我們的輸出添加到out.txt而不是完全地將整個文件替換我們將使用雙定向,就像:
Prog >> out.txt
我們只能像這樣重新定向出錯輸出:
Prog 2> err-out.txt
注意——我們在這里使用一個常數(shù)來代表stderr。在表19.1我們展示了為我們的三個標(biāo)準(zhǔn)輸入輸出流描述符所定義的文件描述符。
如果我們想要把stdout和stderr都定向到一個文件(out.txt),我們可以這么做:
Prog 1> out.txt 2>&1
表19.1:標(biāo)準(zhǔn)輸入輸出描述符的文件描述符
描述符 描述
0 標(biāo)準(zhǔn)輸入(stdin)
1 標(biāo)準(zhǔn)輸出(stdout)
2 標(biāo)準(zhǔn)出錯(stderr)
相反,我們也可以將標(biāo)準(zhǔn)輸出重定向到標(biāo)準(zhǔn)出錯描述符:
Prog 1>&2
我們也可以將輸出重定向到獨(dú)特的文件。例如,如果我們想要將stdout定向到out.txt而stderr定向到err.txt,我們可以這么做:
Prog 1> out.txt 2> err.txt
為了證實描述符路程安排正如我們所希望的,在清單19.1的腳本可以用來測試:
清單 19.1:描述符路程安排測試腳本
1: #!/bin/bash
2: echo “stdout test” >&1
3: echo “stderr test” >&2
最后考慮其它證明重定向順序的例子:
Prog 2>&1 1>out.txt
在這個例子當(dāng)中,我們將stderr定向到了stdout然后將stdout(不包括stderr)定向到了文件out.txt。它鞏固了將stdout和stderr都定向到文件out.txt的效果。
環(huán)境變量
環(huán)境變量是一個包含被Shell和其它應(yīng)用程序使用的內(nèi)容的對象。存在著一系列標(biāo)準(zhǔn)環(huán)境變量,比如PWD變量,而用戶可以為自己的應(yīng)用程序創(chuàng)建自己的環(huán)境變量(或者改變業(yè)已存在的環(huán)境變量)。我們可以通過echo命令來查看PWD變量。
注意:一個進(jìn)程可以看做為一個環(huán)境而且它繼承了來自它父母的環(huán)境變量(比如Shell——它也是一個進(jìn)程)。一個進(jìn)程和腳本也可以有本地變量。
$echo $PWD
PWD=/home/sensen
$
環(huán)境變量PWD能夠鑒別我們當(dāng)前的工作目錄。我們可以通過delcare或者export這兩個bash自帶命令來創(chuàng)建我們自己的環(huán)境變量。
一個腳本可以使得子進(jìn)程能夠訪問父進(jìn)程的環(huán)境變量,但是必須輸出(export)它們。一個腳本不能反輸出給父進(jìn)程。讓我們看一看幾個例子。通過特別的參數(shù)bash自帶命令declare可以用來聲明變量。而bash自帶命令export可以創(chuàng)建一個變量并可以在環(huán)境中標(biāo)識并傳送給它的子進(jìn)程。這些命令的舉例說明如下:
$declare –x myvar=”Hello”
$echo $myvar
Hello
$export myothervar=”Hi”
$echo $myothervar
Hi
$
GNU/Linux上存在著一系列其它十分有用的環(huán)境變量。例如:如果沒有參數(shù)提供給export,它將會顯示所有當(dāng)前環(huán)境可訪問的變量(通過命令declare和set也可以顯示)。
腳本調(diào)用
當(dāng)我們調(diào)用一個命令或者腳本的時候,命令和腳本必須是在我們的二進(jìn)制路徑(PATH環(huán)境變量)來使得它可以被發(fā)現(xiàn)。我們可以通過echo查看PATH環(huán)境變量來查看我們的路徑:
$echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/sensen/bin
如果我們已經(jīng)創(chuàng)建了一個處于所定義的路徑之外的腳本(比如說在我們當(dāng)前工作目錄),那么我們只能這么調(diào)用它:
./script.sh
“./”告訴命令解釋器我們調(diào)用的Shell腳本位于當(dāng)前目錄。否則的話我們將會得到一個告訴我們腳本找不到的錯誤消息。
注意:兩個特殊目錄文件的存在在Linux開發(fā)中是十分重要的!.”文件代表當(dāng)前目錄,而“..”則代表上一個目錄(父目錄)。例如,如果我們提供了命令cd .,結(jié)果是不會有任何改變的,因為我們將我們的當(dāng)前目錄改變?yōu)楫?dāng)前目錄。而命令cd ..則改變當(dāng)前目錄到上一個目錄。這些特殊文件可以通過命令ls –la來查看當(dāng)前子目錄來看到。
如果想不需要如此,我們可以更新我們的路徑環(huán)境變量來添加我們的當(dāng)前工作子目錄:
$export PATH=$PATH:./
$echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/sensen/bin:./
腳本文件script.sh現(xiàn)在可以被直接調(diào)用而不需要添加前綴“./”。
注意:文件鏈接是用來提供其它文件的參照符號的特殊文件。有這樣的兩種鏈接存在:硬鏈接和軟鏈接(亦被稱為象征鏈接)。一個硬鏈接是指向一個已經(jīng)存在的文件的在目錄文件里的一個新入口。硬鏈接和原始文件之間是難以區(qū)別的。硬鏈接的問題是它們和它們所鏈接的對象必須是在同一個文件系統(tǒng)。軟鏈接是一個一般的文件包含有一個指向一個實際文件的指針。軟鏈接可以是絕對的(以全路徑指向一個文件)或者是相對的(從當(dāng)前位置開始的相對路徑)。軟鏈接是可以移動的,同時保持對原始文件的鏈接。注意:特殊文件“.”和“..”實際上是對絕對目錄的鏈接。
命令ln可以用來創(chuàng)建軟鏈接。
基本GNU/Linux命令
既然我們已經(jīng)懂得了基本的重定向和標(biāo)準(zhǔn)輸入輸出描述符(stdin,stdout和stderr),讓我們來研究更多的有用的GNU/Linux命令。我們將以一個互動的方式來研究這些命令,而不是僅僅告訴你這個命令是干什么的和它的所有可用選項。這些命令沒有特別的順序,因此你可以根據(jù)你的需要來獨(dú)立地研究每一個命令。
tar
GNU tar命令(Tape Archive)是一個十分有用的通用存檔壓縮程序。tar的目標(biāo)可以是文件也可以是目錄(目錄的內(nèi)容是被遞歸聚集的)。讓我們來看一看對tar的使用同時研究它的多個選項。
我們可以創(chuàng)建一個新的存檔文件:
tar cf mytar.tar mydir/
我們指定了兩個選項來創(chuàng)建目錄mydir的存檔。C選項指令tar創(chuàng)建一個新的帶有名字(通過f選項鑒別)mytar.tar的新存檔。最后一個參數(shù)為文件清單和(或者)要存檔的目錄。
現(xiàn)在我們想要獲取我們的tar文件(也可以叫做tarball)然后重建子目錄和它的內(nèi)容(也可以叫做提取選項)。我們要這么做只需簡單地打上:
tar xf mytar.tar
如果我們只要知道我們的tarball的內(nèi)容而不想要必須去將內(nèi)容解檔(unarchive),我們可以這么做:
tar tf mytar.tar
它將列出所有文件以及文件的完整目錄路徑。
通過添加v或者詳細(xì)選項我們可以看到當(dāng)tar程序工作時它的操作。對于創(chuàng)建和提取存檔,我們可以這樣使用詳細(xì)選項:
tar cvf mytar.tar mydir/
tar xvf mytar.tar
tar的一個最重要的方面為對tarball的自動壓縮。通過使用z選項創(chuàng)建和提取存檔都可以自動進(jìn)行:
tar czf mytar.tgz mydir/
tar xzf mytar.tgz
一個壓縮的tarball需要更多的時間來創(chuàng)建和存檔提取,但是這樣同樣十分有益,特別是當(dāng)想要在因特網(wǎng)上傳送一堆文件的時候。
cut
通過使用兩種詳細(xì)說明中的一個我們可以使用GNU/Linux cut程序快速地截掉文件中每一行的要素。用戶可以通過字段表示或者編號字符序列來定義所需數(shù)據(jù)。
讓我們首先來看一看cut程序的基本格式然后再通過幾個例子來看一下怎么使用它。就像我們前面所說,cut程序是以兩種模式來操作。在第一個模式中,cut通過一個界定字符和基于字段的詳細(xì)說明來提。
cut -f[spec] -d[delimiter] file
在第二個模式中,cut通過基于字符位置的詳細(xì)說明來提。
cut -c[spec] file
spec是一列以逗號分隔的排列。一個排列可以表格19.2所展示的來描述。
表格19.2:cut程序的排列Spec
排列 意義
n 第n個字符(-c)或者字段(-f)
n- 第n個字符(-c)或者字段(-f)(到末端為止)
n-m 從第n個字符到第m個字符(-c)或者字段(-f)
-m 從開頭到m個字符(-c)或者字段(-f)
現(xiàn)在讓我們來看一看幾個cut程序的例子。我們先使用在清單19.2中的例子探討基于字段的cut
清單19.2:基于字段的cut的例子文件(passwd)
bob:x:500:500::/home/bob:/bin/bash
sally:x:501:501::/home/sally:/bin/bash
jim:x:502:502::/home/jim:/bin/tcsh
dirk:x:503:503::/home/dirk:/bin/ash
我們將用cut進(jìn)行互動地實驗,現(xiàn)在只看一看命令同時還有指定了指定說明以后cut將會產(chǎn)生什么。首先我們想要截掉和顯示第一個字段(名字)。這是cut的一個簡單的例子:
$cut –f1 –d: passwd
bob
sally
jim
dirk
$
在這個例子中,我們詳細(xì)說明了使用冒號字符作為界定字符來截掉字段1(-f1)。如果我們想要知道home目錄而非用戶名,我們可以簡單地更改字段來指向passwd的第六個字段:
$cut –f6 –d: passwd
/home/bob
/home/sally
/home/jim
/home/dirk
$
我們同樣可以提取某幾個字段,比如用戶名(字段1)和所喜歡的Shell(字段7):
$cut –f1,7 –d: passwd
bob:/bin/bash
sally:/bin/bash
jim:/bin/tcsh
dirk:/bin/ash
$
排序?qū)ut來說是十分重要的。例如在前面的例子當(dāng)中如果我們這么指定——-f7,1,結(jié)果將會是一樣的(在原文件中的段排序?qū)槐A簦?br />
現(xiàn)在讓我們來看一下指定字符位置的幾個例子。在這些例子中,我們將從其它命令輸送輸入。命令來說列出某個目錄的內(nèi)容,例如:
$ls –la
Total 20
drwxrwxr-x 2 sensen sensen 4096 Feb 17 20:08 .
drwxr-xr-x 6 sensen sensen 4096 Feb 15 20:47 ..
-rw-rw-r-- 1 sensen sensen 6229 Feb 16 17:59 ch12.txt
-rw-r—r-- 1 sensen sensen 145 Feb 17 20:02 passwd
如果我們只對文件大小、更改日期和文件名感興趣,我們可以這么做:
$ls –la | cut –c38-
4096 Feb 17 20:08 .
4096 Feb 15 20:47 ..
6229 Feb 16 17:59 ch12.txt
145 Feb 17 20:02 passwd
$
如果我們只對文件的大小和名字感興趣,那么我們可以:
$ls –la | cut –c38-42,57-
4096.
4096..
6229ch12.txt
145passwd
$
注意:在這個例子中兩個cut的結(jié)果的區(qū)域沒有包括它們之間的空格。這是因為cut只是簡單地分割文件的區(qū)域而不去顯示這些區(qū)域之間的空格。如果我們對空格有興趣,我們可以像下面這樣來更改命令(從數(shù)據(jù)本身獲取空格)
$ls –la | cut –c38-43,57-
4096 .
4096 ..
6229 ch12.txt
145 passwd
$
程序cut是十分簡單的,但是它又是一個十分有用且靈活的程序。程序cut并非唯一,稍后我們將看一看sed和awk的文字過濾和文字處理功能。
paste
命令paste是從一個或者多個文件獲取數(shù)據(jù)然后將它們連接到一個新的數(shù)據(jù)流中(默認(rèn)顯示到stdout上)。考慮一下在清單19.3和19.4中的文件:
清單:水果文件
Apple
Orange
Banana
Papaya
清單:工具文件
Hammer
Pencil
Drill
Level
使用paste程序我們可以將這些文件連接在一起:
$paste fruits.txt tools.txt
Apple Hammer
Orange Pencil
Banana Drill
Papaya Level
$
如果我們并不想在我們的連貫的要素之間使用制表符而是要某個分隔符,我們可以通過使用-d選項指定新的一個。例如,我們可以使用一個:冒號來代替:
$paste –d: fruits.txt tools.txt
Apple:Hammer
Orange:Pencil
Banana:Drill
Papaya:Level
相比以垂直的方式配對連貫的要素,我們也可以通過使用-s選項用水平的方式配對它們。
$paste –s fruits.txt tools.txt
Apple Orange Banana Papaya
Hammer Pencil Drill Level
$
注意:如果需要的話,我們可以指定更多的文件。
現(xiàn)在讓我們來看一看最后一個闡明paste程序的例子;叵胍幌挛覀儗τ赾ut的討論——變更提取自于文件的字段的順序是不可能的。下面的一個短小的腳本提供了列舉文件名然后列舉文件的大小的效用。
清單:19.5簡單的遞歸的使用cut和paste的ls程序
#!/bin/bash
ls –l | cut –c38-42 > /tmp/filesize.txt
ls –l | cut -57- > /tmp/filename.txt
paste /tmp/filename.txt /tmp/filesize.txt
在這個例子中,我們首先從命令ls -l截掉文件的大小然后將結(jié)果保存到/tmp/filesize.txt。我們提取文件名接下來將它們保存到/tmp/filename.txt。然后,使用paste命令將結(jié)果合并起來并將順序倒轉(zhuǎn)。執(zhí)行腳本,結(jié)果如下:
$./newls.sh
Fruits.txt 27
Newls.sh 133
Tools.txt 26
$
注意:既然對于臨時文件來說在清單19.5中使用目錄/tmp是十分有用。臨時文件可以寫到目錄/tmp中去是因為在系統(tǒng)啟動時/tmp目錄并不保持穩(wěn)固,對/tmp中的文件的清除是一個每天或者是一周一次的進(jìn)程。
Sort
程序sort在以某個已定義的順序排列中排列一個數(shù)據(jù)文件上十分有用。在最簡單的狀況
中,對于sort來說關(guān)鍵的是文件的開頭,我們指定的文件。以在清單19.4中展示的文件tools.txt為例。我們可以這樣簡單地進(jìn)行排列:
$sort tools.txt
Drill
Hammer
Level
Pencil
$
我們可以通過向命令行添加選項-r來以顛倒的順序來排列這個文件。
我們還可以基于一個用戶定義的鍵值來進(jìn)行排列?匆幌略谇鍐19.6中的簡單的文本文件。這個文件共有五行三列沒有一個已經(jīng)預(yù)先排列過的。
清單19.6排列所需的樣品文件
5 11 eee
4 9 ddd
3 21 aaa
2 24 bbb
1 7 ccc
為了指定一列來排序,我們可以使用-k(key)選項。key代表了
我們要求對文件進(jìn)行排序的那一列。我們可以通過使用逗號分隔指定不止一個key。基于第一列進(jìn)行排序,我們可以將key指定為一列(即使不這樣,默認(rèn)的也是一列)。
$sort –k 1 table.txt
7 ccc
24 bbb
21 aaa
9 ddd
11 eee
$
要對第二列進(jìn)行排序,另一個選項被要求用來執(zhí)行數(shù)字排序。在
阿拉伯?dāng)?shù)字之前的空格字符是十分重要的,因此將會排除一個數(shù)字排序。因此,我們將使用-n選項來強(qiáng)制執(zhí)行一個數(shù)字排序。例如:
$sort –k 2 –n table.txt
7 ccc
9 ddd
11 eee
21 aaa
24 bbb
$
萬一發(fā)生空格或者制表符都沒有被使用另一個十分有用的選項允許指定一個新的分隔
符。選項-t允許我們使用一個不同的分隔符——比如:-t:指定冒號字符作為字段分隔符。
find
程序find是一個功能強(qiáng)大但又十分復(fù)雜的程序,它允許在文件系統(tǒng)中基于指定的標(biāo)準(zhǔn)搜索文件。我們將舉例說明一些更為有用的模式勝過去看大量過剩的find可用的選項來進(jìn)行敷衍。
在當(dāng)前子目錄中尋找所有以.c和.h結(jié)尾的文件,可以使用下面的命令:
find . –name ‘*.[ch]’ –print
字符‘.’指定了在當(dāng)前子目錄中開始。選項-name的參數(shù)是指我們要搜索什么,在本例中——任何(‘*’)以c或者h(yuǎn)結(jié)尾的文件。最后我們指定-print來顯示結(jié)果到標(biāo)準(zhǔn)輸出上。
對每一個搜索結(jié)果我們可以使用選項-exec來執(zhí)行一個命令。這允許我們對在搜索中發(fā)現(xiàn)的每一個文件調(diào)用一個命令。例如,如果我們想要將所有發(fā)現(xiàn)的文件的文件許可改變?yōu)橹蛔x,我們可以這么做:
find . –name ‘*.[ch]’ –exec chmod 444 {} \;
通過使用修飾符type我們還可以限制文件的類型。例如,如果我們只要查看一般文件(在搜索源文件中經(jīng)常發(fā)生的事情),我們可以這么做:
find . –name ‘*.[ch]’ –type f –print
選項-type的參數(shù)f代表了一般文件。我們同樣可以明確為查看目錄,象征鏈接(軟鏈接),或者特別的設(shè)備。表格19.3提供了可用的type修飾符。
表格19.3:find可用的Type修飾符
修飾符 描述
b 塊設(shè)備(block device)
c 字符設(shè)備
d 目錄
p 管道(叫做FIFO)
f 一般文件
l 軟鏈接
s 套接字(Socket)
最后一個find十分有用的功能為鑒別在一個目錄中在一段時間里被更改過的文件。下面的命令(使用了mtime)鑒別在指定的時間范圍(24小時的倍數(shù))里被修改過了的文件。下面的命令將鑒別在最近的一天里被修改了的文件:
find -name ‘*’ –type f –mtime -1 –print
為了尋找在最近一星期中被修改了的文件,我們可以將mtime的參數(shù)更改為 -7。選項atime可以被用來指定最近訪問的文件。而選項ctime則用來指定最近狀態(tài)被改變了的文件。
wc
程序wc在計算在一個文件中的字符數(shù),詞數(shù)或者行數(shù)上是十分有用的。
下面的例子可以用來說明wc的功能:
wc -m file.txt #Count characters in file.txt
wc -w file.txt #Count words in file.txt
wc -l file.txt #Count lines in file.txt
三種計算可以通過累積參數(shù)來同時輸出,比如:
wc -l -w -m file.txt
無需考慮標(biāo)記的順序,輸出順序永遠(yuǎn)為行、詞、字符。
grep
命令grep允許在指定的模式之下搜索一個或者多個文件。命令grep的格式是十分復(fù)雜的,但是相對簡單的例子是十分有用的。讓我們來談一談幾個簡單的例子然后討論一下它們的用處。
在最簡單的形式中,我們可以以一個指定的字符串來搜索一個單一文件,比如:
grep “the” file.txt
這個例子的結(jié)果是——在標(biāo)準(zhǔn)輸出中顯示的每一行都包含了單詞-“the”。除了指定一個單一文件,我們也可以通過通配符來檢查多個文件,比如:
grep “the” *.txt
在這個例子當(dāng)中,命令將會以字符串“the”來搜查所有在子目錄之下的以.txt結(jié)尾的文件。
當(dāng)使用了通配符之后,找到匹配字符串的文件的文件名將在輸出它的包含有所需字符串的行到標(biāo)準(zhǔn)輸出之前先被輸出到標(biāo)準(zhǔn)輸出。
如果在文件中的包含有匹配字符串的行的位置十分重要的話,那么可以使用選項-n:
grep -n “the” *.txt
每一次所要搜索的字符串被找到,文件名和行號將會在行的前面顯示。如果我們只對那個匹配字符串是否在文件中被找到感興趣的話,我們可以使用選項-l來簡單地輸出文件名而非字符串所在的行,比如:
grep -l “the”*.txt
當(dāng)我們要在某個文件中特定地搜查單詞。選項-w對于限制為僅對整個詞進(jìn)行搜查上是十分有用的:
grep -w “he” *.txt
這個選項在我們搜查“he”的時候十分有用;我們同時還會發(fā)現(xiàn)單詞“the”的出現(xiàn)。而選項-w限制了搜查僅僅對單詞進(jìn)行匹配,所以“the”和“there”將不會和“he”進(jìn)行匹配。
總結(jié)
在這一章中,我們探索了一些在GNU/Linux Shell中的基本命令。標(biāo)準(zhǔn)輸入輸出描述符已經(jīng)被研究過了(stdin、stdout和stderr),同時還有重定向和命令管道。我們還介紹了調(diào)用Shell腳本的方法,還包括了添加當(dāng)前工作目錄到默認(rèn)搜索路徑。最后,我們舉例說明在GNU/Linux中一些十分有用的命令,包括tar(文件存檔),find(文件搜索),grep(字符串搜索)以及其它十分有用的文本處理命令(cut、paste和sort)。
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u/6957/showart_347695.html |
|