shell基础入门 为什么使用shell 1.安装操作系统(CentOS)自动化安装操作系统(kickstart cobbler)底层shell
2.初始化/优化操作系统
ntp时间同步
更改默认yum源
ssh优化
关闭Selinux
关闭/开启 防火墙(C6:iptables C7:firewalld)
安装基础服务(wget vim lrzsz net-tools unzip gzip…)
优化文件描述符
优化字符集
3.安装服务
Nginx
PHP
MySQL
Redis
MHA
Rsync
NFS
MongoDB
Zabbix
4.启动服务(系统默认的shell脚本)
5.脚本实现自动化代码上线
6.监控服务(使用shell)
7.结合定时任务使用shell
8.重复性工作写入脚本
shell编程需要掌握的基础知识
熟练使用vim编辑器
熟悉ssh终端(Xshell、CRT)
熟练掌握linux常用命令
熟练掌握linux正则表达式及三剑客命令
VScode
shell脚本规范 1.目录统一 2.shell脚本的结尾要以.sh结尾 3.脚本的开头需要有解释器
4.作者信息
5.一定要有注释(可以中文)
6.shell中尽量使用英文
7.成对的符号和语句一次性写完
vim模板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 [root@zabbix01 ~] #!/bin/bash [root@zabbix01 ~] autocmd BufNewFile *.spec 0r /usr/share/vim/vimfiles/template.spec autocmd BufNewFile *.sh 0r /usr/share/vim/vimfiles/template.roger [root@zabbix01 ~] autocmd bufNewFile *.py,*.sh,*.java exec ":call SetTitle()" func SetTitle() if expand("%:e" ) == 'sh' call setline(1, "#!/bin/bash" ) call setline(2, "" ) call setline(3, "# File Name: __" .expand("%" ) . "__" ) call setline(4, "# Version: __v1.1__ " ) call setline(5, "# Author: __RogerWang__ " ) call setline(6, "# Mail: __690705712@qq.com__ " ) call setline(7, "# Blog: __https://rogerxs80.github.io/__ " ) call setline(8, "# DateTime: __" .expand(strftime("%Y-%m-%d %H:%M" )) . "__" ) endif endfunc [root@zabbix01 ~]
脚本执行方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 [root@m01 ~] #!/bin/bash echo 'Hello World' [root@m01 ~] Hello World [root@m01 ~] Hello World [root@m01 ~] Hello World [root@m01 ~] Hello World [root@m01 ~] Hello World [root@m01 ~] Hello World
. 和 source 都是在父shell下执行的 sh , bash ,相对路径 ,绝对路径都是在子shell下执行的
开发语言中程序代码分类
shell中的变量 变量介绍 变量即变化的量,核心是“变”与“量”二字,变即变化,量即衡量状态
量:是记录现实世界当中的某种状态 变:指的是记录的状态是可以发生变化的
如何使用变量 1 2 3 变量名 赋值符号 变量值 name=roger name: roger
定义变量的语法(分三部分): 1)变量名 相当于一个门牌号,便于取出变量值,是访问到值的唯一方式
2)赋值符号 将值的内存地址,绑定给变量名
3)变量值 用来表示状态
变量的使用规则:先定义,在通过变量名去引用
定义变量名的规范 变量名的命名规则: 1.大前提:变量名的命名应该能够反映出值记录的状态 2.变量是用来访问变量值的,所以变量名应该遵循一定规范,来方便我们标识存到内存中值的功能
1 2 3 4 5 1.变量名只能是 字母、数字或下划线的任意组合(区分大小写) 2.变量名不可以使用中文 3.变量名,不要使用命令来命名 4.不要用拼音 5.变量名不能以数字开头
变量名定义的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1.下划线+纯小写 name_of_ww='roger' name_of_xxx='roger' 2.驼峰体 nameOfWw='roger' nameOfWwww='roger' ageOfWwww=73 3.下划线+纯大写 NAME_OF_WWW='xxx' 不好的方式: 1)变量名为中文、拼音 2)变量名过长 3)变量名词不达意
变量的分类 系统内置环境变量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 env declare export LANG PATH PS1 UID HOSTNAME PWD USER HISTSIZE HISTFILESIZE HISTFILE TMOUT HISTCONTROL:export HISTCONTROL=ignorespace PROMPT_COMMAND:export PROMPT_COMMAND
普通变量 1 2 3 4 5 6 DATE=$(date +%F-%T) IP=$(ifconfig eth0|awk 'NR==2{print $2}' ) mkdir $DATE_ $IP_ $HOSTNAME mkdir ${DATE} _${IP} _${HOSTNAME}
位置变量 1 2 3 4 5 6 7 8 9 $N :N正整数,$1 $2 $3 ...$N 两位数要使用{}, ${11} ${10} $0 :执行脚本的路径和名字$# :传递参数的个数$*: 1.不适合数组使用 2.调用是加双引号 $@ :1.适合后面数组数据类型使用 2.调用是加双引号
特殊变量(状态) 1 2 3 4 5 6 7 $?:表示上一个命令执行的状态(上一条命令的返回值)0 成功执行 非0失败 特殊命令: - false - diff $$:表示当前脚本执行的pid $!:上一个脚本或者程序运行的pid $_ :获取上一条命令的最后一个参数(以空格为分隔符) ESC + .
变量的子串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ${#变量名} :获取该变量的值长度 ${变量名} :调用变量 ${变量名:偏移量} :字符串的截取 ${变量名:偏移量:步长} :字符串的截取time for n in {1..10000};do echo ${#n} >/dev/null;done time for n in {1..10000};do echo ${n} |wc -L >/dev/null;done time for n in {1..10000};do echo ${n} |awk '{print length()}' > /dev/null;done ${变量名#字符串} :从变量开头,删除最短匹配word的子串 ${变量名##字符串} :从变量开头,删除最长匹配word的子串 for line in `cat 1.txt`;do echo ${line##*/} echo ${line#*/} done ${parameter%word} 从变量结尾,删除最短匹配的word的子串${parameter%%word} 从变量结尾,删除最长匹配的word的子串${parameter/pattern/string} 使用string替换第一个pattern${parameter//pattern/string} 使用string替换所有的pattern
企业面试题 I am oldboy linux's teacher Roger,welcome to our trainning.
请打印出这句话中,单词大于6的单词并显示个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 1.如何将一句话变成一个一个的单词 2.将每一个单词拿出来跟6进行对比 3.如果大于6就打印 4.如果大于6就打印出具体个数 echo "I am oldboy linux's teacher Roger,welcome to our trainning." |tr ',.' ' ' for word in I am oldboy linux's teacher Roger welcome to our trainning;do if [ ${#word} -gt 6 ];then pass fi done echo "单词:$word" echo "长度:${#word}" # 放入脚本 [root@m01 script]# vim 02_sub_string.sh #!/bin/bash text=`echo "I am oldboy linux' s teacher Roger,welcome to our trainning." |tr ',.' ' '` for word in $text ;do if [ ${#word} -gt 6 ];then echo " 单词:$word " echo " 长度:${#word} " fi done [root@m01 script]# sh 02_sub_string.sh 单词:linux's 长度:7 单词:teacher 长度:7 单词:welcome 长度:7 单词:trainning 长度:9 ## 美化 #!/bin/bash text=`echo " I am oldboy linux's teacher Roger,welcome to our trainning." |tr ' ,.' ' '` for word in $text;do if [ ${#word} -gt 6 ];then echo ' ------ 单词统计结果 ------' echo "单词:$word" echo "长度:${#word}" fi done ## 纯awk方法(简单了解,这里只是为了让你们看看awk的牛逼之处) [root@m01 script]# echo "I am oldboy linux' s teacher Roger,welcome to our trainning."|awk -F '[ ,.]' '{for(i=1;i<=NF;i++) if(length($i ) >6) print " 单词:"$i ," 长度:" length($i )}' # 美化 [root@m01 script]# echo " I am oldboy linux's teacher Roger,welcome to our trainning."|awk -F ' [ ,.]' ' {for (i=1;i<=NF;i++) if (length($i ) >6) print "------ 单词统计结果------\n" "单词:" $i "\n长度:" length($i )}' ------ 单词统计结果------ 单词:linux' s长度:7 ------ 单词统计结果------ 单词:teacher 长度:7 ------ 单词统计结果------ 单词:welcome 长度:7 ------ 单词统计结果------ 单词:trainning 长度:9
shell运算符 基础运算符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 +:加 -:减 *:乘 /:除 %:取余 echo $((RANDOM%10))for ((i=1;i<=10;i++));do echo $i done for n in `seq 10`;do echo $n done
逻辑符号
所有符号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 +、- 加号,减号,一般用于整型、浮点型等类型的运算,其他语言中也可以做字符串的拼接 *、/、% 乘号、除号、取余,一般用于运算 ------- **:幂运算 ++、-- 自增、自减,可前置也可后置,默认步长为1 n++:n=n+1 n--:n=n-1 n++ n+=1 n=n+1 n=n+2 n+=2 n=n-2 n-=2 n=n*2 n*=2 n=n/2 n/=2 n=n%2 n%=2 ==:等于 <:小于 >:大于 >=:大于等于 <=:小于等于 <> 或 != :不等于 =:赋值符号 ==:运算符号,等于 >>:向右位移 <<:向左位移 ~、|、&、^:按位取反、按位异或、按位与、按位或
运算方式 (()) 1 2 3 4 5 6 echo $((1+2))echo $((26/5))a=1 b=2 echo $((a+b))
let 1 2 3 4 5 let a=1+2echo $a let b=26/5echo $b
expr 1 2 3 4 expr 1 + 1 expr 1+1 expr 2 * 2.5 expr 26 / 5
bc 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ 5.20000000000000000000 echo 'scale=100;a(1)*4' |bc -l3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170676 root@m01,172.16.1.61:~ 11111111 root@m01,172.16.1.61:~ 11000000 root@m01,172.16.1.61:~ C0 root@m01,172.16.1.61:~ FF
awk 1 2 3 4 root@m01,172.16.1.61:~ 5.2324 root@m01,172.16.1.61:~ 5.2 3 24
作业脚本:计算器 1 2 3 4 5 6 7 8 9 10 11 1.首先要传递2个参数(数字) 2.传少了报错 报错信息:至少传递两个整数... 3.传的不是数字报错 报错信息:请输入两个整数,不能是字母或特殊符号... 4.计算出传递两个数字的 - + - - - * - / - %
shell条件表达式 条件表达式介绍 条件表达式,我们非常的常用,可以说,任何编程语言,都离不开条件表达式,但是每种变成语言的写法都不太一样,在shell中,有一种独特的写法。
1 2 3 [ 条件 ] [[ 条件 ]] test 条件
条件表达式的选项 判断普通文件 -f file
1 2 3 4 5 6 7 8 9 -f:判断文件是否存在 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ 0 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ test -f /tmp/2.txt && echo '存在' || echo '不存在' [ -f /tmp/2.txt ] && echo '存在' || echo '不存在' [[ -f /tmp/2.txt ]] && echo '存在' || echo '不存在'
判断目录-d directory
1 2 3 4 5 6 7 8 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ 0 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ test -d /tmp/ && echo '存在' || echo '不存在' [ -d /tmp ] && echo '存在' || echo '不存在' [[ -d /tmp ]] && echo '存在' || echo '不存在'
判断文件-e exists
1 2 3 4 5 6 既可以判断文件也可以判断目录 root@m01,172.16.1.61:~ 存在 root@m01,172.16.1.61:~ 存在
判断文件有没有读取权限 -r read
1 test -r /tmp/1.txt && echo '可读' || echo '不可读'
判断文件有没有写入权限 -w write
1 test -w /tmp/1.txt && echo '可写' || echo '不可写'
判断文件有没有执行权限 -x execute
1 test -x /tmp/1.txt && echo '可执行' || echo '不可执行'
判断文件有没有内容 -s size
1 2 test -s /tmp/1.txt && echo '有内容' || echo '文件为空' 文件为空
判断文件是否是一个软链接 -L link
1 2 3 4 root@m01,172.16.1.61:~ 是软链接 root@m01,172.16.1.61:~ 不是软链接
对比两个文件的新旧 -nt newer than
1 2 3 4 5 root@m01,172.16.1.61:~ 1.txt不比2.txt新 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ 1.txt比2.txt新
对比两个文件的新旧 -ot oldder than
1 2 3 4 5 root@m01,172.16.1.61:~ 1.txt不比2.txt老 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ 1.txt比2.txt老
字符串表达式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 -n:判断字符串是否为空,非空则成立 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ 字符串为空 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ 字符串不为空 -z:判断字符串是否为空,空则成立 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ 字符串不为空 root@m01,172.16.1.61:~ root@m01,172.16.1.61:~ 字符串为空 'str1' = 'str2' :字符串相等则成立root@m01,172.16.1.61:~ 字符串相等 root@m01,172.16.1.61:~ 字符串不相等 'str1' != 'str2' :字符串不相等则成立root@m01,172.16.1.61:~ 字符串相等 root@m01,172.16.1.61:~ 字符串不相等
整数表达式 1 2 3 4 5 6 7 8 9 -eq:等于 -ne:不等于 -lt:小于 -le:小于等于 -gt:大于 -ge:大于等于 root@m01,172.16.1.61:~ 1
[[]]正则表达式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 =~:成员运算 [[ =~ ]] [root@m01 ~] [root@m01 ~] 包含 [root@m01 ~] 不包含 [root@m01 ~] 不包含 [root@m01 ~] 包含 [root@m01 ~] 包含 [root@m01 ~] 不包含 [root@m01 ~] 包含 [root@m01 ~] 不包含 [root@m01 ~] 包含
逻辑表达式 1 2 3 !:非 &&:与 -a [[]] && [[]] [ $num -eq 0 -a $num2 -ne 3 ] ||:或 -o [[]] || [[]] [ $num -eq 0 -o $num2 -ne 3 ]
shell流程控制if if条件语句语法 单分支 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 if [ 条件1 ];then 动作1 动作2 动作3 fi if [ 条件1 ]then 动作1 动作2 动作3 fi [ 条件1 ] && { 动作1 动作2 动作3 }
双分支 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 if [ 条件1 ];then 动作1 动作2 动作3 else 动作1 动作2 动作3 fi if [ 条件1 ]then 动作1 动作2 动作3 else 动作1 动作2 动作3 fi [ 条件1 ] && { 动作1 动作2 动作3 } || { 动作1 动作2 动作3 }
多分支 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 if [ 条件1 ];then 动作1 动作2 动作3 elif [ 条件2 ];then 动作1 动作2 动作3 elif [ 条件3 ];then 动作1 动作2 动作3 else 动作1 动作2 动作3 fi if [ 条件1 ]then 动作1 动作2 动作3 elif [ 条件2 ]then 动作1 动作2 动作3 elif [ 条件3 ]then 动作1 动作2 动作3 else 动作1 动作2 动作3 fi
需求: 接收用户输入的用户名和密码进行登录。
1.根据数据库
中的数据判断,如果用户存在则验证密码
2.如果密码错误则返回报错
3.如果密码正确,则登录成功
4.根据数据库
中的数据判断,如果用户不存在则注册
5.如果密码不一致则重新输入
6.如果密码一致,则将注册用户保存到数据库
中
扩展需求:
判断用户输入的密码,如果小于8位,则报错
判断用户输入的密码,如果没有大小写,则报错
判断用户输入的密码,如果没有数字,则报错
判断用户输入的用户名,如果用户名以数字开头,则报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 判断用户是否存在,bug,密码和要注册的用户名一致的情况下,就出问题 程序逻辑: - 登录 输入用户名 输入密码 - 判断用户是否存在 如果用户存在,则验证密码 如果用户不存在,则跳转到注册页面 - 注册页面 需要输入用户名,也需要判断是否存在 如果存在,重新输入用户名 输入注册密码和确认密码 $pass1 == $pass2 $pass1 != $pass2 两次密码不一致,重新输入密码 两次密码一致,将用户写入数据库,跳转到登录页面 #!/bin/bash read -p '请输入一个密码:' passif [ ${#pass} -lt 8 ];then echo '密码至少8位' elif [[ $pass =~ ' ' ]];then echo '密码中不能包含空格' elif [[ $pass =~ [0-9] ]] && [[ $pass =~ [a-z] ]] && [[ $pass =~ [A-Z] ]] ;then echo '注册成功' else echo '密码要包含数字,大小写字母' fi [root@m01 ~] #!/bin/bash . /etc/init.d/functions user_data_file="/root/user_data.txt" [ ! -f $user_data_file ] && { touch $user_data_file } login_page (){cat <<EOF +------------------+ | 欢迎来到登录界面 | +------------------+ EOF } register_page (){cat <<EOF +------------------+ | 欢迎来到注册界面 | +------------------+ EOF } clear login_page read -p '用户名: ' user_nameread -p '密码: ' user_pass[ ${#user_name} -eq 0 -o ${#user_pass} -eq 0 ] && { echo -e "\e[1;31m Error:\e[0m \e[5;31m用户名和密码不能为空\e[0m" exit 1 } user_exists=`awk '{print $1}' $user_data_file | grep -w "$user_name " |wc -l &>/dev/null` [ $user_exists -eq 0 ] && { pass=`grep -w "$user_name " $user_data_file |awk '{print $2}' ` [ "$pass " == "$user_pass " ] && { figlet welcome action "$user_name login accessful" /bin/true } || { echo -e "\n--------- 登录失败 --------" action "$user_name password is missing" /bin/false exit 1 } } || { echo -e "\n--------- 登录失败 --------" action "$user_name not exists" /bin/false clear register_page read -p "请输入注册用户名:" register_name read -p "请输入注册密码:" register_pass1 read -p "请确认注册密码:" register_pass2 grep -w "$register_name " $user_data_file &>/dev/null [ $? -eq 0 ] && { echo -e "\n--------- 注册失败 --------" echo -e "\e[1;31m Error:\e[0m 用户 \e[5;31m[${register_name} ]\e[0m 已存在" } || { [ $register_pass1 == $register_pass2 ] && { echo "$register_name $register_pass1 " >> $user_data_file awk '{print $1}' $user_data_file | grep -w "$register_name " &>/dev/null [ $? -eq 0 ] && { echo -e "user \e[5;32m[$register_name ]\e[0m register successful" login_page read -p '用户名: ' user_name read -p '密码: ' user_pass pass=`grep -w "$user_name " $user_data_file |awk '{print $2}' ` [ "$pass " == "$user_pass " ] && { figlet welcome action "$user_name login accessful" /bin/true } || { echo -e "\n--------- 登录失败 --------" action "$user_name password is missing" /bin/false exit 1 } } } || { echo -e "\nthe password not match" echo -e "\n--------- 重新确认密码 --------" read -p "请输入注册密码:" register_pass1 read -p "请确认注册密码:" register_pass2 [ $register_pass1 == $register_pass2 ] && { echo "$register_name $register_pass1 " >> $user_data_file } } } }
shell端口扫描 企业中常用的监控命令
监控目标
命令
本地端口监控
netstat -lntup ss -lntup lsof telnet
远端监控
nc nmap
进程监控
ps -ef ps -aux
web监控
curl wget
文件内容
md5
端口检查 本地端口检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 [root@m01 ~] tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 6914/sshd tcp6 0 0 :::22 :::* LISTEN 6914/sshd [root@m01 ~] tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 6914/sshd tcp6 0 0 :::22 :::* LISTEN 6914/sshd [root@m01 ~] tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 6914/sshd tcp6 0 0 :::22 :::* LISTEN 6914/sshd [root@m01 ~] [root@m01 ~] 0 [root@m01 ~] [root@m01 ~] 1 [root@m01 ~] 2 [root@m01 ~] 0 [root@m01 ~] tcp LISTEN 0 128 *:22 *:* users:(("sshd" ,pid=6914,fd=3)) tcp LISTEN 0 128 :::22 :::* users:(("sshd" ,pid=6914,fd=4)) [root@m01 ~] tcp LISTEN 0 128 *:22 *:* users:(("sshd" ,pid=6914,fd=3)) tcp LISTEN 0 128 :::22 :::* users:(("sshd" ,pid=6914,fd=4)) [root@m01 ~] COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sshd 6914 root 3u IPv4 37631 0t0 TCP *:ssh (LISTEN) sshd 6914 root 4u IPv6 37633 0t0 TCP *:ssh (LISTEN) sshd 7002 root 3u IPv4 38381 0t0 TCP m01:ssh->10.0.0.1:58616 (ESTABLISHED) sshd 19974 root 3u IPv4 202068 0t0 TCP m01:ssh->10.0.0.1:58531 (ESTABLISHED)
使用脚本判断远程端口是否存活 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #!/bin/bash IP=$1 port_count=`echo '' |telnet 172.16.1.7 80 2>/dev/null |grep 'Connected' |wc -l` if [ $port_count -eq 0 ];then echo '端口不存活' else echo '端口存活' fi #!/bin/bash . /etc/init.d/functions IP=$1 for port in `seq 65535`;do { port_count=`echo '' |telnet $IP $port 2>/dev/null |grep 'Connected' |wc -l` if [ $port_count -ne 0 ];then action "$port 端口" /bin/true fi } & done [root@m01 ~] Ncat: Connection refused. [root@m01 ~] 127 [root@m01 ~] [root@m01 ~] 0 -l:开启一个指定的端口 -k:保持端口持续连接 -u:指定nc使用udp协议(默认tcp) -s:指定发送数据的源IP地址,适用于多网卡机器 -w:设置超时时间 -z:扫描时不发送任何数据 [root@m01 ~] [root@m01 ~] [root@m01 ~] [root@m01 ~]
进程判断 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [root@web01 ~] root 12209 1 0 10:42 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf www 12210 12209 0 10:42 ? 00:00:00 nginx: worker process [root@web01 ~] 2 [root@web01 ~] 0 vim check_process.sh #!/bin/bash proc_count=`ssh 172.16.1.7 'ps -ef|grep [n]ginx|wc -l' ` if [ $proc_count -eq 0 ];then echo 'nginx不存活' else echo 'nginx存活' fi
网站检测 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 curl选项 -I:获取主机响应头部信息 -s:取消默认输出 -o:保存下载页面内容 -w:获取状态码 -u:身份认证 -u 用户名:密码 -H:添加请求头部信息 -v:显示详细信息 -L:跟随跳转 -X:指定请求方式 -A:修改用户的客户端 [root@m01 ~] [root@m01 ~] [root@m01 ~] wget选项 -O:保存下载页面内容 -r:递归下载 --debug:显示访问的详细过程 类似 curl -v -q:静默输出 类似 curl -s --spider:只查看不下载
文件检测 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [root@m01 ~] 6de9439834c9147569741d3c9c9fc010 1.txt [root@m01 ~] [root@m01 ~] 1.txt: OK [root@m01 ~] 1.txt: OK [root@m01 ~] 1.txt: OK [root@m01 ~] 1.txt: OK [root@m01 ~] [root@m01 ~] 1.txt: FAILED md5sum: WARNING: 1 computed checksum did NOT match
shell编程函数 函数介绍 函数就是具备某一个功能的工具
为什么要使用函数 1 2 3 4 如果不使用函数,那么你的代码: 1.程序的组织结构不清晰,可读性差 2.代码冗余 3.可扩展性(功能需要修改的时候...对不起GG)
如何使用函数 1 2 3 函数的使用必须遵循的原则:先定义,后调用 修理工事先准备好工具的过程,即,定义函数 修理工遇到应用场景拿来工具就用即函数的调用
函数语法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 function 函数名 () { 命令1 命令2 命令3 } function 函数名 { 命令1 命令2 命令3 } 函数名 () { 命令1 命令2 命令3 } :() { : | : & };: roger (){ roger | roger & };roger ls ; ifocnfig [root@m01 ~] #!/bin/bash roger (){ xxx } xxx (){ echo 123 } roger [root@m01 ~] #!/bin/bash roger (){ xxx } roger xxx (){ echo 123 } [root@m01 ~] vim function.sh #!/bin/bash name=$1 age=$2 roger (){ echo $1 echo $2 } roger $1 xxx
函数位置变量VS脚本位置变量
特殊变量
脚本
函数
$N
脚本的第N个参数
函数的第N个参数
$0
脚本名称
脚本名称
$*/$@
脚本的所有参数
脚本的所有参数
$#
脚本传递的参数个数
函数传递的参数个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@m01 ~] vim function.sh #!/bin/bash name=$1 age=$2 var=$* echo "函数外 $0 " roger (){ echo $1 echo $2 echo "函数内 $0 " echo $* echo $# } roger abc xxx
函数的返回值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 [root@m01 ~] #!/bin/bash . /etc/init.d/functions domain_name_list=(www.roger.com blog.roger.com php.roger.com) IP_list=(10.0.0.61 10.0.0.7) proc_count=`ps -ef|grep [n]ginx|wc -l` port_80_count=`netstat -lntup|grep -w '80' |wc -l` port_443_count=`netstat -lntup|grep -w '443' |wc -l` check (){ for domain_name in ${domain_name_list[*]} ;do http_code=`curl -s -w "%{http_code}" -o /dev/null $domain_name ` if [ $http_code -eq 401 ];then action "${domain_name} 网站正常,但是身份验证不通过" /bin/false elif [[ $http_code =~ ^[4-5] ]];then action "${domain_name} 网站无法访问" /bin/false elif [ $proc_count -le 0 ];then action "nginx进程" /bin/false elif [ $port_80_count -le 0 ];then action "nginx的80端口检测" /bin/false else action "${domain_name} 网站" /bin/true fi done if [ ];then return 10 else return 20 fi } check if [ $? -eq 20 ];then xxx fi function.sh: line 27: return : ok: numeric argument required 函数返回值只接收,数字类型的参数 function.sh: line 27: return : too many arguments 函数的返回值,只能接收一个参数
作业: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #!/bin/bash cat <<EOF +---------+ | 1.lnmp | +---------+ | 2.lnmt | +---------+ | 3.lamp | +---------+ | 4.lamt | +---------+ | 5.nginx | +---------+ | 6.apache| +---------+ | 7.tomcat| +---------+ | 8.php | +---------+ EOF ansible -m file -a 'mode=0644,owner=root,path=/tmp,state=directory' 根据菜单,安装对应的架构 输入数字和 lnmp nginx
shell 循环 循环的分类 1 2 3 while :当型循环 应用场景:死循环、按行读取文件、有条件的循环do until:直到型循环 应用场景:没有场景for :通用型循环 应用场景:很多应用场景
循环语法 while循环 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 while <条件表达式>;do cmd1 cmd2 cmd3 done while <条件表达式>do cmd1 cmd2 cmd3 done while true ;do echo 'hei hei hei' done while [ 1 -eq 1 ];do echo 'hei hei hei' done while :;do echo 'hei hei hei' done
使用while循环模拟for循环seq 1 2 3 4 5 6 7 8 9 10 11 12 13 14 n=1 while [ $n -le 10 ];do echo $n ((n++)) done for n in `seq 10`;do echo $n done 1+2+3+4+5+6+7+8+9+10+...+100 (1+100)*100/2=5050 1+2+3+...+9
使用while循环实现1加到100 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #!/bin/bash i=1 num=0 while [ $i -le 100 ];do ((num=num+i)) ((i++)) done echo $num [root@m01 ~] 5050 [root@m01 ~] 5050 [root@m01 ~] 5050 [root@m01 ~] 5050
until循环(忘记它) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 until <条件表达式>;do cmd1 cmd2 cmd3 done until <条件表达式> do cmd1 cmd2 cmd3 done #!/bin/bash n=0 until [ $n -gt 10 ];do echo $n ((n++)) done
until 循环执行一系列命令直至条件为 true 时停止。
until 循环与 while 循环在处理方式上刚好相反。
一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。
for循环 语法一 无法指定循环次数,变量表达式中有多少内容就循环多少次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 for var in roger wyk huanglong;do cmd1 cmd2 done for var in 变量表达式do cmd1 cmd2 done 变量表达式: - 可以是文件中的内容(按空格循环) - 可以是序列命令的内容 - 可以是数组中的内容 - 可以是以空格为分隔符的字符串 for var in `cat 1.txt`;do echo $var done for var in $(cat 1.txt);do echo $var done for var in `seq 10`;do echo $var done [root@m01 ~] #!/bin/bash array=(roger wyk huanglong) for var in ${array[*]} ;do echo $var done name="roger wyk huanglong" for var in $name ;do echo $var done
语法二 指定循环次数
1 2 3 for ((i=1;i<=10;i++));do echo $i done
死循环
1 2 3 for (( ; ; ));do echo 123 done
循环的控制语句
break跳出循环 break命令允许跳出所有循环(终止执行后面的所有循环)。
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #!/bin/bash while true ;do read -p 'Please Input A Number: ' num if [ $num -ne 5 ];then echo "你输入的是 $num " else break fi done #!/bin/bash n=0 while [ $n -lt 10 ];do ((n++)) if [ $n -eq 5 ];then break fi echo $n done
continue 跳出循环 continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #!/bin/bash while true ;do read -p 'Please Input A Number: ' num if [ $num -ne 5 ];then echo "你输入的是 $num " else continue fi done #!/bin/bash n=0 while [ $n -lt 10 ];do ((n++)) if [ $n -eq 5 ];then continue fi echo $n done
while循环读取文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 [root@m01 ~] www.roger.com wyk blog.roger.com huanglong php.roger.com wujiahao [root@m01 ~] #!/bin/bash for word in `cat 1.txt`;do echo $word done #!/bin/bash exec < 1.txtwhile read line;do echo '---------' echo $line done #!/bin/bash cat 1.txt|while read line;do echo '---------' echo $line done #!/bin/bash while read line;do echo '---------' echo $line done < 1.txt
while练习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 写一个脚本,读取下面文件内容,并算出所有人年龄总和 [root@zabbix01 ~] 曾老湿 18 苍井空 20 武藤兰 33 天海翼 32 西野翔 18 #!/bin/bash sum=0 while read line;do age=`echo $line |awk '{print $2}' ` ((sum+=age)) done < 1.txtecho $sum #!/bin/bash sum=0 exec < 1.txtwhile read line;do age=`echo $line |awk '{print $2}' ` ((sum+=age)) done < 1.txtecho $sum
案例 案例一: 日志分析案例 写一个shell脚本,防止DDOS攻击,先分析日志,监控某一个IP并发连接数,若短时内PV达到100阈值,则调用防火墙命令,封掉该IP。
可以分析nginx日志或者查看当前网络连接数 ss -ant 或者 netstat -ant
这里使用一个生产的日志 netstat.log
案例二: 在指定目录下,通过随机10个小写字母,然后生成一个文件名为:随机字母_roger.txt
的文件
生成随机内容的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 [root@zabbix01 ~] UUBtKUvUkEfcEw== [root@zabbix01 ~] [root@zabbix01 ~] 3fd3a5c57def5f89481e1961fceb13e8 tr -cd 'a-zA-Z0-9' </dev/urandom|head -c 10
案例三: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 rename roger.txt cls.TXT /root/*.txt #!/bin/bash for name in `ls -1 /abc`;do mv /abc/$name /abc/${name//j2/yml} done
案例四: 创建100个系统用户,生成随机密码
并将用户名和密码保存到文件中
用户名:密码
案例五: 现在我们要模拟黑客,来扫描,指定网段内存活的主机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 for n in `seq 255`;do ping 10.0.0.$n done #!/bin/bash . /etc/init.d/functions for n in `seq 254`;do { ping -c1 -W1 -i1 10.0.0.$n &>/dev/null if [ $? -eq 0 ];then action 10.0.0.$n /bin/true for ;do { xxx } & usleep 300 done fi } & usleep 300 done
figlet
1 2 3 4 [root@zabbix01 ~] [root@zabbix01 ~] [root@zabbix01 ~] [root@zabbix01 ~]
shell case语句 写一个跳板机 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #!/bin/bash cat <<EOF +------------------------+ | 1 172.16.1.7 web01 | +------------------------+ | 2 172.16.1.8 web02 | +------------------------+ | 3 172.16.1.31 nfs | +------------------------+ | 4 172.16.1.41 backup | +------------------------+ | 5 172.16.1.51 db01 | +------------------------+ | 6 172.16.1.52 db02 | +------------------------+ | 7 172.16.1.53 db03 | +------------------------+ | 8 172.16.1.54 db04 | +------------------------+ | 9 172.16.1.61 m01 | +------------------------+ | 10 172.16.1.71 zabbix | +------------------------+ EOF read -p '请输入需要连接的主机:' hostif [ $host == '1' -o $host == '172.16.1.7' -o $host == 'web01' ];then echo '连接 172.16.1.7 web01' elif [ $host == '2' -o $host == '172.16.1.8' -o $host == 'web02' ];then echo '连接 172.16.1.8 web02' elif [ $host == '3' -o $host == '172.16.1.31' -o $host == 'nfs' ];then echo '连接 172.16.1.31 nfs' elif [ $host == '4' -o $host == '172.16.1.41' -o $host == 'backup' ];then echo '连接 172.16.1.41 backup' elif [ $host == '5' -o $host == '172.16.1.51' -o $host == 'db01' ];then echo '连接 172.16.1.51 db01' elif [ $host == '6' -o $host == '172.16.1.52' -o $host == 'db02' ];then echo '连接 172.16.1.52 db02' elif [ $host == '7' -o $host == '172.16.1.53' -o $host == 'db03' ];then echo '连接 172.16.1.53 db03' elif [ $host == '8' -o $host == '172.16.1.54' -o $host == 'db04' ];then echo '连接 172.16.1.54 db04' elif [ $host == '9' -o $host == '172.16.1.61' -o $host == 'm01' ];then echo '连接 172.16.1.61 m01' elif [ $host == '10' -o $host == '172.16.1.71' -o $host == 'zabbix' ];then echo '连接 172.16.1.71 zabbix' fi
case语句 case … esac 为多选择语句,与其他语言中的 switch … case 语句类似,是一种多分枝选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case … esac 语句,esac(就是 case 反过来)作为结束标记。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 case 变量 in 动作1|动作3|动作4) cmd1 ;; 动作2) cmd2 *) echo '脚本的用法' ;; esac case 会将变量和动作进行判断可以进行多动作判断,使用 '|' 或
给shell加颜色 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 \e[1;31mroger\e[0m red_start='\e[1;31m' red_end='\e[0m' $red_start xxx $red_end echo -e '\e[1;31mroger\e[0m' [root@m01 ~] \e \033 \E 字体型号;字体颜色;背景颜色m 0:正常字体 1:字体加粗 2:字体变浅 3:字体斜体 4:字体下划线 5:字体闪烁 30m:黑色 31m:红色 32m:绿色 33m:黄色 34m:蓝色 35m:紫色 36m:天蓝 37m:白色 40m:黑色 41m:红色 42m:绿色 43m:黄色 44m:蓝色 45m:紫色 46m:天蓝 47m:白色
正则表达式 正则表达式,简写:re,全拼:(regular expression) 在某些地区,管它叫做,正规表达式、规则表达式
正则表达式的”祖先”可以一直上溯至对人类神经系统如何工作的早期研究。Warren McCulloch 和 Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。
1956 年, 一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了一篇标题为”神经网事
件的表示法”的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为”正则集的代数”的表达式,因此采用”正则表达式”这个术语。
随后,发现可以将这一工作应用于使用 Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson 是 Unix的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的 qed 编辑器。
如他们所说,剩下的就是众所周知的历史了。从那时起直至现在正则表达式都是基于文本的编辑器和搜索工具中的一个重要部分。
正则和通配符 1 2 3 4 5 6 7 ls /* * 前面的字符出现0次或者多次
为什么使用正则 1.方便处理文本和字符串内容
2.处理有规律的内容(手机号,身份证等等有规律的、固定写法的内容)
3.正则一般给高级的开发语言使用
awk和sed也是一门语言
搜索和替换操作 但是一般的命令,搜索和替换缺乏灵活性,基本写死。 所以我们可以通过正则表达式,灵活的动态
匹配文本。
例如:
1.可以测试输入字符串 以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
2.替换文本。 可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
3.基于模式匹配从字符串中提取子字符串。
4.查找文档内或输入域内特定的文本。
正则表达式在 Linux中的分类在正则表达式的语法中,主要有两个部分 修饰符 和 元字符 。 修饰符,我们在后面介绍,它主要不写在正则中,要写在正则的外面。 元字符,在Linux中会把这些符号区分开,划分为 基础正则 和 扩展正则
所谓的 扩展正则 其实也是元字符中的一部分,只不过在linux中,有些命令不能直接使用某些元字符,需要用一些参
数,才能使用。所以被一部分人称之为 扩展正则
那么我们先简单介绍一下,这个分类,然后再总的来介绍所有修饰符和元字符。
在Linux中的分类
修饰符:它主要不写在正则中,要写在正则的外面
元字符:在Linux中会把这些符号区分开
基础正则 简写bre(basicc regular expression) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ^ 以什么什么开头 $ 以什么什么结尾 . 匹配任意字符 * 前面的字符出现0次或者多次 .* 配合使用 [] 字符集合, 匹配多包含的任意一个字符 例如: [0-9] [a-z] [^] 字符集合的取反 例如: ^[0-9] ^[a-z]
拓展正则 简写ere(extended rugular expression) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 + 前面的一个字符出现一次或者多次 cat 1.txt | awk -F '[ :]+' '{print $5}' [ :]+ 里面的任意字符出现一次或者多次 即使是这两个一起出现也会识别成一个 | 或者的意思 () 被括起来的内容提供看做是一个整体 也可以在sed命令中后项引用 {} 中间写一个非负整数,表示大括号前面的内容,出现指定次数 09:38:41 root@web01:~ z zz zzz zzz zzzz zzzz 09:39:45 root@web01:~ z z z z zz zz zzz zzz zxc zxc asdz asdz ?: 前面的内容,出现0次或者1次 grep -E 'z?' 出现0次也行 grep -E 'z+' 最少出现一次 比如匹配id [0-9].* [0-9]+
正则表达式使用误区 通配符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 *代表所有内容 {}生成序列 echo {1..10}echo {1..10..2}cp /usr/lib/systemd/system/nginx.service{,.bak} cp /usr/lib/systemd/system/{nginx,zzz}.service ?匹配任意一个字符 touch check_1.txt ll ls -l /tmp/c?heck.txt ls -l /tmp/c?eck.txt ls -l /tmp/c?eck_1.txt ls -l /tmp/c?eck_????? ls -l /tmp/c?eck_? ls -l /tmp/c?eck_?* ls -l /tmp/??????????? ll touch 1234 ls -l /tmp/???? ls -l /tmp/checl_????? ls -l /tmp/check_????? ls -l /tmp/c????_????? [] 和[^] 与正则表达式中的用法一样
正则表达式使用注意事项
1.所有符号皆为英文符号
2.使用三剑客时加引号
3.注意字符集,如果出现字符集问题,那么将字符集修改为C(小概率事件)
4.像素眼(空格,换行符,tab键)
5.测试的时候,推荐使用grep -E或者egrep,因为过滤出来的内容会加颜色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 check10.txt check1.txt check 2.txt check 3.txt check4.txt check5.txt check6.txt check7.txt check8.txt check9.txt cat 1.txt | awk '/\t/{print}' check 3.txt cat 1.txt | awk '/ /{print}' check 2.txt 如果要筛选10: 10:20:53 root@web01:~ check10.txt 10:19:45 root@web01:~ check10.txt
1 2 3 4 .* 匹配任意字符 grep -o '.*' . 匹配任意字符 grep -o '.'
正则表达式的修饰符 1 2 3 s sed -i 's#查找的内容#替换的内容#g'
正则表达式常用的修饰符
修饰符
含义
描述
i
gnore-不区分大小写
将匹配设置为不区分大小写,搜索时不区分大小写:A和a没有区别。
g
global-全局匹配
查找所有的匹配项
m
mu ltiline -多行匹配
使边界字符^和$匹配每一行的开头和结尾,记住是多行,而不是整个字 符串的开头和结尾
S
特殊字符圆点.中包含 换行符\n
默认情况下的圆点.是匹配除换行符\n之外的任何字符,加上s修饰符 之后,中包含换行符\n
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 /pattern/fiags /元字符/修饰符 11:36:17 root@web01:~ check_0.txt check_10.tx check_1.txt check_2.txt check_3.txt check_4.txt check _5.txt check _6.txt check_7.txt check_8.txt check_9.txt CHECK.txt 0 ✓ 11:37:43 root@web01:~ check_0.txt check_10.tx check_1.txt check_2.txt check_3.txt check_4.txt check _5.txt check _6.txt check_7.txt check_8.txt check_9.txt CHECK.txt
正则表达式元字符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 grep -帮助 匹配模式选择: -E -extended-regexp 扩展正则表达式egrep -F --fixed-strings一个换行符分隔的字符串的集合fgrep -G -basic-regexp基本正则 -P -perl-regexp调用的实际抽取与汇报语言正则 -e --regexp=PATTERN后面根正则模式,默认无 -f -file=FILE 从文件中获得匹配模式 -i -ignore-case 不区分大小写 -w --word-regexp 匹配整个单词 -x --line-regexp匹配整行 -z -null-data一个O字节的数据行,但不是空行 12:10:24 root@web01:~ zls zls zlllls zlllls zs 12:12:08 root@web01:~ zls zls zllls zllls zs zs 130 ✗ 12:13:21 root@web01:~ zls zls zllls zllls zs zs
正则案例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 echo 123456sed -r 's#(.*)#<\1>#g' sed -r 's#(.)#<\1>#g ' echo {1..10} 带空格的每个都加上<>19:09:03 up 735 day,23:12,2 users,load average: 0.00,0.03,0.05 19:09:03 up 10:20, 3 users,load average: 0.00,0.02,0.05 19:09:03 up 0 min,1 users,load average: 0.31,0.08,0.03 uptime| grep -Po '[0-9]+(?= user)' uptime| grep -Po '\d+(?=user)' uptimel grep -Po '(?< =up).*(?=[0-9] user)' uptime| grep -Po '(?< =up).*(?=\d user)'
零宽断言 截取网卡IP的案例 1 2 3 4 5 6 7 8 9 ifconfig eth0|grep -Po '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(?= netmask)' 12:53:14 root@web01:~ 10.0.0.7 ifconfig eth0|grep -Po '[0-9]{1,3}\..+(?= netmask)' 12:54:32 root@web01:~ 10.0.0.7
基础正则表BRE
符号
描述
应用场景
A
以 … 开头
匹配以指定字符开头的内容:^zls
$
以 … 结尾
匹配以指定字符结尾的内容:zls$
.
匹配除换行符(\In、\r)之外的任何单个字符
一般该元字符不单独用,配合*一起使用
*
前一个字符连续出现0次或多次
zl*能匹配”z”以及”zl”,配合.使用要注意贪婪性
[ ]
字符集合,匹配所包含的任意一个字符
1.”[xyz]’可以匹配”zls”中的’z’ 2.匹配数字[0-9] 3.小写字母[a-z] 4.大写字母[A-Z] 5.大小写都匹配[a-z][A-z]或者[a-Z] 6.在中括号中可以让特殊符号失去特殊含义 7.上面的大前提是^不能放第一个
[^]
反值字符集合,匹配未包含的任意字符
1. [^xyz]可以匹配”zls”中的’s’ 2.匹配数字和 3.取出/etc/passwd第一列
\
\
将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符
\n
匹配一个换行符
等价于\x0a和\cJ
\r
匹配一个回车符(回车键)
等价于\x0d和\cM
\t
匹配一个制表符(Tab键)
等价于\x09和\cl
\v
匹配一个垂直制表符
等价于\x0b和\cK
\f
换页符
等价于\x0c和\cL
\b
匹配一个单词边界,也就是指单词和空格间的位置
er\b’可以匹配”never”中的’er’,但不能匹配”verb” 中的’er’
\B
匹配非单词边界
er\B’能匹配”verb”中的’er’,但不能匹配”never” 中的’er
\d
匹配一个数字字符
等价于[0-9]
\D
匹配一个非数字字符
等价于 [^0-9]
\w
匹配字母、数字、下划线
等价于[A-Za-z0-9 ]
W
匹配非字母、数字、下划线
等价于[^A-Za-z0-9 ]
\s
匹配任何空白字符,包括空格、制表符、 换页符等等
等价于[\f\n\t\v]
\S
匹配任何非空白字符
等价于[^\f\n\r\t\v]
扩展正则表ERE
|
或 者
等价于[^\f\n\r\t\v]
十
前一个字符出现一次或者多次
zl+’能匹配”zl”以及”zll”,但不能匹配”z”,+等价于 {1,}
{n}
n是一个非负整数。匹配确定的n次。
o{2}’不能匹配”bo3”中的’o’ 但是能匹配”foot”中的两个o
{n,}
n是一个非负整数。匹配确定的n次。
o{2,}’不能匹配”Bob”中的’o’ 但能匹配”foooood”中的所有o o{1,}’等价于’o+’ o{0,}’则等价于’o*’
{n,m}
m和n均为非负整数,其中n<=m,最少匹配n 次且最多匹配m次
“o{1,3}”将匹配”fooooood”中的前三个o o{0,1}’等价于’o?’ 请注意在逗号和两个数之间不能有空格
()
1.被括起来的内容看做是一个整体 2.在sed命令中做后向引用
sed -nr’s#(.*)abc#\1#gp’
(?=pattern)
正向肯定预查look ahead(零宽断言)
使用grep-P来使用下面我们在Per语言正则中使用
(?<=pattern)
反肯定预查look behind(零宽断言)
使用grep-P来使用下面我们在Perl语言正则中使用
?
匹配前一个字符出现0次或1次
‘do(es)?”可以匹配”do”或”does”。?等价于{0,1}
正则支持表
字符
说明
Basic RegEx 基础正则
Extended RegEx 扩展正则
python RegEx python正则
Perl regEx Perl正则
转义
\
\
\
\
^
匹配行首,例如’^dog’匹配以字符串dog开头的行(注意:awk 指令中,’^’则是匹配字符串的开始)
^
^
^
^
$
匹配行尾,例如:’^、dog匹配以字符串为结尾的行(注意:指令中,’则是匹配字符串的结尾)
$
$
$
$
^$
匹配空行
^$
^$
^$
^$
^string$
匹配行,例如:’^dog$’匹配只含一个字符串 dog 的行
^string$
^string$
^string$
^string$
<
匹配单词,例如:’<frog’ (等价于’\bfrog’),匹配以 frog 开头的单词
<
<
不支持
不支持 (但可以使用\b来匹配单词,例如:’\bfrog’)
>
匹配单词,例如:’frog>’(等价于’frog\b ‘),匹配以 frog 结尾的单词
>
>
不支持
不支持 (但可以使用\b来匹配单词,例如:’frog\b’)
匹配一个单词或者一个特定字符,例如:’‘(等价于’\bfrog\b’)、’‘
不支持
不支持 (但可以使用\b来匹配单词,例如:’\bfrog\b’
()
匹配表达式,例如:不支持’(frog)’
不支持 (但可以使用,如:dogdog
()
()
()
匹配表达式,例如:不支持’(frog)’
不支持 (同())
不支持 (同())
不支持 (同())
?
匹配前面的子表达式 0 次或 1 次(等价于{0,1}),例如:where(is)?能匹配”where” 以及”whereis”
不支持 (同?)
?
?
?
?
匹配前面的子表达式 0 次或 1 次(等价于’{0,1}’),例如:’whereisis? ‘能匹配 “where”以及”whereis”
?
不支持 (同?)
不支持 (同?)
不支持 (同?)
?
当该字符紧跟在任何一个其他限制符(*, +, ?, {n},{n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 “oooo”,’o+?’ 将匹配单个”o”,而 ‘o+’ 将匹配所有 ‘o’
不支持
不支持
不支持
不支持
.
匹配除换行符(’\n’)之外的任意单个字符(注意:awk 指令中的句点能匹配换行符)
.
.(如果要匹配包括“\n”在内的任何一个字符,请使用:’(^$)|(.)
.
.(如果要匹配包括“\n”在内的任何一个字符,请使用:’ [.\n] ‘
*
匹配前面的子表达式 0 次或多次(等价于{0, }),例如:zo* 能匹配 “z”以及 “zoo”
*
*
*
*
+
匹配前面的子表达式 1 次或多次(等价于’{1, }’),例如:’whereisis+ ‘能匹配 “whereis”以及”whereisis”
+
不支持 (同+)
不支持 (同+)
不支持 (同+)
+
匹配前面的子表达式 1 次或多次(等价于{1, }),例如:zo+能匹配 “zo”以及 “zoo”,但不能匹配 “z”
不支持 (同+)
+
+
+
{n}
n 必须是一个 0 或者正整数,匹配子表达式 n 次,例如:zo{2}能匹配
不支持 (同{n})
{n}
{n}
{n}
{n,}
“zooz”,但不能匹配 “Bob”n 必须是一个 0 或者正整数,匹配子表达式大于等于 n次,例如:go{2,}
不支持 (同{n,})
{n,}
{n,}
{n,}
{n,m}
能匹配 “good”,但不能匹配 godm 和 n 均为非负整数,其中 n <= m,最少匹配 n 次且最多匹配 m 次 ,例如:o{1,3}将配”fooooood” 中的前三个 o(请注意在逗号和两个数之间不能有空格)
不支持 (同{n,m})
{n,m}
{n,m}
{n,m}
x|y
匹配 x 或 y,例如: 不支持’z|(food)’ 能匹配 “z” 或”food”;’(z|f)ood’ 则匹配”zood” 或 “food”
不支持 (同x|y)
x|y
x|y
x|y
[0-9]
匹配从 0 到 9 中的任意一个数字字符(注意:要写成递增)
[0-9]
[0-9]
[0-9]
[0-9]
[xyz]
字符集合,匹配所包含的任意一个字符,例如:’[abc]’可以匹配”lay” 中的 ‘a’(注意:如果元字符,例如:. *等,它们被放在[ ]中,那么它们将变成一个普通字符)
[xyz]
[xyz]
[xyz]
[xyz]
[^xyz]
负值字符集合,匹配未包含的任意一个字符(注意:不包括换行符),例如:’[^abc]’ 可以匹配 “Lay” 中的’L’(注意:[^xyz]在awk 指令中则是匹配未包含的任意一个字符+换行符)
[^xyz]
[^xyz]
[^xyz]
[^xyz]
[A-Za-z]
匹配大写字母或者小写字母中的任意一个字符(注意:要写成递增)
[A-Za-z]
[A-Za-z]
[A-Za-z]
[A-Za-z]
[^A-Za-z]
匹配除了大写与小写字母之外的任意一个字符(注意:写成递增)
[^A-Za-z]
[^A-Za-z]
[^A-Za-z]
[^A-Za-z]
\d
匹配从 0 到 9 中的任意一个数字字符(等价于 [0-9])
不支持
不支持
\d
\d
\D
匹配非数字字符(等价于 [^0-9])
不支持
不支持
\D
\D
\S
匹配任何非空白字符(等价于[^\f\n\r\t\v])
不支持
不支持
\S
\S
\s
匹配任何空白字符,包括空格、制表符、换页符等等(等价于[ \f\n\r\t\v])
不支持
不支持
\s
\s
\W
匹配任何非单词字符 (等价于[^A-Za-z0-9_])
\W
\W
\W
\W
\w
匹配包括下划线的任何单词字符(等价于[A-Za-z0-9_])
\w
\w
\w
\w
\B
匹配非单词边界,例如:’er\B’ 能匹配 “verb” 中的’er’,但不能匹配”never” 中的’er’
\B
\B
\B
\B
\b
匹配一个单词边界,也就是指单词和空格间的位置,例如: ‘er\b’ 可以匹配”never” 中的 ‘er’,但不能匹配 “verb” 中的’er’
\b
\b
\b
\b
\t
匹配一个横向制表符(等价于 \x09和 \cI)
不支持
不支持
\t
\t
\v
匹配一个垂直制表符(等价于 \x0b和 \cK)
不支持
不支持
\v
\v
\n
匹配一个换行符(等价于 \x0a 和\cJ)
不支持
不支持
\n
\n
\f
匹配一个换页符(等价于\x0c 和\cL)
不支持
不支持
\f
\f
\r
匹配一个回车符(等价于 \x0d 和\cM)
不支持
不支持
\r
\r
\
匹配转义字符本身””
\
\
\
\
\cx
匹配由 x 指明的控制字符,例如:\cM匹配一个Control-M 或回车符,x 的值必须为A-Z 或 a-z 之一,否则,将 c 视为一个原义的 ‘c’ 字符
不支持
不支持
\cx
\xn
匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长,例如:’\x41’ 匹配 “A”。’\x041’ 则等价于’\x04’ & “1”。正则表达式中可以使用 ASCII 编码
不支持
不支持
\xn
\num
匹配 num,其中 num是一个正整数。表示对所获取的匹配的引用
不支持
\num
\num
[:alnum:]
匹配任何一个字母或数字([A-Za-z0-9]),例如:’[[:alnum:]] ‘
[:alnum:]
[:alnum:]
[:alnum:]
[:alnum:]
[:alpha:]
匹配任何一个字母([A-Za-z]), 例如:’ [[:alpha:]] ‘
[:alpha:]
[:alpha:]
[:alpha:]
[:alpha:]
[:digit:]
匹配任何一个数字([0-9]),例如:’[[:digit:]] ‘
[:digit:]
[:digit:]
[:digit:]
[:digit:]
[:lower:]
匹配任何一个小写字母([a-z]), 例如:’ [[:lower:]] ‘
[:lower:]
[:lower:]
[:lower:]
[:lower:]
[:upper:]
匹配任何一个大写字母([A-Z])
[:upper:]
[:upper:]
[:upper:]
[:upper:]
[:space:]
任何一个空白字符: 支持制表符、空格,例如:’ [[:space:]] ‘
[:space:]
[:space:]
[:space:]
[:space:]
[:blank:]
空格和制表符(横向和纵向),例如:’[[:blank:]]’ó’[\s\t\v]’
[:blank:]
[:blank:]
[:blank:]
[:blank:]
[:graph:]
任何一个可以看得见的且可以打印的字符(注意:不包括空格和换行符等),例如:’[[:graph:]] ‘
[:graph:]
[:graph:]
[:graph:]
[:graph:]
[:print:]
任何一个可以打印的字符(注意:不包括:[:cntrl:]、字符串结束符’\0’、EOF 文件结束符(-1), 但包括空格符号),例如:’[[:print:]] ‘
[:print:]
[:print:]
[:print:]
[:print:]
[:cntrl:]
任何一个控制字符(ASCII 字符集中的前 32 个字符,即:用十进制表示为从 0 到31,例如:换行符、制表符等等),例如:’ [[:cntrl:]]’
[:cntrl:]
[:cntrl:]
[:cntrl:]
[:cntrl:]
[:punct:]
任何一个标点符号(不包括:[:alnum:]、[:cntrl:]、[:space:]这些字符集)
[:punct:]
[:punct:]
[:punct:]
[:punct:]
[:xdigit:]
任何一个十六进制数(即:0-9,a-f,A-F)
[:xdigit:]
[:xdigit:]
[:xdigit:]
[:xdigit:]
Linux三剑客 grep 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 -n:打印行号 -A:after 打印过滤内容的后N行 -B:before 打印过滤内容的前N行 -C:center 打印过滤内容的前后N行 -E:支持扩展正则 ere -v:取反 -o:只打印匹配到的内容 -w:精确匹配 -P:支持Perl正则 -i:忽略大小写 -r:递归检索文件中的内容 -R:递归检索文件中的内容,包括软链接文件 -l:只显示文件名 -h:只显示文件内容 -f:对比文件内容,内容少的文件在前面,内容多的文件在后面,取反可以看到不同的文件内容 -c:统计行数,类似于 wc -l -G:支持基础正则 bre -m:显示前N行 类似于 head -n [root@m01 web] /root/web/css/style.css:www.roger.com /root/web/js/main.js:www.roger.com /root/web/index.html:www.roger.com [root@m01 web]
sed 在sed中,我们核心的内容,主要分为四个部分:
当然我们还有一些进阶内容:模式空间与保持空间
sed命令执行流程 举个例子:
1 2 3 4 5 1,roger,666 2,wls,777 3,cls,888 4,lls,999
执行 sed -n '3p' roger.txt
命令后,sed都做了啥?
1.sed先是按行读取文件内容 2.每读取一行内容,都会进行一次判断,是不是你想要的行 3.如果不是,则判断是不是加了-n选项 4.如果加了-n,就读取下一行 5.如果没加-n,就会将所有内容输出到命令行(默认输出) 6.如果是,你想要的那一行(第三行)则判断执行的后续动作(p d s a i c) 7.动作处理完成后,输出指定的内容 8.即便是读取完了,内容也输出了,sed也会继续往后读,直到文件的最后一行
sed - 查
sed命令选项
选项含义
sed命令动作
动作含义
-n
取消默认输出
p
print打印
-r
支持扩展正则
d
delete删除
a
append追加
i
insert插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 p:打印,显示 [root@m01 ~] 1,roger,666 2,wls,777 3,cls,888 3,cls,888 4,lls,999 [root@m01 ~] 3,cls,888 [root@m01 ~] 1,roger,666 2,wls,777 3,cls,888 [root@m01 ~] 1,roger,666 [root@m01 ~] 1,roger,666 3,cls,888 [root@m01 ~] 1,roger,666 2,wls,777 3,cls,888 [root@m01 ~] 1,roger,666 2,wls,777 3,cls,888 [root@m01 ~] 1,roger,666 2,wls,777 3,cls,888 [root@m01 ~] 1,roger,666 3,cls,888 [root@m01 ~] 1,roger,666 4,lls,999
sed - 删 1 2 3 4 5 6 7 8 9 10 11 12 d:delete 删除 [root@m01 ~] [root@m01 ~] 1,roger,666 3,cls,888 [root@m01 ~]
sed - 增 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 c:replace 替换整行内容 [root@m01 ~] 1,roger,666 3,cls,888 4,lls,999 [root@m01 ~] 1,roger,666 2,huanglong,438 4,lls,999 a:append 追加 [root@m01 ~] 1,roger,666 3,cls,888 4,lls,999 5,huanglong,438 [root@m01 ~] 1,roger,666 3,cls,888 5,huanglong,438 4,lls,999 [root@m01 ~] 1,roger,666 2,huanglong,438 3,cls,888 4,lls,999 i:insert 插入 [root@m01 ~] 1,roger,666 3,cls,888 2,huanglong,438 4,lls,999 [root@m01 ~] 2,huanglong,438 1,roger,666 3,cls,888 4,lls,999
sed - 改 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 s:substitute 替换 g:global 全局 s s@@@g s啥都行g [root@zabbix01 ~] 1,roger,666 2,wls,777 3,cls,888 4,lls,999 [root@zabbix01 ~] 666,roger,666666666 666,wls,666666666 666,cls,666666666 666,lls,666666666 [root@m01 ~] 10.0.0.61 [root@m01 ~] 172.16.1.61
sed的模式空间 将文件中的,所有换行符,替换成空格
1 N:在读取文件是,让sed把下一行内容一起读进去
awk awk的内置变量和动作和选项
awk内置变量
变量含义
awk选项
选项含义
awk动作
动作含义
NR
Number of Record 行号
-F
指定分隔符
gsub
替换
RS
Record Separator 行的分隔符(\n)
-v
指定变量(内置变量、自定义变量)
print
打印
FS
Field Separator 列的分隔符(空格)
NF
Number Of Filed 每一行有多少列
注意:awk输出变量使用单引号,bash输出变量使用双引号
awk
不是一个命令,是一门语言。
awk
又叫做GNU awk,gawk
1 2 [root@m01 ~] lrwxrwxrwx. 1 root root 4 Jul 5 2021 /usr/bin/awk -> gawk
awk执行流程 三个阶段
读取文件之前
BEGIN{}
1.读取文件之前,先看命令的选项,例如 -F,-v
2.如果写了BEGIN{}则先在BEGIN{}中的指令
读取文件时
{}
1.awk在读取文件时,也是一行一行的读\
2.读取一行之后,判断是否满足条件,如果是,则执行{对应动作}
3.如果不满足条件,awk继续读取下一行,直到满足条件或者到文件的最后一行
读取文件之后
END{}
1.所有文件读取完成之后,走END{}中的指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [root@m01 ~] [root@m01 ~] [root@m01 ~] name uid gid root 0 0 bin 1 1 daemon 2 2 adm 3 4 lp 4 7 sync 5 0 shutdown 6 0 halt 7 0 mail 8 12 operator 11 0 games 12 100 ftp 14 50
awk的行与列 行:记录 record
列:字段 field
awk取行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 NR:Number of Record [root@m01 ~] root:x:0:0:root:/root:/bin/bash [root@m01 ~] root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin [root@m01 ~] root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin [root@m01 ~] 1,roger,666 3,cls,888 roger,111 [root@m01 ~] /tmp/check_2.txt /tmp/check_3.txt /tmp/check_4.txt /tmp/check_5.txt 3,cls,888 roger,111 4,lls,999 [root@m01 ~] 1,roger,666 /tmp/check_1.txt /tmp/check_2.txt /tmp/check_3.txt cls roger 4,lls,999 cls Record Separator [root@m01 ~] awk -F : -vOFS='|' '{print $1,$2,$NF}' /etc/passwd awk -F : -vOFS='# ' {print $1 ,$2 ,$NF }' /etc/passwd
awk取列 1 2 3 4 5 6 7 8 9 10 11 12 FS:内置变量,列分隔符 -F: = -vFS=: [root@m01 ~] [root@m01 ~] [root@m01 ~] [root@m01 ~] [root@m01 ~]
awk取行取列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 [root@m01 ~] 1 [root@m01 ~] 10.0.0.61 [root@m01 ~] 1 Zeng Laoshi 133411023 :110:100:75 2 Deng Ziqi 44002231 :250:10:88 3 Zhang Xinyu 877623568 :120:300:200 4 Gu Linazha 11029987 :120:30:79 5 Di Lireba 253097001 :220:100:200 6 Jiang Shuying 535432779 :309:10:2 7 Ju Jingyi 68005178 :130:280:385 8 Zhang Yuqi 376788757 :500:290:33 9 Wen Zhang 259872003 :100:200:300 [root@m01 ~] 姓 名 捐款数额 [root@m01 ~] 姓 名 捐款数额 Zhang Xinyu 300 Zhang Yuqi 290 Wen Zhang 200 [root@m01 ~] 姓 名 捐款数额 Zhang Xinyu 300 Zhang Yuqi 290 [root@m01 ~] 姓 名 捐款数额 Zhang Xinyu 300 [root@m01 ~] 姓名 捐款数额 ZhangXinyu 300 [root@m01 ~] 姓名 捐款数额 ZhangXinyu 300 [root@m01 ~] DiLireba 253097001 WenZhang 259872003 [root@m01 ~] ZengLaoshi 133411023 DengZiqi 44002231 DiLireba 253097001 WenZhang 259872003 [root@m01 ~] ZengLaoshi 133411023 DengZiqi 44002231 DiLireba 253097001 WenZhang 259872003 [root@m01 ~] ZengLaoshi 133411023 DengZiqi 44002231 DiLireba 253097001 WenZhang 259872003 [root@m01 ~] 1 Zeng Laoshi 133411023 $110 $100 $75 2 Deng Ziqi 44002231 $250 $10 $88 3 Zhang Xinyu 877623568 $120 $300 $200 4 Gu Linazha 11029987 $120 $30 $79 5 Di Lireba 253097001 $220 $100 $200 6 Jiang Shuying 535432779 $309 $10 $2 7 Ju Jingyi 68005178 $130 $280 $385 8 Zhang Yuqi 376788757 $500 $290 $33 9 Wen Zhang 259872003 $100 $200 $300 [root@m01 ~] 1 Zeng Laoshi 133411023 $110 :100:75 2 Deng Ziqi 44002231 $250 :10:88 3 Zhang Xinyu 877623568 $120 :300:200 4 Gu Linazha 11029987 $120 :30:79 5 Di Lireba 253097001 $220 :100:200 6 Jiang Shuying 535432779 $309 :10:2 7 Ju Jingyi 68005178 $130 :280:385 8 Zhang Yuqi 376788757 $500 :290:33 9 Wen Zhang 259872003 $100 :200:300 function gsub (){ $1 $2 $3 xxxx } gsub(xx,aaa,d) gsub("被替换的内容" ,"替换的新内容" ) gsub("被替换的内容" ,"替换的新内容" ,第N列) [root@m01 ~] 10 61 255 255 255 10 255 6 80 20 29 3 64 20 29 3 2 5 2 6 1 172 16 1 61 255 255 255 172 16 1 255 6 80 20 29 3 9 64 20 29 3 9 46 9 117 29 7 73 127 1 255 6 1 128 10
awk模式与动作 1 awk -F: 'NR==1{print $1,$3}' /etc/passwd
上面这条命令我们可以看到,'NR==1{print $1,$3}'
可以理解为,'模式{动作}'
== '条件{指令}'
awk中的模式
1 2 3 4 5 6 '/正则表达式/flag' '$1~/正则表达式/flag' '$1!~/正则表达式/flag' 只不过我们在awk中很少使用flag
1 2 3 4 5 NR==1 NR>=10 NR<=100 NR>=1 && NR<=10 $1 >=100
1 2 3 4 5 6 7 8 9 NR==10,NR==20 '/root/,/roger/' '/从哪个字符串所在行/,/到那个字符串所在行/' '$1~/oo/,$1~/zl/'
awk中的动作
在awk中,我们最常用的动作就是 print
当然我们还有别的动作可以使用:
1 2 useradd name;pass=`echo $RANDOM |md5sum|cut -c 1-10`;echo $pass |passwd --stdin name;echo $pass :$user >> /tmp/user.txt seq 100|awk '{print "useradd test"$1";pass=`echo $RANDOM|md5sum|cut -c 1-10`;echo $pass|passwd --stdin test"$1";echo $pass:test"$1" >> /tmp/user.txt"}' |bash
如果要使用BEGIN模式,那么一定要成双成对的出现:BEGIN{}
那么我们要知道,BEGIN{}中,大括号里面的内容,会在读取文件内容之前执行
主要应用场景:
1 2 [root@zabbix01 ~] 0.333333
END模式 一般来说,END{}要比BEGIN{}重要一些,BEGIN{}可有可无,计算其实可以放在读取文件的时候,也可以执行
END{}中,大括号里面的内容,会在awk读取完文件的最后一行后,进行处理
作用:一般我们使用END{}来显示对日志内容分析后的一个结果 当然,还有其他功能,比如文件读取完了,可以显示一些尾部信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 [root@m01 ~] 1 ... 11176 不需要过程,只要结果 [root@m01 ~] 11176 [root@m01 ~] 11176 [root@m01 ~] 11176 [root@m01 ~] 11176 [root@m01 ~] 11176 /etc/services [root@m01 ~] [root@m01 ~] 17 #!/usr/bin/bash n=0 for line in `cat user.txt`;do if [[ $line =~ [0-9]+ ]];then ((n+=$line )) fi done echo $n [root@m01 ~] 姓名 年龄 曾老湿 23 苍颈空 18 西冶详 99 [root@m01 ~] 23 18 99 [root@m01 ~] 140 [root@m01 ~] 状态码200的次数 总流量 3100 190477111 脚本写法: awk ' BEGIN{ print "状态码200的次数","总流量" } $10~/200/{ code++;byte+=$11 } END{ print code,byte }' [root@m01 ~] 580 519243 zcat blog.driverzeng.com_access.log-20220623.gz |awk ' BEGIN{ print "状态码","总流量" } $10~/200/{ i1++;n1+=$11 } $10~/^3/{ i2++;n2+=$11 } $10~/^4/{ i3++;n3+=$11 } $10~/^5/{ i4++;n4+=$11 } END{ print "200次数:"i1,"200的流量:"n1 print "3xx次数:"i2,"3xx的流量:"n2 print "4xx次数:"i3,"4xx的流量:"n3 print "5xx次数:"i4,"5xx的流量:"n4 }' |column -t
awk数组 在awk中的数组数据类型,是非常好用的一个类型,不像是shell,当然shell中数组也有它自己的优点。
awk中的数组,专门用来统计不同的分类。
** 例如:** 1.nginx日志中每个IP出现的次数 2.nginx日志中每种状态码出现的次数 3.nginx日志中每个URI的访问次数
awk数组赋值
awk数组取值
shell中循环数组
1 2 3 4 5 6 array[0]='roger' array[1]='cls' for name in ${array[*]} ;do echo $name done
awk循环数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 for (条件){ 动作 } for 条件;do 动作 done [root@m01 ~] 0 1 [root@m01 ~] roger wyk zcat blog.driverzeng.com_access.log-20220623.gz |awk '{array[$1]++}END{for(ip in array){print ip,array[ip]}}' https://blog.driverzeng.com/index.html https://blog.driverzeng.com/1.html http://post.driverzeng.com/index.html http://mp3.driverzeng.com/index.html https://blog.driverzeng.com/3.html http://post.driverzeng.com/2.html [root@m01 ~] blog.driverzeng.com 3 post.driverzeng.com 2 mp3.driverzeng.com 1 [root@m01 ~]
awk的判断 awk判断与shell判断对比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 if [ 条件 ];then 动作 fi if [ 条件 ];then else fi if [ 条件 ];then elif [ 条件 ];then else fi if (条件){ 动作 } if (条件){ 动作 }else { 动作 } if (条件){ 动作 }else if (条件){ 动作 }else { 动作 } awk '{}END{for(条件){if(条件){动作}else if(条件){动作}else{动作}}}' awk '{ 读文件的动作 }END{ for(条件){ if(条件){ 动作 }else if(条件){ 动作 }else{ 动作 } } }' [root@m01 ~] 磁盘空间还行 [root@m01 ~] 磁盘空间还行,当前磁盘使用率:9%
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 stu01 70 80 90 100 90 80 stu02 89 78 98 67 97 90 stu03 56 12 33 44 55 66 77 stu04 89 78 77 99 100 30 stu05 98 97 96 95 94 93 stu06 100 20 20 20 20 20 Zeng Laoshi 133411023 :110:100:75 Deng Ziqi 44002231 :250:10:88 Zhang Xinyu 877623568 :120:300:200 Gu Linazha 11029987 :120:30:79 Di Lireba 253097001 :220:100:200 Jiang Shuying 535432779 :309:10:2 Ju Jingyi 68005178 :130:280:385 Zhang Yuqi 376788757 :500:290:33 Wen Zhang 259872003 :100:200:300 1.请找出姓氏是张的人,他们第二次捐款的数额及姓名 2.显示所有以25开头的QQ号及姓名 3.显示所有QQ号最后一位是1或者3的人,全名及QQ 4.显示每个捐款值都以$开头 $110 :$00 $75 5.综合应用:找出ifconfig中范围是1-255的数字