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.178linux.com/74840
评论列表(1条)
厉害,学习了。