天天看點

linux grep awk sed find cut

grep

^:錨定行首的符合條件的内容,用法格式“^pattern”;

$: 錨定行尾的符合條件的内容,用法格式“pattern$”;

.: 比對任意單個字元

*:比對緊挨在其前面的字元任意次;

a*b: ab, aab, acb, b

.*: 比對任意長度的任意字元

[]:比對指定範圍内的任意單個字元

[^]:比對指定範圍外的任意單個字元

\?: 比對緊挨在其前面的字元0次或1次;

\{m,n\}: 比對其前面的字元至少m次,至多n次;

\{0,n\}: 至多n次;0-n次;

{m,\}:至少m次

\{m\}: 精确比對m次;

\<: 錨定詞首,用法格式:\<pattern

\>: 錨定詞尾,用法格式:pattern\>

\(\): 分組,用法格式: \(pattern\)

grep的選項:

--color=auto 自動為比對的字元附色

export GREP_COLOR='01;36'

-r: 遞歸搜尋用法同 -d recurse(遞歸)

-v: 反向選取,隻顯示不符合模式的行;

-o: 隻顯示被模式比對到的字串,而不是整個行;

-i: 不區分字元大小寫;

-A #:顯示比對到的行時,順帶顯示其後面的#個行;

-B #:前面的#行;

-C #:前後的#行;

-E: 使用擴充的正規表達式

sed

sed指令行格式為:

         sed [-nefri] ‘command’ 輸入文本

常用選項:

        -n∶使用安靜(silent)模式。在一般 sed 的用法中,所有來自 STDIN的資料一般都會被列出到螢幕上。但如果加上 -n 參數後,則隻有經過sed 特殊處理的那一行(或者動作)才會被列出來。

        -e∶直接在指令列模式上進行 sed 的動作編輯;

        -f∶直接将 sed 的動作寫在一個檔案内, -f filename 則可以執行 filename 内的sed 動作;

        -r∶sed 的動作支援的是延伸型正規表示法的文法。(預設是基礎正規表示法文法)

        -i∶直接修改讀取的檔案内容,而不是由螢幕輸出。

常用指令:

        a   ∶新增, a 的後面可以接字串,而這些字串會在新的一行出現(目前的下一行)~

        c   ∶取代, c 的後面可以接字串,這些字串可以取代 n1,n2 之間的行!

        d   ∶删除,因為是删除啊,是以 d 後面通常不接任何咚咚;

         i   ∶插入, i 的後面可以接字串,而這些字串會在新的一行出現(目前的上一行);

         p  ∶列印,亦即将某個選擇的資料印出。通常 p 會與參數 sed -n 一起運作~

         s  ∶取代,可以直接進行取代的工作哩!通常這個 s 的動作可以搭配正規表示法!例如 1,20s/old/new/g 就是啦!

awk

awk非常的優秀,運作效率高,而且代碼簡單,對格式化的文本處理能力超強。基本上grep和sed能幹的活awk全部都能幹,而且幹得更好。

先來一個很爽的例子:

檔案a,統計檔案a的第一列中是浮點數的行的浮點數的平均值。用awk來實作隻需要一句話就可以搞定(當然,這個東東用python也可以很輕松的實作,隻是無論如何都得建立一個檔案;别妄想用bash shell來做,那可是浮點數!!!)

$cat a

1.021 33

1#.ll   44

2.53 6

ss    7

awk 'BEGIN{total = 0;len = 0} {if($1~/^[0-9]+\.[0-9]*/){total += $1; len++}} END{print total/len}' a

niubility!

awk的文法:

awk [-F re] [parameter...] ['program'] [-f 'programfile'] [in_file_list]

awk裡面的BEGIN,END結構:

BEGIN和END中的語句分别在開始讀取檔案(in_file)之前和讀取完檔案之後發揮作用,可以了解為初始化和掃尾。

awk裡面的if..else;   while ; do..while; for; break; continue; printf 文法都和C語言的文法一緻;而且awk支援使用if (key in array)這樣的判斷語句(其中,array是數組,這一點和python的文法非常相像。);awk支援使用for (key in array)這樣的文法來周遊數組(也是和python的文法很相像。)

我會用的參數的說明:

-F re:允許awk更改其字段分隔符

-v var=val 把val值指派給var(變量通信的好方法啊~~今天才知道這個選項,想想之前寫的代碼,抓狂啊~~)如果有多個變量要指派,那麼就寫多個-v,每個變量指派對應一個-v

e.g. 要列印檔案a的第num行到num+num1行之間的行, awk -v num=$num -v num1=$num1 'NR==num,NR==num+num1{print}' a

-f progfile:允許awk調用并執行progfile程式檔案,當然progfile必須是一個符合awk文法的程式檔案

我會用的awk内置變量:

ARGC    指令行參數的個數

ARGV:指令行參數數組

ARGIND 目前被處理檔案的ARGV标志符

e.g 有兩個檔案a 和b

awk '{if(ARGIND==1){print "處理a檔案"} if(ARGIND==2){print "處理b檔案"}}' a b

檔案處理的順序是先掃描完a檔案,再掃描b檔案

NR 已經讀出的記錄數

FNR   目前檔案的記錄數

上面的例子也可以寫成這樣:

awk 'NR==FNR{print "處理檔案a"} NR > FNR{print "處理檔案b"}' a b

輸入檔案a和b,由于先掃描a,是以掃描a的時候必然有NR==FNR,然後掃描b的時候,FNR從1開始計數,而NR則接着a的行數繼續計數,是以NR > FNR

e.g 要顯示檔案的第10行至第15行

awk 'NR==10,NR==15{print}' a

FS 輸入字段分隔符(預設為:space:),相當于-F選項

awk -F ':' '{print}' a    和   awk 'BEGIN{FS=":"}{print}' a 是一樣的

OFS輸出字段分隔符(預設為:space:)

awk -F ':' 'BEGIN{OFS=";"}{print $1,$2,$3}' b

如果cat b為

1:2:3

4:5:6

那麼把OFS設定成";"後就會輸出

1;2;3

4;5;6

(小注釋:awk把分割後的第1、2、3個字段用$1,$2,$3...表示,$0表示整個記錄(一般就是一整行))

NF:目前記錄中的字段個數

awk -F ':' '{print NF}' b的輸出為

3

表明b的每一行用分隔符":"分割後都3個字段

可以用NF來控制輸出符合要求的字段數的行,這樣可以處理掉一些異常的行

awk -F ':' '{if (NF == 3)print}' b

RS:輸入記錄分隔符,預設為"\n"

預設情況下,awk把一行看作一個記錄;如果設定了RS,那麼awk按照RS來分割記錄

例如,如果檔案c,cat c為

hello world; I want to go swimming tomorrow;hiahia

運作 awk 'BEGIN{ RS = ";" } {print}' c 的結果為

hello world

I want to go swimming tomorrow

hiahia

合理的使用RS和FS可以使得awk處理更多模式的文檔,例如可以一次處理多行,例如文檔d cat d的輸出為

1 2

3 4 5

6 7

8 9 10

11 12

hello

每個記錄使用空行分割,每個字段使用換行符分割,這樣的awk也很好寫

awk 'BEGIN{ FS = "\n"; RS = ""} {print NF}' d 輸出

2

1

ORS:輸出記錄分隔符,預設為換行符,控制每個print語句後的輸出符号

awk 'BEGIN{ FS = "\n"; RS = ""; ORS = ";"} {print NF}' d 輸出

2;3;1

awk的數組:

awk的數組是一個很值得一說的東東。awk的數組從行為上看的話更像關聯數組,或者說map、字典,或者說散列。awk的數組接受字元串下标,并接受速度很快的in查詢

檔案e是由小寫的字母組成,cat e 輸出為

a

b

z

...

如果要統計不同的字母出現的個數,那麼可以使用數組來實作

awk '{arr[$0]++} END{ for (key in arr) print key, "-->",arr[key] }' e

使用for( key in arr)來周遊數組的時候,輸出的次序是不可預測的,這一點跟python的字典周遊是一緻的。

在gawk中,可以使用asort内置函數實作數組的排序,其他的awk版本中還沒有發現有類似的排序函數。一個折中的辦法是先awk完再用管道傳給sort來排序。sort使用-k選項可以控制使用指定列排序。

awk的多元數組:

awk的多元數組在本質上是一維數組,更确切一點,awk在存儲上并不支援多元數組。awk提供了邏輯上模拟二維數組的通路方式。例如,array[2,4] = 1這樣的通路是允許的。awk使用一個特殊的字元串SUBSEP (\034)作為分割字段,在上面的例子中,關聯數組array存儲的鍵值實際上是2\0344。

類似一維數組的成員測試,多元數組可以使用 if ( (i,j) in array)這樣的文法,但是下标必須放置在圓括号中。

類似一維數組的循環通路,多元數組使用 for ( item in array )這樣的文法周遊數組。與一維數組不同的是,多元數組必須使用split()函數來通路單獨的下标分量。split ( item, subscr, SUBSEP)

awk讀取shell中的變量

可以使用-v選項實作功能

     $b=1

     $cat f

     apple

$awk -v var=$b '{print var, $var}' f

1 apple

除了使用-v選項外,還可以使用"'$variable'"的方式從shell往awk傳遞變量(注意:這裡是單引号)

$awk '{print $b, '$b'}' f

apple 1

至于有沒有辦法把awk中的變量傳給shell呢,這個問題我是這樣了解的。shell調用awk實際上是fork一個子程序出來,而子程序是無法向父程序傳遞變量的,除非用重定向(包括管道)

$a=$(awk '{print $b, '$b'}' f)

$echo $a

getline

getline為awk所提供的輸入指令.

其文法如下 :

$awk 'BEGIN{ "date" | getline d; close("date");print d}' f

Sun Nov 9 20:55:12 CST 2008

$awk 'BEGIN{getline name < "/dev/tty"} '

$awk 'BEGIN{while(getline < "/etc/passwd" > 0) { lc++ }; print lc }' f

隻要getline的傳回值大于0,即讀入一行,循環就會繼續。

getline如果如成功讀取,傳回1,否則傳回-1,如果遇到EOF,則傳回0。getline在讀取的同時會設定NF,NR,FNR等内置變量

如果getline後沒有變量,則預設置于$0

$awk 'BEGIN{ while(("ls" | getline) > 0) print}' f

(以上3個例子來自UNIX Shells By Example Fourth Edition, Section 6.26.4)

輸出重定向

awk的輸出重定向類似于shell的重定向。重定向的目标檔案名必須用雙引号引用起來。

$awk '$4 >=70 {print $1,$2 > "destfile" }' filename

$awk '$4 >=70 {print $1,$2 >> "destfile" }' filename

awk中調用shell指令:

1)使用管道

awk中的管道概念和shell的管道類似,都是使用"|"符号,在上面getline中{"date" | getline d;}就是使用了管道。如果在awk程式中打開了管道,必須先關閉該管道才能打開另一個管道。也就是說一次隻能打開一個管道。shell指令必須被雙引号引用起來。“如果打算再次在awk程式中使用某個檔案或管道進行讀寫,則可能要先關閉程式,因為其中的管道會保持打開狀态直至腳本運作結束。注意,管道一旦被打開,就會保持打開狀态直至awk退出。是以END塊中的語句也會收到管道的影響。(可以在END的第一行關閉管道)”

awk中使用管道有兩種文法,分别是:

awk output | shell input

shell output | awk input

對于awk output | shell input來說,shell接收awk的輸出,并進行處理。需要注意的是,awk的output是先緩存在pipe中,等輸出完畢後再調用shell指令處理,shell指令隻處理一次,而且處理的時機是“awk程式結束時,或者管道關閉時(需要顯式的關閉管道)”

$awk '/west/{count++} {printf "%s %s\t\t%-15s\n", $3,$4,$1 | "sort +1"} END{close "sort +1"; printf "The number of sales pers in the western"; printf "region is " count "." }' datafile

printf函數用于将輸出格式化并發送給管道。所有輸出集齊後,被一同發送給sort指令。必須用與打開時完全相同的指令來關閉管道(sort +1),否則END塊中的語句将與前面的輸出一起被排序。此處的sort指令隻執行一次。

在shell output | awk input中awk的input隻能是getline函數。shell執行的結果緩存于pipe中,再傳送給awk處理,如果有多行資料,awk的getline指令可能調用多次。

$awk 'BEGIN{ while(("ls" | getline d) > 0) print d}' f

2)使用system指令

$awk 'BEGIN{system("echo abc")}'

需要注意的是system中應該使用shell指令的對應字元串。awk直接把system中的内容傳遞給shell,作為shell的指令行。

3)system指令中使用awk的變量

空格是awk中的字元串連接配接符,如果system中需要使用awk中的變量可以使用空格分隔,或者說除了awk的變量外其他一律用""引用起來。

$awk 'BEGIN{a = 12; system("echo " a) }'

還有好多呀,以後再補充

awk的運算符

next等函數

更多的輸入輸出(輸出到多個檔案,關閉檔案,輸出到指令)

awk的内置函數:

gsub, index, length, match, printf, split, sprintf, substr, tolower, toupper, atan, cos, exp, int, log, rand, sin, sqrt, srand, system

find 

指令格式:

find pathname -options [-print -exec -ok ...]

2.指令功能:

用于在檔案樹種查找檔案,并作出相應的處理

3.指令參數:

pathname: find指令所查找的目錄路徑。例如用.來表示目前目錄,用/來表示系統根目錄。

-print: find指令将比對的檔案輸出到标準輸出。

-exec: find指令對比對的檔案執行該參數所給出的shell指令。相應指令的形式為'command' {  } \;,注意{   }和\;之間的空格。

-ok: 和-exec的作用相同,隻不過以一種更為安全的模式來執行該參數所給出的shell指令,在執行每一個指令之前,都會給出提示,讓使用者來确定是否執行。

4.指令選項:

-name   按照檔案名查找檔案。

-perm   按照檔案權限來查找檔案。

-prune  使用這一選項可以使find指令不在目前指定的目錄中查找,如果同時使用-depth選項,那麼-prune将被find指令忽略。

-user   按照檔案屬主來查找檔案。

-group  按照檔案所屬的組來查找檔案。

-mtime -n +n  按照檔案的更改時間來查找檔案, - n表示檔案更改時間距現在n天以内,+ n表示檔案更改時間距現在n天以前。find指令還有-atime和-ctime 選項,但它們都和-m time選項。

-nogroup  查找無有效所屬組的檔案,即該檔案所屬的組在/etc/groups中不存在。

-nouser   查找無有效屬主的檔案,即該檔案的屬主在/etc/passwd中不存在。

-newer file1 ! file2  查找更改時間比檔案file1新但比檔案file2舊的檔案。

-type  查找某一類型的檔案,諸如:

b - 塊裝置檔案。

d - 目錄。

c - 字元裝置檔案。

p - 管道檔案。

l - 符号連結檔案。

f - 普通檔案。

-size n:[c] 查找檔案長度為n塊的檔案,帶有c時表示檔案長度以位元組計。-depth:在查找檔案時,首先查找目前目錄中的檔案,然後再在其子目錄中查找。

-fstype:查找位于某一類型檔案系統中的檔案,這些檔案系統類型通常可以在配置檔案/etc/fstab中找到,該配置檔案中包含了本系統中有關檔案系統的資訊。

-mount:在查找檔案時不跨越檔案系統mount點。

-follow:如果find指令遇到符号連結檔案,就跟蹤至連結所指向的檔案。

-cpio:對比對的檔案使用cpio指令,将這些檔案備份到錄音帶裝置中。

另外,下面三個的差別:

-amin n   查找系統中最後N分鐘通路的檔案

-atime n  查找系統中最後n*24小時通路的檔案

-cmin n   查找系統中最後N分鐘被改變檔案狀态的檔案

-ctime n  查找系統中最後n*24小時被改變檔案狀态的檔案

-mmin n   查找系統中最後N分鐘被改變檔案資料的檔案

-mtime n  查找系統中最後n*24小時被改變檔案資料的檔案

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 />範圍之内,該字元将被寫出;否則,該字元将被排除。

(2)cut一般以什麼為依據呢? 也就是說,我怎麼告訴cut我想定位到的剪切内容呢?

cut指令主要是接受三個定位方法:

第一,位元組(bytes),用選項-b

第二,字元(characters),用選項-c

第三,域(fields),用選項-f

(3)以“位元組”定位

舉個例子吧,當你執行ps指令時,會輸出類似如下的内容:

[rocrocket@rocrocket programming]$ 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個位元組,就這樣:

[rocrocket@rocrocket programming]$ who|cut -b 3

c

(4) 如果“位元組”定位中,我想提取第3,第4、第5和第8個位元組,怎麼辦?

-b支援形如3-5的寫法,而且多個定位之間用逗号隔開就成了。看看例子吧:

[rocrocket@rocrocket programming]$ who|cut -b 3-5,8

croe

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

[rocrocket@rocrocket programming]$ who|cut -b 8,3-5

(5) 還有哪些類似“3-5”這樣的小技巧,列舉一下吧!

[rocrocket@rocrocket programming]$ who|cut -b -3

roc

[rocrocket@rocrocket programming]$ 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的。看:

[rocrocket@rocrocket programming]$ who|cut -b -3,3-

(6)給個以字元為定位标志的最簡單的例子吧!

下面例子你似曾相識,提取第3,第4,第5和第8個字元:

[rocrocket@rocrocket programming]$ who|cut -c 3-5,8

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

[rocrocket@rocrocket programming]$ cat cut_ch.txt

星期一

星期二

星期三

星期四

[rocrocket@rocrocket programming]$ cut -b 3 cut_ch.txt

[rocrocket@rocrocket programming]$ cut -c 3 cut_ch.txt

看到了吧,用-c則會以字元為機關,輸出正常;而-b隻會傻傻的以位元組(8位二進制位)來計算,輸出就是亂碼。

既然提到了這個知識點,就再補充一句,如果你學有餘力,就提高一下。

當遇到多位元組字元時,可以使用-n選項,-n用于告訴cut不要将多位元組字元拆開。

例子如下:

[rocrocket@rocrocket programming]$ cat cut_ch.txt |cut -b 2

[rocrocket@rocrocket programming]$ cat cut_ch.txt |cut -nb 2

[rocrocket@rocrocket programming]$ cat cut_ch.txt |cut -nb 1,2,3

(7)域是怎麼回事呢?解釋解釋:)

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

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

以/etc/passwd的前五行内容為例:

[rocrocket@rocrocket programming]$ 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

[rocrocket@rocrocket programming]$ cat /etc/passwd|head -n 5|cut -d : -f 1

root

bin

daemon

adm

lp

看到了吧,用-d來設定間隔符為冒号,然後用-f來設定我要取的是第一個域,再按回車,所有的使用者名就都列出來了!呵呵 有成就感吧!

當然,在設定-f時,也可以使用例如3-5或者4-類似的格式:

[rocrocket@rocrocket programming]$ 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

[rocrocket@rocrocket programming]$ 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

[rocrocket@rocrocket programming]$ cat /etc/passwd|head -n 5|cut -d : -f -2

root:x

bin:x

daemon:x

adm:x

lp:x

(8)如果遇到空格和制表符時,怎麼分辨呢?我覺得有點亂,怎麼辦?

有時候制表符确實很難辨認,有一個方法可以看出一段空格到底是由若幹個空格組成的還是由一個制表符組成的。

[rocrocket@rocrocket programming]$ cat tab_space.txt

this is tab finish.

this is several space      finish.

[rocrocket@rocrocket programming]$ sed -n l tab_space.txt

this is tab\tfinish.$

this is several space      finish.$

看到了吧,如果是制表符(TAB),那麼會顯示為\t符号,如果是空格,就會原樣顯示。

通過此方法即可以判斷制表符和空格了。

注意,上面sed -n後面的字元是L的小寫字母哦,不要看錯。

(9)我應該在cut -d中用什麼符号來設定制表符或空格呢?

其實cut的-d選項的預設間隔符就是制表符,是以當你就是要使用制表符的時候,完全就可以省略-d選項,而直接用-f來取域就可以了。

如果你設定一個空格為間隔符,那麼就這樣:

[rocrocket@rocrocket programming]$ cat tab_space.txt |cut -d ' ' -f 1

this

注意,兩個單引号之間可确實要有一個空格哦,不能偷懶。

而且,你隻能在-d後面設定一個空格,可不許設定多個空格,因為cut隻允許間隔符是一個字元。

cut: the delimiter must be a single character

Try `cut --help' for more information.

(10)cut有哪些缺陷和不足?

猜出來了吧?對,就是在處理多空格時。

如果檔案裡面的某些域是由若幹個空格來間隔的,那麼用cut就有點麻煩了,因為cut隻擅長處理“以一個字元間隔”的文本内容

本文轉自 295631788 51CTO部落格,原文連結:http://blog.51cto.com/hequan/1764502,如需轉載請自行聯系原作者