shell基础--正则表达式行列提取
目錄
一、概述:什么是正則表達式
二、基礎正側表達式
1..(點)
2.*:
3.^符號
4.和上邊^相對$
5.\{n,m\}符號:
6.\{n,m\} :
7.[]符號
8.\符號
9.?\<符號和\>符號:
?三、擴展正則表達
1.()括號模式單元的使用:
四、字符截命令和替換命令
1.cut列提取命令:
2.文本處理工具awk
3.printf格式化輸出:
4.awk基本使用
awk的保留字:
關系運算符:
正則表達式:
awk內置變量
awk的條件
6.awk流程控制
7.awk中調用腳本
五、.sed命令 文件內增,刪,替換
一、概述:什么是正則表達式
????????正則表達式用來在文件中匹配符合條件的字符串,通配符用來匹配符合條件的文件名。其實這種區別只在shell中適用,因為用來在文件當中搜索字符串的命令,如grep、awk、sed等命令可以支持正則表達式,而在系統當中搜索文件的命令,如:ls、find、cp這些命令不支持正則表達式,所以只能使用shell自己的通配符來進行匹配了。??
二、基礎正側表達式
| 元字符 | 作用 |
| . | 匹配除換行符以外的任意一個字符 |
| * | 前一個字符匹配0或任意多次 |
| ^ | 匹配行首。例:^hello會匹配以hello開頭的行 |
| $ | 匹配行尾。例:hello$會匹配以hello結尾的行 |
| [] | 匹配中括號中指定的任意一個字符,只匹配一個字符。例:[aeiou]匹配任意一個元音字母。[0-9]會匹配任意一位數字。[a-z][0-9]匹配小寫字和一位數字構成的兩位字符。 |
| [^] | 匹配除中括號的字符以外的任意一個字符。例:[^0-9]匹配任意一位非數字字符。 |
| \ | 轉義符。用于取消,將特殊符號的含義取消。 |
| \{n\} | 表示其前面一個字符恰好出現n次。例:[0-9]\{4\} 匹配4位數字。 [1][3-8][0-9]\{9\}匹配手機號 |
| \{n,\} | 表示其前面一個字符出現不小于n次。例:[0-9]\{2,\}匹配2位及以上的數字。 |
| \{n,m\} | 表示前面的一個字符至少出現n次,最多出現m次。例:[a-z]\{6,8\}匹配6-8位的小寫字母。 |
在~/.bashrc文件中添加別名:
【】# vim .bashrc
alias grep='grep --color=auto'
【】# source /root/.bashrc
1..(點)
用于匹配除換行符以外的任意一個字符。例如r.t可以匹配rat、rbt。但不能匹配root。
?
2.*:
????????用于匹配前一個字符零次或任意多次,比如ab*就會匹配a、ab、abbbb等。*還可以和.組合使用。比如“.*”代表任意長度不包含換行符的匹配。
????????(上面例子試圖找到連續的r字符緊跟t的行。因為*會匹配前一個字符零次或多次,所以出現了只找到t的情況。)
(如果是rr*代表這行字符一定要有一個r,但后邊有沒有r都可以,至少會匹配包含有一個r的行)
?
?(正則是rrr*的時候會匹配最少包含兩個連續r的字符串)
?
(如果把r*t換成r.*t代表查找包含字母r,后面緊跟任意長度的字符,再跟一個字母t的行)
3.^符號
稱為尖角號。用于匹配開頭的字符:
(匹配以root開頭的行)
?
4.和上邊^相對$
匹配的是尾部。比如:abc$匹配的就是以abc結尾的行:
(在/etc/passwd中匹配以bash結尾的行)
?
(匹配了以r開頭,中間有一串任意字符,以h結尾的行)
?
5.\{n,m\}符號:
使用此符號可以更加靈活的控制字符的重復次數。
\{n\} :
(匹配前面一個字符n次。上面匹配了包含root的行)
\{n,\} :
?(匹配前面的一個字符至少n次以上,含n次)
6.\{n,m\} :
?
(匹配前面的一個字符n到m次)
7.[]符號
用于匹配方括號內出現的任意字符。比如單項選擇題的選項A、B、C、D,用正則表達就是[ABCD]。如果遇到較大的范圍就是[A-Z],會任意大寫字母。[A-Za-z]匹配所有字母。“-”做范圍限定。如果要匹配不是大寫字母的字符的話需要用到“^(尖角號)”在之前的學習中^代表匹配開頭的意思。但是尖角號出現在[]中。含義就是取反。[^A-Z](不是大寫字母)。下面舉例匹配手機號:
?(首先,在文件中寫入幾串數字。其中有符合手機號條件的字符串。)
(想要匹配手機號,要知道手機號是11位連續的數字。第一位一定是1,所以表示為^1。第二位可能是3(移動)或8(聯通),表示為[38]。后面連續9個任意數字表示為[0-9]\{9\}。)
?(在匹配的結尾加上一個$符號,指定結尾為0-9九位數字結尾。否則只會匹配前面11位數字,至于之后的數字或字母并不限制。)
8.\符號
我們之前了解到.*代表的是任意長度的不包含換行的重復字符。但是如果想匹配任意長度.的時候。就需要用到\了。
例:先在/etc/passwd中插入...和..
(在/etc/passwd中查找至少有一個.的行)
9.?\<符號和\>符號:
這兩個符號分別用于界定左邊界和右邊界。比如\<hello\>用來精確匹配hello這個字符串:
(匹配hello成功。helloworld匹配失敗,沒有輸出。)
?三、擴展正則表達
????????顧名思義,擴展正則表達式一定是針對基礎正則表達式的一些補充。擴展正則表達式比基礎正則表達式多了幾個重要的符號。不過在使用這些擴展符號的時候需要使用egrep命令。
| 擴展元字符 | 作用 |
| + | 前一個字符匹配1次或任意多次。例:go+gle會匹配gogle、google或gooole如果有更多個o也會匹配。 |
| ? | 前一個字符匹配0次或1次。 如colou?r可以匹配colour或color。 |
| | | 匹配兩個或多個分支選擇。 如was|his會匹配包含was的行,也會匹配包含his的行。 |
| () | 匹配其整體為一個字符,可以理解為由多個單個字符組成的 大字符。 如(dog)+會匹配dog、dogdog、dogdogdog等,因為被()包含的字符會當成 一個整體。 但hello (world | earth ) 會匹配hello world 及 hello earth |
1.()括號模式單元的使用:
【】# cat test
love is lover
like is liker
love is liker
like is lover
【】# egrep --color=auto "(l..e).*(l..e)" ./test
love is lover
like is liker
love is liker
like is lover
【】# egrep --color=auto "(l..e).*(\1)" ./test
#可用(\1)表示引用第一個模式單元,也就是第一次匹配第一行(l..e)在匹配到love的時候,就確定了l和e之間的..為o和v,在之后(\1)引用的時候也只會匹配love的字符串。
第二行like同理。第二行匹配時..變成了ik,所以匹配到了后邊like字符串,而不能匹配love字符串。
love is lover
like is liker
四、字符截命令和替換命令
1.cut列提取命令:
子選項:-f 列號 #提取第幾列
-d 分隔符??? #按照指定分隔符分割列
-c 字符范圍? #不依賴分隔符來區分列,而是通過字符范圍(行首為0)來進行字段提取。
“n-”表示從第n個字符到行尾:“n-m”從第n個字符到第m個字符:“-m”表示從第1個字符到第m個字符。
cut命令的默認分隔符是制表符。
首先建立一個測試文件:
【】# cat cj.txt
ID?? Name?? gender Mark
1 ??? zhaosan??? M?? 87
2 ??? lisi?? ??? M?? 90
3 ??? wangwu ??? M?? 9
[root@localhost ~]# cut -f 2 cj.txt???? #提取第二列內容
Name
zhaosan
lisi
wangwu
如果想要提取多列的時候,只要將列號用“,”分開:
【】# cut -f 2,3 cj.txt
Name ??? gender
zhaosan? ??? M
lisi ??? ??? M
wangwu?? ??? M
cut可以按照字符進行提取,需要注意的是“8-”代表的是提取所有行的第八個字符開始到行尾。而“10-20”代表提取所有行的第十個字符到第二十個字符。“-8”代表的是提取所有行從行首到第八個字符:
【】# cut -c -8 cj.txt
ID?? ??? Name
1 ?? ??? zhaosa
2 ?? ??? lisi ? M ? ???
3 ?? ??? wangwu
(提取開頭到第八個字符。結果格式還是比較亂的。因為每行字符個數不相等)
【】# cut -d ":" -f 1,3 /etc/passwd
root:0
bin:1
daemon:2adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
(以:為分隔符,提取/etc/passwd文件的第一列和第三列)
如果想用cut命令截取df命令的第一列和第三列,格式如下:
【】# df -h | cut -d " " -f 1
Filesystem
/dev/sda3
tmpfs
/dev/sda1
/dev/sr0
(但是cut命令不夠智能,因為在截取1列之后。如果繼續截取2,3,4,5.....都會返回為空。因為df -h 的返回值空格太多了)
2.文本處理工具awk
1)awk是基于列的文本處理工具,awk認為文件都是結構化的,也就是說都是由單詞和各種空白字符組成的,這里的“空白字符”包括空格、TAB以及連續的空格和TAB等。每個非空白的部分叫做“域”從左到右依次是第一個域第二個域等。$1、$2分別用于表示域,$0則表示全部域。
-F “”? 指定分割符
$NF?? 最后一列
3.printf格式化輸出:
print和printf區別:
使用printf 需要指定字段格式
使用print? 默認輸出格式
格式:printf ‘輸出類型輸出格式’ 輸出內容
輸出類型:
%ns:輸出字符串。n是數字指左對齊的情況下格式寬度“%-ns表示左對齊”。
%ni:輸出整數。n是數字指右對齊的情況下格式寬度“%-ni表示左對齊”。
%m.nf:輸出浮點數。m和n是數字,指代輸出的整數位和小數位。但整數位并不會受限。小數位四舍五入
輸出格式:輸出格式要加雙引號
\n?? #換行。
\t?? #水平輸出退格鍵,也就是tab鍵。
我們繼續用cj.txt文件演示printf命令:
【】# printf '%s' $(cat ./cj.txt)
IDNamegenderMark1zhaosanM872lisiM903wangwuM89
【】#
【】#
(在使用printf命令時,如果不指定格式就會把所有輸出內容連在一起。在我們使用cat等文本輸出命令之所以可以按照格式輸出,是因為cat命令已經設定了輸出格式。那么,為了用printf輸出合理的格式,應該進行如下操作)
【】# printf '%s\t%s\t%s\t%s\t\n' $(cat ./cj.txt)
ID? ??? Name?? ??? gender ??? Mark
1?? ??? zhaosan??? ??? M?? ??? 87
2?? ??? lisi?? ??? ??? M ? ??? 90
3 ? ??? wangwu ??? ??? M ? ??? 89
(注意:在printf命令的單引號中,只能識別格式輸出符號,而手工輸入的空格是無效的)
如果不想把成績當成字符串輸出,二十按照整數和浮點型輸出則需要進行如下操作:
【】# cat ./cj.txt
ID ??? Name ? ??? gender ??? ??? Mark
1 ? ??? zhaosan ?? M ? ??? ??? ??? 87.12
2 ? ??? lisi?? ??? M ? ??? ??? ??? 90.123
3 ? ??? wangwu ??? M ? ??? ??? ??? 89.1233322
(為了測試浮點型的作用首先修改cj.txt文件)
【】# printf '%i\t%s\t%s\t%8.2f\t\n' $(cat cj.txt | grep -v Name)
1 ? ??? zhaosan ?? M ? ??? 87.12
2 ? ??? lisi ? ??? M ? ??? 90.12
3 ? ??? wangwu ??? M ? ??? 89.12
(成功輸出了文件內信息,浮點型只輸出小數點后兩位。)
4.awk基本使用
awk使用格式:awk ‘條件1{動作1} 條件2{動作2}....’ 文件名
條件(Pattern):
一半使用關系表達式作為條件。這些關系表達式非常多。
例如:x>10????? 判斷變量x是否大于10
x == y?? 判斷變量x是否等于y
A !~ B?? 判斷字符串A是否不包含能匹配B表達式的字符串
動作(Action):
格式化輸出
流程控制語句
我們首先學習awk基本用法,也就是只看看格式化輸出動作的作用是什么。條件類型和流程控制語句我們在后面再詳細介紹:
-F “”? 指定分割符
$NF?? 最后一列
awk的保留字:
| 條件 | 條件 |
| BEGIN | 在awk程序一開始時,尚未讀取任何數據之前執行BEGIN后的動作只在程序開始執行一次 |
| END | 在awk程序處理完所有數據,即將結束時執行。 END后的動作只在程序結束時執行一次。 |
關系運算符:
關系運算符如果查找字符的話,要加雙引號。
| 條件 | 說明 |
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
| == | 等于。用于判斷兩個值是否相等,如果是變量賦值請使用“=”號 |
| != | 不等于 |
| ~ | 判斷字符串A中是否包含能匹配B表達式的字符串 |
| !~ | 判斷字符串A中 是否不包含能匹配B表達式的字符串 |
正則表達式:
| /正則表達式/ | 如果在“//”中可以寫入字符,也可以支持正則表達式 |
awk內置變量
| awk內置變量 | 作用 |
| $0 | 代表目前awk所讀入的整行數據。我們已知awk是一行一行讀入數據的,$0就代表當前讀入行的整行數據。 |
| $n | 代表目前讀入行的第n個字段。 |
| NF | 當前行擁有的字段(列)總數。 |
| NR | 當前awk所處理的行,是總數據的第幾行。 |
| FS | 用戶定義分隔符。awk的默認分隔符是空格。如果想要使用其他分隔符需要FS變量定義。 可以使用FS定義分隔符但是要制定條件為BEGIN否則第一行不生效。 |
【】# awk '{printf $2 "\t" $3 "\n"}' cj.txt #awk后的的格式要加單引號
Name ? ??? gender
zhaosan??? M
lisi?? ??? ??? ??? ??? M
wangwu ??? M
#列出第二列和第六列
在之前用cut截取df命令的結果時,結果并不盡如人意。那么試試awk命令:
【】# df -h | awk '{print $1 "\t" $3}'
Filesystem
Used
/dev/sda3 ??? ??? 3.8G
tmpfs 224K
/dev/sda ? ??? ??? 130M
/dev/sr0 ? ??? ??? 4.2G
通過awk命令可以截取指定的列,但是會發現格式并不是很規范,awk也是有命令可以調整截取后列的格式的左右對齊:
【】# df -h | awk '{printf "%-30s %-30s\n",$1,$5}'
文件系統 ? ??? ??? ??? ??? ??? 已用%
devtmpfs?? ??? ?? ??? ??? 0%
tmpfs ??? ??? ??? ??? ??? 0%
tmpfs? ??? ??? ?? ??? ??? 1%
tmpfs ??? ??? ??? ??? ??? 0%
/dev/mapper/cl-root ??? 10%
/dev/sda1 ??? ??? ??? ??? 14%
tmpfs ??? ??? ??? ??? ??? 1%
tmpfs ??? ??? ??? ??? ??? 1%
例1:顯示時使用10個字符串右對齊顯示。如果要是顯示字符串不夠10個寬度,以字符串的左邊自動添加。一個字符占一個寬度,默認是右對齊。
【】# awk -F ":" '{printf "%10s\n",$1}' /etc/passwd
root
bin
daemon
adm
例2:使用10個寬度,左對齊顯示:
【】# awk -F ":" '{printf "%-10s\n",$1}' /etc/passwd
rootbin
daemon
adm
例3:第1列使用15個字符寬度左對齊輸出,最后一列($NF)使用15個字符寬度右對齊輸出
[root@xuegod63 ~]# awk -F: '{printf "USERNAME: %-15s %15s\n",$1,$NF}'
/etc/passwd
USERNAME: root??? ??? /bin/bash
USERNAME: bin ??? ??? /sbin/nologin
awk的條件
不寫BEGIN每次對每行執行每個動作
BEGIN 在開頭執行一次
END在結尾執行一次
awk的保留字:
| 條件 | 條件 |
| BEGIN | 在awk程序一開始時,尚未讀取任何數據之前執行BEGIN后的動作只在程序開始執行一次 |
| END | 在awk程序處理完所有數據,即將結束時執行。 END后的動作只在程序結束時執行一次。 |
如果有多個BEGIN或END語句,awk會按照他們出現在程序當中的順序來執行。
關系運算符:
關系運算符如果查找字符的話,要加雙引號。
| 條件 | 說明 |
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
| == | 等于。用于判斷兩個值是否相等,如果是變量賦值請使用“=”號 |
| != | 不等于 |
| ~ | 判斷字符串A中是否包含能匹配B表達式的字符串 |
| !~ | 判斷字符串A中 是否不包含能匹配B表達式的字符串 |
正則表達式:
| /正則表達式/ | 如果在“//”中可以寫入字符,也可以支持正則表達式 |
BEGIN:awk的保留字,是一種特殊的文件類型。BEGIN的執行時機是“在awk程序一開始時,尚未讀取任何數據之前執行。”一旦BEGIN后的動作執行一次,當awk開始從文件中讀入數據,BEGIN的條件就不再成立,所以BEGIN定義的動作只能被執行一次。
例:
【】# awk '{printf "This is a cj \n"} {printf $2 "\t" $6 "\n"}' cj.txt
This is a cj
Name
This is a cj
zhaosan
This is a cj
lisi
This is a cj
wangwu
(首先如果不加BEGIN的話,this is a cj 會在每行后打印)
【】# awk 'BEGIN {printf "This is a cj \n"} {printf $2 "\t" $4
"\n"}' cj.txt
This is a cj
Name
Mark
zhaosan 87.12
lisi
90.123wangwu 89.1233322
(添加BEGIN,讓this is a cj在程序開始時執行)
END:也是awk的保留字,不過剛好和BEGIN相反。END是在awk程序處理完所有數據,即將結束時執行。END后的動作只在程序結束時執行一次。
例:
【】# awk 'END {printf "The END \n"} {printf $2 "\t" $4 "\n"}'
cj.txt
Name ? ??? Mark
zhaosan ?? 87.12
lisi ? ??? 90.123
wangwu ??? 89.1233322
The END
(在輸出結尾輸出“the end”這并不是文檔本身的內容,而且只會執行一次。)
所有BEGIN應該放在起始處,而END語句應該放在結尾。
關系運算符:
舉例來說,加入想要查找成績大89分的學員,就可以進行如下操作:
【】# cat cj.txt | grep -v Name | awk '$4 >= 89 {printf $2 "\n"}'
lisi
wangwu
加入了條件之后,只有條件成立動作才會執行,如果條件不滿足,則動作不運行。通過這個
實驗大家可以發現,雖然awk是列提取命令,但是也要按行來讀入的。
例:想查找用戶lisi的成績:
【】# cat cj.txt
ID ??? Name ? gender ??? Mark
1 ? ??? zhaosan ?? M ? ??? 87.12
2 ? ??? lisi ? ??? M ? ??? 90.123
3 ? ??? wangwu ??? M ? ??? 89.1233322
【】# awk '$2~ /lisi/ {printf $4 "\n"}' cj.txt
90.123
(注:在awk中使用//包含的字符串,awk命令才會查找。也就是說字符串必須使用//包含,
awk命令才能正確識別。)
※正則表達式:如果想要讓awk識別字符串,必須使用//包含。
例:
【】# awk '/wangwu/ {print}' cj.txt
3
wangwu M
89.1233322
#打印wangwu的成績
(awk中如果輸出字符的話,有兩種處理方式。print和printf。兩種方式的區別在于:
printf:可以自定義輸出的模式,另外輸出內容之后不自動換行,print:輸出內容之后自動換行。print 中不能使用%s ,%d 或%c。)
當使用df命令查看分區使用情況時,如果只想查看真正的系統分區的使用情況,而不想查看光盤和臨時分區的使用情況時:
【】# df -h | awk '/sda[0-9]/ {printf $1 "\t" $5 "\n"}'
/dev/sda3 ??? 23%
/dev/sda1 ??? 16%
(查詢包含有sda數字的行,并打印第一字段和第五字段。)
5)awk內置變量
| awk內置變量 | 作用 |
| $0 | 代表目前awk所讀入的整行數據。我們已知awk是一行一行讀入數據的,$0就代表當前讀入行的整行數據。 |
| $n | 代表目前讀入行的第n個字段。 |
| NF | 當前行擁有的字段(列)總數。 |
| NR | 當前awk所處理的行,是總數據的第幾行。 |
| FS | 用戶定義分隔符。awk的默認分隔符是空格。如果想要使用其他分隔符需要FS變量定義。 |
例:
[root@localhost ~]# cat /etc/passwd | grep "/bin/bash" | awk '{FS=":"} {printf $1 "\t" $3 "\n"}'
root:x:0:0:root:/root:/bin/bash
(這里“:”生效了。但是并沒有把第一列和第三列截取出來,繼續用BEGIN命令試試)
[root@localhost ~]# cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN{FS=":"} {printf $1 "\t" $3 "\n"}'
root 0
(成功截取第一和第三字段的內容)
cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN {FS=":"} {printf $1 "\t" $3"\t" NR
"\t"NF"\n"}'
root ? 0 ? 1 ? 7
(分隔符是“:” 輸出第一字段和第三字段 輸出行號(NR) 字段數(NF))
如果只想查看sshd這個偽用戶的相關信息需要:cat /etc/passwd | awk 'BEGIN {FS=":"} $1=="sshd" {printf $1 "\t" $3 "\t" NR "\t" NF "\n"}'
sshd ? 74 ??? 32 ??? 7
(可以看到sshd偽用戶的UID是74,是/etc/passwd文件的第32行,共有7個字段)
?
6.awk流程控制
我們繼續用cj.txt文件做練習。首先看一下文件內容:
【】# cat /root/cj.txt
ID ??? Name ? ??? gender ??? ??? Mark
1 ? ??? zhaosan ?? ??? M?? ??? ?? 87.12
2 ? ??? lisi ? ??? ??? M ? ??? ??? 90.123
3 ? ??? wangwu ??? ??? M ? ??? ??? 89.1233322
假設想要統計本次成績的總分,那么我們應該:
【】# awk 'NR==2{cj1=$4}
> NR==3{cj2=$4}
> NR==4{cj3=$4;totle=cj1+cj2+cj3;print "totle cj is" totle}' cj.txt
totle cj is266.366
接下來,演示如何實現流程控制,假設如果成績大于90,就是goodboy:
【】# awk '{if (NR>=2) {if ($4>=90) print $2 " is a good boy \n"}}' cj.txt
lisi is a good boy
7.awk中調用腳本
例:
【】# cat pass.awk
BEGIN {FS=":"}
{print$1"\t"$3}
【】# awk -f pass.awk /etc/passwd
#用-f選項來調用這個腳
本。
root ? ??? 0
bin ?? ??? 1
daemon ??? 2
(此腳本可以用于/etc/passwd、/etc/shadow、/etc/group等以:為分隔符文件的查看)
五、.sed命令 文件內增,刪,替換
????????sed主要是用來將數據進行選取,替換,刪除,新增的命令。sed通過一次僅讀取一行內容來對某些指令進行處理后輸出。首先sed通過文件或管道讀取文件內容,但sed默認并不輸出直接修改源文件,而是將讀入的內容復制到緩沖區域中,稱之為模式空間。
其語法如下:sed?? [選項] ‘[動作]’ 文件名
選項:
-n???? 一般sed命令會把所有數據都輸出到屏幕,如果加入此選項,則只會把經過sed命令處理的行輸出到屏幕。
-e?? 允許對輸入數據應用多條sed命令編輯。
-f?? 腳本文件名? 從sed腳本中讀入sed操作。和awk命令的-f非常相似。
-r??? 在sed中支持擴展正則表達式。
-i??? 用sed的修改結果直接修改讀取數據的文件,而不是由屏幕輸出動作。
a???? 追加,在當前行后添加一行或多行。添加多行時,除最后一行外,每行末尾需要用\代表數據未完結。
c???? 行替換,用c后面的字符串替換原數據行。替換多行時,除
最后一行外,每行末尾需要用\代表數據未完結。
i???? 插入,在當前行前插入一行或多行。插入多行時,除最后一
行外,每行末尾需要用\代表數據為完結。
d???? 刪除,刪除指定的行。
p???? 打印,輸出指定的行。
s???? 字符串替換,用一個字符串替換另外一個字符串。格式
為“行范圍s/舊字串/新字串/g”(和vim中替換格式類似)
例:
行數據操作:
【】# sed '2p' cj.txt
ID ??? Name ? ??? gender ??? ??? Mark
1 ? ??? zhaosan ?? M ? ??? ??? ??? 87.12
1 ? ??? zhaosan??? M ? ??? ??? ??? 87.12
2 ? ??? lisi ? ??? M ? ??? ??? ??? 90.123
3 ? ??? wangwu ??? M ? ??? ??? ??? 89.1233322
(查看cj.txt文件中第二行。p選項的確輸出了第二行數據,但是sed命令還是會把所有數據都輸出一次,這時就會顯示為上邊的效果。如果想要指定輸出某行數據,就需要添加-n選項了。)
【】# sed -n '2p' cj.txt
1 ? ??? zhaosan M ??? 87.12
(添加-n選項,只輸出了cj.txt中的第二行。)
如何刪除文件中數據?[root@localhost ~]# sed '1,3d' cj.txt
#刪除第一行到第三行的數據。
3 ? ??? wangwu M ??? 89.1233322
【】# cat cj.txt
#但是文件本身并沒有進行
刪除。
ID ??? Name ? ??? gender ??? ??? Mark
1 ? ??? zhaosan??? M ? ??? ??? ??? 87.12
2 ? ??? lisi?? ??? M ? ??? ??? ??? 90.123
3 ? ??? wangwu ??? M ? ??? ??? ??? 89.1233322
如何在文件中追加數據?
【】# sed '4a hello' cj.txt
#在第四行后加入hello。
ID ??? Name ? ??? gender ??? ??? Mark
1 ? ??? zhaosan??? M ? ??? ??? ??? 87.12
2 ? ??? lisi ? ??? M ? ??? ??? ??? 90.123
3 ? ??? wangwu ??? M ? ??? ??? ??? 89.1233322
hello
(“a”會在指定行后面追加數據,如果想要在指定行前面插入數據,則需要使用“i”。)
【】# sed '2i hello \
> world' cj.txt
ID ??? Name ? ??? gender ??? ??? Mark
hello
world
#在第二行前面插入兩行數
據。
1 ? ??? zhaosan??? M ? ??? ??? ??? 87.12
2 ? ??? lisi ? ??? M ? ??? ??? ??? 90.123
3 ? ??? wangwu ??? M ? ??? ??? ??? 89.1233322
(如果是想追加或插入多行數據,除最后一行外,每行的末尾都要加入“\”代表數據未完結。)
【】# sed -n '2i hello \
world' cj.txt
hello
world
(還可以加入-n選項,只查看sed命令的操作)
數據替換:假設lisi成績太好了,想要把他的成績進行替換:
【】# cat cj.txt | sed '3c No such preson'ID
1 ? ??? zhaosan??? M ? ??? ??? ??? 87.12
2 ? ??? lisi ? ??? M ? ??? ??? ??? 90.123
NO such preson
3 ? ??? wangwu ??? M ? ??? ??? ??? 89.1233322
sed命令默認情況是不修改文件內容的,在確定要讓sed命令直接處理文件的內容的情況下,可以使用-i選項。
例:
【】# sed -i '3c No such preson' cj.txt
【】# cat cj.txt
1
zhaosan M 1 ? ??? zhaosan??? M ? 87.12
2 ? ??? lisi ? ??? M ? ??? ??? ??? 90.123
No such preson
3 ? ??? wangwu ??? M ? ??? ??? ??? 89.1233322
字符串替換:
“c”動作是進行整行替換的,如果僅僅想替換行中的部分數據,就要使用“s”動作了。
s動作的格式是:sed ‘s/舊字串/新字串/g’ 文件名
比如:
sed '5s/lod/new/2' ./test.txt
#表示替換第五行中出現的第二個old為new。
例如將wangwu的分數進行替換:
[root@localhost ~]# sed '4s/89.1233322/90/g' cj.txt
#在第四行中,把
89...換成90。
ID
1 ? ??? zhaosan??? M ? ??? ??? ??? 87.12
2 ? ??? lisi ? ??? M ? ??? ??? ??? 90.123
3 ? ??? wangwu ??? M ? ??? ??? ??? 90
(如果要修改的字符串是唯一的,那么可以不指定行號。但如果一個文件中存在多個相同字符的時候,不執行行號,就會替換所有舊字符為新字符。)
加入g是表示所有"舊字符串"替換成"新字符串"。如果不加入g那么會替換每行第一個查找到的"舊字符串",也就是說如果一行內出現多個"舊字符串"只替換第一個,其余不替換。g可以用數字代替表示替換某行內找到的第幾個"舊字符串"。
比如:
sed '5s/lod/new/2' ./test.txt
#表示替換第五行中出現的第二個old為new。
【】# cat test.txt
hello world hello world
hello world hello worldhello world hello world
【】# sed '1s/world/linux/2' test.txt
hello world hello linux
hello world hello world
hello world hello world
替換擴展:
【】# sed '/SELINUX/ s/enforcing/xxx/g' /etc/selinux/config
#替換指定文件中含有SELINUX行中的enforcing字符串為xxx。
【】# sed '/SELINUX/ !s/enforcing/xxx/g' /etc/selinux/config
#替換指定文件中所有enforcing為xxx但是不包括含有SELINUX的行。
【】# sed '/root/,/swap/ s/xfs/ext4/g' /etc/fstab
#從含有root的行開始到含有swap的字符串結束。匹配結果中帶有xfs的字符串全部替換成ext4。使用行內字符串確定替換字符串的范圍。
如果想要將zhaosan成績注釋,可以進行如下操作:
【】# sed '2s/^/#/g' cj.txt
#1 ??? zhaosan??? M ? ??? ??? ??? 87.12
2 ? ??? lisi ? ??? M ? ??? ??? ??? 90.123
3 ? ??? wangwu ??? M ? ??? ??? ??? 89.1233322
(這里使用正則表達式^代表行首。)
指定范圍加注釋:
【】# sed '1,3s/^/#/g' cj.txt
#ID ?? Name ? ??? gender ??? ??? Mark
#1 ??? zhaosan??? M ? ??? ??? ??? 87.12
#2 ??? lisi ? ??? M ? ??? ??? ??? 90.123
#3 ??? wangwu ??? M ? ??? ??? ??? 89.1233322
(指定范圍1-3行加#注釋。)
因為在sed中只能指定范圍,所以如果想要把zhaosan、wangwu注釋的話。只能:
【】# sed -e 's/zhaosan//g ; s/wangwu//g' cj.txt
ID? ?? Name ? ??? gender ??? ??? Mark
1 ? ??? ??? ??? ??? M ? ??? ??? ??? 87.12
2 ? ??? lisi ? ??? M ? ??? ??? ??? 90.123
3 ? ??? ??? ??? ??? M ? ??? ??? ??? 89.1233322
-e選項可以同時執行多個sed動作,當然如果只執行一個動作也是可以使用-e選項的,但沒什么意義。還要注意,多個動作之間要用;或回車分割。
例如還可以這么寫:
【】# sed -e 's/zhaosan//g
> s/wangwu//g' cj.txt
ID ??? Name ? ??? gender ??? ??? Mark
1 ? ??? ??? ??? ??? M ? ??? ??? ??? 87.12
2 ? ??? lisi ? ??? M ? ??? ??? ??? 90.123
3 ? ??? ??? ??? ??? M ? ??? ??? ??? 89.1233322
(回車后不能進行tab補全......)
總結
以上是生活随笔為你收集整理的shell基础--正则表达式行列提取的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html游戏寻宝,达内:用scratch
- 下一篇: 【数据分析与挖掘实战】金融风控之贷款违约