6.VIM和正則表達式


1.VIM

1.1vim簡介

vim是一款強大的文本編輯器,它和 vi 使用方法一致,但功能更為強大。官網:www.vim.org、中文手冊:http://vimcdoc.sourceforge.net/

1.2使用vim

1.2.1命令格式

vim [options] [file ..]

常用選項

  • +# 打開文件后,讓光標處於第#行的行首,+默認行尾
  • +/PATTERN 讓光標處於第一個被PATTERN匹配到的行行首
  • -d file1 file2… 比較多個文件,相當於 vimdiff

說明:當使用vim打開文件的時候,如果該文件存在,文件被打開並顯示內容。如果該文件不存在,當編輯后第一次存盤時創建它

1.2.2vim三種模式的切換

三種模式分為

命令或普通模式、插入模式、擴展模式

  • 命令模式 --> 插入模式
i insert, 在光標所在處輸入
I 在當前光標所在行的行首輸入
a append, 在光標所在處后面輸入
A 在當前光標所在行的行尾輸入
o 在當前光標所在行的下方打開一個新行
O 在當前光標所在行的上方打開一個新行
  • 插入模式 --- ESC-----> 命令模式
  • 命令模式 ---- : ----> 擴展命令模式
  • 擴展命令模式 ----ESC,enter----> 命令模式

1.3擴展命令模式

1.3.1 基本命令
w 		寫(存)磁盤文件
wq 	寫入並退出
x		寫入並退出加密
q 		退出,如果修改了內容無法退出
q!   強制不存盤退出,即使更改都將丟失
r filename 讀文件內容到當前文件中
!command 	執行命令
r!command 	讀入命令的輸出
1.3.2 地址定界

格式

:start_pos,end_pos CMD

地址定界符

# 			#具體第#行,例如2表示第2行
#,# 		#從左側#表示起始行,到右側#表示結尾行
#,+# 		#從左側#表示的起始行,加上右側#表示的行數,范例:2,+3 表示2到5行
.   		#當前行
$ 			#最后一行
.,$-1 	#當前行到倒數第二行
% 			#全文, 相當於1,$

/pattern/   	#從當前行向下查找,直到匹配pattern的第一行,即:正則表達式
/pat1/,/pat2/ 	#從第一次被pat1模式匹配到的行開始,一直到第一次被pat2匹配到的行結束
#,/pat/     	#從指定行開始,一直找到第一個匹配patttern的行結束
/pat/,$     	#向下找到第一個匹配patttern的行到整個文件的結尾的所有行

地址定界后可跟一個編輯命令

d       	#刪除
y 			#復制
w file 	#將范圍內的行另存至指定文件中
r file 	#在指定位置插入指定文件中的所有內容
1.3.3 查找和替換
s/要查找的內容/替換為的內容/修飾符

說明

要查找的內容:可使用基末正則表達式模式
替換為的內容:不能使用模式,但可以使用\1, \2, ...等后向引用符號;還可以使用“&”引用前面查找時查
找到的整個內容

修飾符:

i #忽略大小寫
g #全局替換,默認情況下,每一行只替換第一次出現
gc #全局替換,每次替換前詢問

查找替換中的分隔符/可替換為其它字符,如:#,@

s@/etc@/var@g
s#/boot#/#i
1.3.4 定制vim

配置文件:

/etc/vimrc #全局
~/.vimrc #個人

#行號
顯示:set number,簡寫 set nu
取消顯示:set nonumber, 簡寫 set nonu

#忽略字符的大小寫
啟用:set ignorecase,簡寫 set ic
不忽略:set noic

#自動縮進
啟用:set autoindent,簡寫 set ai
禁用:set noai

#設置光標所在行的標識線
啟用:set cursorline,簡寫 set cul
禁用:set nocursorline

#Tab用指定空格的個數代替
啟用:set tabstop=# 指定#個空格代替Tab
簡寫:set ts=4

#文件格式
啟用windows格式:set fileformat=dos
啟用unix格式:set fileformat=unix
簡寫 set ff=dos|unix

#Tab 用空格代替
啟用:set expandtab 默認為8個空格代替Tab
禁用:set noexpandtab
簡寫:set et 

#語法高亮
啟用:syntax on
禁用:syntax of

#高亮搜索
啟用:set hlsearch
禁用:set nohlsearch

#顯示Tab和換行符 ^I 和$顯示
啟用:set list
禁用:set nolist

#set showcmd
顯示命令模式下輸入的字符

1.4 命令模式

1.4.1 退出VIM

ZZ | wq 保存退出

ZQ | q 不保存退出

1.4.2 光標跳轉

字符間跳轉:

h: 左 L: 右 j: 下 k: 上

#COMMAND:跳轉由#指定的個數的字符

單詞間跳轉:

w:下一個單詞的詞首

e:當前或下一單詞的詞尾

b:當前或前一個單詞的詞首

#COMMAND:由#指定一次跳轉的單詞數

當前頁跳轉:

H:頁首 M:頁中間行 L:頁底

zt:將光標所在當前行移到屏幕頂端

zz:將光標所在當前行移到屏幕中間

zb:將光標所在當前行移到屏幕底端

行首行尾跳轉:

^ 跳轉至行首的第一個非空白字符

0 跳轉至行首

$ 跳轉至行尾

行間移動:

#G 或者擴展命令模式下 :# 跳轉至由第#行

G 最后一行

1G, gg 第一行

命令模式翻屏操作

Ctrl+f 向文件尾部翻一屏

Ctrl+b 向文件首部翻一屏

Ctrl+d 向文件尾部翻半屏

Ctrl+u 向文件首部翻半屏

1.4.3 字符編輯

x 刪除光標處的字符

#x 刪除光標處起始的#個字符

xp 交換光標所在處的字符及其后面字符的位置

1.4.4 替換命令(replace)

r 只替換光標所在處的一個字符

R 切換成REPLACE模式(在末行出現-- REPLACE -- 提示),按ESC回到命令模式

1.4.5 刪除命令(delete)

d 刪除命令,可結合光標跳轉字符,實現范圍刪除

d$ 刪除到行尾

d^ 刪除到非空行首

d0 刪除到行首

dd: 剪切光標所在的行

#dd 多行刪除

D:從當前光標位置一直刪除到行尾,等同於d$

1.4.6 復制命令(yank)

y 復制,行為相似於d命令

1.4.7 粘貼命令(paste)

p 緩沖區存的如果為整行,則粘貼當前光標所在行的下方;否則,則粘貼至當前光標所在處的后面

P 緩沖區存的如果為整行,則粘貼當前光標所在行的上方;否則,則粘貼至當前光標所在處的前面

1.4.8 改變命令(change)

c: 刪除后切換成插入模式

c$

c^

c0

cb

1.4.9 查找

/PATTERN:從當前光標所在處向文件尾部查找

?PATTERN:從當前光標所在處向文件首部查找

n:與命令同方向

N:與命令反方向

1.4.10 撤消更改

u 撤銷最近的更改,相當於windows中ctrl+z

#u 撤銷之前多次更改

U 撤消光標落在這行后所有此行的更改

Ctrl - r 重做最后的“撤消”更改,相當於windows中crtl+y

. 重復前一個操作

#. 重復前一個操作#次

1.4.11 高級用法

常見Command:y 復制、d 刪除、gU 變大寫、gu 變小寫

范例

0y$ 命令
#粘貼一個字符100次
100ihello [ESC] 

di" 光標在” “之間,則刪除” “之間的內容

yi( 光標在()之間,則復制()之間的內容

vi[ 光標在[]之間,則選中[]之間的內容

dtx 刪除字符直到遇見光標之后的第一個 x 字符

ytx 復制字符直到遇見光標之后的第一個 x 字符

1.5 可視化模式

在末行有”-- VISUAL -- “指示,表示在可視化模式

進入可視化模式按鍵

  • v 面向字符,-- VISUAL --
  • V 面向整行,-- VISUAL LINE --
  • ctrl-v 面向塊,-- VISUAL BLOCK --

1.6 多文件模式

vim FILE1 FILE2 FILE3 ...

:next 下一個

:prev 前一個

:first 第一個

:last 最后一個

:wall 保存所有

:qall 不保存退出所有

:wqall保存退出所有

1.7 多窗口模式

1.7.1 多文件分割

vim -o|-O FILE1 FILE2 ...

-o: 水平或上下分割

-O: 垂直或左右分割(vim only)

在窗口間切換:Ctrl+w+方向鍵

1.7.2 單文件窗口分割

Ctrl+w+s:split, 水平分割,上下分屏

Ctrl+w+v:vertical, 垂直分割,左右分屏

ctrl+w+q:取消相鄰窗口

ctrl+w+o:取消全部窗口

:wqall 退出

1.8 vim寄存器

有26個命名寄存器和1個無命名寄存器,常存放不同的剪貼版內容,可以在同一個主機的不同會話(終 端窗口)間共享

寄存器名稱a,b,…,z,格式: ”寄存器 放在數字和命令之間

范例:

3"tyy 表示復制3行到t寄存器中 ,末行顯示 3 lines yanked into "t
"tp 表示將t寄存器內容粘貼

1.9 標記和宏(macro)

ma 將當前位置標記為a,26個字母均可做標記, mb 、 mc 等等

'a 跳轉到a標記的位置,實用的文檔內標記方法,文檔中跳躍編輯時很有用

qa 錄制宏 a,a為宏的名稱,末行提示: recording @a

q 停止錄制宏

@a 執行宏 a

@@ 重新執行上次執行的宏

2 文本常見處理工具

2.1查看文件內容

2.1.1 cat

cat 可以查看文本內容

cat [OPTION]... [FILE]...

常見選項

  • -E:顯示行結束符$
  • -A:顯示所有控制符
  • -n:對顯示出的每一行進行編號
  • -b:非空行編號
  • -s:壓縮連續的空行成一行
2.1.2 nl

nl:顯示行號,相當於cat -b

nl [OPTION]... [FILE]...	
2.1.3 tac

tac:逆向顯示文本內容

tac [OPTION]... [FILE]...
2.1.4 rev

rev:將同一行的內容逆向顯示

rev [option] [file...]
[root@centos8 data]# rev lx.txt 
ba321
[root@centos8 data]# cat lx.txt 
123ab
2.1.5 hexdump

hexdump:以十六進制,十進制,八進制或ASCII顯示文件內容

hexdump [options] file...

-C 十六進制+ASCII顯示
[root@centos8 data]# hexdump -C lx.txt 
00000000  31 32 33 61 62 0a                                 |123ab.|
00000006
[root@centos8 data]# cat lx.txt 
123ab

2.2分頁查看文本內容

2.2.1 more

more:分頁查看文件(文本翻至尾部就會自動退出)

more [options] file...

常見選項

  • -d 顯示翻頁以及退出提示
2.2.2 less

less:分頁查看文件(文本末頁不會自動退出)

less 命令是man命令使用的分頁器

[root@centos8 data]# cat passwd | less

2.3 顯示文本前或后行內容

2.3.1 head

head:顯示文件或者標准輸入前面內容

head [OPTION]... [FILE]...

常見選項

  • -c # 指定獲取前#字節
  • -n # 指定獲取前#行
  • -# 同上

范例

[root@centos8 data]# head -2 lx.txt 
1
2
2.3.2 tail

tail:和head 相反,查看文件或標准輸入的倒數行

tail [OPTION]... [FILE]...

常用選項

  • -c # 指定獲取后#字節
  • -n # 指定獲取后#行
  • -# 同上
  • -f 跟蹤顯示文件fd新追加的內容,常用日志監控,相當於 --follow=descriptor,當文件刪除再新建同名 文件,將無法繼續跟蹤文件
  • -F 跟蹤文件名,相當於--follow=name --retry,當文件刪除再新建同名文件,將可以繼續跟蹤文件
  • tailf 類似 tail –f,當文件不增長時並不訪問文件

范例

[root@centos8 data]# tail -2 /data/lx.txt 
9
10
#只查看最新發生的日志
[root@centos8 data]# tail -fn0 /data/lx.txt 
ab

2.4 cut

cut:提取文本文件或者STDIN數據指定列

cut OPTION... [FILE]...

常用選項

  • -d DELIMITER: 指明分隔符,默認tab

  • -f FILEDS:

    ​ #: 第#個字段,例如:3

    ​ #,#[,#]:離散的多個字段,例如:1,3,6

    ​ #-#:連續的多個字段, 例如:1-6

    ​ 混合使用:1-3,7

  • -c 按字符切割

  • --output-delimiter=STRING指定輸出分隔符

范例

#查看主機IP地址
[root@centos8 data]# ifconfig | head -2 | tail -1 | tr -s ' ' | cut -d' ' -f3
172.22.73.89
#顯示df命令中磁盤使用率
[root@centos8 data]# df | tr -s ' ' | cut -d' ' -f5 | tr -dc '[0-9\n]'
0
0
[root@centos8 data]# df | tr -s ' ' % | cut -d% -f5 | tr -d [:alpha:]

0
0

2.5 paste

paste:合並多個文件同行號列到一行

paste [OPTION]... [FILE]...

常用選項

  • -d 分隔符:指定分隔符,默認用TAB
  • -s : 所有行合成一行顯示

2.6 文本分析工具

2.6.1 wc

wc:統計文件的行總數、單詞總數、字節總數和字符總數

wc [OPTION]... [FILE]...

常用選項

  • -l 只計數行數
  • -w 只計數單詞總數
  • -L 顯示文件中最長行的長度
[root@centos8 data]# wc -l lx.txt 
2 lx.txt
2.6.2 sort

sort:把整理過的文本顯示在STDOUT,不改變原始文件

sort [OPTION]... [FILE]...

常用選項

  • -r 執行反方向(由上至下)整理
  • -R 隨機排序
  • -n 執行按數字大小整理
  • -u 選項(獨特,unique),合並重復項,即去重
  • -t c 選項使用c做為字段界定符
  • -k 指定排序的關鍵字

范例

#統計日志訪問量
[root@centos8 data]#cut -d" " -f1 /var/log/nginx/access_log |sort -u|wc -l
201

[root@centos8 data]# cut -d: -f1,3 passwd | sort -k2 -nr | head -5
user3:2004
user2:2003
user1:1002
user:1001
unbound:996
2.6.3 uniq

uniq:命令從輸入中刪除前后相接的重復的行

uniq [OPTION]... [INPUT [OUTPUT]]

常用選項

  • -c: 顯示每行重復出現的次數
  • -d: 僅顯示重復過的行
  • -u: 僅顯示不曾重復的行

uniq常和sort 命令一起配合使用:

范例

#統計日志訪問量最多的請求
[root@centos8 data]# cut -d" " -f1 access_log | sort | uniq -c | sort -nr | head -1
2834 172.20.0.222

#取兩個文件的相同行
[root@centos8 data]# cat a.txt b.txt | sort | uniq -d
200
#取兩個文件的不同行
[root@centos8 data]# cat a.txt b.txt | sort | uniq -u
100
123
23
3321
34556
2.6.4 diff

diff:令比較兩個文件之間的區別

diff [OPTION]... FILES

[root@centos8 data]# cat a.txt b.txt 
a
b
c
a
b
bc
[root@centos8 data]# diff a.txt b.txt 
3c3
< c
---
> bc

3 正則表達式

正則表達式分兩類:

​ 基本正則表達式:BRE

​ 擴展正則表達式:ERE

​ 幫助:man 7 regex

3.1 基本正則表達式元字符

與通配符不同,通配 符功能是用來處理文件名,而正則表達式是處理文本內容中字符

3.1.1 字符匹配
.   匹配任意單個字符,可以是一個漢字
[]   匹配指定范圍內的任意單個字符,示例:[wang]   [0-9]   [a-z]   [a-zA-Z]
[^] 匹配指定范圍外的任意單個字符,示例:[^wang]

[:alnum:] 字母和數字
[:alpha:] 代表任何英文大小寫字符,亦即 A-Z, a-z
[:lower:] 小寫字母,示例:[[:lower:]],相當於[a-z]
[:upper:] 大寫字母
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范圍廣)
[:cntrl:] 不可打印的控制字符(退格、刪除、警鈴...)
[:digit:] 十進制數字
[:xdigit:]十六進制數字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 標點符號
3.1.2 匹配次數
* 匹配前面的字符任意次,包括0次,貪婪模式:盡可能長的匹配
.* 任意長度的任意字符
\? 匹配其前面的字符0或1次,即:可有可無
\+ 匹配其前面的字符至少1次,即:肯定有,>=1
\{n\} 匹配前面的字符n次
\{m,n\} 匹配前面的字符至少m次,至多n次
\{,n\} 匹配前面的字符至多n次,<=n
\{n,\} 匹配前面的字符至少n次
3.1.3 位置錨定
^ 行首錨定,用於模式的最左側
$ 行尾錨定,用於模式的最右側
^PATTERN$ 用於模式匹配整行
^$ 空行
^[[:space:]]*$ 空白行
\< 或 \b 詞首錨定,用於單詞模式的左側
\> 或 \b 詞尾錨定,用於單詞模式的右側
\<PATTERN\> 匹配整個單詞
3.1.4 分組其它

分組

分組:() 將多個字符捆綁在一起,當作一個整體處理,如:(root)+ 后向引用:分組括號中的模式匹配到的內容會被正則表達式引擎記錄於內部的變量中,這些變量的命名 方式為: \1, \2, \3, ...

\1 表示從左側起第一個左括號以及與之匹配右括號之間的模式所匹配到的字符

或者

a\|b #a或b  
C\|cat #C或cat  
\(C\|c\)at #Cat或cat

3.2 擴展正則表達式

擴展正則於正則用法基本相同,大部分擴展正則相比正則只是取消了反斜線

3.2.1 字符匹配元字符
. 任意單個字符
[wang] 指定范圍的字符
[^wang] 不在指定范圍的字符
[:alnum:] 字母和數字
[:alpha:] 代表任何英文大小寫字符,亦即 A-Z, a-z
[:lower:] 小寫字母,示例:[[:lower:]],相當於[a-z]
[:upper:] 大寫字母
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范圍廣)
[:cntrl:] 不可打印的控制字符(退格、刪除、警鈴...)
[:digit:] 十進制數字
[:xdigit:]十六進制數字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 標點符號
3.2.2 次數匹配
*   匹配前面字符任意次
? 0或1次
+ 1次或多次
{n} 匹配n次
{m,n} 至少m,至多n次
3.2.3 位置錨定
^ 行首
$ 行尾
\<, \b 語首
\>, \b 語尾
3.2.4 分組其它
() 分組
后向引用:\1, \2, ...
| 或者
a|b #a或b
C|cat #C或cat
(C|c)at #Cat或cat

4 文本處理三劍客

4.1 grep

grep:文本搜索工具,根據用戶指定的“模式”對目標文本逐行進行匹配檢查;打印匹配到的行

grep [OPTIONS] PATTERN [FILE...]

常用選項

  • -v 顯示不被pattern匹配到的行
  • -i 忽略字符大小寫
  • -n 顯示匹配的行號
  • -c 統計匹配的行數
  • -f file 根據模式文件處理
  • -E 使用ERE,相當於egrep
  • -o 僅顯示匹配到的字符串
  • -e 實現多個選項間的邏輯or關系,如:grep –e ‘cat ’ -e ‘dog’ file

范例

[root@centos8 data]# grep "whoami" /etc/passwd
[root@centos8 data]# grep `whoami` /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

#文件匹配
[root@centos8 data]# cat a.txt b.txt 
a
b
c
a
b
d
[root@centos8 data]# grep -f a.txt b.txt 
a
b

#查看磁盤最高使用率
[root@centos8 data]# df | grep ^/dev/vd | tr -s " " % | cut -d% -f5
7

#計算出所有人年齡之和
[root@centos8 data]# cat lx.txt 
xiaoming=20
xiaodong=18
xiaoqiang=22
[root@centos8 data]# cut -d= -f2 lx.txt | tr "\n" + | grep -Eo .*[0-9] | bc
60
[root@centos8 data]# grep -Eo [0-9]+ /data/lx.txt | tr "\n" + | grep -Eo .*[0-9] | bc
60

練習

1.統計出/etc/passwd文件中默認其shell為非/sbin/nologin的用戶個數,並將用戶都顯示出來
[root@centos8 data]# cat /etc/passwd | grep -v /sbin/nologin | cut -d: -f1
root
user
user1
slackware
user2
user3
2.查出用戶UID的最大值的用戶名、UID及shell類型
[root@centos8 data]# cut -d: -f1,3,7 /etc/passwd | sort -k2 -nr | head -1
user3:2004:/bin/bash
3.統計當前連接本機的每個遠程主機IP的連接數,並按從小到大排序
[root@centos8 data]# ss -nt | grep ^ESTAB | tr -s " " : | cut -d: -f6 | sort -nr
110.152.191.166
100.100.30.25
4.編寫腳本disk.sh,顯示當前硬盤分區中空間利用率最大的值
[root@centos8 data]# cat lx.txt 
#/bin/bash!
df | grep /dev/vd | tr -s " " % | cut -d% -f5
5.編寫腳本systeminfo.sh,顯示當前主機系統信息,包括:主機名,ipv4地址,操作系統版本,內核版本,cpu型號,內存大小,硬盤大小
  1 #/bin/bash!
  2 echo 主機名`hostname`
  3 echo 地址`ifconfig | head -3 | tail -2 | tr -s " " % | cut -d% -f3 | head -1`
  4 echo 操作系統版本`cat /etc/redhat-release`
  5 echo 內核版本`uname -r`
  6 echo cpu型號`cat /proc/cpuinfo | grep "model name" | cut -d: -f2`
  7 echo 內存大小 "`free -h | grep ^Mem | tr -s " " % | cut -d% -f2`"
  8 echo 硬盤大小`lsblk | grep 'vda\>' | grep -Eo '[0-9]+[[:upper:]]'`

4.2 sed

4.2.1 sed 工作原理

Sed是從文件或管道中讀取一行,處理一行,輸出一行,直到 最后一行。

4.2.2 sed 基本用法

格式:

sed OPTIONS... [SCRIPT] [INPUTFILE...]

常用選項:

  • -n 不輸出模式空間內容到屏幕,即不自動打印
  • -e 多點編輯
  • -r, -E 使用擴展正則表達式
  • -i.bak 備份文件並原處編輯
  • -f /PATH/SCRIPT_FILE 從指定文件中讀取編輯腳本

地址格式:

  • 不給地址:對全文進行處理

  • 單地址:

    #:指定某一行

    $: 最后一行

    /pattern/: 被模式匹配的所有行

  • 地址范圍:

    addr1,addr2 從addr1到addr2行

    addr1,+addr2 從addr1到addr1+addr2行

    /part1/,/part2/ 模式1到模式2

  • 步進:~

    1~2 奇數行

    2~2 偶數行

命令:

  • p 打印當前模式空間內容,追加到默認輸出之后

  • Ip 忽略大小寫輸出

  • d 刪除模式空間匹配的行,並立即啟用下一輪循環

  • a [\]text 在指定行后面追加文本,支持使用\n實現多行追加

  • i [\]text 在行前面插入文本

  • c [\]text 替換行為單行或多行文本

  • w /path/file 保存模式匹配的行至指定文件

  • r /path/file 讀取指定文件的文本至模式空間中匹配到的行后

  • = 為模式空間中的行打印行號

  • ! 模式空間中匹配行取反處理

  • s/REGEXP/REPLACEMENT/修飾符 查找替換,支持使用其它分隔符,可以是其它形式:s@@@,s### 替換修飾符:

  • g 行內全局替換

  • p 顯示替換成功的行

  • w /PATH/FILE 將替換成功的行保存至文件中

  • I,i 忽略大小寫

范例:

[root@centos8 data]# ifconfig eth0 | sed -n '2p'
        inet 172.22.74.86  netmask 255.255.240.0  broadcast 172.22.79.255

[root@centos8 data]# sed -n '/root/p' passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

[root@centos8 data]# cat seq.log 
1
2
3
4
5
6
7
8
9
10
[root@centos8 data]# sed -i.bak '2d;3d' seq.log
[root@centos8 data]# cat seq.log
1
4
5
6
7
8
9
10

[root@centos8 data]# sed -i '/abc/c\ 'qwe'' seq.log
[root@centos8 data]# cat seq.log
1
4
 qwe
6
7
8
9
10
[root@centos8 data]# sed -i 's/abc/def/' seq.log
[root@centos8 data]# cat seq.log
1
4
 qwe def
6
7
8
9
10

4.3 awk

4.3.1 awk 工作原理和基本用法說明

用於格式化文本輸出,有多個版本,GNU/Linux發布的AWK目前由自 由軟件基金會(FSF)進行開發和維護,通常也稱它為 GNU AWK。

gawk可以實現下面功能:

  • 文本處理
  • 格式化輸出
  • 執行算數運算和字符串操作

gawk工作過程

gawk工作過程

BEGIN模塊:

語法:
BEGIN	{action;… }

在awk開始從輸入流中讀取行之前被執行,只執行一次,這個模塊是可選的

END模塊:

語法:
END	{action;… }

在awk從輸入流中讀取完所有的行之后即被執行,只執行一次,這個模塊也是可選的

格式:

gawk [ POSIX or GNU style options ] -f program-file  file ...
gawk [ POSIX or GNU style options ]  program-text  file ...

常用選項:

  • -F fs 指明fs作為輸入時的分隔字符,默認分隔符是若干個連續空白符
  • -v var=value 變量賦值

program-text格式:

‘pattern   { action statements }’
pattern   { ‘action statements’}

注意:這里的單引號很有必要,如果沒有會報語法錯誤

pattern:決定動作語句何時觸發及觸發事件,而且當pattern的值為真才會觸發后續動作。

pattern常見類型:

  • BEGIN
  • END
  • 正則表達式

action statements:對數據進行什么處理,放在{}內指明

action statements常見類型:

  • output statements:print,printf
  • Expressions:算術,比較表達式等
  • Compound statements:組合語句
  • Control statements:if, while等
  • input statements

域和記錄

  • 每一條讀入記錄會由分隔符分隔為一個個字段,這些字段稱為域(field),用$1,$2,...,$n來標識域,$0則表示所有域
  • 文件的每一行稱為記錄record
  • 如果省略action,則默認執行 print $0 的操作
4.3.2 動作 print

格式:

print item1, item2, …

說明:

  • 逗號作為分隔符
  • 輸出item可以字符串,也可是數值;當前記錄的字段、變量或awk的表達式
  • 如省略item,相當於print $0
  • 固定字符符需要用" " 引起來,而變量和數字不需要

范例:

[root@centos8 ~]$awk 'BEGIN{print "hello"}'
hello

[root@centos8 ~]$awk -F: '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5

范例:取出網站訪問量最大的前3個IP

[root@centos8 data]$awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -3
     18 60.191.36.75
      6 209.141.33.74
      2 74.120.14.37

范例:取出分區利用率

[root@centos8 data]$df | grep "/dev/vd" | awk -F' +|%' '{print $5}'
7

請提取”.print.com”前面的主機名部分並寫入到回到該文件中

請提取”.print.com”前面的主機名部分並寫入到回到該文件中
[root@centos8 ~]#cat host_list.log
1 www.print.com
2 blog.print.com
3 study.print.com
4 linux.print.com
5 python.print.com

[root@centos8 ~]$awk -F' +|.' '{print $2}' host_list.log 
#上面這種寫法會把.當作正則表達式,所以不能輸出結果
[root@centos8 ~]#awk -F"[ .]" '{print $2}' host_list.log
www
blog
study
linux
python
[root@centos8 ~]#awk -F"[ .]" '{print $2}' host_list.log >> host_list.log
4.3.3 awk變量

awk中的變量分為:內置和自定義變量

常見內置變量:

  • FS:輸入字段分隔符,默認為空白字符,功能相當於 -F
  • OFS:輸出字段分隔符,默認為空白字符
  • RS:輸入記錄record分隔符,指定輸入時的換行符
  • ORS:輸出記錄分隔符,輸出時用指定符號代替換行符
  • NF:域數量
  • NR:記錄的編號
  • FILENAME:當前文件名
  • ARGC:命令行參數的個數
  • ARGV:數組,保存的是命令行所給定的各參數,每一個參數:ARGV[0],......

范例:

#FS
[root@centos8 data]$awk -v FS=' |*' '{print $2}' host_list.log 
www
blog
study
root@centos8 data]$awk -F' |*' '{print $2}' host_list.log 
www
blog
study

#OFS
[root@centos8 ~]$awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd | head -n1
root:0:/bin/bash

#RS
[root@centos8 data]$cat host_list.log 
1 www*print*com
[root@centos8 data]$awk -v RS=' ' '{print }' host_list.log
1
www*print*com

#ORS
[root@centos8 data]$awk -v RS=' ' -v ORS='###' '{print }' host_list.log
1###www*print*com
###

#NF
[root@centos8 data]$cat host_list.log 
1 www*print*com
[root@centos8 data]$awk '{print NF}' host_list.log 
2
[root@centos8 data]$awk '{print $(NF-1)}' host_list.log 
1

#NR
[root@centos8 data]$awk '{print NR,$2}' host_list.log 
1 www*print*com
[root@centos8 data]$ifconfig eth0 | awk 'NR==2{print $2}'
172.22.74.86

#FNR
[root@centos8 ~]#awk '{print NR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
3
4 CentOS Linux release 8.0.1905 (Core)
[root@centos8 script40]#awk '{print FNR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
3
1 CentOS Linux release 8.0.1905 (Core)

#FILENAME
[root@centos8 data]$awk '{print FILENAME}' host_list.log 
host_list.log

#ARGC
[root@centos8 data]$awk '{print ARGC}' /etc/issue 
2
2
2
第一個參數是awk,第二個是/etc/issue

自定義變量:

  • -v var=value
  • 在program中直接定義
[root@centos8 data]$awk -v name='tom cat' BEGIN'{print name}'
tom cat
[root@centos8 data]$awk 'BEGIN{name="tomcat";print name}'
tomcat
4.3.4 printf

與print不同的是printf可以自定義輸出格式

格式:

printf “FORMAT”, item1, item2, ...

說明:

  • 必須指定FORMAT
  • 不會自動換行,需要顯式給出換行控制符 \n
  • FORMAT中需要分別為后面每個item指定格式符

格式符:

  • %c:顯示字符的ASCII碼
  • %d, %i:顯示十進制整數
  • %e, %E:顯示科學計數法數值
  • %f:顯示為浮點數
  • %g, %G:以科學計數法或浮點形式顯示數值
  • %s:顯示字符串
  • %u:無符號整數
  • %%:顯示%自身

注意:格式符應與item一一對應

修飾符

#[.#] 第一個數字控制顯示的寬度;第二個#表示小數點后精度,如:%3.1f
- 左對齊(默認右對齊) 如:%-15s
+   顯示數值的正負符號   如:%+d

范例:

[root@centos8 data]$awk -F: '{printf "%s",$1}' /etc/passwd
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodydbussystemd-coredumpsystemd-resolvetsspolkitdlibstoragemgmtunboundsetroubleshootcockpit-wscockpit
[root@centos8 data]$awk -F: '{printf "%s\n",$1}' /etc/passwd
root
bin
......

[root@centos8 data]$awk -F: '{printf "%-20s %d\n",$1,$3}' /etc/passwd
root                 0
bin                  1
daemon               2
4.3.5 操作符

算數操作符:

x+y, x-y, x*y, x/y, x^y, x%y
-x:轉換為負數
+x:將字符串轉換為數值

賦值操作符:

=, +=, -=, *=, /=, %=, ^=,++, --

比較操作符:

==, !=, >, >=, <, <=

模式匹配符:

~ 左邊是否和右邊匹配,包含關系
!~ 是否不匹配

邏輯操作符:

與:&&,並且關系
或:||,或者關系
非:!,取反

條件表達式(三目表達式)

selector?if-true-expression:if-false-expression

范例:

#先加和后加
[root@centos8 data]$awk 'BEGIN{i=0;print i++,i}'
0 1
[root@centos8 data]$awk 'BEGIN{i=0;print ++i,i}'
1 1

[root@centos8 data]$awk -v n=1 '!n++{print n}' /etc/passwd
[root@centos8 data]$awk -v n=0 '!n++{print n}' /etc/passwd
1

#模式匹配
[root@centos8 data]$awk -F: '$0 ~ /root/{print $1}' /etc/passwd
root
operator

#變量取反值
[root@centos8 data]$awk 'BEGIN{print i}'

[root@centos8 data]$awk 'BEGIN{print !i}'
1
[root@centos8 data]$awk 'BEGIN{i="ab";print !i}'
0
[root@centos8 data]$awk -v i=0 'BEGIN{print !i}'
1
[root@centos8 data]$awk -v i='' 'BEGIN{print !i}'
1

#邏輯判斷
awk -F:   '$3>=0 && $3<=1000 {print $1,$3}' /etc/passwd
4.3.6 關於PATTERN

根據pattern條件,過濾匹配的行,再做處理

格式:

pattern { action statements }’

常用類型:

  • 未指定:空模式,匹配每一行
  • /regular expression/:僅處理能夠模式匹配到的行,需要用/ /括起來,而且使用擴展正則
  • relational expression: 關系表達式,結果為“真”才會被處理
  • /pat1/,/pat2/:從part1開始匹配到part2
  • BEGIN/END模式

范例:

#空模式
[root@centos8 data]$awk '{print $1}' /etc/redhat-release 
CentOS

#/regular expression/
[root@centos8 data]$awk '/UUID/{print $1}' /etc/fstab 
UUID=ccd25378-c82e-4bea-ad12-81fba73fdf70

[root@centos8 data]$awk '0' /etc/redhat-release 
[root@centos8 data]$awk '1' /etc/redhat-release 
CentOS Linux release 8.2.2004 (Core)

#relational expression
[root@centos8 data]$awk 'NR>=3 && NR<=6{print $1}' /etc/passwd
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

#/pat1/,/pat2/
[root@centos8 data]$awk '/^root/,/^daemon/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
4.3.7 條件判斷 if-else

格式:

if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else if(condition3)
{statement3}......else{statementN}

范例:

[root@centos8 data]$awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
nobody 65534
git 1000
mageia 1100
slackware 2002
user 2003

[root@centos8 data]$awk -F: '{if($3>=1000){print "common user",$1,$3} else {print "sysuser",$1,$3}}' /etc/passwd
sysuser root 0
sysuser bin 1

[root@centos8 data]$awk -F: '{if($3>=1000)print "common user",$1,$3; else print "sysuser",$1,$3}' /etc/passwd
sysuser root 0
sysuser bin 1
4.3.8 switch語句

格式:

switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or
/REGEXP2/: statement2; ...; default: statementn}
4.3.9 循環while

格式:

while (condition) {statement;…}

使用場景: 對一行內的多個字段逐一類似處理時使用 ,對數組中的各元素逐一處理時使用

[root@centos8 data]$awk '{i=1;while(i<=NF){print $i,length($i); i++}}' /data/host_list.log
1 1
www*print*com 13
linux 5
new 3
test1 5
4.3.10 循環 do-while

格式:

do {statement;…}while(condition)

意義:無論真假,至少執行一次循環體

4.3.11 循環for

格式:

for(expr1;expr2;expr3) {statement;…}

可以用來遍歷數組中的元素

for(var in array) {for-body}

范例:

#求1-100以內數字之和
[root@centos8 data]$awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i};print sum}'
5050

time (total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
time (for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
time (seq –s ”+” 10000|bc)

相比較之下awk計算的速度最快,性能最好

4.3.12 continue和break

continue 中斷本次循環

break 中斷整個循環

范例:

[root@centos8 ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++)
{if(i%2==0)continue;sum+=i}print sum}'
2500
4.3.13 next

可以提前結束對本行處理而直接進入下一行處理(awk自身循環)

用法與continue和break相同

4.3.14 數組

awk的數組為關聯數組

格式:

array_name[index-expression]

說明:

  • 可使用任意字符串;字符串要使用雙引號括起來
  • 如果某數組元素事先不存在,在引用時,awk會自動創建此元素,並將其值初始化為“空串”
  • 若要判斷數組中是否存在某元素,要使用“index in array”格式進行遍歷

范例:

#基本用法
[root@centos8 data]$awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday

#去重
[root@centos8 data]$cat file 
a
b
a
bb
b
d
[root@centos8 data]$awk '!line[$0]++' file 
a
b
bb
d

#判斷索引是否存在
[root@centos8 data]$awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";if ("mon" in weekdays){print "存在"}else{print "不存在"}}'
存在
[root@centos8 data]$awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";if ("awk" in weekdays){print "存在"}else{print "不存在"}}'
不存在

使用for循環遍歷數組

for(var in array) {for-body}
[root@centos8 data]$awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays){print weekdays[i]}}'
Tuesday
Monday
4.3.15 awk函數

常見內置函數:

  • rand():返回0和1之間一個隨機數

  • srand():配合rand() 函數,生成隨機數的種子

  • int():返回整數

自定義函數:

格式:

#定義
function name ( parameter, parameter, ... ) {
   statements
   return expression
}

#調用
pattern{action name ( parameter, parameter, ... )}
4.3.16 awk腳本

將awk程序寫成腳本,直接調用或執行

范例:

#使用-f選項調用
[root@centos8 data]$awk -F: -f passwd.awk /etc/passwd
nobody 65534
git 1000
mageia 1100
slackware 2002
user 2003
[root@centos8 data]$cat passwd.awk 
{if($3>=1000)print $1,$3}

#awk腳本調用
[root@centos8 data]$cat passwd.awk 
#!/bin/awk -f
{if($3>=1000)print $1,$3}
[root@centos8 data]$chmod +x passwd.awk 
[root@centos8 data]$./passwd.awk -F: /etc/passwd
nobody 65534
git 1000
mageia 1100
slackware 2002
user 2003

向awk腳本傳遞參數

格式:

awkfile var=value var2=value2... Inputfile

注意:在BEGIN過程中不可用。直到首行輸入完成以后,變量才可用。可以通過-v 參數,讓awk在執行 BEGIN之前得到變量的值。命令行中每一個指定的變量都需要一個-v參數

練習

1.使用ifconfig獲取本機的IPV4地址

grep broadcast lx.t | sed -nr 's/^[^0-9]+([0-9.]+).*$/\1/p'

2.刪除/etc/fstab文件種所有以#開頭,后面至少跟一個空白字符的行的行首的#和空白字符

sed -ri.bak 's/^#[[:blank:]]+//' fstab

3.處理/etc/fstab路徑,使用sed命令取出其目錄名和基名

[root@centos8 data]# echo /etc/fstab | sed -r 's#(.*)/([^/]+/?)#\1#'
/etc
[root@centos8 data]# echo /etc/fstab | sed -r 's#(.*)/([^/]+/?)#\2#'
fstab

4.解決Dos攻擊生產案例:根據web日志或者或者網絡連接數,監控當某個IP並發連接數或者短時內 PV達到100,即調用防火牆命令封掉對應的IP,監控頻率每隔5分鍾。防火牆命令為:iptables -A INPUT -s IP -j REJECT

#方式1
[root@centos8 script]$cat iptable.sh 
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | while read times ip;do 
	if [ $times -gt 5 ];then
    	iptables -A INPUT -s $ip -j REJECT
    fi
done
[root@centos8 script]$cat !*
cat /var/spool/cron/root
*/5 * * * * /data/script/iptable.sh

#方式2
[root@centos8 script]$cat iptable.sh 
awk '{count[$1]++}END{for(i in count){if(count[i]>5){system("iptables -A INPUT -s "$ip" -j REJECT")}}}' /var/log/nginx/access.log
[root@centos8 script]$cat !*
cat /var/spool/cron/root
*/5 * * * * /data/script/iptable.sh


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM