官术网_书友最值得收藏!

3.1 shell基本功能與基本概念

Linux系統的shell作為操作系統的外殼,為用戶提供使用操作系統的接口。在UNIX/Linux中有多種shell,其中默認使用的是bsh或bash,簡稱sh。Fedora系統默認的shell為bash(bourne again shell),它包含了bsh的所有特性。

3.1.1 shell基本功能

shell是用戶和Linux內核之間的接口程序,作為人機交互的橋梁,其功能有6個:命令解釋執行、文件名替換、I/O重定向、通信管道建立、系統環境設置和shell編程。

首先,shell是一個命令解釋器,負責人機交互,接收并解釋用戶輸入的命令,并將它傳送到系統內核,由內核執行完畢后,再將結果按指定格式傳遞給用戶或顯示到終端屏幕上。

shell擁有自己內部命令集,也能被系統中其他應用程序調用,如改變工作目錄命令cd,是內部的;還有一些命令,如文件復制命令cp和文件移動命令mv,是存在于文件系統中某個目錄下的程序;也還有一些命令,如echo,既是內部的也是外部的。對用戶而言,一般不必關心一個命令是內部的還是外部的。默認情況下,當用戶從鍵盤輸入一個命令時,shell首先檢查它是否帶有路徑,若有則按路徑搜索它,找到后執行,找不到則報錯。若沒有帶路徑,則首先檢查它是否為內部命令,若是則執行;若不是,再檢查是否是一個外部命令或應用程序。此時,shell在PATH指定的搜索路徑里尋找。如果能夠成功找到命令,則shell在進行相應的處理后將其傳給內核執行,執行完畢后,再將輸出返回給用戶。如果找不到該可執行文件,將會顯示一條錯誤信息。對于既是內部又是外部的命令,或者說內、外部命令同名的,shell也有一種機制可以有選擇的執行,但默認情況下是執行內部命令。

shell的另一個重要特性是它自身就是一個解釋型的程序設計語言。shell程序設計語言支持絕大多數在高級語言中能見到的程序元素,如函數、變量、數組和控制結構等。任何在提示符中能輸入的命令,都能放到一個可執行的shell腳本程序中,作為一個語句來使用。shell編程將在第10章專門介紹,shell的其他功能將在稍后陸續介紹。

3.1.2 字符與保留字

1.字符

shell中除使用普通鍵盤可以輸入的字符外,還有一些具有特殊含義和功能的特殊字符。使用它們時,應注意其特殊的含義和作用范圍。

1)白空格

在UNIX/Linux系統中空格和Tab稱為白空格(White Space),主要用于命令行中命令名、參數及選項的分隔。在特殊時候,白空格中也包含回車字符。

2)通配符

通配符用于模式匹配,如文件名匹配、路徑名搜索、字符串查找等。常用的通配符有“*”、“?”和括在方括號“[]”中的字符序列。用戶可以在作為命令參數的文件名中包含這些通配符,構成一個所謂的“模式串”,在執行過程中進行模式匹配。

(1)*:代表從它所在位置開始的任何字符串,如“f*”匹配以f打頭的任意字符串。但應注意,文件名前的圓點“.”和路徑名中的斜線“/”必須顯式匹配。例如,“*”不能匹配.file,而“.*”可以匹配.file。

(2)?:代表它所在位置上的任何單個字符。

(3)[ ]:代表一個指定范圍的字符,只要文件名中“[]”位置處的字符在“[]”中指定的范圍之內,那么這個文件名在此處可以被匹配。方括號中的字符范圍可以由直接給出的字符組成,也可以由表示限定范圍的起始字符、終止字符及中間的連字符“-”組成。例如,f[a-d]與f[abcd]的作用相同。[ ]內的第一個字符若“^”或“!”,則表示非運算,意為不匹配[ ]內的任何字符,如f[!a-d]或f[^a-d]表示不匹配方括號內的a-d的字符集,但匹配[ ]之外的字符集。

表3-1給出了通配符的具體含義及實例。

表3-1 通配符含義舉例

需要說明的是,連字符“-”僅在方括號內且在中間時有效,表示字符范圍,如在方括號外面或在方括號內最前或最后就成為普通字符了;字符“^”和“!”只有在方括號內且位于開始位置才起“非”的作用;而“*”和“?”只在方括號外面是通配符,若出現在方括號之內,它們也失去通配符的能力,成為普通字符。例如,模式“-a[*?]abc”中只有一對方括號是通配符,“*”和“?”均為普通字符,因此它匹配的字符串只能是“-a*abc”或“-a?abc”。

以上是通配符在文件名模式匹配中的應用,但它們在shell編程或不作為文件名模式匹配時還具有另外的意義(參見正則表達式)。總的來說,它們對于shell具有比較特殊的意義,因此在正常的文件名中不應出現這些字符。

3)注釋符與注釋

在所有編程語言中都有注釋,以增加程序的可讀性。在shell命令或shell編程中,規定從字符“#”開始以后到行末的部分作為注釋,因此以“#”開頭的行是注釋行。以后將會發現,事情并非總是這樣,例如,$#表示命令行參數的個數,而${#name}表示變量name的值作為字符串的長度。若在行中需要使用“#”開始注釋,則“#”前至少要有一個白空格。

4)轉義字符

UNIX/Linux系統中還有一個特殊字符“\”,用于對某些特殊字符的表示,部分特殊字符如表3-2所示。基于此,字符“\”被稱為轉義字符(ESCape char)。

表3-2 Linux的部分特殊字符

2.特殊鍵

在UNIX/Linux系統中,鍵盤上常規鍵的用法與其他操作系統相同。但對于特殊鍵和組合鍵其意義就可能不同于其他的操作系統。另外,在UNIX/Linux系統中的意義和使用方法可能還與所使用的終端類型有關。UNIX/Linux系統的部分特殊鍵如表3-3所示。

表3-3 UNIX/Linux系統的部分特殊鍵

3.保留字

任何編程語言或系統都有一定數量的保留字,bash的部分保留字如下:

!、[,]、(,)、{,}、break、continue、cd、echo、eval、exec、exit、export、function、getopts、hash、pwd、read、readonly、return、select、set、shift、test、time、trap、type、ulimit、unset、umask、wait、for、do、done、case、in、esac、if、else、elif、fi、while、until。

3.1.3 文件命名及文件類型

1.文件與文件名

多數操作系統都有文件的概念。文件是被命名(稱為文件名)的存儲在某種介質(如磁盤、光盤和磁帶等)上的一組信息的集合。UNIX/Linux的文件均為無結構的字符流形式。文件名是文件的一種標志,一般情況下,它由字母、數字、下畫線和圓點組成的字符串構成。其實,在UNIX/Linux系統中,可用于文件名的字符是廣泛的,只要是用戶能夠輸入的字符均可用于文件名,但在實際應用中應該定義有實際意義的文件名。

Linux支持長文件名,但要求文件名的長度限制在255個字符以內。為了便于管理和識別,用戶可以把擴展名作為文件名的一部分。圓點“.”用于區分文件名和擴展名。擴展名對于文件分類是十分有用的。用戶可能對某些大眾已接納的標準擴展名比較熟悉,如C語言程序以.c為擴展名。用戶也可以根據自己的需要,定義自己的文件擴展名。

2.文件類型

UNIX/Linux系統中有三種基本的文件類型:普通文件、目錄文件和設備文件。

1)普通文件

普通文件是用于存放數據的文件,它是用戶最經常面對的文件,它又分為文本文件和二進制文件。

(1)文本文件:以可閱讀的ASCII碼形式存儲在計算機存儲器中,大多數情況下,是以“行”為基本結構的一種信息組織和存儲方式。

(2)二進制文件:是用戶一般不能直接讀懂的文件,只有通過相應的軟件才能對其進行操作。二進制文件一般是經編譯程序編譯后生成的可執行程序、圖形、圖像或聲音等。

2)目錄文件

目錄文件用于存儲一組相關的文件項信息或文件說明信息,其中包括文件名及其屬性的信息。在UNIX/Linux系統中,它只包括文件名和i節點號等相關信息,而文件的屬性信息保存在i節點號信息中。目錄文件在形式上同普通文件一樣,但具有目錄屬性,只能用目錄管理命令來訪問和管理。

目錄文件中的文件項信息結構如下:

                struct dir_entry {
                    __u32  inode;      //i節點號,32位無符號長整數
                    … … … …
                    char  name[255];   //文件名,最長為255
                };

當文件系統對文件進行搜索時,首先按名存取,查到文件名,再由文件名得到對應的i節點號,最后通過i節點號找到文件屬性和位置信息,從而實現對文件的訪問。

一個目錄文件內至少要有兩個文件項:“.-”當前目錄;“..-”上級目錄。

目錄文件的大小只能增加,盡管可以從目錄中刪除文件或子目錄,但不能使目錄變小。使目錄變小的方法是刪除后重建。

目錄文件往往簡稱為目錄或子目錄,在圖形界面下稱為文件夾。因為目錄也是文件,所以它的命名規則和文件命名規則相同。

3)設備文件

設備文件是UNIX/Linux系統的一個重要特色。UNIX/Linux系統把每一個I/O設備都看成一個文件,與普通文件一樣處理,這樣可以使文件與設備的操作盡可能統一。從用戶的角度來看,對I/O設備的使用和一般文件的使用一樣,不必了解I/O設備的細節。

設備文件與普通文件和目錄文件不同,它除了在目錄文件和文件說明信息表(i節點)中占據相應的位置之外,并不占有實際的物理存儲空間。當用戶使用設備文件時,可通過設備的名稱得到其i節點,然后通過其中的主、次設備號取得與內核中的設備驅動程序的聯系,從而達到訪問設備的目的。

為了區分普通文件、目錄文件和不同設備文件之間的不同,系統把設備文件稱為“設備特別文件”,簡稱設備文件。通常情況下,設備文件存放在系統的設備目錄/dev下。常見的設備文件有以下幾種。

(1)塊設備文件(b):以塊方式存取的設備,如硬盤、磁盤、磁帶等。

(2)字符設備文件(c):以字符方式存取的設備,如字符打印機、顯示器等。

(3)管道設備文件(p):用于進程之間通信的先進先出(FIFO)“臨時文件”。

(4)符號鏈接文件(l):用于通過此文件的內容指向它所鏈接的文件或資源。

(5)套接字文件(s):套接字分為文件套接字和網絡套接字。文件套接字存在于文件系統中,讓用戶以文件的方式訪問網絡連接。

管道設備有以下兩類。

(1)無名管道:主要用于有直接繼承關系的父子進程之間的通信。當創建無名管道的進程結束后,無名管道自動消失。

(2)命名管道:命名管道是一種特殊的設備文件,在文件系統里以文件形式存在。由于是以文件形式存在的,所以使有家族關系的進程間可使用它進行通信,不具有家族關系的進程也使用它進行通信。在通信結束后,若不主動刪除它,它不會自動消失,仍以文件的形式存在于文件系統中。

文件鏈接有以下兩類。

(1)硬鏈接(-):兩個或多個文件名共用一個文件體,也就是說一個文件可以具有多個不同的名字,但它們具有相同的i節點號。

(2)符號鏈接(l):與硬鏈接不同的是,它們不是同一個文件,各有自己的i節點,但可以通過鏈接內容訪問被鏈接文件。符號鏈接也稱為軟鏈接,在Windows系統中被稱為快捷方式。

硬鏈接來自UNIX系統本身,不能實現跨越文件系統的鏈接。符號鏈接是在現代計算機應用基礎上發展起來的,具有廣泛的靈活性,可以跨文件系統鏈接,可以指向網絡資源,甚至可以指向一個不存在的資源或位置。

3.1.4 目錄結構與路徑

1.目錄與目錄結構

在操作系統中有大量的文件,如何有效地組織與管理它們,并為用戶提供一個使用方便的接口是文件系統的一大任務。UNIX/Linux系統以文件目錄的方式來組織和管理系統中的所有文件。所謂文件目錄就是將所有文件項或文件的說明信息采用樹形結構組織起來——即常說的樹形目錄。UNIX/Linux系統中,整個文件系統只有一個“根”(root),然后在根上分“杈”(directory),任何一個分杈上都可以再分杈,也可以長出“葉子”。“根”和“杈”在Linux中被稱為“目錄”或“文件夾”,而“葉子”則是一個個的文件。在UNIX/Linux系統中,文件系統的根目錄用符號“/”表示。

UNIX/Linux系統通過目錄將系統中所有的文件分級、分層組織在一起,形成了樹形層次結構,它以根目錄為起點,所有其他的目錄都由根目錄派生而來。

實際上,各個目錄節點“之下”都會有一些文件或子目錄,并且系統在建立每一個目錄時,都會自動為它創建兩個目錄文件,一個是“.”,代表該目錄自己;另一個是“..”,代表該目錄的父目錄,通過它取得與上級目錄的聯系。對于根目錄,“.”和“..”都代表其自己。

UNIX/Linux提供管理文件和目錄的方便途徑。用戶可以方便地從一個目錄切換到另一個目錄,也可為自己創建文件或目錄,或可以把一個目錄下的內容移動或復制到另一個目錄下,并且還可與系統中的其他用戶共享目錄或文件。用戶還可以設置目錄和文件的管理權限,以便進行訪問控制。

Linux是一個多用戶系統,操作系統本身的程序或數據存放在以根目錄開始的某些專用目錄中,有時被指定為系統目錄。用戶也可創建自己的目錄,用于存放自己的程序或數據。Linux系統的目錄結構如圖3-1所示(需要說明是,不同版本或廠家的系統中,目錄結構可能存在差異)。

圖3-1 Linux系統的目錄結構

/:系統的根目錄。

/dev:系統的設備目錄,其中存放著幾乎所有的設備文件。

/etc:存放Linux系統和大部分應用軟件的配置文件。

/home:用戶家目錄所在的目錄。家目錄也稱為主目錄。默認情況下,每創建一個用戶,就會在這里新建一個與用戶同名的目錄,給該用戶一個自己的空間,如/home/lisi為用戶lisi的家目錄。

/root:root用戶的家目錄。

/lost+found:丟失文件的存放目錄。當系統因非法關機等原因造成文件系統損壞時,經修復后一些丟失的文件存放在這里。

/mnt:外部設備的掛裝點,用于掛載設備文件。在系統安裝后,可用于安裝外來文件系統。用戶也可以在此目錄下創建自己的目錄,如cdrom、usb和hd等用于安裝光盤、U盤、硬盤分區或其他設備。

/boot:Linux的啟動目錄。系統內核文件、引導器GRUB等存放在這里。

/proc:偽文件系統目錄,參見5.3.1節。

/usr:用戶級目錄。

/tmp、/usr/tmp:臨時目錄。

/sbin、/usr/sbin:系統級的命令與工具目錄。

/bin、/usr/bin:用戶級的命令與工具目錄。

/usr/include:C語言,內核編譯所需要的頭文件存放目錄。

/lib、/usr/lib:庫文件存放目錄,其中有表態庫和動態庫。

/usr/src:Linux源代碼目錄,編譯內核時使用。

/var:通常用來存放一些經常變化的內容,如各種網絡服務的工作目錄都在這里。

/var/log:系統日志目錄。

/var/spool:存放郵件、新聞、打印隊列任務等。

/usr/share:存放共享使用的,如各種共享或在線幫助等。

2.工作目錄、用戶主目錄與路徑

1)工作目錄與用戶主目錄

自從用戶登錄到系統中之后,每時每刻都“處在”某個目錄之中,此目錄被稱為工作目錄或當前目錄(Working Directory)。工作目錄用“.”表示,并且可以隨時改變。用戶初始登錄到系統中時,其主目錄或家目錄(Home Directory)就成為其工作目錄。每個用戶都有自己的主目錄,不同用戶的家目錄一般互不相同。

默認情況下,用戶剛登錄到系統中時的工作目錄便是該用戶家目錄。root用戶的主目錄為/root,其他用戶的家目錄是在/home下的與登錄名相同的目錄。用戶可以通過一個“~”字符或環境變量HOME來引用自己的家目錄。

工作目錄或當前目錄可以根據需要隨時改變,但用戶家目錄不可輕易改變。

2)路徑

路徑是指從樹形目錄中的某個目錄層次到某個文件或目錄路線。此路徑的主要構成是所經過的目錄名稱,中間用“/”分隔。

任一文件在文件系統中的位置可以由相對路徑或絕對路徑來決定。絕對路徑是指從“根”開始的路徑;相對路徑是從用戶工作目錄開始的路徑。應該注意到,引入鏈接的文件系統中,從某位置到另一位置的路徑可以不止一個,因此又有物理路徑和邏輯路徑的概念。絕對路徑是確定不變的,而相對路徑則隨著用戶工作目錄的變化而不斷變化。

用戶要訪問一個文件時,可以通過路徑名來實現,并且可以根據要訪問的文件與用戶工作目錄的相對位置來引用它,而不需要列出這個文件的完整路徑名。例如,處在圖3-1中dir目錄的用戶要訪問目錄usrn中的文件file1,可通過相對路徑../../usrn/或絕對路徑/home/usrn/來實現,此時帶有路徑的文件名可表示為../../usrn/file1或/home/usrn/file1。也可把這種帶有路徑的文件名稱為文件名。

3.1.5 shell命令解釋及執行

用戶登錄到Linux系統時,可以看到一個shell提示符,說明用戶可以在其后輸入命令。用戶可以在提示符后面輸入任何命令及參數。例如:

                #date

用戶登錄成功后,實際上進入了shell,它遵循一定的語法將輸入的命令加以解釋并傳給系統。命令行中輸入的第一個字必須是一個命令的名字,若有,則以后的內容為由分隔符分隔的選項或參數,格式如下:

                命令名 [選項 …][參數 …]

1.分隔符

在Linux系統中默認的分隔符為白空格。

2.選項和參數

參數是Linux命令操作的對象,而選項則影響命令對對象的操作行為。選項是由符號“-”引導的字符或字符串,“-”是必需的,Linux用它來區別選項和參數。在Linux系統中,選項有兩種形式:一種是傳統UNIX風格的選項,以“-”開始,后面緊跟一個字符;另一種是GNU風格的選項,以“--”開始,后面緊跟著完整的英文單詞或由“-”連接的單詞組合,用來說明選項的意義(參見示例)。考慮到書寫等因素,本書更多的是介紹傳統UNIX風格的選項格式,只有在必要時才采用GNU風格的選項。兩種風格的選項使用示例如下:

                #date                            #以默認方式顯示當前日期和時間
                # #以Greenwich Mean Time顯示當前日期和時間
                #date-u                          #傳統UNIX風格選項
                #date--utc                        #GNU風格選項
                #date--universal                   #GNU風格選項
                # #顯示文件/etc/passwd的屬性信息
                #ll/etc/passwd                    #默認模式或-u。傳統UNIX風格選項
                #ll-n/etc/passwd                  #傳統UNIX風格選項
                #ll--numeric-uid-gid/etc/passwd     #GNU風格選項
                #ll-n--time-style=iso/etc/passwd    #傳統UNIX和GNU風格選項混合使用

由上可見,選項-u影響了date的輸出,-n等選項也影響了ll的輸出。由于Linux命令一般都帶有多個參數或選項,描述不便,所以本書在以后的描述中,在不引起混淆的情況下不再區分參數和選項,統稱為參數。

3.命令行編輯特性

1)命令和文件名擴展

bash命令行具有命令和文件名擴展特性。當輸入一個還沒完成的命令或文件名時,只需按“Tab”鍵就能激活命令和文件名擴展特性,從而完成該命令的剩余輸入。如果有多個命令或文件的前綴相同,bash將響鈴并等待用戶輸入足夠的字符,以便選擇唯一的命令或文件名。如果找到,系統將自動補齊搜索到的命令或文件名,用戶按“Enter”鍵后,系統將執行這條指令。例如,若此時系統中只有一個以“pre”開頭的文件preface,當用戶輸入cat pre然后再按“Tab”鍵,將補全整個內容。

                #cat pre        #按“Tab”鍵后變為
                # cat preface

當備選文件名不唯一時,按下“Tab”鍵后,bash會在補齊最大可能長度后響鈴,若此時用戶先后按下“Esc”鍵和“?”鍵,bash將列出所有與輸入的字符串相匹配的文件名供etyn選擇,然后用戶可再輸入少量可以區分文件名的字符,再按“Tab”鍵補全命令行。如果需要補全的文件名很長且區分度不高,則可重復使用以上方法,直到最終補全命令行。

設當前目錄內有dcrease.c、deveice.txt、document和docudrama文件,要顯示document文件的內容,可按以下步驟進行。

                #cat do<Tab>       #按“Tab”鍵后,響鈴,結果如下:
                #cat docu<Tab>     #按2次“Tab”鍵后,或先后按“Esc”鍵和“?”鍵,顯示如下可選內容:
                              docudrama document
                #cat docum         #輸入m,再按“Tab”鍵補齊
                #cat document      #按“Enter”鍵執行命令

對于命令本身也可按同樣方法擴展。

從上面可以看到,bash總是盡力根據用戶輸入的信息來補全命令。當無法根據現有信息補全命令時,提示用戶給出進一步的信息,然后根據用戶的提示來補全命令。

2)命令行編輯

bash允許用戶對正在輸入的命令行進行編輯,編輯過程主要通過如表3-4 所示的編輯鍵來完成。

表3-4 bash的命令行編輯鍵

3)歷史記錄

命令行實際上是可以編輯的一個文本緩沖區,在按“Enter”鍵之前,可以對輸入的文本進行編輯。在Linux的bash中,回車后命令行也被保留在歷史記錄文件中,可通過光標鍵“↑”和“↓”上下翻閱歷史記錄,對出現的當前記錄可以進行編輯和使用。利用這一功能可以重復執行以前執行過的命令,而無須重新輸入該命令。

在Linux系統中,為每個用戶在~/.bash_history文件內預設了1000條記錄的歷史,使用命令:

                history

會列出所有歷史記錄,并為每條記錄一個編號。若用戶要重新執行某條歷史記錄的命令,可以使用以下格式:

                !記錄編號

需要說明的是,就某一個歷史命令來講,“記錄編號”是變化的,按以上格式引用的“記錄編號”必須是上次剛剛執行過的history命令顯示的編號,否則可能會執行錯誤的命令。

用戶還可使用格式:

                history n

讓其顯示最近的n條歷史記錄。

history命令的使用示例如下:

                #history                   #顯示所有歷史記錄
                #history 5                 #顯示最近5條歷史記錄
                  999  ls-l/
                  … … … … … …
                #!999                    #執行第999條歷史記錄:ls-l/
                ls -l /

3.1.6 環境變量與變量

1.環境變量

shell在開始執行時就已經定義了一些和系統的工作環境有關的變量,用來控制用戶程序的執行,或為用戶程序的執行提供環境支持,用戶還可以重新定義這些變量。環境變量可用命令env或set來查詢。常用的shell環境變量如下所述。

(1)HOME:家目錄。默認情況下,用戶成功登錄后所在目錄的完全路徑名。

(2)LOGNAME:登錄用戶名。用戶成功登錄時使用的用戶名。

(3)IFS:命令行內部參數、選項間的分割符。默認為白空格。

(4)PATH:由冒號分隔的目錄路徑名。shell將按PATH變量中給出的路徑順序搜索鍵盤輸入的命令名,找到的第一個與命令名稱一致的可執行文件將被執行。

(5)TERM:終端的類型。常用的有Linux和xterm等。

(6)PWD:當前工作目錄的絕對路徑名。該變量的取值隨cd命令而變化。

(7)OLDPWD:舊目錄,剛剛離開的目錄。該變量的取值隨cd命令而變化。

(8)PS1:主提示符。默認情況下,超級用戶的主提示符是#,普通用戶的主提示符是$。

(9)PS2:輔提示符(繼續使用提示符)。在shell接收用戶輸入命令的過程中,如果用戶在輸入行的末尾輸入“\”然后按“Enter”鍵,或者當用戶按“Enter”鍵時shell判斷出用戶輸入的命令沒有結束時(如引號或括號不成對等),就顯示這個輔助提示符,提示用戶繼續輸入命令的其余部分,默認的輔助提示符是“>”。

2.變量

在UNIX/Linux系統中,除了環境變量外,用戶還可以定義自己的變量。定義后的變量就像在其他程序設計語言里一樣被引用。引用變量時需要使用“$”作為變量名的前導字符。

變量的定義方法:

                var_name=var_value

變量的定義和使用示例:

                #x=123                   #定義一個數值變量x,其值為123
                #y='I am a student'          #定義一個字符串變量y,其值為'I am a student'
                #echo$x$y$HOME        #顯示用戶變量x、y和環境變量HOME的值
                #z="$x$y"                #由變量x和y定義變量z,其值為'123 I am a student'

由于shell是解釋語言,所以在變量定義和使用時不需要聲明類型,shell在使用變量時會根據變量的值來具體確定變量的類型。

3.1.7 標準流與輸入/輸出重定向

1.標準流

當執行一個命令時,shell通常會自動為其打開三個標準流(文件):標準輸入流、標準輸出流和標準錯誤流。三種標準流所使用的文件描述符及物理設備如表3-5所示。默認情況下,程序將從標準輸入流讀取輸入數據,而將正常輸出數據輸出到標準輸出流,將錯誤信息送到標準錯誤流。

表3-5 標準I/O流及相關設備信息

直接使用標準流存在以下問題:

(1)輸入數據從終端輸入時,用戶輸入的數據只能用一次,易出錯且修改不便。

(2)輸出到終端屏幕上的信息只能看,不便使用。

UNIX/Linux系統的標準I/O重定向可以解決這些問題。

2.I/O重定向

I/O重定向(也稱為改道)是指通過文件的形式實現標準I/O流。I/O重定向可以通過以下符號實現。

(1)<:標準輸入重定向。

(2)>:覆蓋方式標準輸出重定向。若文件不存在,則創建;否則覆蓋。

(3)>>:追加方式標準輸出重定向。若文件不存在,則創建;否則在其尾部追加。

(4)&>或>&:標準輸出和標準錯誤同時重定向(不能用于追加方式)。

1)輸入重定向

輸入重定向是指讓命令(或可執行程序)的標準輸入從指定的文件中讀取,即輸入可以不來自鍵盤,而來自一個指定的文件。因此,輸入重定向主要用于解決一個命令的輸入源數據,尤其是需要大量輸入數據的問題。

例如,命令wc可用于統計指定文件包含的行數、單詞數和字符數。

                #wc/etc/passwd     #統計文件/etc/passwd的行、詞和字符信息。也可使用:
                #wc</etc/passwd   #標準輸入重定向

2)輸出重定向

輸出重定向是指把命令(或可執行程序)的標準輸出保存到文件中,可用兩種方式:覆蓋方式(>)和追加方式(>>)。例如:

                #ls>/tmp/dir.out        #覆蓋方式,將當前目錄信息重定向到文件/tmp/dir.out
                #ls/usr>>/tmp/dir.out   #追加方式,將/usr信息重定向追加到/tmp/dir.out

輸出的重定向是有副作用的,一是它可能覆蓋已經存在的文件,二是它在一個具有完整意義的文件后面追加了一些外來或無意義信息。

3)標準錯誤重定向

標準錯誤重定向與標準輸出重定向意義相同,但它是針對標準錯誤的。在對標準輸入和標準輸出重定向時沒有使用文件號,但在對標準錯誤改道時要使用文件號2。方法是:

                命令 2> 文件
            或   命令 2>> 文件

在2和>之間不能有空格。例如:

                #ls-l/home/w-w-w 2>/tmp/err.out    #將標準錯誤重定向到文件/tmp/err.out
                #cat/home/w-w-w 2>>/tmp/err.out    #將標準錯誤追加到文件/tmp/err.out
                #cat/tmp/err.out                   #查看文件/tmp/err.out內容

4)標準輸出和標準錯誤同時重定向

使用符號&>或>&可以讓一個程序的標準輸出和標準錯誤以覆蓋方式同時重定向到一個文件。需要注意的是,此方式不能用于追加,也就是說不能使用符號&>>或>>&。

3.1.8 管道

管道機制是在兩個或多個進程之間建立一種連接,使前一個命令的輸出作為后一個命令的輸入。管道機制常用于進程間的通信。將一個程序或命令的輸出作為另一個程序或命令的輸入,有兩種方法:

(1)通過臨時文件將多個命令或程序結合在一起。

(2)通過UNIX/Linux所提供的管道功能。

后者優于前者。

1.管道

實現管道機制的符號是“|”,其方法為:

                命令1| 命令2| … |命令n

例如:

                #ls-l/dev|wc-l                       #統計系統設備目錄/dev內有多少文件或子目錄
                #cat sample.txt|grep "High"|wc-l      #統計sample.txt內有多少行包含High

2.三通

有時,對某文件進行處理時,既要在屏幕上看到輸出,又要同時保存一個副本,這時可使用管道與tee命令配合來實現三通。

tee命令的功能是讀取標準輸入的數據,并將其內容輸出到指定文件,其用法為:

                tee [-ai] [files]

tee命令的選項如表3-6所示。

表3-6 tee命令的選項

tee命令的使用示例:

                # #將當前目錄的*.txt文件目錄顯示在屏幕上,同時保存兩個副本f1和f2
                # ls *.txt | tee f1 f2

3.1.9 引號機制、命令替換與參數替換

1.引號機制

在shell中有三種引號:單引號('),雙引號(")和反單引號(`),前兩者用于變量定義,后者用于命令替換。

1)單引號

由單引號括起來的字符都作為普通字符。特殊字符用單引號括起來以后,也會失去原有意義。例如:

                #string='$PATH'        #定義string變量,其值為'$PATH'
                #echo$string           #顯示變量的值:$PATH

2)反單引號

反單引號的作用是命令替換。所謂命令替換是指反單引號內的內容將作為命令首先被執行,然后再將命令執行的結果替換反單引號及其括住位置的信息。例如:

                #x=`pwd`              #通過命令pwd替換定義變量x。pwd的功能是顯示用戶工作目錄
                #y=`whoami`           #通過命令whoami替換定義變量y。whoami的功能是顯示用戶名
                #echo$x$y            #顯示變量x和y的內容

命令替換的另一種形式是:

$(cmd)

它的作用與`cmd`相同。例如:

                #MyⅤar=$(whoami)        #通過命令whoami替換定義變量MyⅤar
                #echo$MyⅤar$(pwd)       #顯示變量MyⅤar和$(pwd)的值

命令替換也稱為命令擴展。

3)雙引號

雙引號的作用與單引號的功能基本一樣,可用來定義變量,所不同的是,在雙引號內可進行變量替換和命令替換。雙引號中的特殊字符仍具有特殊意義。所謂變量替換,是指在雙引號中對變量的引用將被替換成變量的值,變量替換也叫變量擴展。若在雙引號內使用特殊字符且又把它作為特殊字符本身來看待,則必須使用轉義字符,如雙引號中的雙引號必須表示為\",\必須表示為\\。

雙引號使用示例:

                #myname=`whoami`        #通過命令替換定義變量myname
                # #定義變量myself,注意使用了變量替換和命令替換
                # myself="I am a student, my uname is $myname and my work dir is `pwd`."
                # #定義變量myself1。注意使用了繼續行和轉義字符
                # myself1="I am a student my uname is \"$myname\" \
                and my work dir is \"`pwd`\""
                #echo$myself             #顯示變量myself的值
                #echo$myself1            #顯示變量myself1的值

2.參數替換

在引號機制中已經看到變量替換和命令替換。參數替換主要是指命令行參數中的變量和命令替換。在執行命令時,其命令行參數既可以是常量也可以是變量,還可以包含命令替換。設有命令DispAllVar用于顯示它自己的所有的命令行參數,設變量x的值為“test parm”,則命令

                DispAllⅤar I am `whoami` the value of x is $x

的輸出為:

                I am root the value of x is test parm

由此可見,在程序的執行過程中`whoami`被替換為root,$x被替換為“test parm”。像這樣,參數在命令行被替換的過程稱為參數替換。

3.1.10 shell命令的執行

1.標準流與程序I/O

當一個shell命令執行時,系統首先為其打開三個標準流:標準輸入、標準輸出和標準錯誤。程序執行時,默認從標準輸入讀、向標準輸出寫、出錯時將錯誤信息寫向標準錯誤。

當一個程序需要從輸入文件中讀取、向輸出文件輸出信息時,若沒有為之提供相關文件,則使用標準I/O:將輸入文件定向到標準輸入,將輸出文件定向到標準輸出。需要時,也可將標準輸入和標準輸出重定向通信管道。當從文件讀取信息時,結束符為文件結束標志EOF;當從標準輸入讀取信息時,輸入完成時的結束符為^D。例如,命令grep是用于信息過濾的,現在通過命令ls /dev > x產生一個文件x,然后用于grep從x中過濾軟盤設備信息。方法是:

                grep fd x                  #使用文件
                grep fd<x                 #使用標準輸入

如果僅為了統計ls /dev輸出中的信息,完全可以不使用中間文件x,而直接使用管道:

                ls/dev|grep fd             #使用管道

如果需要,也可將以上命令的輸出重定向到輸出文件或通過管道傳給其他程序,例如:

                ls/dev|grep fd>y          #通過標準輸出重定向到文件y
                ls/dev|grep fd|wc         #通過標準輸出重定向到管道

由于UNIX/Linux系統的shell命令大都做成了從標準輸入讀、向標準輸出寫的過濾器,因此用戶可將從標準輸入讀的信息重定向到標準輸入,將向標準輸出寫的信息重定向到文件,也可將標準錯誤重定向到文件。

2.命令的返回值

UNIX/Linux系統默認約定shell命令在結束時向調用者返回一個狀態碼或返回值,以表示執行成功與否。一般情況下,返回值為0表示成功,非0表示失敗。當命令是由管道連接的命令串時,最后執行的一個命令返回作為整個命令串的返回值。返回值可以通過$?來訪問。

命令:

                ls/dev|grep fd          #執行命令
                echo$?               #顯示返回狀態(值)

將輸出0,表示/dev目錄內有軟驅設備文件,而命令:

                ls/dev|grep FD         #執行命令
                echo$?               #顯示返回狀態

將返回非0(此處為1),表示ls /dev的輸出中沒有字符串FD。

3.1.11 shell種類

UNIX/Linux系統中的shell有多種類型,其中最常用的幾種是Bourne shel(l sh或bsh)、Bourne again shell(bash),C shell(csh)、tc shell(tcsh)、Korn shell(ksh)和Z shell(zsh)等。

bsh是Stephen Bourne在貝爾實驗室設計的shell,是UNIX shell的一種,并且在每種UNIX上都可以使用。在眾多的UNIX系統中,bsh基本保持一致,它是大多數UNIX系統默認的shell。

bash是GNU工程中使用的shell,即GNU操作系統的默認shell。bash是在bsh基礎上發展起來的。bash與bsh稍有不同,它兼有csh、tcsh和ksh的特色。大多數bsh腳本程序在其上不加修改就可運行,但bash的腳本程序則不一定能在bsh上運行。bash實現了IEEE POSIX 1003.2/ISO 9945.2 shell和工程規范。Linux操作系統默認的shell是bash。

csh是在bsh之后、ksh之前,由vi的設計者Bill Joy編寫的,它不是bsh的擴展。它采用C語言作為語法模型,是一種比Bourne shell更適于編程的shell。Linux為喜歡使用C shell的人提供了tcsh。tcsh是C shell的一個擴展版本。tcsh包括命令行編輯、可編程單詞補全、拼寫校正、歷史命令替換、作業控制和類似C語言的語法,它不僅和Bash shell提示符兼容,而且還提供比Bash shell更多的提示符參數。

ksh是由貝爾實驗室的David G. Korn命名的,可以說它是對bsh的發展,在大部分內容上與bsh兼容,幾乎所有bsh腳本程序都可以在ksh上運行,但反之不行。Korn shell集合了C shell和Bourne shell的優點。Linux系統提供了pdksh(ksh的擴展),它支持任務控制,可以在命令行上掛起、后臺執行、喚醒或終止程序。

Linux也并沒有冷落其他shell用戶,還提供了一些流行的shell,如ash、zsh等。每個shell都有它的用途,有些shell是有專利的,有些能從Internet或其他來源獲得。

主站蜘蛛池模板: 黄龙县| 乌鲁木齐市| 玛多县| 雷波县| 陆川县| 资讯 | 乌拉特中旗| 诸城市| 南川市| 黄平县| 成都市| 大埔县| 株洲县| 牙克石市| 青铜峡市| 八宿县| 双鸭山市| 大理市| 海林市| 马公市| 边坝县| 伊春市| 疏勒县| 汉川市| 浙江省| 固始县| 凤庆县| 交口县| 辽中县| 星子县| 恭城| 建平县| 石台县| 黎川县| 蒙山县| 丹棱县| 罗山县| 始兴县| 安顺市| 芮城县| 涿州市|