總結sed和awk的詳細用法;
sed用法
sed(Stream EDitor)是一款流編輯器,用來對文本進行過濾與替換操作。其原理是:通過文件或管道讀取文件內容,但是sed默認并不直接修改源文件,而是一次僅讀取文件的一行至模式空間(pattern space)根據sed指令進行編輯并輸出結果后清除模式空間,即所有的操作都是在模式空間中進行的。
語法格式
sed [option]… ‘script’ inputfile…
OPTIONS選項
-n,–quite,–silent:靜默輸出,即不輸出模式中的內容至輸出
-e script:使用多個腳本指令執行編輯
-f /PATH/TO/SCRIPT_FILE:從指定的文件中讀取編輯腳本
-r:支持在腳本中使用正則表達式
-i,–in-place:直接在文件原處執行編輯,即修改源文件
SCRIPT,地址定界+編輯指令
地址定界
(1) 不給地址:對全文進行處理;
(2) 單地址
#:指定的行 $:文件的最后一行 /PATTERN/:被模式匹配到的每一行
(3) 地址范圍
m,n:指定m行到n行 #,+n:指定#行到#+n行 /pat1/,/pat2/:匹配到的pat1到pat2之間的行 #,/pat/:第#行到匹配到pat
(4) 步進:~
1~2:所有奇數行,從一開始,步進2 2~2:所有偶數行,從二開始,步進2
注意:如果//中正則表達式為空,則匹配最近一次正則表達式的匹配地址!
編輯命令
d:刪除
p:顯示模式空間的內容
a \text:在行后面追加內容,支持使用\n(換行符)實現多行追加
i \text:在行前面插入內容,支持使用\n(換行符)實現多行追加
c \text:替換行為單行或多行文本,支持使用\n(換行符)
w /PATH/TO/SOMEFILE:保存模式空間匹配到的行至指定文件中
r /PATH/FROM/SOMEFILE:讀取指定文件的文本流至模式空間中匹配到的行的行后
=:為模式空間中的行打印行號
!:取反條件
s/pattern/replacement/flags:替換,支持使用其他分隔符,如:s@@@, s###
替換標記(flags): #:替換行內匹配到的第#次的內容 g:行內全局替換 p:顯示替換成功的行 w /PATH/TO/SOMEFILE:將替換后的結果保存至指定文件 replacement: &:用pattern匹配到的內容進行替換 \n:在pattern中使用\(\)指定時,匹配第n個子串
【難點】高級編輯命令:
h:把模式空間中的內容覆蓋至保持空間中; H:把模式空間中的內容追加至保持空間中; g:把保持空間中的內容覆蓋至模式空間中; G:把保持空間中的內容追加至模式空間中; x:把模式空間中的內容與保持空間中的內容互換; n:顯示并清空模式空間,然后讀取匹配到的行的下一行覆蓋至模式空間; N:追加讀取匹配到的行的下一行至模式空間中; d:刪除模式空間中的行; D:刪除多行模式空間中的所有行; 示例: sed -n 'n;p' FILE:顯示偶數行; sed '1!G;h;$!d' FILE:逆序顯示文件的內容; sed ’$!d' FILE:取出最后一行; sed '$!N;$!D' FILE:取出文件后兩行; sed '/^$/d;G' FILE:刪除原有的所有空白行,而后為所有的非空白行后添加一個空白行; sed 'n;d' FILE:顯示奇數行; sed 'G' FILE:在原有的每行后方添加一個空白行;
awk用法
其用法博大精深,且聽我細細道來
首先,grep,sed,awk三者區別,回顧一下:
grep, egrep, fgrep
文本過濾工具,只讀不寫,加上各種正則及關鍵字,那叫一個爽快。
sed
行編輯器,有模式空間及保持空間,實現文本行的編輯及輸出。
awk
報告生成器,格式化文本輸出;功能及其強大,不光可用正則,還可以使用條件判斷語句,函數、數組,不愧為上古神器。
有一點很重要,也很激勵人心,就是“結合awk與其他工具諸如grep和sed,將會使shell編程更加容易,也更有逼格?!?
awk命令的使用格式:
awk [options] ‘program’ file1,file2,…
awk [options] ‘PATTERN { action }’ file1,file2,…
program與PATTERN { action }的關系
很多同學在剛開始學習awk的時候,這里常常犯迷糊,me too!所以我覺得這個關系先理清楚,對awk往后的學習是有幫助的。
program包括PATTERN和ACTION,PATTERN和ACTION最少得有一個,語句之間用分號分隔
【理解關鍵點】模式( pattern ) 用于匹配輸入中的每行文本。對于匹配上的每行文本,awk 都執行對應的 動作( action )。模式和動作之間使用花括號隔開。awk 順序掃描每一行文本,并使用 記錄分隔符(一般是換行符)將讀到的每一行作為 記錄,使用 域分隔符( 一般是空格符或制表符 ) 將一行文本分割為多個 域, 每個域分別可以使用 $1, $2, … $n 表示。$1 表示第一個域,$2 表示第二個域,$n 表示第 n 個域。 $0 表示整個記錄。模式或動作都可以不指定,缺省模式的情況下,將匹配所有行。缺省動作的情況下,將執行動作 {print},即打印整個記錄。
先來說說ACTION
其中最常用的ACTION參數之一就是print和printf了,前者實現打印輸出,后者實現格式化輸出
語法:
print item1, item2, …
要點
(1) 逗號分隔符;
(2) 輸出的各item可以字符串,也可以是數值;當前記錄的字段、變量或awk的表達式;
(3) 如省略item,相當于print $0,打印整行字符
printf命令,這個就很有內涵了
要點:
(1) FORMAT必須給出;
(2) 不會自動換行,需要顯式給出換行控制符,\n
(3) FORMAT中需要分別為后面的每個item指定一個格式化符號;
語法:
printf 格式符/修飾符, item1, item2, …
格式符: %c: 顯示字符的ASCII碼; %d, %i: 顯示十進制整數; %e, %E: 科學計數法數值顯示; %f:顯示為浮點數; %g, %G:以科學計數法或浮點形式顯示數值; %s:顯示字符串; %u:無符號整數; %%: 顯示%自身; 修飾符: #[.#]:第一個數字控制顯示的寬度;第二個#表示小數點后的精度; %3.1f -: 左對齊 +:顯示數值的符號
記住哦,格式符和修飾符可以靈活組合使用
ACTION還支持以下干貨,
(1) Expressions表達式
(2) Control statements:if, while等;
(3) Compound statements:組合語句;
(4) input statements
(5) output statements(print printf)
我們來看看控制語句:
(1)if(condition) {statments} :單分支if語句
(2)if(condition) {statments} else {statements} :雙分支if語句
(3)while(conditon) {statments}
(4)do {statements} while(condition) :循環體
(5)for(expr1;expr2;expr3) {statements}
(6)break
(7)continue
(8)delete array[index]
(9)delete array
(10)exit
支持這么多,已經看傻,下面一個個來看看:
if-else
語法:if(condition) statement [else statement] ~]# awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd ~]# awk '{if(NF>5) print $0}' /etc/fstab ~]# df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=20) print $1}' 使用場景:對awk取得的整行或某個字段做條件判斷;
while循環
語法:while(condition) statement 條件“真”,進入循環;條件“假”,退出循環; ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)}; i++}}' /etc/grub2.cfg 使用場景:對一行內的多個字段逐一類似處理時使用;對數組中的各元素逐一處理時使用;
do-while循環
語法:do statement while(condition) 意義:至少執行一次循環體
for循環
語法:for(expr1;expr2;expr3) statement for(variable assignment;condition;iteration process) {for-body} ~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg 特殊用法: 能夠遍歷數組中的元素; 語法:for(var in array) {for-body}
switch語句
語法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; ...; default: statement}
next
提前結束對本行的處理而直接進入下一行; ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
數組array
關聯數組:array[index-expression] index-expression: (1) 可使用任意字符串;字符串要使用雙引號; (2) 如果某數組元素事先不存在,在引用時,awk會自動創建此元素,并將其值初始化為“空串”; 若要判斷數組中是否存在某元素,要使用"index in array"格式進行; weekdays[mon]="Monday" 若要遍歷數組中的每個元素,要使用for循環; for(var in array) {for-body}
函數
內置函數 數值處理: rand():返回0和1之間一個隨機數; 字符串處理: length([s]):返回指定字符串的長度; sub(r,s,[t]):以r表示的模式來查找t所表示的字符中的匹配的內容,并將其第一次出現替換為s所表示的內容; gsub(r,s,[t]):以r表示的模式來查找t所表示的字符中的匹配的內容,并將其所有出現均替換為s所表示的內容; split(s,a[,r]):以r為分隔符切割字符s,并將切割后的結果保存至a所表示的數組中;
好,上邊ACTION啰嗦完了,哈哈哈哈哈,下面就要高潮咧O(∩_∩)O哈哈~
PATTERN
PATTERN有什么,有很多,超乎你的想象,它支持
(1) empty:空模式,匹配每一行; (2) /regular expression/:僅處理能夠被此處的模式匹配到的行; (3) relational expression: 關系表達式;【結果有“真”有“假”;結果為“真”才會被處理】; 【真:結果為非0值,非空字符串】這個跟bash的命令返回值不一樣; (4) line ranges:行范圍, startline,endline:/pat1/,/pat2/ 例子:[root@CentOS7 ~]# awk -F: '/^h/,/^u/{print $1}' /etc/passwd 注意: 不支持直接給出數字的格式 可以使用如下方式: ~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd (5) BEGIN/END模式 BEGIN{}: 僅在開始處理文件中的文本之前執行一次; END{}:僅在文本處理完成之后執行一次 ;
選項[options]
-F:指明輸入時用到的字段分隔符;
-v var=value: 自定義變量;
awk的options主要用來定義各種變量和使用各種內建變量。
內建變量
FS:input field seperator,默認為空白字符; OFS:output field seperator,默認為空白字符; RS:input record seperator,輸入時的換行符; ORS:output record seperator,輸出時的換行符; NF:number of field,字段數量 {print NF}, {print $NF} 它們之間是有區別的,NF是有多少個字段數量,而$NF表示最后一個字段的內容 NR:number of record, 行數; FNR:各文件分別計數;行數; $0:代表一行,讀一行進行切片 FILENAME:當前文件名; ARGC:命令行參數的個數; ARGV:數組,保存的是命令行所給定的各參數; PS:在awk中要做變量替換,是不能用引號引起來的
自定義變量
(1) -v var=value #變量名區分字符大小寫哦; (2) 在program中直接定義
好了,awk就介紹到這里,下面來寫例子
例子1:顯示/etc/passwd的賬戶
#cat /etc/passwd |awk -F ':' '{print $1}' root daemon bin sys
上邊這種是awk+action的示例,每行都會執行action{print $1}。
-F指定域分隔符為’:’。
例子2:搜索/etc/passwd有root關鍵字的所有行
#awk -F: '/root/' /etc/passwd root:x:0:0:root:/root:/bin/bash
上邊這種是pattern的使用示例,匹配了pattern(這里是root)的行才會執行action(沒有指定action,默認輸出每行的內容)。
搜索支持正則,例如找root開頭的: awk -F: ‘/^root/’ /etc/passwd
例子3:搜索/etc/passwd有root關鍵字的所有行,并顯示對應的shell
# awk -F: '/root/{print $7}' /etc/passwd /bin/bash
上邊這里指定了匹配了pattern(這里是root)的行才會執行action{print $7}
例子4:刪除/boot/grub/grub.conf文件中所有行的行首的空白字符
sed ‘s/^[[:space:]]+//’ /boot/grub/grub.conf
這里的sed使用了查找替換,思路就是先查找文件中所有行的行首的空白字符,用正則的行首錨定空字符,之后查找替換為空,即刪除。
例子5:刪除/etc/fstab文件中所有以#開頭,后跟至少一個空白字符的行的行首的#和空白字符
sed ‘s/^#[[:space:]]*//’ /etc/fstab
同樣是查找替換的套路,參照例子4
例子6:把/etc/fstab文件的奇數行另存為/tmp/fstab.3
sed ‘1~2!d’ /etc/fstab > /tmp/fstab.3
sed ‘1~2w /tmp/fstab.3’ /etc/fstab
這里用到了sed地址定界中的步進+編輯命令,兩種不同的編輯命令實現,真是飛刀又見飛刀,套路又見套路,套路就是熟悉其語法,命令,靈活組合使用。
例子7:echo一個文件路徑給sed命令,取出其基名;進一步地,取出其路徑名
路徑名
echo “/tmp/test/fstab” | sed ‘s#[^/]+\?$##’
上邊sed的#為分隔符,[^/]指匹配指定范圍外的任意單個字符,
+:匹配其前面的字符1次或多次:即其前面的字符要出現至少1次;
\?:匹配其前面的字符0次或1次;即其前面的字符是可有可無的;
$:行尾錨定;用于模式的最右側
基名
echo “/tmp/test/fstab” | sed ‘s#(\/.*\/)##’
上邊的sed分隔符為#,用到了sed的查找替換、正則表達式及其分組,形式為\(正則表達式\) 正則為\/.*\/,其中\為轉移符,正則抽取出來就是/.*/ 意思就是匹配到/開頭的以/結尾期間的任意單個字符任意次。 各位應該明白了吧。
例子8:統計指定文件中所有行中每個單詞出現的次數
awk ‘{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}’ /etc/fstab
[root@CentOS7 ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab swap 2 fstab(5), 1 filesystems, 1 on 1 /etc/fstab 1 /boot 1 more 1 mount(8) 1 pages 1 '/dev/disk' 1 /dev/mapper/cl_centos7-swap 1 blkid(8) 1 See 1 /dev/mapper/cl_centos7-root 1 for 1 and/or 1 anaconda 1 / 1 findfs(8), 1 under 1 17:33:09 1 Created 1 UUID=fe2021fb-ac21-474d-8256-f72b87fc915a 1 0 6 info 1 Accessible 1 22 1 # 7 defaults 3 xfs 2 man 1 are 1 reference, 1 Mar 1 by 2 maintained 1 2017 1 Wed 1 [root@CentOS7 ~]#
7、統計當前系統上所有tcp連接的各種狀態的個數;
netstat -n | awk ‘/^tcp/ {++state[$NF]} END {for(key in state) print key,”t”,state[key]}’
例子
root@xxx:~# netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"t",state[key]}' FIN_WAIT2 t 71 CLOSE_WAIT t 1 TIME_WAIT t 2049 ESTABLISHED t 1392 LAST_ACK t 3 FIN_WAIT1 t 4
8、統計指定的web訪問日志中各ip的資源訪問次數:
awk ‘{ip[$1]++}END{for(i in ip) print i,ip[i]}’ /opt/nginx/logs/access.log
9、寫一個腳本:定義一個數組,數組元素為/var/log目錄下所有以.log結尾的文件的名字;顯示每個文件的行數;
[root@CentOS7 ~]# cat week15_title9.sh #!/bin/bash files=/var/log/*.log for i in $files do wc -l $i done
輸出如下:
[root@CentOS7 ~]# ./week15_title9.sh 248 /var/log/boot.log 9 /var/log/openlmi-install.log 177 /var/log/vmware-install.log 326 /var/log/vmware-vmsvc.log 85 /var/log/vmware-vmusr.log 10 /var/log/wpa_supplicant.log 436 /var/log/Xorg.0.log 320 /var/log/Xorg.9.log 328 /var/log/yum.log [root@CentOS7 ~]#
10、寫一個腳本,能從所有同學中隨機挑選一個同學回答問題;進一步地:可接受一個參數,做為要挑選的同學的個數;
[root@CentOS7 ~]# cat week15_title10.sh #!/bin/bash if [ $1 ];then #判斷有無腳本參數傳入,如有則執行,沒有就執行else的語句 for((i=1;i<=$1;i++));do a=$[$RANDOM%11] #定義一個0~10的隨機數 echo $a done else a=$[$RANDOM%11] echo $a fi
11、授權centos用戶可以運行fdisk命令完成磁盤管理,以及使用mkfs或mke2fs實現文件系統管理;
visudo centos ALL=(root) NOPASSWD:/sbin/fdisk,/sbin/mke2fs,/sbin/mkfs
12、授權gentoo用戶可以運行邏輯卷管理的相關命令;
visudo gentoo ALL=(root) lvm
13、基于pam_time.so模塊,限制用戶通過sshd服務遠程登錄只能在工作時間進行;
vim /etc/ssh/sshd_config UsePAM yes #開啟Pam模塊認證 /lib64/security/pam_time.so #確保pam_time.so存在 vim /etc/pam.d/sshd 增加 account required pam_time.so vim /etc/security/time.conf 添加 *;*;*;MoTuWeThFr0900-1800
14、基于pam_listfile.so模塊,定義僅某些用戶,或某些組內的用戶可登錄系統;
[root@localhost ~]# vim /etc/sshd_userlist root centos gentoo chmod 600 /etc/sshd_userlist chown root /etc/sshd_userlist vim /etc/pam.d/sshd #auth required pam_listfile.so item=user sense=allow file=/etc/sshd_userlist onerr=succeed
原創文章,作者:N24_Jerry,如若轉載,請注明出處:http://www.www58058.com/77539