grep ||sed||awk
Grep命令:
grep語法格式:
grep [option] [pattern] [file1,file2...]
必須掌握的選項:
-v 顯示不匹配pattern的行
-i 搜索時忽略大小寫
-n 顯示行號
-E 支持擴展的正則表達式
-F 不支持正則表達式,按字符串的字面意思進行匹配
-r 遞歸搜索
需瞭解的選項:
-c 只輸出匹配行的數量,不顯示具體內容
-w 匹配整詞
-x 匹配整行
-l 只列出匹配的文件名,不顯示具體匹配行內容
grep和egrep區別:
grep默認不支持擴展正則表達式,只支持基礎正則表達式
使用grep -E可以支持擴展正則表達式
使用egrep可以支持擴展正則表達式,與grep -E等價
舉例:
查看不包括nologin的字符串,並顯示行號
[root@ansible fang]# grep -nv "nologin" /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
6:sync:x:5:0:sync:/sbin:/bin/sync
7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8:halt:x:7:0:halt:/sbin:/sbin/halt
43:fangqiming:x:1000:1000:fangqiming:/home/fangqiming:/bin/bash
[root@ansible fang]#
重點:
[pattern]正則表達式的使用
Sed命令:
sed語法(查詢,刪除,增加):
舉例:
sed -n '/192.*/p' dd.yml
功能:將dd.yml文件中的包含192.的行打印出來,值打印匹配的行
sed –i ‘s/love/like/g’ sed.txt
功能:將sed.txt中所有love替換爲like
將list.txt文件中的內容插入到匹配到的行後面
sed –i ‘/root/r list’ password
將sed匹配到的行內容寫入到文件中
sed ‘/\/bin\/bash/w /tmp/user_login.txt’ passwd
將匹配到的內容對源文件進行替換爲大寫
Sed –i ‘s/\/bin\/bash/ \/BIN\/BASH/g’ passwd
將匹配到的內容,對源文件進行大寫的修改,並且同一行內只替換前兩個
Sed –i ‘s/root/ROOT/2g’ passwd
想匹配到的內容只顯示行號
Sed –n ‘/\/sbin\/nologin/=’ passwd
其他編輯命令
其他的編輯命令
= 顯示行號
反向引用:
&和\1 引用模式匹配到的整個串
Sed “s/1..e/&r/g” file 在file中搜尋以1開頭,然後跟兩個任意字符,以e結尾的字符串,用&代替搜尋到的字符串增加r字符後,對file進行修改
Sed “s/\(1..e\)/\1r/g” file 和上一條命令實現同樣的功能,\1代表搜尋到的字符串
注意: \1使用()對匹配到的字符串進行引用,如果只是想要替換匹配到的字符串的一部分,必須使用\1這種方式進行引用替換
反向引用
將正則匹配到的had..p的內容替換爲had..ps &表示引用前面整個字符串
將所有匹配到的had..p 後面家s
sed –i ‘s/had..p/&s/g’ str.txt
1也表示引用前面第一個()中的字符串,相對&更加靈活
sed –i ‘s/\(had..p\)/\1O/g’ str.txt
sed "s/\(l..e\)/\1r/g" file 和上面實現一樣的功能,使用\1代表搜尋到的字符串
在腳本中使用sed注意事項
- 匹配模式中存在變量,則建議使用雙引號
- Sed中需要引入自定義變量時,如果外面使用單引號,則自定義變量也必須使用單引號
引用變量的方式一
[root@ansible fang]# cat shell.sh
#!/bin/bash
#
old_str=fangqiming
new_str=FangQiMing
file="$1"
sed -i "s/$old_str/$new_str/g" $file
[root@ansible fang]# bash shell.sh 1.txt 執行
引用變量的方式二
#!/bin/bash
old_str=fangqiming
new_str=FangQiMing
file="$1"
sed -i 's/'$old_str'/'$new_str'/g' $file
這是在腳本中修改腳本內容的快捷方法
其實只是做的演示,如此簡單的功能,我們在腳本中就可以實現拉,
當前行到最後一行,將所有的HADOOP替換爲hadoop
:.,$s/Fang/fang/g
舉例:
需求描述: 處理一個類似MYSQL配置文件my.cnf的文本,示例如下;
編寫腳本實現以下功能:輸出文件有幾段,並且針對每個段可以統計配置參數總個個數
=====================
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Settings user and group are ignored when systemd is used.
# If you need to run mysqld under a different user or group,
# customize your systemd unit file for mariadb according to the
# instructions in http://fedoraproject.org/wiki/Systemd
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
輸出是這樣的格式
[root@ansible test]# bash mysql_client.sh
1: mysqld 3
2: mysqld_safe 4
技術要點:
首先,過濾標題的信息,去掉左右的中括號
[root@ansible test]# sed -n '/\[*\]/p' my.cnf | sed -e 's/\[//g' -e 's/\]//g'
mysqld
mysqld_safe
[root@ansible test]#
其次,按照標題信息,取出每個標題之間的信息,過濾掉空行的數據,過濾掉註釋的行數據,過濾掉標題行的數據,最終的實現是如下的樣子
[root@ansible test]# sed -n '/\[mysqld\]/,/\[.*\]/p' my.cnf | grep -v "^$" | grep -v "#" | grep -v "\[.*\]"
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
[root@ansible test]#
再次,對過濾完成的數據進行循環統計個數,最後組合成想要的數據就好了
實現代碼如下:
[root@ansible test]# cat mysql_client.sh
#!/bin/bash
#
DIR_NAME=/etc/ansible/fang/test/my.cnf
function output_line
{
echo "`sed -n '/\[.*\]/p' $DIR_NAME | sed -e 's/\[//g' -e 's/\]//g'`"
}
function output_line_items
{
index=0
items=`sed -n '/\['$1'\]/,/\[.*\]/p' $DIR_NAME | grep -v "^$" | grep -v "#" | grep -v "\[.*\]"`
for item in $items
do
index=`expr $index + 1`
done
echo $index
}
number=0
for out in `output_line`
do
number=`expr $number + 1`
items_count=`output_line_items $out`
echo "$number: $out $items_count"
done
[root@ansible test]#
刪除操作,是不推薦的,因爲匹配刪除後,會繼續進行下面的匹配,和預期結果是不一致的,匹配和行數顛倒以下,可以進行匹配,如下
Sed –i ‘/\/sbin\/nologin/,13d’ passwd 這種不推薦
Sed –i ‘13,/ \/sbin\/nologin /d’ passwd這種可以
練習題:
刪除/etc/passwd中德爾第15行
sed –i ‘15d’ /etc/passwd
刪除/etc/passwd中的第8行到第14行的所有內容
sed –i ‘8,14d’ /etc/passwd
刪除/etc/passwd中的不能登錄的用戶(篩選條件: /sbin/nologin)
sed –i ‘/\/sbin\/nologin/d’ /etc/passwd
刪除/etc/passwd中以mail開頭的行,到以yarn開頭的行的所有內容
sed –i ‘/^mail/,/^yarn/d’ /etc/passwd
刪除/etc/passwd中以yarn開頭的行到最後行的所有內容
sed –i ‘/^yarn/,$’ /etc/passwd
以#開頭的註釋刪除掉,其中#號之前的空格也需要匹配[:blank:]表示空格
sed –i ‘/[:blank:]*#/d’ nginx.conf
在配置文件中所有不以#開頭的行前面添加*符號,注意: 以#開頭的行不添加
sed –i ‘s/[^#]/\*&/g’ nginx.cnf
sed語法(修改):
sed命令 匹配方式 /pattern1/s/old/new/
[root@ansible test]# sed -i '/socket=/s/socket/sockets/g' my.cnf
[root@ansible test]# cat my.cnf
[mysqld]
datadir=/var/lib/mysql
sockets=/var/lib/mysql/mysql.sock
練習題:
1、修改/etc/passwd中第1行中第1個root爲ROOT
sed -i '1s/root/ROOT/' passwd
2、修改/etc/passwd中第5行到第10行中所有的/sbin/nologin爲/bin/bash
sed -i '5,10s/\/sbin\/nologin/\/bin\/bash/g' passwd
3、修改/etc/passwd中匹配到/sbin/nologin的行,將匹配到行中的login改爲大寫的LOGIN
sed -i '/\/sbin\/nologin/s/login/LOGIN/g' passwd
4、修改/etc/passwd中從匹配到以root開頭的行,到匹配到行中包含mail的所有行。修改內爲將這些所有匹配到的行中的bin改爲HADOOP
sed -i '/^root/,/mail/s/bin/HADOOP/g' passwd
5、修改/etc/passwd中從匹配到以root開頭的行,到第15行中的所有行,修改內容爲將這些行中的nologin修改爲SPARK
sed -i '/^root/,15s/nologin/SPARK/g' passwd
6、修改/etc/passwd中從第15行開始,到匹配到以yarn開頭的所有航,修改內容爲將這些行中的bin換位BIN
sed -i '15,/^yarn/s/bin/BIN/g' passwd
sed語法(修改)匹配的行後面追加
1、a 在匹配行後面追加
2、i 在匹配行前面追加
3、r 將文件內容追加到匹配行後面
4、w 將匹配行寫入指定文件
示例:
追加用法示例詳解:
1、a append
(1)、passwd文件第10行後面追加"Add Line Behind"
sed -i '10a Add Line Begind' passwd
(2)、passwd文件第10行到第20行,每一行後面都追加"Test Line Behind"
sed -i '10,20a Test Line Behind' passwd
(3)、passwd文件匹配到/bin/bash的行後面追加"Insert Line For /bin/bash Behind"
sed -i '/\/bin\/bash/a Insert Line For /bin/bash Behind' passwd
2、i
(1)、passwd文件匹配到以yarn開頭的行,在匹配航前面追加"Add Line Before"
sed -i '/^yarn/i Add Line Before' passwd
(2)、passwd文件每一行前面都追加"Insert Line Before Every Line"
sed -i 'i Insert Line Before Every Line' passwd
3、r
(1)、將/etc/fstab文件的內容追加到passwd文件的第20行後面
sed -i '20r /etc/fstab' passwd
(2)、將/etc/inittab文件內容追加到passwd文件匹配/bin/bash行的後面
sed -i '/\/bin\/bash/r /etc/inittab' passwd
(3)、將/etc/vconsole.conf文件內容追加到passwd文件中特定行後面,匹配以ftp開頭的行,到第18行的所有行
sed -i '//,18r /etc/vconsole.conf' passwd
4、w
(1)、將passwd文件匹配到/bin/bash的行追加到/tmp/sed.txt文件中
sed -i '/\/bin\/bash/w /tmp/sed.txt' passwd
(2)、將passwd文件從第10行開始,到匹配到hdfs開頭的所有行內容追加到/tmp/sed-1.txt
sed -i '10,/^hdfs/w /tmp/sed-1.txt' passwd
匹配到行之前插入
Awk命令:
命令的格式:
Awk ‘BEGIN{}PATTERN{command}END{}’ file_name
語法格式 解釋
BEGIN{} 正式處理數據之前執行
Pattern 匹配模式
{commands} 處理命令,可以多行
END{} 處理玩所有匹配數據後執行
內置變量:
$0 打印行所有信息
$1~$n 打印行的第1到n個字段的信息
NF Number Field 處理行的字段個數
NR Number Row 處理行的行號
FNR File Number Row多文件處理時,每個文件單獨記錄行號
FS Field Separator字段分割符,不指定時默認以空格或tab鍵分割
RS Row Separator 行分隔符,不指定時以回車分割\n
OFS Output Filed Separator 輸出字段分隔符。
ORS Output Row Separator 輸出行分隔符
FILENAME 處理文件的文件名
ARGC 命令行參數個數
ARGV 命令行參數數組
例如:
輸出每行的內容,默認是一個空格或者tab進行分割列
awk ‘{print $0}’ /etc/passwd
行分割 域分割 輸出行分割符號
[root@ansible test]# cat 2.txt
xiaoli|xiaoming|xiaohua--fang|qi|ming--ni|shi|shui
[root@ansible test]#
[root@ansible test]# awk 'BEGIN{RS="--"}{print $0}END{}' 2.txt
xiaoli|xiaoming|xiaohua
fang|qi|ming
ni|shi|shui
[root@ansible test]# awk 'BEGIN{RS="--";FS="|";OFS="&"}{print $3}END{}' 2.txt
xiaohua
ming
shui
Printf格式化輸出,參數介紹
awk格式化輸出之printf總結:
格式符
%s 打印字符串
%d 打印10進制數
%f 打印浮點數
%x 打印16進制數
%o 打印8進制數
%e 打印數字的科學計數法格式
%c 打印單個字符的ASCII碼
修飾符
- 左對齊
+ 右對齊
# 顯示8進制在前面加0,顯示16進制在前面加0x
格式符示例:
1、以字符串格式打印/etc/passwd中的第7個字段,以":"作爲分隔符
awk 'BEGIN{FS=":"} {printf "%s",$7}' /etc/passwd
2、以10進制格式打印/etc/passwd中的第3個字段,以":"作爲分隔符
awk 'BEGIN{FS=":"} {printf "%d\n",$3}' /etc/passwd
3、以浮點數格式打印/etc/passwd中的第3個字段,以":"作爲分隔符
awk 'BEGIN{FS=":"} {printf "%0.3f\n",$3}' /etc/passwd
4、以16進制數格式打印/etc/passwd中的第3個字段,以":"作爲分隔符
awk 'BEGIN{FS=":"} {printf "%#x\n",$3}' /etc/passwd
5、以8進制數格式打印/etc/passwd中的第3個字段,以":"作爲分隔符
awk 'BEGIN{FS=":"} {printf "%#o\n",$3}' /etc/passwd
6、以科學計數法格式打印/etc/passwd中的第3個字段,以":"作爲分隔符
awk 'BEGIN{FS=":"} {printf "%e\n",$3}' /etc/passwd
Awk模式匹配用法:
第一種方法:RegExp
第二種方法:運算符匹配
正則匹配RegExp
匹配/etc/passwd文件行中含有root字符串的所有行
awk 'BEGIN{FS=":"}/root/{print $0}' /etc/passwd
匹配/etc/passwd文件行中以yarn開頭的所有行
awk 'BEGIN{FS=":"}/^yarn/{print $0}' /etc/passwd
運算符匹配
關係運算符匹配:
< 小於
> 大於
<= 小於等於
>= 大於等於
== 等於
!= 不等於
~ 匹配正則表達式
!~ 不匹配正則表達式
(1)、以:爲分隔符,匹配/etc/passwd文件中第3個字段小於50的所有行信息
awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd
(2)、以:爲分隔符,匹配/etc/passwd文件中第3個字段大於50的所有行信息
awk 'BEGIN{FS=":"}$3>50{print $0}' /etc/passwd
(3)、以:爲分隔符,匹配/etc/passwd文件中第7個字段爲/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' /etc/passwd
(4)、以:爲分隔符,匹配/etc/passwd文件中第7個字段不爲/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$7!="/bin/bash"{print $0}' /etc/passwd
(5)、以:爲分隔符,匹配/etc/passwd中第3個字段包含3個以上數字的所有行信息
awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/{print $0}' /etc/passwd
布爾運算符匹配
|| 或
&& 與
! 非
(1)、以:爲分隔符,匹配/etc/passwd文件中包含hdfs或yarn的所有行信息
awk 'BEGIN{FS=":"}$1=="hdfs" || $1=="yarn" {print $0}' /etc/passwd
(2)、以:爲分隔符,匹配/etc/passwd文件中第3個字段小於50並且第4個字段大於50的所有行信息
awk 'BEGIN{FS=":"}$3<50 && $4>50 {print $0}' /etc/passwd
awk動作中的表達式
+ 加
- 減
* 乘
/ 除
% 取模
^或** 乘方
++x 在返回x變量之前,x變量加1
x++ 在返回x變量之後,x變量加1
--x 在返回x變量之前,x變量減1
x-- 在返回x變量之後,x變量減1
1、使用awk計算/etc/services中的空白行數量
awk '/^$/{sum++}END{print sum}' /etc/services
2、計算學生課程分數平均值,學生課程文件內容如下:
Alice 79 80 88 100
xiaoming 88 69 92 99
xiaoli 69 90 99 89
命令如下:
[root@ansible test]# cat student.txt
Alice 79 80 88 100
xiaoming 88 69 92 99
xiaoli 69 90 99 89
[root@ansible test]# awk 'BEGIN{printf "%-8s%-8s%-8s%-8s%-8s%-8s\n","Name","yuwen","math","pysical","English","Average"}{sum=$2+$3+$4+$5;AVG=sum/4;printf "%-8s%-8d%-8d%-8d%-8d%0.2f\n",$1,$2,$3,$4,$5,AVG}' student.txt
Name yuwen math pysical English Average
Alice 79 80 88 100 86.75
xiaoming88 69 92 99 87.00
xiaoli 69 90 99 89 86.75
[root@ansible test]#
條件及循環語句
條件語句:
if(條件表達式1)
動作
else if(條件表達式2)
動作
else
動作
循環語句:
while循環:
while(條件表達式)
動作
do while循環:
do
動作
while(條件表達式)
for循環:
for(初始化計數器;計數器測試;計數器變更)
動作
1、以:爲分隔符,只打印/etc/passwd中第3個字段的數值在50-100範圍內的行信息
代碼:
[root@ansible test]# cat script.awk
BEGIN{
FS=":"
}
{
if($3<50)
{
printf "%-20s%-20s%10d\n","uid>50",$1,$3
}
else if($3>50 && $3<100)
{
printf "%-20s%-20s%10d\n","100>uid>50",$1,$3
}
else
{
printf "%-20s%-20s%10d\n","uid>100",$1,$3
}
}
[root@ansible test]# awk -f script.awk passwd
uid>50 root 0
uid>50 bin 1
uid>50 daemon 2
uid>50 adm 3
uid>50 lp 4
練習: 使用do..while while for 來實現1+2+3….+100的和
字符串函數對照表
length(str) 計算長度
index(str1,str2) 返回在str1中查詢到的str2的位置
tolower(str) 小寫轉換
toupper(str) 大寫轉換
split(str,arr,fs) 分隔字符串,並保存到數組中
match(str,RE) 返回正則表達式匹配到的子串的位置
substr(str,m,n) 截取子串,從m個字符開始,截取n位。n若不指定,則默認截取到字符串尾
sub(RE,RepStr,str) 替換查找到的第一個子串,在str中搜索符合RE的字符串,將其替換爲RepStr;只替換第一個
gsub(RE,RepStr,str) 替換查找到的所有子串,同上,區別替換所有
練習題:
字符串的長度
1、以:爲分隔符,返回/etc/passwd中每行中每個字段的長度
root:x:0:0:root:/root:/bin/bash
4:1:1:1:4:5:9
思考:利用到NF內置的變量,處理行的字段個數,每個遍歷出來的字段利用函數算出長度打印輸出
代碼:
[root@ansible test]# cat test.awk
BEGIN{
FS=":"
}
{
i=1
while(i<=NF)
{
if(i==NF)
printf "%d",length($i)
else
printf "%d:",length($i)
i++
}
printf "\n"
}
[root@ansible test]# awk -f test.awk passwd1
4:1:0:0:4:5:9
17
3:1:0:0:3:4:13
6:1:0:0:6:5:13
匹配字符串的位置
搜索字符串"I have a dream"中出現"ea"子串的位置
[root@ansible test]# awk 'BEGIN{string="I hava a dream";aa=match(string,"ea");print aa}'
12
大小寫轉換
[root@ansible test]# awk 'BEGIN{str="i Want you";print toupper(str);print tolower(str)}'
I WANT YOU
i want you
子字符串的獲取
[root@ansible test]# awk 'BEGIN{str="my name is fangqiming";print substr(str,12,19)}'
Fangqiming
字符串的分割
[root@ansible test]# awk 'BEGIN{str="My Name Is FangQiMing";split(str,arr," ");print arr[4]}'
FangQiMing
字符串的替換
[root@ansible test]# awk 'BEGIN{str="My Name Is FangQiMing1988 [email protected]";print gsub(/[0-9]+/,"@secret@",str);print str}'
2
My Name Is FangQiMing@secret@ @secret@@qq.com
[root@ansible test]#
Awk選項總結:
awk中常用選項
-v 定義或引用變量
-f 指定awk命令文件
-F 指定分隔符
-V 查看awk的版本號
[root@ansible test]# awk -v var=$var1 -v ages=$age 'BEGIN{print var,ages}'
fangqiming 32
[root@ansible test]#
指定分隔符
[root@ansible test]# awk -F: '{print $7}' passwd
[root@ansible test]# awk 'BEGIN{FS=":"}{print $7}' passwd
以上兩種方式作用相同
[root@ansible test]# awk -V
GNU Awk 4.0.2
數組的使用:
Shell中數組的用法:
array=("Allen" "Mike" "Messi" "Jerry" "Hanmeimei" "Wang")
打印元素: echo ${array[2]}
打印元素個數: echo ${#array[@]}
打印元素長度: echo ${#array[3]}
給元素賦值: array[3]="Li"
刪除元素: unset array[2];unset array
分片訪問: echo ${array[@]:1:3}
元素內容替換: ${array[@]/e/E} 只替換第一個e;${array[@]//e/E}替換所有的e
數組的遍歷:
for a in ${array[@]}
do
echo $a
done
示例如下:
[root@ansible test]# arr=("xiaoli" "hanmeimemi" "lilei" "fang" "zhang")
[root@ansible test]# echo $arr
xiaoli
[root@ansible test]# echo ${arr[@]}
xiaoli hanmeimemi lilei fang zhang
[root@ansible test]# unset arr[0]
[root@ansible test]# echo ${arr[@]}
hanmeimemi lilei fang zhang
[root@ansible test]# for i in ${arr[@]}; do echo $i; done
hanmeimemi
lilei
fang
zhang
[root@ansible test]#
Awk中數組的用法:
在awk中,使用數組時,不僅可以使用1.2..n作爲數組下標,也可以使用字符串作爲數組下標
當使用1.2.3..n時,直接使用array[2]訪問元素;需要遍歷數組時,使用以下形式:
str="Allen Jerry Mike Tracy Jordan Kobe Garnet"
split(str,array)
for(i=1;i<=length(array);i++)
print array[i]
當使用字符串作爲數組下標時,需要使用array[str]形式訪問元素;遍歷數組時,使用以下形式:
array["var1"]="Jin"
array["var2"]="Hao"
array["var3"]="Fang"
for(a in array)
print array[a]
數組是以數字爲下標的情況,默認是從1開始的
[root@ansible test]# awk 'BEGIN{arr="xiaoli xiaoming fang";split(arr,array1);for(i=1;i<=length(array1);i++) print array1[i]}'
xiaoli
xiaoming
fang
[root@ansible test]#
數組下標以字符串爲標示的情況下使用
[root@ansible test]# awk 'BEGIN{array1["num1"]="xiaoli";array1["num2"]="fang";for(arr in array1) print array1[arr]}'
xiaoli
fang
[root@ansible test]#
練習題:
1、統計主機上所有的TCP連接狀態數,按照每個TCP狀態分類
netstat -an | grep tcp | awk '{array[$6]++}END{for(a in array) print a,array[a]}'
2、計算橫向數據總和,計算縱向數據總和
allen 80 90 87 91 348
mike 78 86 93 96 256
Kobe 66 92 82 78 232
Jerry 98 74 66 54 356
Wang 87 21 100 43 322
234 342 451 456 342
- 確保系統中有httpd
Rpm –ql httpd
[root@ansible test]# netstat -an | grep tcp #查看tcp的監聽情況
[root@ansible test]# netstat -an | grep tcp | awk '{print $6}'#查看tcp監聽端口的第六個元素
Awk統計命令如下
[root@ansible test]# netstat -an | grep tcp | awk 'BEGIN{}{array1[$6]++}END{for( arr in array1) print arr,array1[arr]}'
LISTEN 13
ESTABLISHED 1
[root@ansible test]#
- 計算橫向數據總和,計算縱向數據總和