正則表達式與字符處理
正則表達式
正則表達式和通配符的區別是,正則表達式的作用是在文件中搜索符合條件的字符串(常用命令有grep、awk、sed),而通配符用來匹配符合條件的文件名(ls、find、cp這些命令只能用通配符,不能用正則表達式)。且通配符是完全匹配,而正則表達式是包含匹配,如當用grep命令查找時,只要包含該字符串的行就會顯示。
正則表達式:

通配符:

*表示前一個字符匹配0次或任意多次(和通配符中的*不同),故grep "a*" test_rule.txt
表示匹配所有內容,包括空白行,而grep "aa*" test_rule.txt
表示匹配至少包含有一個a的行。
.表示匹配除了換行符外的任意一個字符,grep "s.*d" test_rule.txt
表示匹配在s和d字母之間有任意字符的行,grep ".*" test_rule.txt
表示匹配所有內容。
和$表示能匹配行首和行尾,M表示行首是M,d$表示行尾是d,而grep -n "^$" test_rule.txt
表示會匹配空白行。
常見的匹配:
grep "^[^a-z\]" test_rule.txt
表示匹配不用小寫字母開頭的行
grep "^[^a-zA-Z\]" test_rule.txt
表示匹配不用字母開頭的行
grep "\.$" test_rule.txt
表示匹配使用“.”結尾的行
字符截取命令
截取命令有grep、cut、awk和sed四個。
cut命令
grep是將符合條件的行提取出來,而cut是提取列。
使用的基本格式:cut [選項] 文件名
-f后跟列號代表提取第幾列,-d后跟分隔符表示設置提取時的分隔符。對於文件(每行中的分隔符是tab)
ID Name gender Mark
1 Liming M 86
2 Sc M 90
3 Gao M 83
執行cut -f 2,3 student.txt
結果就是提取第2、3列(中間分隔符還保留):
Name gender
Liming M
Sc M
Gao M
cut命令會一行一行進行切分,取返回結果中每行第12個字符以后的所有字符串:export | cut -c 12
cut命令常和grep命令配合使用,如對/etc/passwd,該文件中每一行代表一個用戶,如果想提取這個文件中的普通用戶名,應該執行:
cat /etc/passwd | grep /bin/bash | grep -v root | cut -d ":" -f 1
就會將普通用戶名提取出來。這里第一部分代表用cat命令查看該文件,然后選取行內帶/bin/bash的行(相當於除掉系統用戶),然后去除root用戶(-v代表過濾掉某個結果),最后用cut命令提取第一列,分割符是冒號(不設置的話默認分隔符是制表符),中間用管道符連接。
但如果要讀取的文件分隔符是多個空格,則cut無法正確提取內容,cut的分隔符只支持一個字符,awk命令可以解決這個問題。
printf命令
printf的基本用法是printf '輸出格式' 輸出內容
輸出格式主要有三種,%ns表示輸出字符串,n代表輸出字符的個數;%ni代表輸出整數,n指輸出數字的個數;%m.nf表示輸出小數,m指輸出數字的個數,n值其中小數的位數。
輸出格式中有一些特殊字符,常用的有\n換行,\r回車,\t制表符。
printf %s 1 2 3 4 5 6
會輸出123456
printf %s %s %s 1 2 3 4 5 6
會輸出%s%s123456
必須將輸出格式用單引號括起來:printf '%s %s %s' 1 2 3 4 5 6
會輸出1 2 34 5 6
printf '%s %s %s\n' 1 2 3 4 5 6
會輸出1 2 3換行4 5 6
也就是說當后面內容多於輸出格式時,會反復使用輸出格式。
想要按照一定的格式輸出文件時,要這樣處理:printf '%s' $(cat student.txt)
,注意這里不能用管道符,這樣會將文件所有內容在一行輸出,如果想按照文件格式輸出必須按照文件的格式來寫輸出命令:printf '%s\t %s\t %s\t %s\t %s\t %s\t \n' $(cat student.txt)
這樣就能完整的輸出文件了student.txt:
ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
printf '%10s %5i %8.2f \n' $(cat file)
,輸出格式依次是長度為10的字符串、長度為5的數字、長度為8其中可以留兩位小數點。
print和printf的區別在於print命令會自動加換行,linux中默認沒有print命令,但在awk中可以使用print命令。
awk命令
awk使用格式:awk ‘條件1{動作1} 條件2{動作2}…’ 文件名
條件通常是關系表達式,當使用awk處理文件時,文件是按行讀取的,然后判斷條件,確定是否執行動作。
整個awk的處理流程是:
1、讀取第一行,然后初始化$0/$1/$2...。
2、根據條件值判斷是否進行后面的動作。
3、執行所有的條件和動作,如果后面還有后續的行則重復上述步驟,直到所有行都讀完。
對student.txt來說,awk '{printf $2 "\t" $6 "\n"}' student.txt
能將第2列和第6列提取出來,這里的printf不是系統命令,可以用$n代表第幾列,$0代表整行,printf中的特殊字符要用雙引號括起來,因為外層已經使用了單引號,所以這里用雙引號,特殊字符控制的都是輸出格式。
awk默認的字段分隔符是空格或tab,所以對於用多個空格作為分隔符的文件或輸出,awk也能處理,如df -h | awk '{print $1 "\t" $3}'
這里用的是print命令,和printf手動加換行符效果相同。
如果想提取df -h中的百分數,如下圖:

此時應該執行df -h | grep root | awk '{printf $5}' | cut -d "%" -f 1
這條語句就是用grep命令提取對應行,然后用awk來提取對應列,最后用cut命令來以%為分隔符切割,相當於去掉%,最后得到數字。
BEGIN是一種條件,表示讀取前優先處理。awk 'BEGIN{printf "This is a transcript \n" } {printf $2 "\t" $6 "\n"}' student.txt
此時打印內容第一行就是This is a transcript,第二行開始讀取文件。
設置分隔符awk 'BEGIN {FS=":"} {printf $1 "\t" $3 "\n"}'
FS就代表設置分隔符為冒號,這里前面必須加BEGIN ,如果不加那么文件第一行會原封不動打印,因為在讀取第一個大括號時就已經讀取第一行了,如果不加BEGIN程序會直接讀取第二行然后開始處理。
END也是一種條件,表示最后執行。awk 'END{printf "The End \n" } {printf $2 "\t" $6 "\n"}' student.txt
此時就會最后打印一行The End。
awk的強大之處在於可以插入邏輯表達式,cat student.txt | grep -v Name | \ awk '$6 >= 87 {printf $2 "\n" }'
,同樣是對student文件,如果想輸出平均分大於87分的Name就可以執行這條命令,首先讀取該文件,然后除掉第一行,如果第六列的元素大於等於87就打印第二列。
awk有幾個內建變量:NF(每一行擁有的字段總數)、NR(目前處理的是第幾行的數據)、FS(分隔符默認為空格),這些變量都可以直接放在大括號里打印出來,或者放在括號外作為條件判斷都可以,不需要加$。
sed命令
sed命令是一種輕量級流編輯器,主要是用來將數據選取、替換、刪除和新增。vim也可以修改文件,但是vim難以修改命令輸出內容,只能將輸出內容寫入文件然后修改,而sed在這方面優於vim。
sed命令的執行格式是sed [選項] ‘[動作]’ 文件名
提取文件第2行並輸出:sed -n '2p' student.txt
,動作中p代表輸出指定的行,而-n代表僅輸出sed處理過的行,如果不加-n那么會輸出全部文件內容,第二行會輸出兩次。sed不僅可以用在文件中,還能用在命令輸出的內容中:df -h | sed -n '2p'
刪除第2行到第4行的數據(相當於輸出其他行,它不會修改文件本身):sed '2,4d' student.txt
在第二行后插入一行(不修改文件本身):sed '2a hello' student.txt
,a代表某行后插入。
在第二行前插入兩行(不修改文件本身):sed '2i hello \ world' student.txt
,反斜杠代表輸入第二行,插入時除了最后一行,當想插入多行時必須在行末處加反斜杠,i代表某行前插入。
將第二行替換(不修改文件本身):sed '2c No such person‘ student.txt
數據替換可以精確到字符串,格式是sed ‘s/舊字串/新字串/g’ 文件名
把第三行中的74換成99:sed '3s/74/99/g' student.txt
同時把“Liming”和“Gao”替換為空:sed -e 's/Liming//g ; s/Gao//g' student.txt
,注意當有多個動作時用分號隔開,-e代表允許多條編輯,當s前沒有數字時代表針對所有行。
總結:sed命令的常用選項有三個,-n、-e和-i‘;常用動作有6種,a、c、i、d、p、s。
字符處理命令
1、排序命令sort,使用方法:sort [選項] 文件名
選項有幾種:
-f: 忽略大小寫
-n: 以數值型進行排序,默認使用字符串型排序
-r: 反向排序
-t: 指定分隔符,默認是分隔符是制表符
-k n[,m]: 按照指定的字段范圍排序。從第n字段開始, m字段結束(默認到行尾)
排序用戶信息文件:sort /etc/passwd
此時會輸出按照文件每行首字母排序的結果:

如果想按照每行第三個字段排序,必須先指定冒號為分隔符:sort -t ":" -k 3,3 /etc/passwd
-k 3,3的意思是從第三個字段開始到第三個字段結束,也就是按照第3個字段排序。但是排序結果會把10排在3前,這是因為默認只識別第一個字符,如果想按數字排序應該加上-n選項:
sort -n -t ":" -k 3,3 /etc/passwd
。
2、去重命令uniq:經常結合排序使用,僅取出賬號欄,然后排序后去重:
last | cut -d ' ' -f 1 | sort | uniq
3、統計命令wc:wc [選項] 文件名
。選項有以下幾種:-l: 只統計行數、-w: 只統計單詞數、-m: 只統計字符數。如果不加選項那么上述三種都會輸出。
字符轉換命令
1、tr命令可以用來刪除一段訊息中的文字或進行替換
將last輸出信息中的所有小寫字母換成大寫的:last | tr '[a-z]' '[A-Z]'
將輸出信息中的冒號全部刪除:cat /etc/passwd | tr -d ':'
2、col命令可以將tab轉成對等的空格鍵,命令是col -x
3、join命令用來通過兩個文件數據相同的部分,來把兩個文件的數據整合到一起,如/etc/passwd和/etc/shadow兩個文件每行的第一個字段都是相同的賬號名:

此時就可以用join方法:
join -t ':' /etc/passwd /etc/shadow
這樣整合后,兩個文件的數據都會整合到一起,查看上面輸出的內容:

可以發現最后每一行輸出的內容就是文件1+文件2沒有連接字段的那部分。join的字段也可以不采用首個字段。
join常常在sort之后,防止出現對應行不匹配的現象。
4、paste命令用來將兩行粘在一起,中間用tab鍵分開:paste 文件1 文件2
,如果加-d后面跟分隔符的話就可以重新設置分隔符。
5、expand和unexpand分別是將tab轉成空格,和把空格轉成tab,expand后跟文件名會自動將文件內的tab轉成8個空格,也可以用-t加數字來自定義轉換數字。
6、分區命令split,它可以將一個大文件分成多個小文件,以便於復制。
切割成300k一個的小文件:split -b 300k 文件名
,此時原文件會被刪除,假設原文件名為1,那么結果就會多出1aa、1ab、1ac文件,將這三個文件合並:cat 1* >> 1
,這樣就可以復原。
將ls輸出信息每十行記錄一個文件:ls -al / | split -l 10 - lsroot
,這里新生成的文件名開頭就是lsroot,-的意思是輸入流,但是為空所以就用-來表示。
7、xargs命令可以創造標准輸入,令不支持用管道符的命令能夠接受其他命令的返回結果並執行。