【Linux命令】《鳥哥Linux基礎》第十一章 正則表達式與文件格式化處理

第十一章 正則表達式與文件格式化處理

11.1 基礎概念

正則表達式是對字符串的處理的表示方式。

11.2 基礎正則表達式

11.2.1 語系

採用LANG=C的語系。

特殊符號 意義
[:alnum:] 英文大小寫字符和數字 0-9 a-z A-Z
[:alpha:] 英文大小寫字符 a-z A-Z
[:blank:] 代表空格鍵和Tab鍵兩種空格符
[:cntrl:] 代表 鍵盤上面的控制按鍵,包括CR LF Tab Del 等
[:digit:] 數字 0-9
[:graph:] 除了空格符(空格鍵、Tab鍵)之外的其他所有按鍵
[:lower:] 小寫字母 a-z
[:upper:] 大寫字母 A-Z
[:print:] 任何可以被打印出來的字符
[:punct:] 標點符號
[:space:] 任何會產生空白的字符,包括空格鍵、Tab鍵、CR等
[:xdigit:] 十六進制數字,包括0-9 A-F a-f
grep [-A] [-B] [--color=auto] '查找字符' filename
		-A 後可接數字,爲after的意思,除了列出該行之外,後續的n行也跟着列出
		-B 後可接數字,爲before的意思,除了列出該行之外,前面的n行也跟着列出


dmesg | grep -n 'tun'				從dmesg輸出的所有內容中,將帶有關鍵字tun的那行帶行號顯示
dmesg | grep -n -A3 -B 2 'tun'		同上,在此基礎上,將前面的2行和後面的3行一起顯示出來

11.2.3 基礎正則表達式練習

調整語系:
export LANG=C
export LC_ALL=C


grep -n 'the' regular_express.txt 				有the的行顯示
grep -vn 'the' regular_express.txt 				無the的行顯示
grep -ni 'the' regular_express.txt				有不論大小寫的the的行都顯示
grep -n 't[ae]st' regular_express.txt			有test的和taste的行都會被顯示出來,[ae]表示a或者e
grep -n '[^a-z]oo' regular_express.txt 			字符串'oo'前面未出現小寫字母的行都顯示
grep -n '[^[:lower:]]oo' regular_express.txt 	同上
grep -n '[0-9]' regular_express.txt				有數字的行都顯示,
grep -n '[[:digit:]]' regular_express.txt		同上
grep -n '[0-9][0-9]*' regular_express.txt		同上,這是使用正則表達式匹配,上面使用通配符匹配
grep -n '^the' regular_express.txt 				開頭是the的行都顯示
grep -n '^[a-z]' regular_express.txt 			開頭是小寫字母的行都顯示
grep -n '^[[:lower:]]' regular_express.txt 		同上
grep -n '^[^a-zA-Z]' regular_express.txt		開頭別是英文字母的行都顯示
grep -n '^[^[:alpha:]]' regular_express.txt		同上
grep -n '\.$' regular_express.txt 				行尾是小數點的行都顯示
grep -n '^$' regular_express.txt 				顯示空白行,結果是22:
grep -n '^$' regular_express.txt | cat -A		顯示空白行,並顯示特殊字符,結果是22:$
grep -v '^$' /etc/rsyslog.conf | grep -v '^#'	空白行與開頭是井號鍵的註釋行都不顯示
grep -n 'g..d' regular_express.txt 				將g與d之間存在兩個任意字符的那行顯示
grep -n 'oo*' regular_express.txt				第一個o務必存在,後面的o*表示可以有0到無窮多個o
grep -n 'ooo*' regular_express.txt				含有兩個或更多連續o的行顯示
grep -n 'goo*g' regular_express.txt				字符串首尾都是g,且中間有1個以上的連續o,沒有其他雜字符
grep -n 'g.*g' regular_express.txt				字符串首尾都是g就行,不管中間有啥有多少,都顯示
grep -n 'o\{2\}' regular_express.txt 			含有兩個o的行顯示
grep -n 'go\{2,5\}g' regular_express.txt		找到g後面接2-5個o,之後又有個g的行顯示
grep -n 'go\{2,\}g' regular_express.txt			找到g後面接2個或2個以上的o,只有又有個g的行顯示

^,在字符集合符號(中括號[])內外表示含義不同,在內表示反向選擇,在外表示定位在行首。

Windows下的換行符是^M$ ,而Linux下的換行符是$。兩者有別。

通配符*,代表任意字符,0個或多個;小數點.代表【一定有一個任意字符】;星號*代表【重複前一個字符,0到無窮多次】,是組合形態。

cat -An regular_express.txt |head -n 10 | tail -n 5		將第5-10行顯示出來,帶行號,且顯示特殊字符
輸出:
     6	GNU is free air not free beer.$
     7	Her hair is very beauty.$
     8	I can't finish the test.$
     9	Oh! The soup taste good.$
    10	motorcycle is cheap than car.$

11.2.4 基礎正則表達式字符集合

RE字符 意義
^word 帶查找的字符串word在行首
word$ 帶查找的字符串word在行尾
小數點. 一定有一個任意字符
\ 轉義符,將特殊符號的特殊意義去除
* 重複0個到無窮多個的籤一個RE字符
[list] 字符集合的RE字符,裏面列出想要選取的字符
[n1-n2] 字符集合的RE字符,裏面列出想要選取的字符範圍
[^list] 字符集合的RE字符,裏面列出不要的字符串或範圍
{n,m} 連續n到m個的前一個RE字符;{n}是連續n個的前一個RE字符;{n,}連續n個以上的前一個RE字符
ls -l *					匹配任意文件
ls -l a*				匹配文件名開頭是a的文件
ls | grep -n '^a.*'		匹配文件名開頭是a的文件
ls -l /etc | grep '^l'	找到/etc下的鏈接文件【lrwxrwxrwx】開頭是l
ls -l /etc | grep '^l'|wc -l	這樣的文件總共有多少個,列出個數

11.2.5 sed工具

sed本身也是管道命令,可以分析標準輸入。可以完成替換、刪除、新增、選取特定行等功能。

sed [-nefr] [操作]
		-n  安靜模式,只有經過sed處理的行才顯示到屏幕上
		-e  直接在命令行模式上進行sed的操作編輯
		-f  直接將sed的操作寫在一個文件內,-f filename 可以執行filename內的sed操作
		-r  sed的操作使用的是擴展性正則表達式語法(默認是基礎正則表達式語法)
		-i  直接修改讀取的文件內容,而不是由屏幕輸出
操作:[n1[,n2]] function
		n1,n2  未必存在,選擇進行操作的行數
		function包括: 	a  新增
						c  替換
						d  刪除
						i  插入
						p  打印
						s  替換		
nl /etc/passwd | sed '2,5d'		刪除2-5行後的內容顯示在屏幕上
nl /etc/passwd | sed '2d'		刪除第2行後的內容顯示在屏幕上
nl /etc/passwd | sed '3,$d'		刪除第3行到最後一行之後的內容顯示在屏幕上
nl /etc/passwd | sed '/^$/d'	刪除空白行



nl /etc/passwd | sed '2a drink tea' 即在第二行結束,第三行開頭添加drink tea字樣
nl /etc/passwd | sed '2i drink tea' 即在第二行前面,第一行後面添加drink tea字樣

可以新增好幾行數據,必須用轉義字符+Enter鍵隔開:
nl /etc/passwd | sed '2a drink tea or \
> drink bear?'



替換整行:
nl /etc/passwd | sed '2,5c No 2-5 number'		將第2-5行數據替換成No 2-5 number
輸出:
     1	root:x:0:0:root:/root:/bin/bash
No 2-5 number
     6	sync:x:5:0:sync:/sbin:/bin/sync



按行數輸出整行內容:
nl /etc/passwd | sed -n '5,7p'



以行爲單位,實現部分數據的查找和替換:
sed 's/要被替換的字符/新的字符/g'
sed 's/要被替換的字符//g'		將匹配到的字符串刪除
cat /etc/man_db.conf | grep 'MAN'|sed 's/#.*$//g'	刪除掉每一行註釋之後的內容,原本的註釋行都變成了空白行
cat /etc/man_db.conf | grep 'MAN'|sed 's/#.*$//g' | sed '/^$/d'	因此還得刪除空白行



直接修改文件,將文件末尾的點換成感嘆號:
sed -i 's/\.$/\!/g' regular_express.txt 
直接修改文件,在文件末尾添加一句註釋# This is a test
sed -i '$a # This is a test' regular_express.txt

11.3 擴展正則表達式

RE字符 意義
+ 重複1個或1個以上的前一個RE字符
? 0個或1個的前一個RE字符
| 用或(or)的方式找出數個字符串
() 找出羣組字符串
()+ 多個重複羣組的判別

11.4 文件的格式化與相關處理

11.4.1 格式化打印:printf

printf '打印格式' 實際內容
		\a		警告聲音輸出
		\b		退格鍵(backspace)
		\f		清屏
		\n		輸出新行
		\r		回車按鍵
		\t		水平的Tab鍵
		\v		垂直的Tab鍵
		\xNN   	NN是兩位數數字,可以轉換數字成爲字符
		%ns  	多少個字符
		%ni	 	多少個整數位數
		%N.nf  	共要N個位數,其中小數點佔n位
		
printf '%s\t %s\t %s\t %s\t \n' $(cat printf.txt) 	要先把文件中的內容提取出來給printf用
printf '\x45\n'		看十六進制的數值45代表的字符是啥

11.4.2 awk:好用的數據處理工具

awk比較傾向於一行當中分成數個字段來處理,適合處理小型文本數據。

awk '條件類型1{操作1} 條件類型2{操作2} ...'  filename   默認分隔符是空格鍵和Tab鍵

last -n 5 | awk '{print $1 "\t" $3}'				 顯示前5行中的第一字段和第三字段(awk最常用的功能)

last -n 5 | awk '{print $1 "\t lines:" NR "\t columns:" NF}'	輸出字段1,目前處理的第幾行NR,該行有幾個字段NF

cat /etc/passwd | awk '{FS=":"} $3 < 10 {print $1 "\t" $3}'		將第3字段的UID號碼小於10的那行的字段1和字段3顯示出來(這種方式,第一行數據無法正確處理,那個時候的分隔符還是默認爲空格)

cat /etc/passwd | awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t" $3}' 將第3字段的UID號碼小於10的那行的字段1和字段3顯示出來(解決上述問題)
變量名稱 意義
NF 每一行($0)擁有的字段總數
NR 目前awk所處理的是第幾行數據
FS 目前的分隔字符,默認是空格鍵

11.4.3 文本比對工具

diff通常用在同一個文件(或軟件)的新舊版本差異上,以爲單位比對。不要用diff比較兩個不相關的文件。

diff [-bBi] from-file to-file
		from-file  	文件名,作爲原始比對文件的文件名
		to-file   	文件名,作爲目標比對文件的文件名
		from-file和to-file可以用-來替換,-此處代表標準輸入
		-b			忽略一行當中,僅有多個空白的差異,認爲“a a”與“a    a”相同
		-B			忽略空白行的差異
		-i			忽略大小寫的不同



mkdir -p /tmp/testpw
cd /tmp/testpw/
cp /etc/passwd passwd.old
cat /etc/passwd | sed -e '4d' -e '6c no six line'>passwd.new
diff passwd.old passwd.new 
輸出:						
4d3											左邊第4行被刪除了,基準是右邊的第三行
< adm:x:3:4:adm:/var/adm:/sbin/nologin		列出了左邊文件被刪除的那一行內容
6c5											左邊文件的第6行被替換成右邊文件的第5行
< sync:x:5:0:sync:/sbin:/bin/sync			左邊文件第6行
---
> no six line								右邊文件第5行




diff /etc/rc0.d/ /etc/rc5.d/				運行級別0和運行級別5的啓動腳本文件對比
輸出:
只在 /etc/rc0.d/ 存在:K90network
只在 /etc/rc5.d/ 存在:S10network
cmp [-l] file1 file2
		-l  將所有不同點的字節處都列出來,默認僅輸出第一個發現的不同點


cmp passwd.old passwd.new 	
輸出:
passwd.old passwd.new 不同:第 106 字節,第 4 行
diff -Naur passwd.old passwd.new > passwd.patch		製作補丁文件
cat passwd.patch 
輸出:
--- passwd.old	2020-06-07 16:02:19.455870231 +0800
+++ passwd.new	2020-06-07 16:03:01.811869325 +0800
@@ -1,9 +1,8 @@
 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
-sync:x:5:0:sync:/sbin:/bin/sync
+no six line
 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
 halt:x:7:0:halt:/sbin:/sbin/halt
 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

需要安裝軟件才能使用:
patch -pN < patch_file
patch -R -pN < patch_file

patch -p0 < passwd.patch	用剛剛製作出來的patch文件更新舊文件
patch -R -p0 <passwd.patch  恢復舊文件

11.4.4 文件打印設置:pr

打印的時候,打印標題和頁碼的設置。

pr /etc/man_db.conf

11.6 習題

grep '\*' /etc/* 2>/dev/null					找到/etc文件夾下的帶*內容

grep '\*' $(find /etc -type f) 2>/dev/null		找到/etc包括子文件夾下的文件的帶*內容

grep -l '\*' $(find /etc -type f) 2>/dev/null	找到符合的文件名就行,不用找內容



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章