Linux運維筆記-日常操作命令總結(3)

散盡浮華發表於2016-11-09

 

文字操作:sed

sed是一個很好的檔案處理工具,本身是一個管道命令,主要是以行為單位進行處理,可以將資料行進行替換、刪除、新增、選取等特定工作。

sed命令列格式為:
sed [-nefri] ‘command’ 輸入文字

常用選項:
-n∶使用安靜(silent)模式。在一般 sed 的用法中,所有來自 STDIN的資料一般都會被列出到螢幕上。但如果加上 -n 引數後,則只有經過sed 特殊處理的那一行(或者動作)才會被列出來。
-e∶直接在指令列模式上進行 sed 的動作編輯;
-f∶直接將 sed 的動作寫在一個檔案內, -f filename 則可以執行 filename 內的sed 動作;
-r∶sed 的動作支援的是延伸型正規表示法的語法。(預設是基礎正規表示法語法)
-i∶直接修改讀取的檔案內容,而不是由螢幕輸出。kevin.txt  

常用命令:
a   ∶新增, a 的後面可以接字串,而這些字串會在新的一行出現(目前的下一行)~
c   ∶取代, c 的後面可以接字串,這些字串可以取代 n1,n2 之間的行!
d   ∶刪除,因為是刪除啊,所以 d 後面通常不接任何咚咚;
i   ∶插入, i 的後面可以接字串,而這些字串會在新的一行出現(目前的上一行);
p  ∶列印,亦即將某個選擇的資料印出。通常 p 會與引數 sed -n 一起運作~
s  ∶取代,可以直接進行取代的工作哩!通常這個 s 的動作可以搭配正規表示法!例如 1,20s/old/new/g 就是啦!

替換一行中的某部分。s後面的替換符號可以使用/,#,_三種符號
格式:sed 's/要替換的字串/新的字串/g'   (要替換的字串可以用正規表示式)
[root@kevin ~]# sed -n '/ruby/p' kevin.txt | sed 's/ruby/bird/g'    #替換ruby為bird
[root@kevin ~]# sed -n '/ruby/p' kevin.txt | sed 's#ruby#bird#g'    #替換ruby為bird
[root@kevin ~]# sed -n '/ruby/p' kevin.txt | sed 's_ruby_bird_g'    #替換ruby為bird

定址
定址用於決定對哪些行進行編輯。地址的形式可以是數字、正規表示式、或二者的結合。
如果沒有指定地址,sed將處理輸入檔案的所有行。
地址是一個數字,則表示行號;是“$"符號,則表示最後一行。例如: 
[root@kevin ~]# sed -n '3p' datafile
只列印第三行

只顯示指定行範圍的檔案內容,例如只檢視檔案的第100行到第200行
[root@kevin ~]# sed -n '100,200p' mysql_slow_query.log

地址是逗號分隔的,那麼需要處理的地址是這兩行之間的範圍(包括這兩行在內)。範圍可以用數字、正規表示式、或二者的組合表示。
[root@kevin ~]# sed '2,5d' datafile
刪除第二到第五行

[root@kevin ~]# sed '/My/,/You/d' datafile
刪除包含"My"的行到包含"You"的行之間的行

[root@kevin ~]# sed '/My/,10d' datafile
刪除包含"My"的行到第十行的內容
 

示例說明
kevin.txt刪除某行
[root@kevin ~]# sed '1d' kevin.txtkevin.txt    #刪除第一行 
[root@kevin ~]# sed '$d' kevin.txtkevin.txt     #刪除最後一行
[root@kevin ~]# sed '1,2d' kevin.txt   #刪除第一行到第二行
[root@kevin ~]# sed '2,$d' kevin.txt   #刪除第二行到最後一行

顯示某行
[root@kevin ~]# sed -n '1p' kevin.txt   #顯示第一行 
[root@kevin ~]# sed -n '$p' kevin.txt   #顯示最後一行
[root@kevin ~]# sed -n '1,2p' kevin.txt    #顯示第一行到第二行
[root@kevin ~]# sed -n '2,$p' kevin.txt     #顯示第二行到最後一行

使用模式進行查詢
[root@kevin ~]# sed -n '/ruby/p' kevin.txt    #查詢包括關鍵字ruby所在所有行
[root@kevin ~]# sed -n '/\$/p' kevin.txt      #查詢包括關鍵字$所在所有行,使用反斜線\遮蔽特殊含義

增加一行或多行字串
[root@kevin ~]# cat kevin.txt
kevin.txtHello!
kevin.txtruby is me,welcome to my blog.
kevin.txtend

[root@kevin ~]# sed '1a drink tea' kevin.txt  #第一行後增加字串"drink tea"
kevin.txtHello!
kevin.txtdrink tea
kevin.txtruby is me,welcome to my blog. 
kevin.txtend

[root@kevin ~]# sed '1,3a drink tea' kevin.txt #第一行到第三行後增加字串"drink tea"
kevin.txtHello!
kevin.txtdrink tea
kevin.txtruby is me,welcome to my blog.
kevin.txtdrink tea
kevin.txtend
kevin.txtdrink tea

[root@kevin ~]# sed '1a drink tea\nor coffee' kevin.txt   #第一行後增加多行,使用換行符\n
kevin.txtHello!
kevin.txtdrink tea
kevin.txtor coffee
kevin.txtruby is me,welcome to my blog.
kevin.txtend

代替一行或多行
[root@kevin ~]# sed '1c Hi' kevin.txt#第一行代替為Hi
kevin.txtHi
kevin.txtruby is me,welcome to my blog.
kevin.txtend

[root@kevin ~]# sed '1,2c Hi' kevin.txtkevin.txt#第一行到第二行代替為Hi
kevin.txtHi
kevin.txtend

替換一行中的某部分
格式:sed 's/要替換的字串/新的字串/g'   (要替換的字串可以用正規表示式)
[root@kevin ~]# sed -n '/ruby/p' kevin.txt | sed 's/ruby/bird/g'       #替換ruby為bird
 [root@kevin ~]# sed -n '/ruby/p' kevin.txt | sed 's/ruby//g'    #刪除ruby

kevin.txt插入
[root@kevin ~]# sed -i '$a bye' kevin.txt     #在檔案kevin.txt中最後一行直接輸入"bye"
[root@kevin ~]# cat kevin.txt
kevin.txtHello!
kevin.txtruby is me,welcome to my blog.
kevin.txtend
kevin.txtbye

替換:
-e是編輯命令,用於sed執行多個編輯任務的情況下。在下一行開始編輯前,所有的編輯動作將應用到模式緩衝區中的行上。

[root@kevin ~]# sed -e '1,10d' -e 's/My/Your/g' datafile
選項-e用於進行多重編輯。
第一重編輯刪除第1-3行。
第二重編輯將出現的所有My替換為Your。
因為是逐行進行這兩項編輯(即這兩個命令都在模式空間的當前行上執行),所以編輯命令的順序會影響結果。
 
替換兩個或多個空格為一個空格
[root@kevin ~]# sed 's/[ ][ ]*/ /g' file_name

替換兩個或多個空格為分隔符:
[root@kevin ~]# sed 's/[ ][ ]*/:/g' file_name
    
如果空格與tkevin.txt共存時用下面的命令進行替換
替換成空格
[root@kevin ~]# sed 's/[[:space:]][[:space:]]*/ /g' filename

替換成分隔符:
[root@kevin ~]# sed 's/[[:space:]][[:space:]]*/:/g' filename

=======================================
sed命令的呼叫:
在命令列鍵入命令;將sed命令插入指令碼檔案,然後呼叫sed;將sed命令插入指令碼檔案,並使sed指令碼可執行
sed [option] sed命令 輸入檔案            在命令列使用sed命令,實際命令要加單引號
sed [option] -f sed指令碼檔案 輸入檔案     使用sed指令碼檔案
sed指令碼檔案 [option] 輸入檔案            第一行具有sed命令直譯器的sed指令碼檔案

option如下:
n 不列印; sed不寫編輯行到標準輸出,預設為列印所有行(編輯和未編輯),p命令可以用來列印編輯行
c 下一命令是編輯命令,使用多項編輯時加入此選項
f 如果正在呼叫sed指令碼檔案,使用此選項,此選項通知sed一個指令碼檔案支援所用的sed命令,如
# sed -f myscript.sed input_file      這裡myscript.sed即為支援sed命令的檔案

使用重定向檔案即可儲存sed的輸出
 
使用sed在文字中定位文字的方式:
x       x為一行號,比如1
x,y     表示行號範圍從x到y,如2,5表示從第2行到第5行
/pattern/    查詢包含模式的行,如/disk/或/[a-z]/
/pattern/pattern/   查詢包含兩個模式的行,如/disk/disks/
/pattern/,x  在給定行號上查詢包含模式的行,如/disk/,3
x,/pattern/  通過行號和模式查詢匹配行,如 3,/disk/
x,y!    查詢不包含指定行號x和y的行
 
基本sed編輯命令:
p      列印匹配行                      c/    用新文字替換定位文字
=      顯示檔案行號                    s     使用替換模式替換相應模式
a/     在定位行號後附加新文字資訊        r     從另一個文字中讀文字
i/     在定位行號後插入新文字資訊        w     寫文字到一個檔案
d      刪除定位行                      q     第一個模式匹配完成後退出或立即退出
l      顯示與八進位制ASCII程式碼等價的控制字元        y  傳送字元
n      從另一個文字中讀文字下一行,並附加在下一行   {}     在定位行執行的命令組
g      將模式2貼上到/pattern n/
 
基本sed程式設計舉例:
使用p(rint)顯示行: sed -n '2p' temp.txt   只顯示第2行,使用選項n
列印範圍:  sed -n '1,3p' temp.txt         列印第1行到第3行
列印模式:  sed -n '/movie/'p temp.txt     列印含movie的行
使用模式和行號查詢:  sed -n '3,/movie/'p temp.txt   只在第3行查詢movie並列印
顯示整個檔案:  sed -n '1,$'p temp.txt      $為最後一行
任意字元:  sed -n '/.*ing/'p temp.txt     注意是.*ing,而不是*ing
列印行號:  sed -e '/music/=' temp.txt

附加文字:(建立sed指令碼檔案)chmod u+x script.sed,執行時./script.sed temp.txt
        #!/bin/sed -f
        /name1/ a/             #a/表示此處換行新增文字
        HERE ADD NEW LINE.     #新增的文字內容
插入文字: /name1/ a/ 改成 4 i/ 4表示行號,i插入
修改文字: /name1/ a/ 改成 /name1/ c/ 將修改整行,c修改
刪除文字: sed '1d' temp.txt  或者 sed '1,4d' temp.txt
替換文字: sed 's/source/OKSTR/' temp.txt     將source替換成OKSTR
             sed 's//$//g' temp.txt             將文字中所有的$符號全部刪除
             sed 's/source/OKSTR/w temp2.txt' temp.txt 將替換後的記錄寫入檔案temp2.txt
替換修改字串: sed 's/source/"ADD BEFORE" &/p' temp.txt
             結果將在source字串前面加上"ADD BEFORE",這裡的&表示找到的source字元並儲存
sed結果寫入到檔案: sed '1,2 w temp2.txt' temp.txt
                     sed '/name/ w temp2.txt' temp.txt
從檔案中讀文字: sed '/name/r temp2.txt' temp.txt
在每列最後加文字: sed 's/[0-9]*/& Pass/g' temp.txt
從shell向sed傳值: echo $NAME | sed "s/go/$REP/g"   注意需要使用雙引號
 
快速一行命令:
's//.$//g'         刪除以句點結尾行
'-e /abcd/d'       刪除包含abcd的行
's/[][][]*/[]/g'   刪除一個以上空格,用一個空格代替
's/^[][]*//g'      刪除行首空格
's//.[][]*/[]/g'   刪除句號後跟兩個或更多的空格,用一個空格代替
'/^$/d'            刪除空行
's/^.//g'          刪除第一個字元,區別  's//.//g'刪除所有的句點
's/COL/(.../)//g'  刪除緊跟COL的後三個字母
's/^////g'         刪除路徑中第一個/
 
=================================================
1)使用句點匹配單字元    
句點“.”可以匹配任意單字元。“.”可以匹配字串頭,也可以是中間任意字元。假定正在過濾一個文字檔案,對於一個有1 0個字元的指令碼集,要求前4個字元之後為X C,匹配操作如下:. . . .X C. . . .

2)在行首以^匹配字串或字元序列    
^只允許在一行的開始匹配字元或單詞。在行首第4個字元為1,匹配操作表示為:^ . . . 1

3)在行尾以$匹配字串或字元    
可以說$與^正相反,它在行尾匹配字串或字元, $符號放在匹配單詞後。如果在行尾匹配單詞j e t 0 1,操作如下:j e t 0 1 $    如果只返回包含一個字元的行,操作如下:^ . $

4)使用*匹配字串中的單字元或其重複序列    
使用此特殊字元匹配任意字元或字串的重複多次表示式。

5)使用/遮蔽一個特殊字元的含義    有
時需要查詢一些字元或字串,而它們包含了系統指定為特殊字元的一個字元。如果要在正規表示式中匹配以* . p a s結尾的所有檔案,可做如下操作:/ * / . p a s

6)使用[]匹配一個範圍或集合     
使用[ ]匹配特定字串或字串集,可以用逗號將括弧內要匹配的不同字串分開,但並不強制要求這樣做(一些系統提倡在複雜的表示式中使用逗號),
這樣做可以增 加模式的可讀性。使用“ -”表示一個字串範圍,表明字串範圍從“ -”左邊字元開始,到“ -”右邊字元結束。假定要匹配任意一個數字,
可以使用:[ 0 1 2 3 4 5 6 7 8 9 ]    要匹配任意字母,則使用:[ A - Z a - z ]表明從A - Z、a - z的字母範圍。

7)使用/{/}匹配模式結果出現的次數    
使用*可匹配所有匹配結果任意次,但如果只要指定次數,就應使用/ { / },此模式有三種形式,即:
pattern/{n/} 匹配模式出現n次。
pattern/{n,/} 匹配模式出現最少n次。
pattern/{n,m} 匹配模式出現n到m次之間,n , m為0 - 2 5 5中任意整數。
匹配字母A出現兩次,並以B結尾,操作如下:A / { 2 / } B匹配值為A A B    匹配A至少4次,使用:A / { 4 , / } B
  
======================
替換單引號為空,可以這樣寫:
sed 's/'"'"'//g'
sed 's/'\''//g'
sed s/\'//g
 
=====================
在檔案的第一行前面插入一行abc
sed -i '1i\abc' urfile

awk命令(http://www.gnu.org/software/gawk/manual/gawk.html)

awk是一個強大的文字分析工具,相對於grep的查詢,sed的編輯,awk在其對資料分析並生成報告時,顯得尤為強大。簡單來說awk就是把檔案逐行的讀入,
以空格為預設分隔符將每行切片,切開的部分再進行各種分析處理。

awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk,gawk 是 AWK 的 GNU 版本。

awk其名稱得自於它的創始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母。實際上 AWK 的確擁有自己的語言: 
AWK 程式設計語言 , 三位建立者已將它正式定義為“樣式掃描和處理語言”。它允許您建立簡短的程式,這些程式讀取輸入檔案、為資料排序、處理資料、
對輸入執行計算以及生成報表,還有無數其他的功能。

使用方法
awk '{pattern + action}' {filenames}

儘管操作可能會很複雜,但語法總是這樣,其中 pattern 表示 AWK 在資料中查詢的內容,而 action 是在找到匹配內容時所執行的一系列命令。
花括號({})不需要在程式中始終出現,但它們用於根據特定的模式對一系列指令進行分組。 pattern就是要表示的正規表示式,用斜槓括起來。

awk語言的最基本功能是在檔案或者字串中基於指定規則瀏覽和抽取資訊,awk抽取資訊後,才能進行其他文字操作。完整的awk指令碼通常用來格式化文字
檔案中的資訊。
通常,awk是以檔案的一行為處理單位的。awk每接收檔案的一行,然後執行相應的命令,來處理文字。

呼叫awk
有三種方式呼叫awk
1)命令列方式
awk [-F  field-separator]  'commands'  input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可選的。 input-file(s) 是待處理的檔案。
在awk中,檔案的每一行中,由域分隔符分開的每一項稱為一個域。通常,在不指名-F域分隔符的情況下,預設的域分隔符是空格。

2)shell指令碼方式
將所有的awk命令插入一個檔案,並使awk程式可執行,然後awk命令直譯器作為指令碼的首行,一遍通過鍵入指令碼名稱來呼叫。
相當於shell指令碼首行的:#!/bin/sh
可以換成:#!/bin/awk

3)將所有的awk命令插入一個單獨檔案,然後呼叫:
awk -f awk-script-file input-file(s)
其中,-f選項載入awk-script-file中的awk指令碼,input-file(s)跟上面的是一樣的。


假設last -n 5的輸出如下:
[root@kevin ~]# last -n 5 <==僅取出前五行
root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in
root     pts/1   192.168.1.100  Tue Feb 10 00:46 - 02:28  (01:41)
root     pts/1   192.168.1.100  Mon Feb  9 11:41 - 18:30  (06:48)
dmtsai   pts/1   192.168.1.100  Mon Feb  9 11:41 - 11:41  (00:00)
root     tty1                   Fri Sep  5 14:09 - 14:10  (00:01)

如果只是顯示最近登入的5個帳號
[root@kevin ~]# last -n 5 | awk  '{print $1}'
root
root
root
dmtsai
root

awk工作流程是這樣的:
讀入有'\n'換行符分割的一條記錄,然後將記錄按指定的域分隔符劃分域,填充域,$0則表示所有域,$1表示第一個域,$n表示第n個域。
預設域分隔符是"空白鍵" 或 "[tab]鍵",所以$1表示登入使用者,$3表示登入使用者ip,以此類推。

如果只是顯示/etc/passwd的賬戶
[root@kevin ~]# cat /etc/passwd |awk  -F ':'  '{print $1}'  
root
daemon
bin
sys

這種是awk+action的示例,每行都會執行action{print $1}。
-F指定域分隔符為':'。

如果只是顯示/etc/passwd的賬戶和賬戶對應的shell,而賬戶與shell之間以tab鍵分割
[root@kevin ~]# cat /etc/passwd |awk  -F ':'  '{print $1"\t"$7}'
root    /bin/bash
daemon  /bin/sh
bin     /bin/sh
sys     /bin/sh
 
如果只是顯示/etc/passwd的賬戶和賬戶對應的shell,而賬戶與shell之間以逗號分割,而且在所有行新增列名name,shell,在最後一行新增"blue,/bin/nosh"。

[root@kevin ~]# cat /etc/passwd |awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'
name,shell
root,/bin/bash
daemon,/bin/sh
bin,/bin/sh
sys,/bin/sh
....
blue,/bin/nosh

awk工作流程是這樣的:
先執行BEGING,然後讀取檔案,讀入有/n換行符分割的一條記錄,然後將記錄按指定的域分隔符劃分域,填充域,$0則表示所有域,$1表示第一個域,
$n表示第n個域,隨後開始執行模式所對應的動作action。接著開始讀入第二條記錄······直到所有的記錄都讀完,最後執行END操作。

搜尋/etc/passwd有root關鍵字的所有行
[root@kevin ~]# awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
這種是pattern的使用示例,匹配了pattern(這裡是root)的行才會執行action(沒有指定action,預設輸出每行的內容)。

搜尋支援正則,例如找root開頭的: awk -F: '/^root/' /etc/passwd

搜尋/etc/passwd有root關鍵字的所有行,並顯示對應的shell
[root@kevin ~]# awk -F: '/root/{print $7}' /etc/passwd             
/bin/bash

這裡指定了action{print $7}

awk內建變數
awk有許多內建變數用來設定環境資訊,這些變數可以被改變,下面給出了最常用的一些變數。

ARGC               命令列引數個數
ARGV               命令列引數排列
ENVIRON            支援佇列中系統環境變數的使用
FILENAME           awk瀏覽的檔名
FNR                瀏覽檔案的記錄數
FS                 設定輸入域分隔符,等價於命令列 -F選項
NF                 瀏覽記錄的域的個數
NR                 已讀的記錄數
OFS                輸出域分隔符
ORS                輸出記錄分隔符
RS                 控制記錄分隔符

此外,$0變數是指整條記錄。$1表示當前行的第一個域,$2表示當前行的第二個域,......以此類推。

統計/etc/passwd:檔名,每行的行號,每行的列數,對應的完整行內容:
[root@kevin ~]# awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/sh
filename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh
filename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh
 
使用printf替代print,可以讓程式碼更加簡潔,易讀
[root@kevin ~]# awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
 
print和printf
awk中同時提供了print和printf兩種列印輸出的函式。

其中print函式的引數可以是變數、數值或者字串。字串必須用雙引號引用,引數用逗號分隔。如果沒有逗號,引數就串聯在一起而無法區分。
這裡,逗號的作用與輸出檔案的分隔符的作用是一樣的,只是後者是空格而已。

printf函式,其用法和c語言中printf基本相似,可以格式化字串,輸出複雜時,printf更加好用,程式碼更易懂。

awk程式設計:變數和賦值
除了awk的內建變數,awk還可以自定義變數。

下面統計/etc/passwd的賬戶人數
[root@kevin ~]# awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
......
user count is  40

count是自定義變數。之前的action{}裡都是隻有一個print,其實print只是一個語句,而action{}可以有多個語句,以;號隔開。

這裡沒有初始化count,雖然預設是0,但是妥當的做法還是初始化為0:
[root@kevin ~]# awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd
[start]user count is  0
root:x:0:0:root:/root:/bin/bash
...
[end]user count is  40
 
統計某個資料夾下的檔案佔用的位元組數
[root@kevin ~]# ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
[end]size is  8657198
 
如果以M為單位顯示:
[root@kevin ~]# ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}' 
[end]size is  8.25889 M

注意,統計不包括資料夾的子目錄。

條件語句
awk中的條件語句是從C語言中借鑑來的,見如下宣告方式:
if (expression) {
    statement;
    statement;
    ... ...
}

if (expression) {
    statement;
} else {
    statement2;
}

if (expression) {
    statement1;
} else if (expression1) {
    statement2;
} else {
    statement3;
}

統計某個資料夾下的檔案佔用的位元組數,過濾4096大小的檔案(一般都是資料夾):
[root@kevin ~]# ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'
[start]size is  0
[end]size is  0.0610514 M

迴圈語句
awk中的迴圈語句同樣借鑑於C語言,支援while、do/while、for、break、continue,這些關鍵字的語義和C語言中的語義完全相同。

陣列
因為awk中陣列的下標可以是數字和字母,陣列的下標通常被稱為關鍵字(key)。值和關鍵字都儲存在內部的一張針對key/value應用hash的表格裡。
由於hash不是順序儲存,因此在顯示陣列內容時會發現,它們並不是按照你預料的順序顯示出來的。陣列和變數一樣,都是在使用時自動建立的,awk
也同樣會自動判斷其儲存的是數字還是字串。一般而言,awk中的陣列用來從記錄中收集資訊,可以用於計算總和、統計單詞以及跟蹤模板被匹配的次數等。

顯示/etc/passwd的賬戶
[root@kevin ~]# awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
0 root
1 daemon
2 bin
3 sys
4 sync
5 games
......

這裡使用for迴圈遍歷陣列

grep命令:從檔案中查詢匹配模式的行

1.作用
Linux系統中grep命令是一種強大的文字搜尋工具,它能使用正規表示式搜尋文字,並把匹 配的行列印出來。grep全稱是Global Regular Expression Print,表示全域性正規表示式版本,它的使用許可權是所有使用者。

2.格式
grep [options]

3.主要引數
[options]主要引數:
-c:只輸出匹配行的計數。
-I:不區分大 小寫(只適用於單字元)。
-h:查詢多檔案時不顯示檔名。
-l:查詢多檔案時只輸出包含匹配字元的檔名。
-n:顯示匹配行及 行號。
-s:不顯示不存在或無匹配文字的錯誤資訊。
-v:顯示不包含匹配文字的所有行。

pattern正規表示式主要引數:
\: 忽略正規表示式中特殊字元的原有含義。
^:匹配正規表示式的開始行。
$: 匹配正規表示式的結束行。
\<:從匹配正則表達 式的行開始。
\>:到匹配正規表示式的行結束。
[ ]:單個字元,如[A]即A符合要求 。
[ - ]:範圍,如[A-Z],即A、B、C一直到Z都符合要求 。
。:所有的單個字元。
* :有字元,長度可以為0。

grep -v 過濾
grep -c 列印關鍵字元所在的行數
grep -An  列印關鍵字元所在的行的後n行內容
grep -Bn  列印關鍵字元所在的行的前n行內容
grep -Cn  列印關鍵字元所在的行的前後各n行內容

cat filename |grep "abc"
fgrep -R "abc" ./*

4.grep命令使用簡單例項
[root@kevin ~]# grep ‘test’ d*
顯示所有以d開頭的檔案中包含 test的行。

[root@kevin ~]# grep ‘test’ aa bb cc
顯示在aa,bb,cc檔案中匹配test的行。

[root@kevin ~]# grep ‘[a-z]\{5\}’ aa
顯示所有包含每個字串至少有5個連續小寫字元的字串的行。

[root@kevin ~]# grep ‘w\(es\)t.*\1′ aa
如果west被匹配,則es就被儲存到記憶體中,並標記為1,然後搜尋任意個字元(.*),這些字元後面緊跟著 另外一個es(\1),找到就顯示該行。
如果用egrep或grep -E,就不用”\”號進行轉義,直接寫成’w(es)t.*\1′就可以了。

5.grep命令使用複雜例項
假設您正在’/usr/src/Linux/Doc’目錄下搜尋帶字元 串’magic’的檔案:
[root@kevin ~]# grep magic /usr/src/Linux/Doc/*
sysrq.txt:* How do I enable the magic SysRQ key?
sysrq.txt:* How do I use the magic SysRQ key?

其中檔案’sysrp.txt’包含該字串,討論的是 SysRQ 的功能。

預設情況下,’grep’只搜尋當前目錄。如果 此目錄下有許多子目錄,’grep’會以如下形式列出:
grep: sound: Is a directory

這可能會使’grep’ 的輸出難於閱讀。這裡有兩種解決的辦法:
明確要求搜尋子目錄:grep -r
或忽略子目錄:grep -d skip

如果有很多 輸出時,您可以通過管道將其轉到’less’上閱讀:
[root@kevin ~]# grep magic /usr/src/Linux/Documentation/* | less
這樣,您就可以更方便地閱讀。

有一點要注意,
您必需提供一個檔案過濾方式(搜尋全部檔案的話用 *)。如果您忘了,’grep’會一直等著,直到該程式被中斷。
如果您遇到了這樣的情況,按 <CTRL c> ,然後再試。

下面還有一些有意思的命令列引數:
grep -i pattern files :不區分大小寫地搜尋。預設情況區分大小寫,
grep -l pattern files :只列出匹配的檔名,
grep -L pattern files :列出不匹配的檔名,
grep -w pattern files :只匹配整個單詞,而不是字串的一部分(如匹配’magic’,而不是’magical’),
grep -C number pattern files :匹配的上下文分別顯示[number]行,
grep pattern1 | pattern2 files :顯示匹配 pattern1 或 pattern2 的行,
grep pattern1 files | grep pattern2 :顯示既匹配 pattern1 又匹配 pattern2 的行。

grep -n pattern files  即可顯示行號資訊
grep -c pattern files  即可查詢總行數

這裡還有些用於搜尋的特殊符號:
\< 和 \> 分別標註單詞的開始與結尾。
例如:
grep man * 會匹配 ‘Batman’、’manic’、’man’等,
grep ‘\<man’ * 匹配’manic’和’man’,但不是’Batman’,
grep ‘\<man\>’ 只匹配’man’,而不是’Batman’或’manic’等其他的字串。
‘^’:指匹配的字串在行首,
‘$’:指匹配的字串在行 尾,

==============grep、fgrep、egrep的區別=================
者都是搜尋工具,但功能上有區別。
1)首先,grep支援的是標準正規表示式。
2)fgrep,不支援正規表示式,只用於匹配固定字串。
grep把模式當做正規表示式看,fgrep把模式當做固定字串看,所以後者要比前者速度快,當然同時後者的搜尋功能要弱於前者。
3)egrep:為grep 的擴充版本, 改良了許多傳統 grep 不能或不便的操作. 比如:
- grep 之下不支援 ? 與 + 這兩種 modifier, 但 egrep 則可。
- grep 不支援 a|b 或 (abc|xyz) 這類"或一"比對, 但 egrep 則可。
- grep 在處理 {n,m} 時, 需用 \{ 與 \} 處理, 但 egrep 則不需。

===========================================
示例說明
[root@kevin ~]# ps -ef | grep in.telnetd 
root 19955 181 0 13:43:53 ? 0:00 in.telnetd 

[root@kevin ~]# more size.txt size檔案的內容 
b124230 
b034325 
a081016 
m7187998 
m7282064 
a022021 
a061048 
m9324822 
b103303 
a013386 
b044525 
m8987131 
B081016 
M45678 
B103303 
BADc2345 

[root@kevin ~]# more size.txt | grep '[a-b]' 範圍 ;如[A-Z]即A,B,C一直到Z都符合要求 
b124230 
b034325 
a081016 
a022021 
a061048 
b103303 
a013386 
b044525 

[root@kevin ~]# more size.txt | grep '[a-b]'* 
b124230 
b034325 
a081016 
m7187998 
m7282064 
a022021 
a061048 
m9324822 
b103303 
a013386 
b044525 
m8987131 
B081016 
M45678 
B103303 
BADc2345 

[root@kevin ~]# more size.txt | grep 'b' 單個字元;如[A] 即A符合要求 
b124230 
b034325 
b103303 
b044525 

[root@kevin ~]# more size.txt | grep '[bB]' 
b124230 
b034325 
b103303 
b044525 
B081016 
B103303 
BADc2345 

[root@kevin ~]# grep 'root' /etc/group 
root::0:root 
bin::2:root,bin,daemon 
sys::3:root,bin,sys,adm 
adm::4:root,adm,daemon 
uucp::5:root,uucp 
mail::6:root 
tty::7:root,tty,adm 
lp::8:root,lp,adm 
nuucp::9:root,nuucp 
daemon::12:root,daemon 

[root@kevin ~]# grep '^root' /etc/group      //匹配正規表示式的開始行 
root::0:root 

[root@kevin ~]# grep 'uucp' /etc/group 
uucp::5:root,uucp 
nuucp::9:root,nuucp 

[root@kevin ~]# grep '\<uucp' /etc/group 
uucp::5:root,uucp 

[root@kevin ~]# grep 'root[root@kevin ~]#' /etc/group       //匹配正規表示式的結束行 
root::0:root 
mail::6:root 

[root@kevin ~]# more size.txt | grep -i 'b1..*3' -i :忽略大小寫 
b124230 
b103303 
B103303 

[root@kevin ~]# more size.txt | grep -iv 'b1..*3' -v :查詢不包含匹配項的行 
b034325 
a081016 
m7187998 
m7282064 
a022021 
a061048 
m9324822 
a013386 
b044525 
m8987131 
B081016 
M45678 
BADc2345 

[root@kevin ~]# more size.txt | grep -in 'b1..*3' 
1:b124230 
9:b103303 
15:B103303 

[root@kevin ~]# grep '[root@kevin ~]#' /etc/init.d/nfs.server | wc -l 
128 

[root@kevin ~]# grep '\[root@kevin ~]#' /etc/init.d/nfs.server | wc –l      //忽略正規表示式中特殊字元的原有含義 
15 

[root@kevin ~]# grep '\$' /etc/init.d/nfs.server
case "$1" in
>/tmp/sharetab.$$
[ "x$fstype" != xnfs ] &&
echo "$path\t$res\t$fstype\t$opts\t$desc"
>>/tmp/sharetab.$$
/usr/bin/touch -r /etc/dfs/sharetab /tmp/sharetab.$$
/usr/bin/mv -f /tmp/sharetab.$$ /etc/dfs/sharetab
if [ -f /etc/dfs/dfstab ] && /usr/bin/egrep -v '^[ ]*(#|$)'
if [ $startnfsd -eq 0 -a -f /etc/rmmount.conf ] &&
if [ $startnfsd -ne 0 ]; then
elif [ ! -n "$_INIT_RUN_LEVEL" ]; then
while [ $wtime -gt 0 ]; do
wtime=`expr $wtime - 1`
if [ $wtime -eq 0 ]; then
echo "Usage: $0 { start | stop }"
 
[root@kevin ~]# more size.txt
the test file
their are files
The end
 
[root@kevin ~]# grep 'the' size.txt
the test file
their are files
 
[root@kevin ~]# grep '\<the' size.txt
the test file
their are files
 
[root@kevin ~]# grep 'the\>' size.txt
the test file
 
[root@kevin ~]# grep '\<the\>' size.txt
the test file
 
[root@kevin ~]# grep '\<[Tt]he\>' size.txt
the test file
 

多個檔案查詢
[root@kevin ~]# grep "sort" *.txt       #見檔名的匹配
 
行匹配:輸出匹配行的計數
[root@kevin ~]# grep -c "48" kevin.txt   #輸出文件中含有48字元的行數
 
顯示匹配行和行數
[root@kevin ~]# grep -n "48" kevin.txt       #顯示所有匹配48的行和行號
 
顯示非匹配的行
[root@kevin ~]# grep -vn "48" kevin.txt      #輸出所有不包含48的行
 
顯示非匹配的行
[root@kevin ~]# grep -vn "48" kevin.txt      #輸出所有不包含48的行
 
大小寫敏感
[root@kevin ~]# grep -i "ab" kevin.txt       #輸出所有含有ab或Ab的字串的行
 
====================================
正規表示式的應用 (注意:最好把正規表示式用單引號括起來)
[root@kevin ~]# grep '[239].' kevin.txt      #輸出所有含有以2,3或9開頭的,並且是兩個數字的行
 
不匹配測試
[root@kevin ~]# grep '^[^48]' kevin.txt      #不匹配行首是48的行
 
使用擴充套件模式匹配
[root@kevin ~]# grep -E '219|216' kevin.txt
 
使用類名
可以使用國際模式匹配的類名:
[[:upper:]]   [A-Z]
[[:lower:]]   [a-z]
[[:digit:]]   [0-9]
[[:alnum:]]   [0-9a-zA-Z]
[[:space:]]   空格或tab
[[:alpha:]]   [a-zA-Z]
 
[root@kevin ~]# grep '5[[:upper:]][[:upper:]]' kevin.txt     #查詢以5開頭以兩個大寫字母結尾的行

cat、more、less、tail、head命令

cat 是一個文字檔案(檢視)和(連線)工具,通常與more搭配使用,與more不同的是cat可以合併檔案。檢視一個檔案的內容,用cat比較簡單,
就是cat後面直接接檔名。 

cat [選項] [檔案]... 
選項 
-A, --show-all           等價於 -vET 
-b, --number-nonblank    對非空輸出行編號 
-e                       等價於 -vE 
-E, --show-ends          在每行結束處顯示 $ 
-n, --number             對輸出的所有行編號 
-s, --squeeze-blank      不輸出多行空行 
-t                       與 -vT 等價 
-T, --show-tabs          將跳格字元顯示為 ^I 
-u                       (被忽略) 
-v, --show-nonprinting   使用 ^ 和 M- 引用,除了 LFD 和 TAB 之外 
--help     顯示此幫助資訊並離開 

cat 檢視檔案內容例項: 
[root@kevin ~]# cat /etc/profile           //檢視/etc/目錄下的profile檔案內容; 
[root@kevin ~]# cat -b /etc/fstab         //檢視/etc/目錄下的profile內容,並且對非空白行進行編號,行號從1開始; 
[root@kevin ~]# cat -n /etc/profile      //對/etc目錄中的profile的所有的行(包括空白行)進行編號輸出顯示; 
[root@kevin ~]# cat -E /etc/profile      //檢視/etc/下的profile內容,並且在每行的結尾處附加$符號; 
  
cat 加引數-n 和nl工具差不多,檔案內容輸出的同時,都會在每行前面加上行號; 
[root@kevin ~]# cat -n /etc/profile 
[root@kevin ~]# nl /etc/profile 

cat 可以同時顯示多個檔案的內容,比如我們可以在一個cat命令上同時顯示兩個檔案的內容; 
[root@kevin ~]# cat /etc/fstab /etc/profile 
  
cat 對於內容極大的檔案來說,可以通過管道|傳送到more 工具,然後一頁一頁的檢視; 
[root@kevin ~]# cat /etc/fstab /etc/profile | more 
  
cat 的建立、連線檔案功能例項: 
cat 有建立檔案的功能,建立檔案後,要以EOF或STOP結束; 

[root@kevin ~]# cat > kevin.txt<< EOF          
> 我來測試 cat 建立檔案,並且為檔案輸入內容;       
> 北京是個好地方;         
> EOF   

[root@kevin ~]# cat kevin.txt
我來測試 cat 建立檔案,並且為檔案輸入內容; 
北京是個好地方; 
  
cat 還有向已存在的檔案追加內容的功能; 
[root@kevin ~]# cat grace.txt 
I am BeiNanNanBei From grace.Org .   
我正在為cat命令寫文件 

[root@kevin ~]# cat >> grace.txt << EOF   
> 我來測試cat向文件追加內容的功能;       
> OK? 
> OK~ 
> 北京你好 
> EOF    

[root@kevin ~]# cat grace.txt //檢視檔案內容,看是否追回成功。 
I am BeiNanNanBei From grace.Org . 
我正在為cat命令寫文件 
我來測試cat向文件追加內容的功能;   
OK? 
OK~ 
北京你好 

cat 連線多個檔案的內容並且輸出到一個新檔案中; 
假設我們有sir01.txt、sir02.tx和sir03.txt ,並且內容如下; 

[root@kevin ~]# cat sir01.txt   
123456 
i am testing 

[root@kevin ~]# cat sir02.txt 
56789 
BeiNan Tested 

[root@kevin ~]# cat sir03.txt 
09876 
grace.org testing 
  
我想通過cat 把sir01.txt、sir02.txt及sir03.txt 三個檔案連線在一起(也就是說把這三個檔案的內容都接在一起)並輸出到一個新的檔案sir04.txt 中。 

注意:
其原理是把三個檔案的內容連線起來,然後建立sir04.txt檔案,並且把幾個檔案的內容同時寫入sir04.txt中。特別值得一提的是,如果您輸入到一個已經
存在的sir04.txt 檔案,會把sir04.txt內容清空。 

[root@kevin ~]# cat sir01.txt sir02.txt sir03.txt > sir04.txt 
[root@kevin ~]# more sir04.txt 
123456 
i am testing 
56789 
BeiNan Tested 
09876 
grace.org testing 
  
cat 把一個或多個已存在的檔案內容,追加到一個已存在的檔案中 
[root@kevin ~]# cat sir00.txt 
grace.org forever 

[root@kevin ~]# cat sir01.txt sir02.txt sir03.txt >> sir00.txt 

[root@kevin ~]# cat sir00.txt 
grace.org forever 
123456 
i am testing 
56789 
BeiNan Tested 
09876 
grace.org testing 
  

======================================================
more 是我們最常用的工具之一,最常用的就是顯示輸出的內容,然後根據視窗的大小進行分頁顯示,然後還能提示檔案的百分比; 

引數如下: 
+num   從第num行開始顯示; 
-num   定義螢幕大小,為num行; 
+/pattern   從pattern 前兩行開始顯示; 
-c   從頂部清屏然後顯示; 
-d   提示Press space to continue, 'q' to quit.(按空格鍵繼續,按q鍵退出),禁用響鈴功能; 
-l    忽略Ctrl+l (換頁)字元; 
-p    通過清除視窗而不是滾屏來對檔案進行換頁。和-c引數有點相似; 
-s    把連續的多個空行顯示為一行; 
-u    把檔案內容中的下劃線去掉退出more的動作指令是q 

more 的引數應用舉例: 
[root@kevin ~]# more -dc /etc/profile        //顯示提示,並從終端或控制檯頂部顯示; 
[root@kevin ~]# more +4 /etc/profile         //從profile的第4行開始顯示; 
[root@kevin ~]# more -4 /etc/profile          //每屏顯示4行; 
[root@kevin ~]# more +/MAIL /etc/profile         //從profile中的第一個MAIL單詞的前兩行開始顯示; 

more 的動作指令: 
我們檢視一個內容較大的檔案時,要用到more的動作指令,比如ctrl+f(或空格鍵) 是向下顯示一屏,ctrl+b是返回上一屏; Enter鍵可以向下滾動顯示n行,要通過定,預設為1行; 

我們只說幾個常用的; 自己嘗試一下就知道了; 
Enter       向下n行,需要定義,預設為1行; 
Ctrl+f    向下滾動一屏; 
空格鍵          向下滾動一屏; 
Ctrl+b  返回上一屏; 
=         輸出當前行的行號; 
:f      輸出檔名和當前行的行號; 
v      呼叫vi編輯器; 
! 命令            呼叫Shell,並執行命令; 
q     退出more當我們檢視某一檔案時,想呼叫vi來編輯它,不要忘記了v動作指令,這是比較方便的; 

其它命令通過管道和more結合的運用例子: 
比如我們列一個目錄下的檔案,由於內容太多,我們應該學會用more來分頁顯示。這得和管道 | 結合起來,比如:
[root@kevin ~]# ls -l /etc |more 

=======================================================
less 檢視檔案內容 工具 

less 工具也是對檔案或其它輸出進行分頁顯示的工具,應該說是linux正統檢視檔案內容的工具,功能極其強大;您是初學者,我建議您用less。
由於less的內容太多,我們把最常用的介紹一下; 

常用引數 
-c 從頂部(從上到下)重新整理螢幕,並顯示檔案內容。而不是通過底部滾動完成重新整理; 
-f 強制開啟檔案,二進位制檔案顯示時,不提示警告; 
-i 搜尋時忽略大小寫;除非搜尋串中包含大寫字母; 
-I 搜尋時忽略大小寫,除非搜尋串中包含小寫字母; 
-m 顯示讀取檔案的百分比; 
-M 顯法讀取檔案的百分比、行號及總行數; 
-N 在每行前輸出行號; 
-p pattern 搜尋pattern;比如在/etc/profile搜尋單詞MAIL,就用 less -p MAIL /etc/profile 
-s 把連續多個空白行作為一個空白行顯示; 
-Q 在終端下不響鈴; 
  
比如:我們在顯示/etc/profile的內容時,讓其顯示行號; 
[root@kevin ~]# less -N   /etc/profile 
  
less的動作命令: 
進入less後,我們得學幾個動作,這樣更方便 我們查閱檔案內容;最應該記住的命令就是q,這個能讓less終止檢視檔案退出; 

動作: 
Enter鍵 向下移動一行; 
y 向上移動一行; 
空格鍵 向下滾動一屏; 
b 向上滾動一屏; 
d 向下滾動半屏; 
h less的幫助; 
u 向上洋動半屏; 
w 可以指定顯示哪行開始顯示,是從指定數字的下一行顯示;比如指定的是6,那就從第7行顯示; 
g 跳到第一行; 
G 跳到最後一行; 
p n% 跳到n%,比如 10%,也就是說比整個檔案內容的10%處開始顯示; 
/pattern 搜尋pattern ,比如 /MAIL表示在檔案中搜尋MAIL單詞; 
v 呼叫vi編輯器; 
q 退出less 
!command 呼叫SHELL,可以執行命令;比如!ls 顯示當前列當前目錄下的所有檔案; 
  
就less的動作來說,內容太多了,用的時候查一查man less是最好的。在這裡就不舉例子了; 

==========================================================
head 工具,顯示檔案內容的前幾行 
head 是顯示一個檔案的內容的前多少行; 

用法比較簡單; 
head -n 行數值 檔名; 

比如我們顯示/etc/profile的前10行內容,應該是: 
[root@kevin ~]# head -n 10 /etc/profile 

=========================================================
tail 工具,顯示檔案內容的最後幾行 

tail 是顯示一個檔案的內容的最後多少行; 

用法比較簡單; 
tail   -n 行數值 檔名; 

比如我們顯示/etc/profile的最後5行內容,應該是: 
[root@kevin ~]# tail -n 5 /etc/profile 

tail -f /var/log/syslog 顯示檔案 syslog 的後十行內容並在檔案內容增加後,且自動顯示新增的檔案內容。 

cut命令:列印每行特定範圍內內容

cut是一個選取命令,就是將一段資料經過分析,取出我們想要的。一般來說,選取資訊通常是針對“行”來進行分析的,並不是整篇資訊分析的。

其語法格式為:
cut  [-bn] [file] 或 cut [-c] [file]  或  cut [-df] [file]

使用說明
cut 命令從檔案的每一行剪下位元組、字元和欄位並將這些位元組、字元和欄位寫至標準輸出。
如果不指定 File 引數,cut 命令將讀取標準輸入。必須指定 -b、-c 或 -f 標誌之一。

主要引數
-b :以位元組為單位進行分割。這些位元組位置將忽略多位元組字元邊界,除非也指定了 -n 標誌。
-c :以字元為單位進行分割。
-d :自定義分隔符,預設為製表符。
-f  :與-d一起使用,指定顯示哪個區域。
-n :取消分割多位元組字元。僅和 -b 標誌一起使用。如果字元的最後一個位元組落在由 -b 標誌的 List 引數指示的<br />範圍之內,該字元將被寫出;否則,該字元將被排除。

cut一般以什麼為依據呢? 也就是說,我怎麼告訴cut我想定位到的剪下內容呢?
cut命令主要是接受三個定位方法:
第一,位元組(bytes),用選項-b
第二,字元(characters),用選項-c
第三,域(fields),用選項-f

=========================================
cut在取列內容的時候和awk相識

awk -F"" '{print $n}'     以-F後的引號內的內容為列的分隔符,列印第n行
cut -d"" -fn              以-d後的引號內的內容為列的分隔符,列印第n行

比如列印a.txt檔案中以空格為列的分隔符,列印第5行
awk -F" " '{print $5}' a.txt  當以空格為分隔符的時候,-F" " 可以省去
cut -d" " -f5 a.txt
=========================================

以“位元組”定位
舉個例子吧,當你執行ps命令時,會輸出類似如下的內容:
[root@kevin ~]# who
rocrocket :0           2009-01-08 11:07
rocrocket pts/0        2009-01-08 11:23 (:0.0)
rocrocket pts/1        2009-01-08 14:15 (:0.0)
如果我們想提取每一行的第3個位元組,就這樣:

[root@kevin ~]# who|cut -b 3
c
c
c

如果“位元組”定位中,我想提取第3,第4、第5和第8個位元組,怎麼辦?
-b支援形如3-5的寫法,而且多個定位之間用逗號隔開就成了。看看例子吧:
[root@kevin ~]# who|cut -b 3-5,8
croe
croe
croe

但有一點要注意,cut命令如果使用了-b選項,那麼執行此命令時,cut會先把-b後面所有的定位進行從小到大排序,然後再提取。
可不能顛倒定位的順序哦。這個例子就可以說明這個問題:

[root@kevin ~]# who|cut -b 8,3-5
croe
croe
croe

還有哪些類似“3-5”這樣的小技巧,列舉一下吧!
[root@kevin ~]# who
rocrocket :0           2009-01-08 11:07
rocrocket pts/0        2009-01-08 11:23 (:0.0)
rocrocket pts/1        2009-01-08 14:15 (:0.0)
[root@kevin ~]# who|cut -b -3
roc
roc
roc
[root@kevin ~]# who|cut -b 3-
crocket :0           2009-01-08 11:07
crocket pts/0        2009-01-08 11:23 (:0.0)
crocket pts/1        2009-01-08 14:15 (:0.0)

-3表示從第一個位元組到第三個位元組,而3-表示從第三個位元組到行尾。如果你細心,你可以看到這兩種情況下,都包括了第三個位元組“c”。
如果我執行who|cut -b -3,3-,你覺得會如何呢?答案是輸出整行,不會出現連續兩個重疊的c的。看:

[root@kevin ~]# who|cut -b -3,3-
rocrocket :0           2009-01-08 11:07
rocrocket pts/0        2009-01-08 11:23 (:0.0)
rocrocket pts/1        2009-01-08 14:15 (:0.0)

給個以字元為定位標誌的最簡單的例子吧!
下面例子你似曾相識,提取第3,第4,第5和第8個字元:
[root@kevin ~]# who|cut -c 3-5,8
croe
croe
croe

不過,看著怎麼和-b沒有什麼區別啊?莫非-b和-c作用一樣? 其實不然,看似相同,只是因為這個例子舉的不好,who輸出的都是單位元組字元,
所以用-b和-c沒有區別,如果你提取中文,區別就看出來了,來,看看中文提取的情況:

[root@kevin ~]# cat cut_ch.txt
星期一
星期二
星期三
星期四
[root@kevin ~]# cut -b 3 cut_ch.txt
�
�
�
�
[root@kevin ~]# cut -c 3 cut_ch.txt
一
二
三
四

看到了吧,用-c則會以字元為單位,輸出正常;而-b只會傻傻的以位元組(8位二進位制位)來計算,輸出就是亂碼。
既然提到了這個知識點,就再補充一句,如果你學有餘力,就提高一下。
當遇到多位元組字元時,可以使用-n選項,-n用於告訴cut不要將多位元組字元拆開。例子如下:

[root@kevin ~]# cat cut_ch.txt |cut -b 2
�
�
�
�
[root@kevin ~]# cat cut_ch.txt |cut -nb 2

[root@kevin ~]# cat cut_ch.txt |cut -nb 1,2,3
星
星
星
星

域是怎麼回事呢?解釋解釋:)
為什麼會有“域”的提取呢,因為剛才提到的-b和-c只能在固定格式的文件中提取資訊,而對於非固定格式的資訊則束手無策。這時候“域”就派上用場了。
如果你觀察過/etc/passwd檔案,你會發現,它並不像who的輸出資訊那樣具有固定格式,而是比較零散的排放。但是,冒號在這個檔案的每一行中都
起到了非常重要的作用,冒號用來隔開每一個項。

cut命令提供了這樣的提取方式,具體的說就是設定“間隔符”,再設定“提取第幾個域”,就OK了!

以/etc/passwd的前五行內容為例:
[root@kevin ~]# cat /etc/passwd|head -n 5
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@kevin ~]# cat /etc/passwd|head -n 5|cut -d : -f 1
root
bin
daemon
adm
lp

用-d來設定間隔符為冒號,然後用-f來設定我要取的是第一個域,再按回車,所有的使用者名稱就都列出來了!
當然,在設定-f時,也可以使用例如3-5或者4-類似的格式:

[root@kevin ~]# cat /etc/passwd|head -n 5|cut -d : -f 1,3-5
root:0:0:root
bin:1:1:bin
daemon:2:2:daemon
adm:3:4:adm
lp:4:7:lp
[root@kevin ~]# cat /etc/passwd|head -n 5|cut -d : -f 1,3-5,7
root:0:0:root:/bin/bash
bin:1:1:bin:/sbin/nologin
daemon:2:2:daemon:/sbin/nologin
adm:3:4:adm:/sbin/nologin
lp:4:7:lp:/sbin/nologin
[root@kevin ~]# cat /etc/passwd|head -n 5|cut -d : -f -2
root:x
bin:x
daemon:x
adm:x
lp:x

如果遇到空格和製表符時,怎麼分辨呢?我覺得有點亂,怎麼辦?
有時候製表符確實很難辨認,有一個方法可以看出一段空格到底是由若干個空格組成的還是由一個製表符組成的。
[root@kevin ~]# cat tab_space.txt
this is tab finish.
this is several space      finish.
[root@kevin ~]# sed -n l tab_space.txt
this is tab\tfinish.$
this is several space      finish.$

如果是製表符(TAB),那麼會顯示為\t符號,如果是空格,就會原樣顯示。
通過此方法即可以判斷製表符和空格了。
注意,上面sed -n後面的字元是L的小寫字母哦,不要看錯。

我應該在cut -d中用什麼符號來設定製表符或空格呢?
其實cut的-d選項的預設間隔符就是製表符,所以當你就是要使用製表符的時候,完全就可以省略-d選項,而直接用-f來取域就可以了。

如果你設定一個空格為間隔符,那麼就這樣:
[root@kevin ~]# cat tab_space.txt |cut -d ' ' -f 1
this
this

注意,兩個單引號之間可確實要有一個空格哦,不能偷懶。
而且,你只能在-d後面設定一個空格,可不許設定多個空格,因為cut只允許間隔符是一個字元。

[root@kevin ~]# cat tab_space.txt |cut -d ' ' -f 1
cut: the delimiter must be a single character
Try `cut --help' for more information.

cut有哪些缺陷和不足?
猜出來了吧?對,就是在處理多空格時。
如果檔案裡面的某些域是由若干個空格來間隔的,那麼用cut就有點麻煩了,因為cut只擅長處理“以一個字元間隔”的文字內容。

tr命令:刪除,去重,替換文字內容

可以把tr看作為一個簡化的sed工具,tr表示為:translate。tr命令主要用於實現以下兩個功能

替換操作的字串轉換。
刪除操作的字串轉換,可以很容易的刪除一些控制字元或者是空行。
tr命令能夠實現的功能,都能夠用sed命令來實現。但就具體的替換功能來說,tr用起來更容易,也比較簡單。

一,命令格式

tr [option] ["string1"] ["string2"] < file  

常用的選項有:
預設選項。就是沒有任何選項的時候,tr預設為替換操作,就是將string1在檔案中出現的字元替換為string2中的字元,這裡要注意的是替換關係。
-c選項,用string1中字元的補集替換string1,這裡的字符集為ASCII。
-d選項,刪除檔案中所有在string1中出現的字元。
-s選項,刪除檔案中重複並且在string1中出現的字元,只保留一個。
-c選項在使用時,只是將string1替換為現在的補集

[root@kevin ~]# echo "hello world,root,2012" | tr -c "0-9" "*"  
*****************2012*  

可以看出,我們使用0-9,新增-c選項後,會把0-9替換為其補集,這時補集自然不包含0-9,而包含很多其它的字元,接下來就把所有的其它字元都替換成*號,
但不包含數字。

如果只需要替換數字的話:
[root@kevin ~]# echo "hello world,root,2012" | tr "0-9" "*"  
hello world,root,****  

二,字串的取值範圍
指定string或string2的內容時,只能使用單字元或字串範圍或列表。
[a-z] a-z內的字元組成的字串。
[A-Z] A-Z內的字元組成的字串。
[0-9] 數字串。
\octal 一個三位的八進位制數,對應有效的ASCII字元。
[O*n] 表示字元O重複出現指定次數n。因此[O*2]匹配OO的字串。

三,控制字元的不同表達方式
速記符 含義 八進位制方式
\a Ctrl-G  鈴聲\007
\b Ctrl-H 退格符\010
\f Ctrl-L  走行換頁\014
\n Ctrl-J  新行\012
\r Ctrl-M 回車\015
\t  Ctrl-I  tab鍵\011
\v Ctrl-X \030 注意這些控制字元,如果想在linux下輸入,如我們可能需要輸入^M這種字元,只需ctrl+V+M同時按下即可。

四,字元替換
這是tr的預設操作,先看下面的命令和輸出

[root@kevin ~]# echo "hello world" | tr "a-z" "A-Z"  
HELLO WORLD  
[root@kevin ~]# echo "hello world" | tr "a-l" "A-Z"  
HELLo worLD  
[root@kevin ~]# echo "hello world" | tr "a-z" "A-H"  
HEHHH HHHHD  
第一行輸出就是將小寫換成大寫。
第二行輸出將小寫中的a-l分別換成A-L,而將小寫中的l以後的字元都不替換。
第三行輸出將小寫中的a-h換成A-H,而h以後的字元都換成H,因為後者的替換空間沒有前面的字元空間大,所以就重複後面的H,
相當於後面的字元是A-HHH......HHHHH。

如果我們想要進行大小寫轉換,可以按下面的輸入:
tr "a-z" "A-Z" < inputfile  

五,去除重複字元
這個時候,所用的選項是-s選項,如:
[root@kevin ~]# echo "hello world,root" | tr -s "ao"  
hello world,rot  
[root@kevin ~]# echo "hello world,root" | tr -s "lo"  
helo world,rot  
[root@kevin ~]# echo "hello world,root" | tr -s "a-z"  
helo world,rot  
[root@kevin ~]# echo "hello world,root" | tr -s "0-9"  
hello world,root  
第一行表示將輸入字串中的包含在"ao"字符集中的重複字元去掉,只留一個。因為"hello world,root",只有o滿足條件,所以將root變成rot,把中間的兩個o變成一個。
第二行將hello和root兩個字元都壓縮了。
第三行表示將a-z中的除復字元都去掉。
第三行表示將字串中的重複的且重複字元在0-9字符集中的字元去掉,這裡沒有。


如果我們想要去掉空行,可以這樣操作:
tr -s "\n" < inputfile 或者 tr -s "\012" <inputfile // 這兩個是一樣的。  
就是將重複的換行符去掉,只留一個。

六,刪除字元
-d選項和-s選項類似,只不過-d選項會刪除所有出現的字元。
[root@kevin ~]# echo "hello world,root" | tr -d "a-h"  
llo worl,root  
[root@kevin ~]# echo "hello world,root,2012" | tr -d "a-z"  
 ,,2012  
[root@kevin ~]# echo "hello world,root,2012" | tr -d "0-9"  

sort/uniq/cut/wc命令

sort 命令對 File 引數指定的檔案中的行排序,並將結果寫到標準輸出。如果 File 引數指定多個檔案,那麼 sort 命令將這些檔案連線起來,並當作一個檔案進行排序。

sort語法
sort [-fbMnrtuk] [file or stdin]

選項與引數:
-f  :忽略大小寫的差異,例如 A 與 a 視為編碼相同;
-b  :忽略最前面的空格符部分;
-M  :以月份的名字來排序,例如 JAN, DEC 等等的排序方法;
-n  :使用『純數字』進行排序(預設是以文字型態來排序的);
-r  :反向排序;
-u  :就是 uniq ,相同的資料中,僅出現一行代表;
-t  :分隔符,預設是用 [tab] 鍵來分隔;
-k  :以那個區間 (field) 來進行排序的意思

對/etc/passwd 的賬號進行排序
[root@kevin ~]# cat /etc/passwd | sort
adm:x:3:4:adm:/var/adm:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

sort 是預設以第一個資料來排序,而且預設是以字串形式來排序,所以由字母 a 開始升序排序。

/etc/passwd 內容是以 : 來分隔的,我想以第三欄來排序,該如何
[root@kevin ~]# cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin

預設是以字串來排序的,如果想要使用數字排序:
[root@kevin ~]# cat /etc/passwd | sort -t ':' -k 3n
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh

預設是升序排序,如果要倒序排序,如下
[root@kevin ~]# cat /etc/passwd | sort -t ':' -k 3nr
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
ntp:x:106:113::/home/ntp:/bin/false
messagebus:x:105:109::/var/run/dbus:/bin/false
sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
 
如果要對/etc/passwd,先以第六個域的第2個字元到第4個字元進行正向排序,再基於第一個域進行反向排序。
[root@kevin ~]# cat /etc/passwd |  sort -t':' -k 6.2,6.4 -k 1r      
sync:x:4:65534:sync:/bin:/bin/sync
proxy:x:13:13:proxy:/bin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
 
檢視/etc/passwd有多少個shell:對/etc/passwd的第七個域進行排序,然後去重:
[root@kevin ~]# cat /etc/passwd |  sort -t':' -k 7 -u
root:x:0:0:root:/root:/bin/bash
syslog:x:101:102::/home/syslog:/bin/false
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
 
==================================================================
uniq命令可以去除排序過的檔案中的重複行,因此uniq經常和sort合用。也就是說,為了使uniq起作用,所有的重複行必須是相鄰的。

uniq語法
uniq [-icu]

選項與引數:
-i   :忽略大小寫字元的不同;
-c  :進行計數
-u  :只顯示唯一的行
 
[root@kevin ~]# cat testfile
hello
world
friend
hello
world
hello
 
直接刪除未經排序的檔案,將會發現沒有任何行被刪除
[root@kevin ~]# uniq testfile  
hello
world
friend
hello
world
hello

排序檔案,預設是去重
[root@kevin ~]# cat words | sort |uniq
friend
hello
world
 
排序之後刪除了重複行,同時在行首位置輸出該行重複的次數
[root@kevin ~]# sort testfile | uniq -c
1 friend
3 hello
2 world
 
僅顯示存在重複的行,並在行首顯示該行重複的次數
[root@kevin ~]# sort testfile | uniq -dc
3 hello
2 world
 
僅顯示不重複的行
[root@kevin ~]# sort testfile | uniq -u
friend  
 
===============================================
sort|uniq    排序去重
sort|uniq -c|srot -rn  排序去重,並降序
sort|uniq -c  列印重複的行數
sort|uniq -d  列印交集部分
sort|uniq -u  列印交集以外的部分
==============================================

[root@kevin ~]# cat a.txt 
sdfsdf
123
123
1234
123
dasdfsd
sdfsdf
asfd34234

[root@kevin ~]# cat a.txt |sort|uniq
123
1234
asfd34234
dasdfsd
sdfsdf

[root@kevin ~]# cat a.txt |sort|uniq -c
      3 123
      1 1234
      1 asfd34234
      1 dasdfsd
      2 sdfsdf

[root@kevin ~]# cat a.txt |sort|uniq -d
123
sdfsdf

[root@kevin ~]# cat a.txt |sort|uniq -u
1234
asfd34234
dasdfsd

[root@kevin ~]# cat a.txt 
sdfsdf
123
123
1234
123
dasdfsd
sdfsdf
asfd34234

[root@kevin ~]# cat b.txt 
sdf
123
err
2345
123
gggg

[root@kevin ~]# cat a.txt b.txt |sort|uniq
123
1234
2345
asfd34234
dasdfsd
err
gggg
sdf
sdfsdf

[root@kevin ~]# cat a.txt b.txt |sort|uniq -c
      5 123
      1 1234
      1 2345
      1 asfd34234
      1 dasdfsd
      1 err
      1 gggg
      1 sdf
      2 sdfsdf

[root@kevin ~]# cat a.txt b.txt |sort|uniq -d
123
sdfsdf

[root@kevin ~]# cat a.txt b.txt |sort|uniq -u
1234
2345
asfd34234
dasdfsd
err
gggg
sdf

=======================================================
cut命令可以從一個文字檔案或者文字流中提取文字列。

cut語法
cut -d'分隔字元' -f fields <==用於有特定分隔字元
cut -c 字元區間            <==用於排列整齊的資訊

選項與引數:
-d  :後面接分隔字元。與 -f 一起使用;
-f  :依據 -d 的分隔字元將一段資訊分割成為數段,用 -f 取出第幾段的意思;
-c  :以字元 (characters) 的單位取出固定字元區間;
 
PATH 變數如下
[root@kevin ~]# echo $PATH
/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/games
# 1 | 2       | 3   | 4       | 5            | 6            | 7
 
將 PATH 變數取出,我要找出第五個路徑。
[root@kevin ~]# echo $PATH | cut -d ':' -f 5
/usr/local/bin
 
將 PATH 變數取出,我要找出第三和第五個路徑。
[root@kevin ~]# echo $PATH | cut -d ':' -f 3,5
/sbin:/usr/local/bin
 
將 PATH 變數取出,我要找出第三到最後一個路徑。
[root@kevin ~]# echo $PATH | cut -d ':' -f 3-
/sbin:/usr/sbin:/usr/local/bin:/usr/X11R6/bin:/usr/games
 
將PATH 變數取出,我要找出第一到第三個路徑。
[root@kevin ~]# echo $PATH | cut -d ':' -f 1-3
/bin:/usr/bin:/sbin:
 
將PATH 變數取出,我要找出第一到第三,還有第五個路徑。
[root@kevin ~]# echo $PATH | cut -d ':' -f 1-3,5
/bin:/usr/bin:/sbin:/usr/local/bin
 
實用例子:只顯示/etc/passwd的使用者和shell
[root@kevin ~]# cat /etc/passwd | cut -d ':' -f 1,7 
root:/bin/bash
daemon:/bin/sh
bin:/bin/sh
 
====================================================
wc
統計檔案裡面有多少單詞,多少行,多少字元。

wc語法
[root@kevin ~]# wc [-lwm]
選項與引數:
-l  :僅列出行;
-w  :僅列出多少字(英文單字);
-m  :多少字元;
 
預設使用wc統計/etc/passwd
[root@kevin ~]# wc /etc/passwd
40   45 1719 /etc/passwd
40是行數,45是單詞數,1719是位元組數

wc的命令比較簡單使用,每個引數使用如下:
[root@kevin ~]# wc -l /etc/passwd   #統計行數,在對記錄數時,很常用
40 /etc/passwd       #表示系統有40個賬戶

[root@kevin ~]# wc -w /etc/passwd  #統計單詞出現次數
45 /etc/passwd

[root@kevin ~]# wc -m /etc/passwd  #統計檔案的位元組數
1719

split命令:切分檔案

split命令用於將一個檔案分割成數個。
該指令將大檔案分割成較小的檔案,在預設情況下將按照每1000行切割成一個小檔案。

語法
split [--help][--version][-<行數>][-b <位元組>][-C <位元組>][-l <行數>][要切割的檔案][輸出檔名]

引數說明:
-<行數> : 指定每多少行切成一個小檔案.如split -3 a.txt  
-b<位元組> : 指定每多少位元組切成一個小檔案
-l, --lines=NUMBER:對file進行切分,每個檔案有NUMBER行。
--help : 線上幫助
--version : 顯示版本資訊
-C<位元組> : 與引數"-b"相似,但是在切 割時將盡量維持每行的完整性
[輸出檔名] : 設定切割後檔案的前置檔名, split會自動在前置檔名後再加上編號

示例1:
使用指令split將檔案a.txt每3行切割成一個檔案,輸入如下命令:
注意:是按照a.txt檔案中的行數進行分割的,每3行切分到一個檔案中,切割成多個以"x"開頭的小檔案。直至所有行數被分完。
[root@kevin ~]# cat a.txt   
sdfsdf
123123123
sdfasdf2r345345
kljljkl
sjkdfjsdofopf
sadfsd2343
123123
asdf4555
66666
888888

[root@kevin ~]# split -3 a.txt 
[root@kevin ~]# ls
anaconda-ks.cfg  a.txt  xaa  xab  xac  xad
[root@kevin ~]# cat xaa
sdfsdf
123123123
sdfasdf2r345345
[root@kevin ~]# cat xab
kljljkl
sjkdfjsdofopf
sadfsd2343
[root@kevin ~]# cat xac
123123
asdf4555
66666
[root@kevin ~]# cat xad
888888 

示例2:
有個檔案要處理,因為很大,所以想把它切成若干份,每份N行,以便並行處理。
引數說明:
-b, --bytes=SIZE:對file進行切分,每個小檔案大小為SIZE。可以指定單位b,k,m。
-l, --lines=NUMBER:對file進行切分,每個檔案有NUMBER行。
prefix:分割後產生的檔名字首。

示例:
假設要切分的檔案為test.2012-08-16_17,大小1.2M,12081行。
1)
[root@kevin ~]# split -l 5000 test.2012-08-16_17  
生成xaa,xab,xac三個檔案。
[root@kevin ~]# wc -l #看到三個檔案行數如下:
5000 xaa
5000 xab
2081 xac
12081 總計

2)
[root@kevin ~]# split -b 600k test.2012-08-16_17  
生成xaa,xab兩個檔案
[root@kevin ~]# ls -lh #看到兩個檔案大小如下:
600K xaa
554K xab

3)
[root@kevin ~]# split -b 500k test.2012-08-16_17 example  
得到三個檔案,檔名的字首都是example
[root@kevin ~]# ls -lh  #看到檔案資訊如下:
500K exampleaa
500K exampleab
154K exampleac

示例3:
將一個大檔案分成若干個小檔案方法
例如將一個BLM.txt檔案分成字首為 BLM_ 的1000個小檔案,字尾為係數形式,且字尾為4位數字形式
[root@kevin ~]# wc -l BLM.txt       #讀出 BLM.txt 檔案一共有多少行
[root@kevin ~]# split -l 2482 ../BLM/BLM.txt -d -a 4 BLM_

將檔案 BLM.txt 分成若干個小檔案,每個檔案2482行(-l 2482),檔案字首為BLM_ ,係數不是字母而是數字(-d),字尾係數為四位數(-a 4)

=====================================================
Linux下檔案分割可以通過split命令來實現,可以指定按行數分割和安大小分割兩種模式。Linux下檔案合併可以通過cat命令來實現,非常簡單。
在Linux下用split進行檔案分割:

模式一:指定分割後檔案行數
對與txt文字檔案,可以通過指定分割後檔案的行數來進行檔案分割。
命令:split -l 300 large_file.txt new_file_prefix

模式二:指定分割後檔案大小
split -b 10m server.log waynelog

對二進位制檔案我們同樣也可以按檔案大小來分隔。


在Linux下用cat進行檔案合併:
命令:cat small_files* > large_file

將a.txt的內容輸入到b.txt的末尾
cat a.txt >> b.txt

comm命令:對於兩個已排序檔案,逐行比對

一、常用用法
comm FILE1 FILE2

二、含義與選項
2.1、含義
對於兩個已排序的檔案,逐行比對。 
列印結果有3列:第1列,只屬於“FILE1”的行;第2列,只屬於“FILE2”的行;第3列,既屬於“FILE1”,又屬於“FILE2”的行。

2.2、選項表示的意思
“FILE1,FILE2”:指代已排序檔案“FILE1”和“FILE2”

三、其他
3.1、“LC_COLLATE”等環境變數
由於涉及到兩個字串的比較等,故而程式實現中使用“LC_COLLATE”等環境變數,最終結果受到“LC_COLLATE”等環境變數的控制。

3.2、排序策略
comm命令實現設定的排序策略是“按照字典序排序”。兩個已排序檔案使用的排序策略組合共有3種情況。

3.2.1、情況1
一個排序檔案按照字典序排序,另外一個排序檔案按照非字典序(其他排序策略)排序。顯而易見,在這種情況下,comm命令的執行結果會比較奇怪。
[root@localhost ~]# cat a.txt 
001
02
3
10
[root@localhost ~]# cat b.txt 
001
02
5
06
007
10
即已按照“數值大小”排序,執行“逐行比對”過程,我們的預期結果是:“3”只屬於“c.txt”,“5,06,007”只屬於“d.txt”,“001,02,10”共屬於兩個檔案。

現在執行comm a.txt b.txt命令,得到如圖1所示結果,不能達到預期。
[root@localhost ~]# comm a.txt b.txt 
                001
                02
3
comm: file 1 is not in sorted order
10
        5
comm: file 2 is not in sorted order
        06
        007
        10

執行comm --nocheck-order a.txt b.txt命令,得到如圖2所示結果,也不能達到預期。
[root@localhost ~]# comm --nocheck-order a.txt b.txt
                001
                02
3
10
        5
        06
        007
        10


兩個檔案都已按照字典序排序,這符合comm命令實現的設定,comm命令的執行結果能夠達到預期。執行下述命令,得到如圖3所示結果,結果符合預期。
[root@localhost ~]# sort a.txt > aa.txt
[root@localhost ~]# sort b.txt > bb.txt
[root@localhost ~]# comm aa.txt bb.txt
                001
        007
                02
        06
                10
3
        5
[root@localhost ~]# cat aa.txt 
001
02
10
3
[root@localhost ~]# cat bb.txt 
001
007
02
06
10
5

join命令:根據兩行中具有相同值的兩個欄位,將該兩行內容拼接成一行列印輸出

一、常用用法
join [-t CHAR] [-i] [--header] [-1 FIELD] [-2 FIELD] [-e STR] FILE1 FILE2

二、含義與選項
2.1、含義
存在兩個已排序檔案,假如檔案1中的某條記錄的某個欄位值(預設是第一個欄位,從1開始計數)與檔案2中的某條記錄的某個欄位值
(預設是第一個欄位,從1開始計數)一致,那麼在最終列印結果中,將這兩條記錄拼接成一條記錄。

2.2、選項表示的意思
“-t CHAR”:以“CHAR”字元作為記錄內欄位間的分隔符,預設的分隔符是“空格符” 
“-i”:兩個欄位值比較時,忽略大小寫 
“–header”:兩個檔案的第一行作為說明行,不參與比較 
“-1 FIELD”:FILE1中以第“FIELD”個欄位作為比較欄位 
“-2 FIELD”:FILE2中以第“FIELD”個欄位作為比較欄位 
“-e STR”:在最終的拼接記錄中,如果某個欄位的值為空,那麼以“STR”替換 
“FILE1”:檔案1 
“FILE2”:檔案2

示例一
有檔案“a.txt”和“b.txt”,內容分別如下:
[root@localhost ~]# cat a.txt 
a 1
b 2
[root@localhost ~]# cat b.txt 
a 3
b 4

執行以下命令,得到如下結果:
[root@localhost ~]# join a.txt b.txt
a 1 3
b 2 4

示例二
有檔案“a.txt”和“b.txt”,內容分別如下:
[root@localhost ~]# cat a.txt 
a;1
b;2
[root@localhost ~]# cat b.txt 
a;3
b;4

執行以下命令,得到如下結果:
[root@localhost ~]# join -t ';' a.txt b.txt
a;1;3
b;2;4

示例三
有檔案“a.txt”和“b.txt”,內容分別如下:
[root@localhost ~]# cat a.txt 
A 1
b 2
[root@localhost ~]# cat b.txt 
a 3
b 4

執行以下命令,得到如下結果:
[root@localhost ~]# join -i a.txt b.txt
A 1 3
b 2 4

示例四
有檔案“a.txt”和“b.txt”,內容分別如下:
[root@localhost ~]# cat a.txt 
Col1 Col2
a 1
b 2
[root@localhost ~]# cat b.txt 
Col3 Col4
a 3
b 4

執行以下命令,得到如下結果:
[root@localhost ~]# join --header a.txt b.txt
Col1 Col2 Col4
a 1 3
b 2 4

示例五
有檔案“a.txt”和“b.txt”,內容分別如下:
[root@localhost ~]# cat a.txt 
a 1 f
b 2 g
[root@localhost ~]# cat b.txt 
f 3 5
g 4 6

執行以下命令,得到如下結果:
[root@localhost ~]# join -1 3 -2 1 a.txt b.txt
f a 1 3 5
g b 2 4 6

示例六
有檔案“a.txt”和“b.txt”,內容分別如下:
[root@localhost ~]# cat a.txt 
a 
b 2
[root@localhost ~]# cat b.txt 
a 3
b 4

執行以下命令,得到如下結果:
[root@localhost ~]# join -e "hello world" a.txt b.txt
a hello world 3
b 2 4

四、其他
4.1、“LC_COLLATE”等環境變數
由於涉及到兩個字串的比較等,故而程式實現中使用“LC_COLLATE”等環境變數,最終結果受到“LC_COLLATE”等環境變數的控制。

4.2、排序策略
跟“comm”命令一樣,join命令實現設定的排序策略是“按照字典序排序”。因而,兩個檔案“已排序”應該是按照字典序已排序,否則執行join命令得到的結果很有可能不能符合預期。

相關文章