sed和awk
sed
sed(Stream Editor) 流編輯器,用來處理文件的
sed是一行一行讀取文件內容并按照要求進行處理,把處理后的結果輸出到屏幕
- 首先sed讀取文件中的一行內容,把其保存在一個臨時緩存區中(也稱為模式空間)
- 然后根據需求處理臨時緩沖區中的行,完成后把該行發送到屏幕上
總結:
- 由于sed把每一行都存在臨時緩沖區中,對這個副本進行編輯,所以不會直接修改源文件
- sed主要用來自動編輯一個或多個文件,簡化對文件的反復操作,對文件進行過濾或轉換操作
sed使用方法
sed常見的語法格式有兩種,一種叫命令行模式,另一種叫腳本模式
命令行格式
sed [options] '處理動作' 文件名
-e 進行多項(多次)編輯
-n 取消默認輸出 不自動打印模式空間
-r 使用擴展正則表達式
-i 原地編輯(修改源文件)
-f 指定sed腳本的文件名
常見處理動作
以下所有的動作都必須在單引號里
'p' 打印
'i' 在指定行之前插入內容 類似vim里的大寫O
'a' 在指定行之后插入內容 類似vim里的小寫o
'c' 替換指定行所有內容
'd' 刪除指定行
對文件進行增、刪、改、查操作
語法:sed選項 '定位+命令' 需要處理的文件
1)打印文件內容
sed '' a.txt # 對文件什么都不做
sed -n 'p' a.txt # 打印每一行,并取消默認輸出
sed -n '1p' a.txt # 打印第1行
sed -n '2p' a.txt # 打印第2行
sed -n '1,5p' a.txt # 打印1到5行
sed -n '$p' a.txt # 打印最后1行
sed -n '/root/p' 1.txt #打印包含root的行
2)增加文件內容
i 地址定位的上面插入
a 下面插入
sed '$a99999' a.txt 文件最后一行下面增加內容
sed 'a99999' a.txt 文件每行下面增加內容
sed '5a99999' a.txt 文件第5行下面增加內容
sed '$i99999' a.txt 文件最后一行上一行增加內容
sed 'i99999' a.txt 文件每行上一行增加內容
sed '6i99999' a.txt 文件第6行上一行增加內容
sed '/^uucp/ihello' a.txt 以uucp開頭行的上一行插入內容
# 注意 如果要需要連續插入兩行有兩種方法
# (1) 利用\n
# (2) 輸入 \ 然后回車輸入內容
- 修改文件內容
c 替換指定的整行內容
sed '5chello world' a.txt 替換文件第5行內容
sed 'chello world' a.txt 替換文件所有內容
sed '1,5chello world' a.txt 替換文件1到5行內容為一行hello world
sed '/^user01/c888888' a.txt 替換以user01開頭的行
- 刪除文件內容
sed '1d' a.txt 刪除文件第1行
sed '1,5d' a.txt 刪除文件1到5行
sed '$d' a.txt 刪除文件最后一行
sed -r '/正則匹配/d'
對文件進行搜索替換操作
語法:sed 選項 's/搜索的內容/替換的內容/動作' 需要處理的文件
其中,s表示search搜索,斜杠/表示分隔符,可以自己定義;動作一般是打印p和全局替換g(不加默認只替換第一個)
sed -n 's/root/ROOT/p' 1.txt # 只替換第一個root
sed -n 's/root/ROOT/gp' 1.txt
sed -n 's/^#//gp' 1.txt # 將#開頭的行刪除
sed -n 's@/sbin/nologin@itcast@gp' a.txt # 將/sbin/nologin@itcast替換成itcast @為自定義分隔符
sed -n 's/\/sbin\/nologin/itcast/gp' a.txt
sed -n '10s#/sbin/nologin#itcast#p' a.txt # 只替換第10行的內容
sed -n 's@/sbin/nologin@itcast@p' 2.txt # 注意:搜索替換中的分隔符可以自己指定
sed -n '1,5s/^/#/p' a.txt # 注釋掉文件的1-5行內容
sed -n 's/\(10.1.1.\)1/\1254/gp' a.txt #將10.1.1.1替換成10.1.1.254 其中后面的\1代表前面的10.1.1.
其他命令
r # 從另外文件中讀取內容
w # 內容另存為 sed '1,3w new.txt' 1.txt
& # 保存查找串以便在替換串中引用 和\(\)相同
sed -n 's/^sync/#&/gp' 1.txt 將sync開頭的那一行注釋掉, 用&引用^sync
sed -n 's\(^sync\)/#\1/gp' 1.txt 與上一行等價
= # 打印行號
sed -ne '/root/p' -ne '/root/=' 1.txt # e表示多次編輯
sed -n '/root/=;/root/p' 1.txt
! # 對所選行以外的所有行應用命令,放到行數之后
q # 退出 處理到這一行退出
其他選項
-e 多項編輯
-r 擴展正則
-i 修改原文件
sed -ne '/root/=' -ne '/root/p' 1.txt
sed -e '5ihello world' -e '8a哈哈哈哈' 1.txt -e '5=;8='
# 過濾/etc/vsftpd/vsftpd.conf文件中以#開頭和空行:
grep -Ev '^#|^$' 1.txt
sed -e '/^#/d' -e '/^$/d' 1.txt
sed '/^#/d;/^$/d' 1.txt
sed -r '/^#|^$/d' 1.txt
過濾smb.conf文件中生效的行:
sed -e '/^#/d' -e '/^;/d' -e '/^$/d' -e '/^\t$/d' -e '/^t#/d' 1.txt
sed -r '^(#|$|;|\t#|\t$)/d' 1.txt
grep '^[^a-z]' 1.txt
sed -n '/^[^a-z]/p' 1.txt
# 過濾出文件中的ip地址
grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}' 1.txt
sed -nr '/([0-9]{1,3}\.){3}[0-9]{1,3}/p' 1.txt
ifconfig | sed -nr '/([0-9]{1,3}\.)[0-9]{1,3}/p' | head -1|sed -r 's/([a-z:]|[A-Z\t])//g' |
sed 's/ /\n/g' | sed '/^$/d'
ifconfig eth0 | sed -n '2p' | sed -n 's/.*addr:\(.*\) Bcast:\(.*\) Mask:\(.*\)/\1\n\2\n\3/p'
-i 選項 直接修改原文件
sed -i 's/root/ROOT;s/stu/STU/' 1.txt
sed -i '1,5s/^/#&' a.txt # 加注釋
注意:
-n 不要與-i一起使用
p命令 不要與-i一起使用
sed結合正則使用
sed 選項 'sed命令或者正則表達式或者地址定位' 文件名
- 地址用于決定對哪些行進行編輯,地址的形式可以是數字、正則表達式、或兩者的結合
- 如果沒有地址定位,sed將處理輸入文件的所有行
/key/ 查詢包含關鍵字的行 sed -n '/root/p' 1.txt
/key1/,/key2/ 匹配包含兩個關鍵字之間的行 sed -n '/^adm/,/^mysql/p' 1.txt
/key/,x 從匹配關鍵字的行開始到文件第x行之間的行(包含關鍵字所在行) sed -n '/^ftp/,7p'
x,/key/ 從文件第x行開始到與關鍵字的匹配行之間的行
x,y! 不包含x到y的行
/key/! 不包括關鍵字的行 sed -n '/bash$/!p' 1.txt
腳本格式
用法
# sed -f scripts.sh file 使用腳本處理文件
建議使用 ./sed.sh file
腳本的第一行寫上
#!/bin/sed -f
1,5d
s/root/hello/g
3i777
5i888
a999
p
注意事項
1) 腳本文件是一個sed的命令行清單,'coomands'
2) 在每行的末尾不能有任何空格,制表符(tab)或其他文本
3) 如果在一行中有多個命令,應該用分號分隔
4) 不需要且不可用引號保護命令
5) #號開頭的行為注釋
例子:
#!/bin/sed -f
2a\
*********************
2,$s/stu/user/
$a\
we insert a new line
s/^[a-z].*/#&/
#!/bin/sed -f
3a*********************
$chelloworld
1,3s/^/#&/
awk
awk是一種編程語言,主要用在linux/unix下對文本和數據進行處理,是linux/unix下的一個工具,數據可以來自標準輸入,一個或多個文件,或其他命令的輸出。
awk的處理文本和數據的方式:逐行掃描文件,默認從第一行到最后一行,尋找匹配的特定模式的行,并在這些行上進行你想要的操作
gawk是awk的GNU版本,它提供了Bell實驗室和GNU的一些擴展,linux系統中已經把awk鏈接到gawk
作用
- awk用來處理文件和數據,是類unix下的一個工具,也是一種編程語言
- 可以用來統計數據,比如網站的訪問量,訪問的IP量等等
- 支持條件判斷,支持for和while循環
awk的使用方式
命令行模式使用
awk 選項 '命令部分' 文件名
特別說明:
引用shell變量需要用雙引號引起
luck_line=123456
sed -i "/$luck_line/d" file
常用選項
- -F 定義字段分割符號,默認的分隔符是空格
- -v 定義變量并賦值
命名部分說明
- 正則表達式,地址定位
'/root/{awk語句}' sed中:'/root/p'
'NR==1,NR==5{awk語句}' sed中:'1,5p'
'/^root/,/^ftp/{awk語句}' sed中:'/^root/,/^ftp/p'
'{print $0;print $1}' sed中:'p'
'NR==5{print $0}' sed中:'5p'
注:awk命令語句間用分號間隔
- BEGIN(文件處理前)...END(文件處理后)...
'BEGIN{awk語句};{處理中};END{awk語句}'
'BEGIN{awk語句};{處理中}'
'{處理中};END{awk語句}'
腳本模式使用
腳本編寫
#!/bin/awk -f 定義魔法字符
以下是awk引號里的命令清單,不要用引號保護命令,多個命令用分號間隔
BEGIN{FS=":"}
NR==1,NR==3{print $1"\t"$NF}
...
腳本執行
方法1:
awk 選項 -f awk的腳本文件 要處理的文本文件
awk -f awk.sh filename
sed -f sed.sh -i filename
方法2:
./awk的腳本文件(或者絕對路徑) 要處理的文件
./awk.sh filename
./sed.sh filename
awk內部相關變量
$0 當前處理行的所有記錄
$1,$2,$3...$n 文件中每行以間隔符號分割的不同字段 awk -F: '{print $1,$3}' # :分隔
NF 當前記錄的字段數(列數) awk -F: '{print NF}'
$NF 最后一列 $(NF-1)表示倒數第二列
FNR/NR 行號 用||(第1和第5行) 和,(1到5行)NR>=1 && NR<=5 連接
FS 定義間隔符 'BEGIN{FS=":"};{print $1,$3}'
OFS 定義輸出字段分隔符,默認空格 'BEGIN{OFS="\t"};{print $1,$3}'
RS 輸入記錄分隔符,默認換行 'BEGIN{RS="\t"};{print $0}'
ORS 輸出記錄分隔符,默認換行 'BEGIN{ORS="\n\n"};{print $1,$3}'
常用內置變量舉例
awk -F: '/root/{print $1,$NF}' 1.txt # 匹配到包含root的行以:分隔的第一列和最后一列
awk 'NR==1,NR==5;/^root/{print $0}' 1.txt
#;前第一到第五行都要打印,后面開頭為root的再打印一遍,逐行處理
awk 'BEGIN{FS=":";OFS="@@@@"};{print $1,$NF}' 1.txt
awk 'BEGIN{FS=":"};{print "用戶名是"$1"@@@@@@@@@@"$NF}' 1.txt
awk -F: 'BEGIN{RS="\t"};{print $1}' 1.txt #將輸入中\t分隔的看做一行
awk工作原理
awk -F: '{print $1,$3}' 1.txt
-
awk使用一行作為輸入,并將這一行賦給內部變量$0,每一行也可以稱為一個記錄,以換行符(RS)結束
-
每行被間隔符:(默認為空格或制表符)分解成字段(或域),每個字段存儲在已編號的變量中,從$1開始
問:awk如何知道用空格來分隔字段的呢?
答:因為有一個內部變量FS來確定字段分隔符,初始時FS賦為空格
-
awk使用print函數打印字段,打印出來的字段會以空格分隔,因為$1,$3之間有一個逗號,逗號比較特殊,它映射為另一個內部變量,稱為輸出字段分隔符OFS,OFS默認為空格
-
awk處理完一行后,將從文件中獲取另一行,并將其存儲在$0中,覆蓋原來的內容,然后將新的字符串分隔成字段并進行處理,該過程將處理所有行處理完畢
awk進階
- 格式化輸出print和printf
print函數 類似echo "hello world"
data | awk '{print "Month: "$2 "\nYear: "$NF}' /etc/passwd # 默認以空格分隔
printf函數 類似echo -n "hello world"
awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}' /etc/passwd
%s 字符類型 strings %-20s
%d 數值類型
占15字符
- 表示左對齊,默認是右對齊
printf默認不會在行尾自動換行,要加\n
- awk變量定義
awk -v NUM=3 -F: '{print NUM}' /etc/passwd # 會輸出文件行數這么多行的3
awk -v num=1 'BEGIN{print $num}'
注意:
awk中調用定義的變量不需要加$, 加了相當于$0 $1 $2這種分隔后的字段而不是定義的變量值
- awk中BEGIN..END使用
BEGIN:表示在程序開始前執行
END:表示所有文件處理完后執行
用法:'BEGIN{開始處理前};{處理中};END{處理結束后}' # 不用同時存在
- awk和正則的綜合運用
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
~ 匹配
!~ 不匹配
! 邏輯非
&& 邏輯與 邏輯運算符用來連接表達式
|| 邏輯或
awk -F: '/^lp/,NR==10{print $0}' passwd # 打印從以lp開頭到文件第10行
awk -F: '/^root/ || /^lp/{print $0}' # 打印以root和lp開頭的這兩行
awk -F: '/^root/;/^lp/{print $0}' # ;分隔命令,默認打印 效果同上
awk 'NR==1,NR==5;/^root/{print $0}' 1.txt # 打印1到5行,且以root開頭的被多打印一遍,一行一行處理
打印1-5行以root開頭的行
awk 'NR>=1 && NR<=5 && $0 ~ /^root/{print $0}' 1.txt # 匹配
awk 'NR>=1 && NR<=5 && /^root/{print $0}'
ifconfig eth0| grep Bcast|awk -F'[: ]+' '{print $4}' # 分隔符設為:和空格(一個或多個)
ifconfig eth0| awk -F"[: ]+" '/inet addr/{print $4RS$6}'
流程控制語句
if 結構
if語句:
if [ xxx ];then
xxx
fi
格式:
awk 選項 '正則,地址定位{awk語句}' 文件名
{ if(表達式) {語句1;語句2;...} }
awk -F: '{if($3>=500 && $3<=60000)} {print $1,$3}' passwd
awk -F: '{if($3==0) {print $1"是管理員"}}' passwd
awk 'BEGIN{if($(id -u)==0) {print "admin"} }'
if...else結構
if...else語句
if [ xxx ];then
xxxx
else
xxxx
fi
格式:
{if(表達式) {語句;語句;...} else {語句;語句;...}}
awk -F: '{ if($3>=500 && $3!=65534) {print $1"是普通用戶"} else {print $1,"不是普通用戶"}}' passwd
if...elif...else語句
if [ xxx ]
xxxx
elif [ xxx ]
xxxx
...
else
xxxx
fi
if...else if...else語句
for ((i=1;i<=5;i++));do echo $i;done
格式:
{ if(表達式1) {語句;語句;...} else if(表達式2) {語句;語句;...} else if(表達式3) {語句;語句;...} else {語句;語句;...} }
awk 'BEGIN {for(i=1;i<=5;i++){print i}}
計算1-5的和
awk 'BEGIN{for(i=1;i<=5;i++)(sum+=i);{print sum}'
while循環
打印1-5
i=1;while (($i<=5));do echo $i;let i++;done
awk 'BEGIN{i=1;while(i<=5){print i;i++}}'
打印1-5的和
awk 'BEGIN{i=1;while(i<=5){sum+=i;i++};print sum}' # 定義變量默認為0
嵌套循環
for ((y=1;y<=5;y++))
do
for ((x=1;x<=$y;x++))
do
echo -n $x
done
echo
done
awk 'BEGIN{for(y=1;y<=5;y++){for(x=1;x<=y;x++){printf x};print}}'
awk算數運算
+ - * / % ^
可以在模式中執行計算,awk都將按浮點數方式執行算術運算
awk 'BEGIN{print 1+1}'
awk 'BEGIN{print 2**3}'
awk 'BEGIN{print 2/3}'
awk統計案例
- 統計系統中各種類型的shell
- awk中關聯數組不需要聲明
awk -F: '{ shell[$NF]++};END{for(i in shells) {print i,shells[i]}}' /etc/passwd

浙公網安備 33010602011771號