1. 程式人生 > >Linux基礎命令(三):重定向、展開與引用——cat、sort、uniq、grep、wc、head、tail、tee

Linux基礎命令(三):重定向、展開與引用——cat、sort、uniq、grep、wc、head、tail、tee

I/O重定向

通過這個工具,可以重定向命令的輸入輸出,命令的輸入來自檔案,而輸出也存到檔案。 也可以把多個命令連線起來組成一個強大的命令管道。

cat — 連線檔案

sort — 排序文字行

uniq — 報道或省略重複行

grep — 列印匹配行

wc — 列印檔案中換行符,字,和位元組個數

head — 輸出檔案第一部分

tail — 輸出檔案最後一部分

tee — 從標準輸入讀取資料,並同時寫到標準輸出和檔案

標準輸入、輸出和錯誤

標準輸出通常由兩種型別組成:

1、程式執行結果(程式要完成的功能)

2、程式執行狀態和錯誤資訊(程式進展)

“everything is a file”,程式實際是把執行的結果輸送到一個叫做標準輸出的特殊檔案(通常用stdout表示),把狀態資訊輸送到叫做標準錯誤的檔案(stderr)。預設情況下,標準輸出和標準錯誤都連線到螢幕,而不是儲存到磁碟。另一方面,很多程式從叫做標準輸入的檔案中(stdin)得到輸入,標準輸入預設連線到鍵盤。I/O重定向允許我們更改輸入來源和輸出地點。

標準輸出重定向

可以使用 “>” 重定向符號接檔名將標準輸出輸送到螢幕以外的其他檔案。注意:使用 “>” 重定向操作符來重定向輸出結果時,目標檔案總是從開頭被重寫。所以每次使用重定向操作,目標檔案原本的內容會被清空。

事實上,我們也可以使用重定向符號清空一個檔案的內容(或者建立一個新的空檔案):

> file_name

我們還可以使用 “>>” 重定向操作符把重定向內容追加到檔案原來的內容後面(也可以用作建立新檔案),而不是重寫檔案:

echo ‘I am a boy’ >> a.txt   #追加單行文字
ls -l /usr/bin >> a.txt   #將ls命令的結果(標準輸出)追加到檔案中

標準錯誤重定向

標準錯誤重定向沒有專用的操作符,為了重定向標準錯誤,我們必須結合其檔案描述符。一個程式可以在任一個經過編號的檔案流上產生輸出。我們將前三個編號的檔案流稱作標準輸入、輸出和錯誤,shell分別將其稱為檔案描述符0、1和2。即檔案描述符2等同於標準錯誤,我們可以將檔案描述符 “2” 與重定位符連在一起來重定向標準錯誤

ls -l /bin/usr 2> a.txt   #/bin/usr是一個不存在的目錄,因此ls命令會輸出標準錯誤

重定向標準輸出和錯誤到同一個檔案

相容舊版本shell的方法:

 ls -l /bin/usr > a.txt 2>&1

首先重定向標準輸出到檔案a.txt,然後 重定向檔案描述符2(標準錯誤)到檔案描述符1(標準輸出)使用表示法2>&1。注意重定向的順序,標準錯誤的重定向必須總是出現在標準輸出 重定向之後,要不然它不起作用。

現在的bash版本還提供第二種方法:

ls -l /bin/usr &> a.txt

我們使用一個&符號跟重定向操作符連線起來 “&>” 來重定向標準輸出和錯誤到檔案 a.txt。

處理不需要的輸出

有時候我們不想要一個命令的輸出結果,例如錯誤和狀態資訊。系統中有一個叫做 “/dev/null” 的特殊檔案,它是一個系統裝置,叫做位儲存桶,它可以接受輸入但並不對輸入做任何處理。我們可以將標準錯誤重定向到該檔案中。

ls -l /bin/usr 2> /dev/null

標準輸入重定向

先介紹一個能夠用到標準輸入的命令 catcat命令讀取一個或多個檔案,然後複製它們的內容到標準輸出。可以使用cat不分頁的顯示檔案內容。

cat file_name...

cat 經常被用來顯示簡短的文字檔案。因為 cat 可以 接受不只一個檔案作為引數,所以它也可以用來把檔案連線在一起。比方說我們下載了一個 大型檔案,這個檔案被分離成多個部分(USENET 中的多媒體檔案經常以這種方式分離), 我們想把它們連起來。如果檔案命名為:

movie.mpeg.001 movie.mpeg.002 … movie.mpeg.099

我們可以使用萬用字元將它們連線起來,並重定向到一個檔案中:

cat movie.mpeg.0* > movie.mpeg

目前為止,和標準輸入還沒什麼關係。但是,如果我們不給cat輸入引數直接執行,它就會從標準輸入讀入資料,而標準輸入預設連線到鍵盤,所以當我們運行了不帶參的cat命令的時候,它就會等待我們輸入資料而不會顯示任何內容。

當我們從鍵盤輸入內容並按下enter鍵的時候,就可以看到螢幕上的文字行重複出現。

[email protected]:~$ cat
his cat is black.
his cat is black.

我們可以不斷的輸入內容,直到按下Ctrl+d告訴cat已經到達了檔案末尾(EOF)。

我們可以利用cat結合重定向操作符建立簡短的文字檔案或程式碼檔案,比如:

[email protected]:~$ cat > a.txt
hahahahahaha,打不過我吧。
哈哈哈哈哈,沒有辦法我就是這麼強大。

注意結束輸入的時候需要enter換行然後按下Ctrl+d,或者不換行連續使用兩次Ctrl+d。

接下來,我們使用重定向操作符 “<” 來重定向標準輸入

cat < a.txt   #將標準輸入源從鍵盤改到檔案a.txt

管道線

命令從標準輸入讀取資料並輸送到標準輸出的能力被一個稱為管道線的 shell 特性所利用。 使用管道操作符 ”|”(豎槓),一個命令的標準輸出可以通過管道送至另一個命令的標準輸入(也屬於I/O重定向):

command1 | command2

為了說明這個操作符,這裡介紹一下less命令的另一個功能,除了瀏覽檔案內容,它還可以接收標準輸入並把其輸送到標準輸出並一頁一頁地顯示。

ls -l /usr/bin | less

利用這個功能,我們可以非常方便的檢視會產生標準輸出的任一命令的執行結果。

過濾器

管道線經常用來對資料完成複雜的操作。有可能會把幾個命令放在一起組成一個管道線。 通常,以這種方式使用的命令被稱為過濾器。

比如,把目錄 /bin 和 /usr/bin 中的可執行程式放在一起並進行排序然後輸出

ls /bin /usr/bin | sort | less

因為我們指定了兩個目錄(/bin 和 /usr/bin),ls 命令的輸出結果由兩個有序列表組成, 各自針對一個目錄。通過在管道線中包含 sort,我們改變輸出資料,從而產生一個有序列表。

uniq

uniq 命令經常和 sort 命令結合在一起使用。uniq 從標準輸入或單個檔名引數接受資料有序 列表,預設情況下,從資料列表中刪除重複行。(/bin 和 /usr/bin中有重名的程式 )

ls /bin /usr/bin | sort | uniq | less

如果想要輸出重複行的資料,可以使用uniq的-d選項

ls /bin /usr/bin | sort | uniq -d | less

wc

wc命令是用來顯示檔案所包含的行數、字數(一個字被定義為由空格或換行字元分隔的字串)和位元組數

wc a.txt

檢視有序列表中的程式個數,-l 選項表示只輸出行數

ls /bin /usr/bin | sort | uniq | wc -l

grep

grep 是個很強大的程式,用來找到檔案中的匹配文字

grep pattern file_name...

當 grep 遇到一個檔案中的匹配”模式”(正則表示式),它會打印出包含這個型別的行。比如在程式列表中,找到檔名中包含單詞”zip”的所有程式:

ls /bin /usr/bin | sort | uniq | grep zip

grep 有一些方便的選項:”-i”使得 grep 在執行搜尋時忽略大小寫(通常,搜尋是大小寫 敏感的),”-v”選項會告訴 grep 只打印不匹配的行。

head / tail

head 命令列印檔案的前十行,而 tail 命令列印檔案的後十行。預設情況下,兩個命令都列印十行文字,但是可以通過”-n”選項來調整命令列印的行數。

head -n 5 a.txt
tail -n 5 a.txt
ls /usr/bin | tail -n 5

tail 有一個選項 “-f” 允許你實時地瀏覽檔案。當觀察日誌檔案的進展時很有用,因為它們同時在被寫入。

tail -f logfile_name

使用”-f”選項,tail 命令持續監測這個檔案,當新的內容新增到檔案後,會立即出現在螢幕上。直到你輸入 Ctrl+c。

tee

從標準輸入讀取資料,並且同時輸出到標準輸出(允許資料繼續隨著管道線流動)和一個或多個檔案。主要用於在某個中間處理 階段來捕捉管道線的內容

ls /usr/bin | tee ls.txt | grep zip

字元展開

再介紹一個新命令 echo顯示引數文字。(自動將引數排列成一行,超過一行的文字顯示為單段落)

echo this is a test

傳遞到 echo 命令的任一個引數都會在(螢幕上)顯示出來。

路徑名展開

萬用字元所依賴的工作機制叫做路徑名展開。eg:

echo D*
echo *s
echo [[:upper:]]*
echo /usr/*/share

隱藏檔案路徑名展開

echo * 不會顯示隱藏檔案。

echo .* 可以顯示隱藏檔案,但是結果中也會包括 "."(當前目錄) 和 ".."(父目錄) 這兩個名字。(注意:多個圓點開頭的檔名也屬於隱藏檔案。

波浪線展開

波浪線字元(“~”)用在 一個單詞的開頭時,它會展開成指定使用者的家目錄名,如果沒有指定使用者名稱,則展開成當前使用者的家目錄:

echo ~ username

算術表示式展開

shell 會在展開過程中執行算術表示式。所以我們可以把 shell 提示當作計算器來使用:

[email protected]:~$ echo $((2 + 2))
4

算術表示式展開使用這種格式:(美元符號加兩層圓括號

$((expression))

注意:算術表示式只支援整數

算術操作符
操作符 說明
+
-
*
/ 除(但是記住,因為展開只是支援整數除法,所以結果是整數。)
% 取餘,只是簡單的意味著,“餘數”
** 取冪

算術表示式中空格並不重要,並且表示式可以巢狀。eg:

echo $(((5**2) * 3))  #也可以把每一層分別展開:echo $(($((5**2)) * 3))

算術表示式也可以嵌入文字中:

[email protected]:~$ echo Five divided by two equals $((5/2))
Five divided by two equals 2

花括號展開

通過花括號展開可以從一個包含花括號的模式中 建立多個文字字串。eg:

[email protected]:~$ echo Front-{A,B,C}-Back
Front-A-Back Front-B-Back Front-C-Back

花括號展開模式可能包含一個開頭部分叫做報頭(如上例的Front-),一個結尾部分叫做附言(如上例的-Back)。花括號表示式本身可能包含一個由逗號分開的字串列表,或者一個整數區間,或者單個的字元的區間。這種模式不能嵌入空白字元。

整數區間:

echo Number_{1..5}

倒序字母區間:

 echo {Z..A}

花括號展開可以巢狀

[email protected]:~$ echo a{A{1,2},B{3,4}}b
aA1b aA2b aB3b aB4b

最常見的應用是,建立一系列的檔案或目錄列表。

mkdir {2007..2009}-0{1..9} {2007..2009}-{10..12}

引數展開

這個特性在 shell 指令碼中比直接在命令列中更有用。 它的許多功能和系統儲存小塊資料(變數),並給每塊資料命名的能力有關係。簡言之,就是變數值展開。格式為美元符號加變數名($variable)。

eg:”USER”變數中存放的是使用者名稱

[email protected]:~$ echo $USER
ldz

如果是對未定義的變數進行引數展開會將其替換為一個空字串。eg:數字1是沒有定義的變數

[email protected]:~$ echo The total is $100.00
The total is 00.00

檢視有效的變數列表

printenv | less

在其它展開型別中,如果你誤輸入一個模式,展開就不會發生。但在引數展開中,如果你拼寫錯了一個變數名, 展開仍然會進行,只是展開的結果是一個空字串。

命令替換

命令替換即把一個命令的輸出作為一個展開模式來使用

echo $(ls)
ls -l $(which cp)

這裡我們把 which cp 的執行結果作為一個引數傳遞給 ls 命令,因此可以在不知道 cp 命令 完整路徑名的情況下得到它的檔案屬性列表。

不只限制於簡單命令,也可以使用整個管道線的輸出作為展開模式。使管道線的輸出結果成為 file 命令的引數列表。

file $(ls /usr/bin/* | grep zip)

bash中還支援舊版shell中的另一種語法,使用倒引號來替代美元符號和括號。

ls -l `which cp`

引用

shell 提供了一種 叫做引用的機制,來有選擇地禁止不需要的展開

雙引號

放在雙引號中的文字都被當作普通字元來看待。但有幾個例外:$、\ 和 ` `(倒引號)。也就是說,單詞分割、路徑名展開、 波浪線展開和花括號展開都將失效,但引數展開、算術展開和命令替換仍然執行

所謂單詞分割:Linux的單詞分割機制先查詢是否存在空格、製表符以及換行符,然後將它們作為單詞間的界定符號,並全部替換成為單個空格。也就是說空格、製表符以及換行符都不會作為文字的一部分,而是作為分隔符使用,直接替換為單個空格(刪除多餘的空格)。Linux通過識別這些來將單詞分割為不同的引數。eg:

[email protected]:~$ echo this is a   test
this is a test

如果我們想要阻止單詞分割,比如我們的檔名包含一個空格(即空格作為名稱文字一部分),可以使用雙引號來保留空格文字:

ls -l "two words.txt"

如果不使用雙引號,系統會將檔名識別為兩個引數:two 和 words.txt 。

注意,雙引號中引數展開、算術表示式展開和命令替換仍然有效:

[email protected]:~$ echo "$USER $((2+2)) $(cal)"  
ldz 4    September 2018                  
Su Mo Tu We Th Fr Sa                     
                   1                     
 2  3  4  5  6  7  8                     
 9 10 11 12 13 14 15                     
16 17 18 19 20 21 22                     
23 24 25 26 27 28 29                     
30                                       

單詞分割機制把換行符看作界定符,對命令替換產生了一個微妙但有趣的影響。

[email protected]:~$ echo $(cal)
September 2018 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
[email protected]:~$ echo "$(cal)"
   September 2018
Su Mo Tu We Th Fr Sa
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30

在第一個例項中,沒有引用的命令替換由於單詞分割的原因導致命令列包含38個引數。在第二個例子中, 命令列只有一個引數,引數中包括嵌入的空格和換行符。

單引號

單引號可以禁止所有的展開

[email protected]:~$ echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER'
text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER

轉義字元

轉義字元(即反斜槓 “\”)用來引用單個字元。通常在雙引號中使用轉義字元,來有選擇地阻止展開。eg:

[email protected]:~$ echo "The balance for user $USER is: \$5.00"
The balance for user ldz is: $5.00

也常常使用轉義字元來消除檔名中一個字元的特殊含義,如“$”, “!”, “&”, “ “(空格) 等字元。eg:建立一個名為"a a.txt"的檔案

touch a\ a.txt

注意在單引號中,反斜槓也將失去它的特殊含義,被看作普通字元。

反斜槓轉義字元序列

反斜槓除了作為轉義字元外,也可以構成一種表示法,來代表某種特殊字元,這些特殊字元叫做控制碼。ASCII 編碼表中前32個字元被用來把命令轉輸到電報機之類的裝置。如製表符、退格符、換行符、回車符等,還有大家不太熟悉的如空值、傳輸結束碼、和確認。

常見的反斜槓轉義字元序列:

轉義序列 含義
\a 響鈴(”警告”-導致計算機嘟嘟響)
\b 退格符
\n 新的一行。在類 Unix 系統中,產生換行。
\r 回車符
\t 製表符

echo 命令帶上 ‘-e’ 選項,能夠解釋轉義序列。可以把轉義序列放在 $' ' (美元符號加單引號) 裡面或者" "(雙引號)裡面。eg:

sleep 10; echo -e "Time's up\a"   #十秒後計算機發出一聲警告聲

sleep 10; echo "Time's up" $'\a'  #同上

echo -e "\a"   #發出警告聲

echo -e $'\a'  #同上