1、總結sed和awk的詳細用法;
(1) sed
sed:Stream EDitor,流編輯器,行編輯器
基本原理:
一次從文本中讀取一行,放到sed自己的工作車間加工, 該工作車間叫做模式空間(pattern space)
判斷該行是否符合過濾模式,
-
如果符合過濾模式:
- 送往標準輸出(終端)
- 執行編輯操作, 從模式空間中處理以后,處理過后送到標準輸出(不一定有輸出,比如刪除操作)
- 如果不能被模式過濾,不做任何操作,直接送到標準輸出
也可以理解為模式空間的的內容,不管匹配不匹配都會送到標準輸出,但刪除(d)操作例外
基本語法:
sed [OPTION]… ‘script’ [input-file] …
script: 地址定界編輯命令 常用選項: -n:不輸出模式空間中的內容至屏幕;默認是輸出的 -e script, --expression=script:多點編輯;同時執行多個編輯命令 -f /PATH/TO/SED_SCRIPT_FILE : sed腳本,每行一個編輯命令; -r, --regexp-extended:支持使用擴展正則表達式; -i[SUFFIX], --in-place[=SUFFIX]:直接編輯原文件 ;危險:修改前先備份 地址定界: (1) 空地址:對全文進行處理; (2) 單地址: #:指定行; /pattern/:被此模式所匹配到的每一行; (3) 地址范圍 #,#: 從第#行到第#行 #,+#: 從第#行開始,一直到向下的#行 #,/pat1/ 從指定行開始到第一次被patteren匹配的行結束 /pat1/,/pat2/ 從第一次pattern匹配的行,到第一次被pattern匹配的行 $:最后一行 (4) 步進:~ 1~2:所有奇數行 2~2:所有偶數行 編輯命令: d:刪除模式空間中的內容 p:顯示模式空間中的內容; a \text:在行后面追加文本“text”,支持使用\n實現多行追加; i \text:在行前面插入文本“text”,支持使用\n實現多行插入; c \text:把匹配到的行替換為此處指定的文本“text”; w /PATH/TO/SOMEFILE:保存模式空間匹配到的行至指定的文件中; r /PATH/FROM/SOMEFILE:讀取指定文件的內容至當前文件被模式匹配到的行后面;文件合并; =:為模式匹配到的行打印行號; !:條件取反; 地址定界!編輯命令; s///:查找替換,其分隔符可自行指定,常用的有s@@@, s###等; 替換標記: g:全局替換; w /PATH/TO/SOMEFILE:將替換成功的結果保存至指定文件中; p:顯示替換成功的行; 高級編輯命令: 保持空間 hold space h:把模式空間中的內容覆蓋至保持空間中; H:把模式空間中的內容追加至保持空間中; g:把保持空間中的內容覆蓋至模式空間中; G:把保持空間中的內容追加至模式空間中; x:把模式空間中的內容與保持空間中的內容互換; n:覆蓋讀取匹配到的行的下一行至模式空間中; 覆蓋原行 N:追加讀取匹配到的行的下一行至模式空間中; 追加原行 d:刪除模式空間中的行; D:刪除多行模式空間中的所有行;
(2) awk
awk:報告生成器,格式化文本輸出
gawk – pattern scanning and processing language
模式掃描及編程語言
基本用法
gawk [options] ‘program’ FILE …
program: PATTERN{ACTION STATEMENTS}
模式{動作語句};
語句之間用分號分隔
PATTERN: 主要用來定界 awk本身實現文件遍歷一次讀取一行文本,按輸入分隔符切片,每一片放在內置變量中($1,$2...),整行用$0表示,支持條件判斷,循環(字段間循環) print, printf 選項: -F:指明輸入時用到的字段分隔符;默認空白字符 -v var=value: 自定義變量; 1、print print item1, item2, ... 要點: (1) 逗號分隔符; (2) 輸出的各item可以字符串,也可以是數值;當前記錄的字段、變量或awk的表達式; (3) 如省略item,相當于print $0; 示例: [root@localhost ~]# tail -3 /etc/fstab | awk '{print $2,$3}' / xfs /boot xfs swap swap [root@localhost ~]# tail -3 /etc/fstab | awk '{print "hello",$2,$3,6}' hello / xfs 6 hello /boot xfs 6 hello swap swap 6 變量不能放到引號內 [root@localhost ~]# tail -3 /etc/fstab | awk '{print "hello:$1"}' hello:$1 hello:$1 hello:$1 [root@localhost ~]# tail -3 /etc/fstab | awk '{print "hello:"$1}' hello:UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 hello:UUID=6caa3eec-f48d-4c2d-a2b0-8657112f6f55 hello:UUID=e2b0cd8f-89a0-458c-8ed9-5ad05f865565 輸入整行 [root@localhost ~]# tail -3 /etc/fstab | awk '{print}' UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 / xfs defaults 0 0 UUID=6caa3eec-f48d-4c2d-a2b0-8657112f6f55 /boot xfs defaults 0 0 UUID=e2b0cd8f-89a0-458c-8ed9-5ad05f865565 swap swap defaults 0 0 每行輸入空白 [root@localhost ~]# tail -3 /etc/fstab | awk '{print ""}' 2、變量 2.1 內建變量 FS:input field seperator輸入字段分隔符,默認為空白字符; OFS:output field seperator輸入字段分隔符,默認為空白字符; RS:input record seperator行分隔符,輸入時的換行符; ORS:output record seperator,輸出時的換行符; NF:number of field,字段數量 變量前不加$ {print NF}, 字段數量 {print $NF} 顯示的是字段 不要混淆 NR:number of record, 行數; FNR:各文件分別計數;行數; FILENAME:當前文件名; ARGC:命令行參數的個數; ARGV:數組,保存的是命令行所給定的各參數; 示例: 指明輸入文件字段分隔符 [root@localhost ~]# awk -v FS=':' '{print $1}' /etc/passwd root bin daemon 或直接使用選項,效果相同 [root@localhost ~]# awk -F: '{print $1}' /etc/passwd root bin daemon 指明輸入分隔符和輸出分隔符 [root@localhost ~]# awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd root:0:/bin/bash bin:1:/sbin/nologin daemon:2:/sbin/nologin 指定行分隔符, 遇到空格和原換行符都換行, 了解 [root@localhost ~]# awk -v RS=' ' '{print}' /etc/passwd 指定輸出行分隔符, 結果比較詭異, 空格分割的右#號隔開, 原換行符依然解析為換行 [root@localhost ~]# awk -v RS=' ' -v ORS='#' '{print}' /etc/passwd 輸入每行字段個數 [root@localhost ~]# awk '{print NF}' /etc/fstab 0 1 2 10 1 9 12 1 6 6 6 顯示行數, 此處為單個文件,表示為行編號 [root@localhost ~]# awk '{print NR}' /etc/fstab 1 2 3 4 5 6 7 8 9 10 11 兩個文件的行數,14行 [root@localhost ~]# awk '{print NR}' /etc/fstab /etc/issue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 單獨計算行數 [root@localhost ~]# awk '{print FNR}' /etc/fstab /etc/issue 1 2 3 4 5 6 7 8 9 10 11 1 2 3 顯示當前正在處理的文件名 [root@localhost ~]# awk '{print FILENAME}' /etc/fstab /etc/issue /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/issue /etc/issue /etc/issue 命令行參數個數,及 各參數 [root@localhost ~]# awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue 3 [root@localhost ~]# awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/issue awk [root@localhost ~]# awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue /etc/fstab [root@localhost ~]# awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/issue /etc/issue 2.2 自定義變量 (1) -v var=value 變量名區分字符大小寫; (2) 在program中直接定義 注意: 對文件不做處理時,文件可不帶 示例: 輸出自定義變量 [root@localhost ~]# awk -v test='hello awk' '{print test}' /etc/fstab hello awk hello awk hello awk hello awk hello awk hello awk hello awk hello awk hello awk hello awk hello awk 自定義變量,不帶文件 [root@localhost ~]# awk -v test='hello awk' 'BEGIN{print test}' hello awk 自定義變量,在程序中定義 [root@localhost ~]# awk 'BEGIN{test="hello awk";print test}' hello awk 3、printf命令 格式化輸出:printf FORMAT, item1, item2, ... FORMAT : 占位 (1) FORMAT必須給出; (2) 不會自動換行,需要顯式給出換行控制符,\n (3) FORMAT中需要分別為后面的每個item指定一個格式化符號; 格式符: 可加入字符串 %c: 顯示字符的ASCII碼; %d, %i: 顯示十進制整數; %e, %E: 科學計數法數值顯示; %f:顯示為浮點數; %g, %G:以科學計數法或浮點形式顯示數值; %s:顯示字符串; %u:無符號整數; %%: 顯示%自身; 修飾符: #[.#]:第一個數字控制顯示的寬度;第二個#表示小數點后的精度; %3.1f -: 左對齊 +:顯示數值的符號 示例: [root@localhost ~]# awk -F: '{printf "%s\n",$1}' /etc/passwd root bin daemon [root@localhost ~]# awk -F: '{printf "username: %s\n",$1}' /etc/passwd username: root username: bin username: daemon [root@localhost ~]# awk -F: '{printf "username: %s,uid: %d\n",$1,$3}' /etc/passwd username: root,uid: 0 username: bin,uid: 1 username: daemon,uid: 2 右對齊 [root@localhost ~]# awk -F: '{printf "username: %15s,uid: %d\n",$1,$3}' /etc/passwd username: root,uid: 0 username: bin,uid: 1 username: daemon,uid: 2 左對齊 [root@localhost ~]# awk -F: '{printf "username: %-15s,uid: %d\n",$1,$3}' /etc/passwd username: root ,uid: 0 username: bin ,uid: 1 username: daemon ,uid: 2 4、操作符 算術操作符: x+y, x-y, x*y, x/y, x^y, x%y -x : 正數轉為負數 +x: 轉換為數值; 字符串操作符:沒有符號的操作符,字符串連接 賦值操作符: =, +=, -=, *=, /=, %=, ^= ++, -- 比較操作符: >, >=, <, <=, !=, == 模式匹配符: ~:是否匹配 !~:是否不匹配 邏輯操作符: && || ! 函數調用: function_name(argu1, argu2, ...) 條件表達式: selector?if-true-expression:if-false-expression # awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd 示例: [root@localhost ~]# awk -F: '{$3>=1000?usertype="common user":usertype="sysadmin or sysuser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd root:sysadmin or sysuser bin:sysadmin or sysuser 5、PATTERN (1) empty:空模式,匹配每一行; (2) /regular expression/:僅處理能夠被此處的模式匹配到的行; (3) relational expression: 關系表達式;結果有“真”有“假”;結果為“真”才會被處理; 真:結果為非0值,非空字符串; (4) line ranges:行范圍, startline,endline:/pat1/,/pat2/ 注意: 不支持直接給出數字的格式 ~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd (5) BEGIN/END模式 BEGIN{}: 僅在開始處理文件中的文本之前執行一次; END{}:僅在文本處理完成之后執行一次; 示例: 取UUID開頭的行 [root@localhost ~]# awk '/^UUID/{print $1}' /etc/fstab UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 UUID=6caa3eec-f48d-4c2d-a2b0-8657112f6f55 UUID=e2b0cd8f-89a0-458c-8ed9-5ad05f865565 取非UUID開頭的行 [root@localhost ~]# awk '!/^UUID/{print $1}' /etc/fstab # # # # # # # 查找id對于1000的用戶 [root@localhost ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd han 1000 user101 1001 取出默認shell為bash的用戶 條件表達式 [root@localhost ~]# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd root /bin/bash han /bin/bash 取出默認shell為bash的用戶 模式匹配 [root@localhost ~]# awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd root /bin/bash han /bin/bash 定界(模式) [root@localhost ~]# awk -F: '/^root/,/^daemon/{print $1}' /etc/passwd root bin daemon 定界(行號) [root@localhost ~]# awk -F: '(NR>=1&&NR<=3){print $1}' /etc/passwd root bin daemon 表頭和表尾 [root@localhost ~]# awk -F: 'BEGIN{print " username uid \n------------------------"}{print $1,$3}END{print "==============="}' /etc/passwd username uid ------------------------ root 0 bin 1 daemon 2 =============== 6、常用的action (1) Expressions 表達式 (2) Control statements:if, while等; 控制語句 (3) Compound statements:組合語句; 多個語句作為單個代碼塊 (4) input statements 輸入語句 (5) output statements 輸出語句 7、控制語句 if(condition) {statments} if(condition) {statments} else {statements} while(conditon) {statments} do {statements} while(condition) for(expr1;expr2;expr3) {statements} break continue delete array[index] 從數組中刪除某個元素 delete array 刪除整個數組 exit 退出 { statements } 組合語句 7.1 if-else 語法:if(condition) statement [else statement] 注意: 有else語句時,需使用花括號 ~]# awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd 默認shell為bash ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd 行數大于5 ~]# awk '{if(NF>5) print $0}' /etc/fstab 設備使用率大于20% ~]# df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=20) print $1}' 使用場景:對awk取得的整行或某個字段做條件判斷; 示例: 單分支 取用戶id大于1000的用戶 [root@localhost ~]# awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd han 1000 user101 1001 取默認shell為bash [root@localhost ~]# awk -F: '{if($NF=="/bin/bash")print $1,$7}' /etc/passwd root /bin/bash han /bin/bash 每行字段數大于5的行 [root@localhost ~]# awk '{if(NF>5)print $0}' /etc/fstab # Created by anaconda on Sat Aug 20 07:19:36 2016 # Accessible filesystems, by reference, are maintained under '/dev/disk' # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 / xfs defaults 0 0 UUID=6caa3eec-f48d-4c2d-a2b0-8657112f6f55 /boot xfs defaults 0 0 UUID=e2b0cd8f-89a0-458c-8ed9-5ad05f865565 swap swap defaults 0 0 雙分支 [root@localhost ~]# awk -F: '{if($3>=1000) {printf "Common user: %s\n", $1} else {printf "root or sysuser: %s\n",$1}}' /etc/passwd root or sysuser: root root or sysuser: bin 查看硬盤使用情況,大于20% [root@localhost ~]# df -h | awk -F% '/^\/dev/{print $1}' | awk '{if($NF>=20)print $1,$NF}' /dev/sda2 37 /dev/sda1 29 /dev/sr0 100 7.2 while循環 語法:while(condition) statement 條件“真”,進入循環;條件“假”,退出循環; 使用場景:對一行內的多個字段逐一類似處理時使用;對數組中的各元素逐一處理時使用; 示例: 顯示每行的每一個字段,和字段的字符個數 ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg 顯示每行的每一個字段,和字段的字符個數(長度大于等于7) ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)}; i++}}' /etc/grub2.cfg 練習1, 每行的每字段的長度 [root@localhost ~]# awk '/^[[:space:]]*linux16/{print}' /etc/grub2.cfg linux16 /vmlinuz-3.10.104-1.el7 root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 ro rhgb quiet LANG=en_US.UTF-8 linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 ro rhgb quiet LANG=en_US.UTF-8 linux16 /vmlinuz-0-rescue-f6f5e947dd374a46b0b7238d0ae4becb root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 ro rhgb quiet [root@localhost ~]# linux16 7^C [root@localhost ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.104-1.el7 23 root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46 ro 2 rhgb 4 quiet 5 LANG=en_US.UTF-8 16 linux16 7 /vmlinuz-3.10.0-327.el7.x86_64 30 root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46 ro 2 rhgb 4 quiet 5 LANG=en_US.UTF-8 16 linux16 7 /vmlinuz-0-rescue-f6f5e947dd374a46b0b7238d0ae4becb 50 root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46 ro 2 rhgb 4 quiet 5 大于等于7的字段: [root@localhost ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){if(length($i)>=7){print $i,length($i)};i++}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.104-1.el7 23 root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46 LANG=en_US.UTF-8 16 linux16 7 /vmlinuz-3.10.0-327.el7.x86_64 30 root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46 LANG=en_US.UTF-8 16 linux16 7 /vmlinuz-0-rescue-f6f5e947dd374a46b0b7238d0ae4becb 50 root=UUID=fcaeeb31-be94-4915-a2cd-0663a733f140 46 7.3 do-while循環 語法:do statement while(condition) 意義:至少執行一次循環體 7.4 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} 7.5 switch語句 語法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; ...; default: statement} 用于字符串比較判斷 7.6 break和continue 針對的是字段 break [n] 跳出n層循環 continue 進入下一輪循環 7.7 next 控制awk的內生循環 針對的是行 提前結束對本行的處理而直接進入下一行; 顯示偶數行 ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd 8、array 關聯數組:array[index-expression] index-expression: (1) 可使用任意字符串;字符串要使用雙引號; (2) 如果某數組元素事先不存在,在引用時,awk會自動創建此元素,并將其值初始化為“空串”;數值運算的話會當成0 若要判斷數組中是否存在某元素,要使用"index in array"格式進行; weekdays[mon]="Monday" 若要遍歷數組中的每個元素,要使用for循環; for(var in array) {for-body} 示例: ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}' [root@localhost ~]# awk 'BEGIN{weekday["mon"]="monday";weekday["tue"]="tuesday";for( i in weekday) {print weekday[i]}}' tuesday monday 注意:var會遍歷array的每個索引; 使用該特性,計算每個狀態的次數 state["LISTEN"]++ state["ESTABLISHED"]++ ~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}' [root@localhost ~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state){print i,state[i]}}' LISTEN 2 ESTABLISHED 1 ~]# awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log 統計httpd日志中每個ip的訪問情況 [root@localhost ~]# awk '/^[^:]/{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log 172.16.0.1 143 練習1:統計/etc/fstab文件中每個文件系統類型出現的次數; ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab [root@localhost ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs){print i,fs[i]}}' /etc/fstab swap 1 xfs 2 練習2:統計指定文件中每個單詞出現的次數; ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab 9、函數 9.1 內置函數 數值處理: rand():返回0和1之間一個隨機數; 注意: 只有第一次是隨機的 [root@localhost ~]# awk 'BEGIN{print rand()}' 0.237788 [root@localhost ~]# awk 'BEGIN{print rand()}' 0.237788 字符串處理: length([s]):返回指定字符串的長度; sub(r,s,[t]):以r表示的模式來查找t所表示的字符中的匹配的內容,并將其第一次出現替換為s所表示的內容; gsub(r,s,[t]):以r表示的模式來查找t所表示的字符中的匹配的內容,并將其所有出現均替換為s所表示的內容; split(s,a[,r]):以r為分隔符切割字符s,并將切割后的結果保存至a所表示的數組中; awk數組從1開始編號 ~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}' 9.2 自定義函數 推薦: 《sed和awk》
2、刪除/boot/grub/grub.conf文件中所有行的行首的空白字符;
[root@node1 ~]# sed 's#^[[:space:]]\+##' /boot/grub/grub.conf # grub.conf generated by anaconda # # Note that you do not have to rerun grub after making changes to this file # NOTICE: You have a /boot partition. This means that # all kernel and initrd paths are relative to /boot/, eg. # root (hd0,0) # kernel /vmlinuz-version ro root=/dev/mapper/VolGroup-lv_root # initrd /initrd-[generic-]version.img #boot=/dev/sda default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title CentOS 6 (2.6.32-504.el6.x86_64) root (hd0,0) kernel /vmlinuz-2.6.32-504.el6.x86_64 ro root=/dev/mapper/VolGroup-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=VolGroup/lv_swap SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=VolGroup/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet initrd /initramfs-2.6.32-504.el6.x86_64.img
3、刪除/etc/fstab文件中所有以#開頭,后跟至少一個空白字符的行的行首的#和空白字符;
[root@node1 ~]# sed 's@^#[[:space:]]\+@@' /etc/fstab # /etc/fstab Created by anaconda on Sun Apr 23 14:26:50 2017 # Accessible filesystems, by reference, are maintained under '/dev/disk' See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info # /dev/mapper/VolGroup-lv_root / ext4 defaults 1 1 UUID=2bf153ef-3ae1-4a1f-8140-813aead76d0a /boot ext4 defaults 1 2 /dev/mapper/VolGroup-lv_home /home ext4 defaults 1 2 /dev/mapper/VolGroup-lv_swap swap swap defaults 0 0 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0
4、把/etc/fstab文件的奇數行另存為/tmp/fstab.3;
[root@node1 ~]# sed -n '1~2w /tmp/fstab.3' /etc/fstab [root@node1 ~]# cat /tmp/fstab.3 # /etc/fstab # # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info /dev/mapper/VolGroup-lv_root / ext4 defaults 1 1 /dev/mapper/VolGroup-lv_home /home ext4 defaults 1 2 tmpfs /dev/shm tmpfs defaults 0 0 sysfs /sys sysfs defaults 0 0
5、echo一個文件路徑給sed命令,取出其基名;進一步地,取出其路徑名;
取基名:
[root@node1 ~]# echo "/etc/fstab" | sed -r 's@.*/(.*)@\1@' fstab [root@node1 ~]# echo "/var/name/html" | sed -r 's@.*/(.*)@\1@' html
取路徑名:
[root@node1 ~]# echo "/var/www/html" | sed -r 's@(.*/).*@\1@' /var/www/ [root@node1 ~]# echo "/etc/fstab" | sed -r 's@(.*/).*@\1@' /etc/
6、統計指定文件中所有行中每個單詞出現的次數;
[root@node1 ~]# awk '{i=1;while(i<=NF){word[$i]++;i++}}END{for(i in word){print i,word[i]}}' /etc/fstab mount(8) 1 Accessible 1 pages 1 reference, 1 /dev/pts 1 /dev/mapper/VolGroup-lv_swap 1 info 1 devpts 2 tmpfs 2 /dev/mapper/VolGroup-lv_home 1 blkid(8) 1 and/or 1 # 7 gid=5,mode=620 1 Sun 1 / 1 anaconda 1 /proc 1 0 10 1 4 2 2 findfs(8), 1 on 1 /boot 1 Apr 1 /dev/mapper/VolGroup-lv_root 1 /etc/fstab 1 sysfs 2 2017 1 are 1 more 1 /sys 1 '/dev/disk' 1 /home 1 14:26:50 1 defaults 7 proc 2 ext4 3 by 2 swap 2 /dev/shm 1 23 1 for 1 man 1 See 1 filesystems, 1 UUID=2bf153ef-3ae1-4a1f-8140-813aead76d0a 1 maintained 1 Created 1 under 1 fstab(5), 1
7、統計當前系統上所有tcp連接的各種狀態的個數;
~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state){print i,state[i]}}' ESTABLISHED 3 LISTEN 14
8、統計指定的web訪問日志中各ip的資源訪問次數:
~]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log 172.16.0.23 2
9、寫一個腳本:定義一個數組,數組元素為/var/log目錄下所有以.log結尾的文件的名字;顯示每個文件的行數;
#!/bin/bash # description: 顯示/var/log下所有以.log結尾的文件對應的行數 # author: han declare -a filenames filenames=(/var/log/*.log) for((i=0;i<${#filenames[*]};i++));do filename=`basename ${filenames[$i]}` lines=`wc -l ${filenames[$i]} | cut -d' ' -f1` printf "%-30s %-5s\n" $filename $lines done 執行結果: ]# bash file_lines.sh anaconda.ifcfg.log 168 anaconda.log 257 anaconda.program.log 387 anaconda.storage.log 1466 anaconda.yum.log 224 boot.log 45 dracut.log 1639 heartbeat.log 5719 mysqld.log 128 yum.log 82
10、寫一個腳本,能從所有同學中隨機挑選一個同學回答問題;進一步地:可接受一個參數,做為要挑選的同學的個數;
]# cat choose.sh #!/bin/bash # 隨機抽選一個或幾個同學 # han #定義一個數組,保存同學名字 declare -a names names=("張三" "李四" "王五" "劉六" "田七" "韓信" "匆匆" "忙忙" "豆豆" "五行") total=${#names[*]} #定義一個函數,判斷新生成的隨機數是否已經在下標列表數組choices中,存在則返回3, function isexited(){ for((j=0;j<${#choices[*]};j++));do if [ ${choices[$j]} -eq $choice ];then return 3 fi done } #參數大于一個時,提示使用方法 [ $# -gt 1 ] && echo "Usage $0 [1-${#names[*]}]" && exit 1 #沒有參數時,默認顯示一位同學 if [ $# -eq 0 ];then choice=$[$RANDOM%${total}] echo "${names[$choice]} " #有一個參數時 else #參數非數字時,退出 if [[ ! $1 =~ [0-9] ]];then echo "Invalid agrument" exit 2 fi #參數大小在正確范圍時 #定義一個數組,存放出現過的學生下標 declare -a choices if [ $1 -ge 1 ] && [ $1 -le $total ];then #循環$1次 for((i=0;i<$1;i++));do #生成隨機數,作為數組下標 choice=$[$RANDOM%${total}] #調用函數,判斷該下標是否在choices數組中 isexited #判斷函數返回值,已存在則將i自減1,使得下個循環變量依然為i,保證下標存在時有多一次循環機會,保證最后choices組有$1個元素 if [ $? -eq 3 ];then let i-- else choices[$i]=$choice fi done #根據下標顯示挑選出的同學 for i in ${choices[*]};do echo -n "${names[$i]} " done echo else echo "Usage $0 [1-${#names[*]}]" && exit 1 fi fi
效果
[root@node1 scripts]# ./choose.sh 忙忙 [root@node1 scripts]# ./choose.sh 3 匆匆 韓信 劉六 [root@node1 scripts]# ./choose.sh 9 李四 五行 忙忙 豆豆 匆匆 王五 劉六 韓信 張三 [root@node1 scripts]# ./choose.sh 9 張三 韓信 劉六 忙忙 王五 匆匆 李四 五行 田七 [root@node1 scripts]# ./choose.sh 12 Usage ./choose.sh [1-10]
備注: 此題用的方法有些麻煩,看了下其他同學的方法,有個非常簡單記錄在此:
#!/bin/bash # students=(a b c d e f g h i j k) read -t 5 -p "Please input the number of students: " num if [[ $num -le ${#students[@]} ]] then for ((i=0;i<num;i++)) do x=$[$RANDOM % ${#students[@]}] echo ${students[$x]} students[$x]=${students[${#students[@]}-1]} unset students[${#students[@]}-1] #這樣刪就不會再選到這個索引號 #unset students[$x] 這個刪除只刪除了元素的值,但索引號仍在值為空 done else echo "Error";exit fi 備注: 大致思路看明白了,只是比較費解這種unset方法
另外一種徹底刪除元素加索引的方法:
[root@node1 scripts]# files=(/etc/[Pp]*) [root@node1 scripts]# echo ${files[@]} /etc/pam.d /etc/pango /etc/passwd /etc/passwd- /etc/pkcs11 /etc/pki /etc/plymouth /etc/pm /etc/popt.d /etc/postfix /etc/ppp /etc/printcap /etc/profile /etc/profile.d /etc/protocols [root@node1 scripts]# echo ${#files[@]} 15 #當前數組有15個元素 #刪除特定索引的元素(同時刪除索引) [root@node1 scripts]# pos=3 #刪除索引3的元素 [root@node1 scripts]# files=(${files[@]:0:$pos} ${files[@]:$(($pos + 1))}) #通過數組切片將前3各元素的數組和從第4各元素開始的數組合并為一個數組 [root@node1 scripts]# echo ${#files[@]} 14 #此時元素各數為14 [root@node1 scripts]# echo ${files[@]} /etc/pam.d /etc/pango /etc/passwd /etc/pkcs11 /etc/pki /etc/plymouth /etc/pm /etc/popt.d /etc/postfix /etc/ppp /etc/printcap /etc/profile /etc/profile.d /etc/protocols # 索引為3的元素/etc/passwd-已經被刪除
11、授權centos用戶可以運行fdisk命令完成磁盤管理,以及使用mkfs或mke2fs實現文件系統管理;
root用戶: ]# visudo centos ALL=(ALL) /sbin/fdisk,/sbin/mkfs,/sbin/mke2fs
12、授權gentoo用戶可以運行邏輯卷管理的相關命令;
[root@node1 ~]# visudo gentoo ALL=(ALL) /sbin/pvs,/sbin/pvdisplay,/sbin/pvcreate,/sbin/vgs,/sbin/vgdisplay,/sbin/vgcreate,/sbin/vgextend,/sbin/vgreduce,/sbin/vgremove,/sbin/lvs ,/sbin/lvdisplay,/sbin/lvcreate,/sbin/lvremove,/sbin/lvextend,/sbin/resize2fs
13、基于pam_time.so模塊,限制用戶通過sshd服務遠程登錄只能在工作時間進行;
需用到pam模塊pam_time.so
1) ssh
]# vim /etc/pam.d/sshd #%PAM-1.0 auth required pam_sepermit.so auth include password-auth account required pam_time.so #添加該行 account required pam_nologin.so ...
2)配置time.conf
time.conf配置文件格式:services;ttys;users;times
services — pam服務名列表,可以ls /etc/pam.d查看
tty —終端名.
users —用戶名
times —可以使用services 的時間段
]# vim /etc/security/time.conf sshd;*;centos;MoTuWeThFr0900-1800 #centos用戶只能在工作時間通過ssh遠程登錄
驗證:
[centos@node1 ~]$ ssh centos@172.16.0.20 centos@172.16.0.20's password: Connection closed by 172.16.0.20
14、基于pam_listfile.so模塊,定義僅某些用戶,或某些組內的用戶可登錄系統;
創建允許訪問的用戶列表 [root@node1 ~]# vim /etc/sshd_userlist root centos 修改文件權限(非必須) [root@node1 ~]# chmod 600 /etc/sshd_userlist 修改pam配置文件 [root@node1 ~]# vim /etc/pam.d/sshd #%PAM-1.0 auth required pam_listfile.so item=user sense=allow file=/etc/sshd_userlist onerr=succeed auth required pam_sepermit.so
驗證:
centos可以訪問 [centos@node1 ~]$ ssh centos@172.16.0.20 centos@172.16.0.20's password: Last login: Sat May 6 17:04:12 2017 from node1.magedu.com fedora被拒絕訪問 [root@node2 ~]# ssh fedora@172.16.0.20 fedora@172.16.0.20's password: Permission denied, please try again. fedora@172.16.0.20's password: Permission denied, please try again. fedora@172.16.0.20's password:
原創文章,作者:hansj,如若轉載,請注明出處:http://www.www58058.com/74840
厲害,學習了。