shell Shell基础教程 发表于 2022-01-11 浏览量 399 没有评论 ## shell脚本的命名: 名字要有意义,最好不要用a、b、c、d、1、2、3、4这种方式命名;虽然linux系统中,文件没有扩展名的概念,依然建议你用.sh结尾;名字不要太长,最好能在30个字节以内解决。例如:check_memory.sh ## shell脚本格式: shell脚本开头必须指定脚本运行环境 以 #!这个特殊符号组合来组成。如: #!/bin/bash 指定该脚本是运行解析由/bin/bash来完成的; ## shell中的注释使用 # 号 ``` 1)定义脚本的执行环境 #!/bin/bash 2) #号代表注释 #!是特列 3)脚本信息 Author:Ewain Created Time: 2020/7/10 Release: 1.0 Script Description: nginx install script 4) 脚本组成 # 解释环境 #!/bin/bash env | python | perl #注释说明 #执行脚本 5) 运行脚本两种方法 给权限:chmod +x 直接用shell 执行:bash filename 不需要给权限 ``` 内存使用率算法 echo "当前内存使用率:`echo "scale=2;559*100/1837" |bc`%" scale 保留两个小数点 bc Linux计算器 599已使用 1837总内存 ## 变量分类 + 1.本地变量:用户私有变量,只有本用户可以使用,保存在家目录下.bash_profile、.bashrc文件中 + 2.全局变量:所有用户都可以使用,保存在/etc/profile、/etc/bashrc文件中 + 3.用户自定义变量:用户自定义,比如脚本中的变量 ## 定义变量 变量格式:变量名=值 在shell编程中的变量名和等号之间不能有空格 ``` 变量名命名规则: 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头 中间不能有空格,可以使用下划线(_)。 不能使用标点符号。 不能使用bash里的关键字(可以用help命令查看保留关键字,如test不能设置) ``` VAR1=1 age=18 name='Ewain' score=99.9 注意:字符串要用单引号或双引号引起来 ## 读取变量内容 读取变量内容符:$ 读取变量方法:$变量名 ``` [root@02 /]# echo $name ewain ``` ## 取消变量unset ,一般都是取消零时变量 ``` [root@02 /]# unset name [root@02 /]# echo $name ``` ## 定义全局变量export ``` export name="ewain" #不加export就是本地变量 定义全局变量一般都是变量文件中,以便永久使用。 /etc/profile、/etc/bashrc ``` ## 数组 一个变量只能存一个值,但是数组可以让用户一次赋予多个值,需要读取数据时只需通过引索调用就能读出来。 数组语法 数组名称=(元素1 元素2 元素3....) 数组读出 ${数组名称[元素1]} ``` #!/usr/bin/bash array1=('a' 'b' 'c' 'd') echo ${array1[2]} #访问数组中的第三个元素,0开始 array1[4]='e' #数组第5位添加一个e array1[5]='f' echo ${array1[4]} #打印第5个元素 echo ${array1[@]} #打印所有元素 echo ${#array1[@]} #统计元素的个数 echo ${!array1[@]} #打印数组元素的索引 echo ${array1[@]:2} #从数组下标2开始 echo ${array1[@]:1:2} #打印1开始的两位 ``` ## 遍历数组 默认通过数组元素的个数进行遍历 echo ${array1[@]} echo ${array1[1]} ## 关联数组 关联数组可以允许用户自定义数组的索引,这样使用起来更加方便、高效。 ``` ass_array1[index1]=pear #一次一个赋值 ass_array2=([index1]=tom [index2]=jack [index3]=alice) #一次赋值多个 ``` ## shell流程控制--if判断语句 shell中的五大运算---数学比较运算 ``` -eq #等于 -gt #大于 -lt #小于 -ge #大于或等于 -le #小于或等于 -ne #不等于 ``` 小数点运算 ``` #!/bin/bash num1=`echo "1.5*10"|bc|cut -d "." -f1` #把小数点给他处理下再做对比 num2=$((2*10)) test $num1 -gt $num2;echo $? ``` ## 字符串比较运算 ``` 运算符解释,注意字符串一定要使用引号引起来 == 等于 != 不等于 -n 检查字符串的长度是否大于0 -z 检查字符串的长度是否为0 ``` ## 文件比较与检查 ``` -d 检查文件是否存在且为目录 -e 检查文件是否存在 -f 检查文件是否存在且为文件 -r 检查文件是否存在且可读 -w 检查文件是否存在且可写 -x 检查文件是否存在且可执行 -s 检查文件是否存在且不为空 -O 检查文件是否存在并且被当前用户拥有 -G 检查文件是否存在且默认组为当前用户组 file1 -nt file2 检查file1是否比file2新 file1 -ot file2 检查file1是否比file2旧 stat file 查看文件详细记录信息 ``` 注意:man test 都能查到所有选项 ## 逻辑运算 ``` && #逻辑与运算 || #逻辑或运算 ! #逻辑非运算 注意事项: 逻辑与 或 运算都需要两个或以上条件,逻辑非运算只能一个条件。 口诀: 逻辑与运算 真真为真 真假为假 假假为假 逻辑或运算 真真为真 真假为真 假假为假 逻辑非运算 非假为真 非真为假 ``` ## 赋值运算 ``` = 赋值运算符 a=10 name='ewain' ``` ## if语法 语法一:单一if语句 适合范围:只需要一步判断,条件返回为真干什么或者返回为假干什么。 语句格式 ``` #!/bin/bash if [ ! -d /tmp/abc ] then mkdir -v /tmp/abc echo "create /tmp/abc OK!" fi 翻译: 如果 条件为真 那么 执行commands代码块 结束 ``` 语法二:if-then-else语句 适用范围:两步判断,条件为真干什么,条件为假干什么。 ``` #!/bin/bash if [ $USER == 'root' ] then echo "管理员,你好" else echo "guest,你好" fi 翻译: 假如条件为真 那么 执行代码块1 否则 执行代码块2 结束 [root@lianshou if]# bash user_login.sh 管理员,你好 [root@lianshou if]# su - test -c "/bin/bash /shell/if/user_login.sh" guest,你好 ``` 语法三:if--then--elif语句 适用范围:多于两个以上的判断结果 ``` #!/bin/bash if [ $1 -gt $2 ] then echo "$1 > $2" elif [ $1 -eq $2 ] then echo "$1 = $2" else echo "$1 < $2" fi 翻译: 假如 条件1为真 那么 执行代码块1 假如 条件2为真 那么 执行代码块2 否则 【以上所有条件没有一个满足】 执行代码块X 结束 方法二:嵌套 #!/bin/bash if [ $1 -eq $2 ] then echo "$1 = $2" else if [ $1 -gt $2 ] then echo "$1 > $2" else echo "$1 < $2" fi fi ``` if高级应用 1、条件符号使用双圆括号,可以在条件中植入数学表达式 ``` #!/bin/bash if (( 100%3+1>1 )) then echo "yes" else echo "no" fi ``` 2、使用双方括号,可以在条件中使用通配符 ``` #!/bin/bash for i in r1 r2 cc rr3 do if [[ $i == r* ]];then echo $i fi done ``` ## shell流程控制--for循环语句 优点,节省内存,结构清晰,节省时间 for 语法一 ``` for var in value1 value2 ..... do commands done #!/bin/bash for i in `seq 10 -1 1` do echo $i done ``` for 语法二 c式的for命令 ``` for (( var;条件;加减运算 )) do 代码块 done #!/bin/bash #方法一,单个变量 for (( i=1;i<10;i++ )) do echo $i done #方法二,多个变量 for (( n=10,m=0;n>0,m<10;n--,m++ )) do echo -e "$n\t$m" done ``` for无限循环,使用((;;))条件可以实现 ``` for ((;;)) do echo "hehe" done ``` ## 循环控制语句 sleep N 脚本执行到该步休眠N秒,不影响CPU ``` #!/bin/bash #监控存活主机,这里使用了死循环。 for ((;;)) do ping -c1 $1 &>/dev/null if [ $? -eq 0 ] then echo -e "`date +"%F %H:%M:%S"`:$1 is \033[32mUP\033[0m" else echo -e "`date +"%F %H:%M:%S"`:$1 is \033[31mDown\033[0m" fi #控制脚本节奏,生产环境建议一分钟以上 sleep 5 done ``` continue跳过循环中的某次循环 ``` #!/bin/bash for (( i=1;i<10;i++ )) do if [ $i -eq 5 ] then #注意,到了5次就跳过,不执行下面的代码,是跳过,不是退出。 continue else echo $i fi done ``` break跳出循环继续执行后续代码 ``` #方法一 #!/bin/bash for ((;;)) do read -p "char:" ch if [ $ch == "Q" ] then #终止本次循环 break #如果循环多层嵌套,循环从里往外排序0-N #如果想跳出某层循环 break N else echo "你输入的字符是$ch" fi done #方法二: #!/bin/bash for (( i=1;i<100;i++ )) do echo "loop $i" for ((;;)) do echo "haha" break 2 #直接跳出循环 done sleep 3 done ``` ## shell流程控制--while循环语句 和for一样,功能一样,明确知道要循环多少次,选用for,不知道要循环多少次,选用while。 while语法 ``` while [ 条件 ] #注意,条件为真while才会循环,条件为假的时候,while停止循环 do commands done 方法一: #!/bin/bash #while基础语法 #条件可以是五种运算中的任意一种 #数学运算 字符比较 文件类型 逻辑运算 赋值运算 read -p "NUM:" num1 while [ $num1 -gt 1 ] #大于1,循环,小于1,直接退出循环 do echo "大于" sleep 3 done 方法二: #1/bin/bash #丈母娘选女婿标准 #1)姑娘带回第一个男朋友 read -p "存款有多少:" money read -p "小轿车有多少台:" car_num read -p "有多少套房子:" house read -p "小伙子,你叫什么名字:" name #2)第一个男朋友不符合条件时,进入循环,开始海选模式 while [ $money -lt 1000000 ] || [ $car_num -lt 1 ] || [ $house -lt 1 ] do echo "不好意思,你不符合!" echo "换下一个" read -p "小伙子,你叫什么名字:" read -p "存款有多少:" money read -p "小轿车有多少台:" car_num read -p "有多少套房子:" house done echo "$name 我的女儿就交给你了!" ``` if嵌套与循环控制 ``` #!/bin/bash #打印1-9,当数值为5时停止循环 i=1 while [ $i -lt 10 ] do echo $i if [ $i -eq 5 ];then break fi i=$((i+1)) done #打印1-9,当数值为5时跳过当前循环 i=0 while [ $i -lt 10 ] do i=$((i+1)) if [ $i -eq 5 ];then continue fi echo $i done 99乘法表:内嵌for #!/bin/bash n=1 while [ $n -lt 10 ];do for (( m=1;m<=$n;m++ ));do echo -ne "$m * $n = $(( n*m ))\t" done echo n=$((n+1)) done 99乘法表2:内嵌while #!/bin/bash n=1 while [ $n -lt 10 ];do m=1 while [ $m -le $n ];do echo -n -e "$m * $n = $((n*m))\t" m=$((m+1)) done echo n=$((n+1)) done ``` while遍历文件文件内容 ``` #b!/bin/bash while read i do echo $i done <$1 bash while.sh /etc/passwd ``` 使用while读出文件中的列,IFS指定默认分割符 ``` #!/bin/bash IFS=$":" while read f1 f2 f3 f do echo "$f1 $f2 $f3" done < /etc/passwd bash while.sh ``` ## until语句 和while正好相反,until是条件为假开始执行,条件为真停止执行 until语法跟while一样 ``` #!/bin/bash num=1 #打印1-9 while [ $num -lt 10 ];do #条件为真执行 echo $num num=$((num+1)) #打印10-20 until [ $num -lt 10 ];do #条件为假执行 echo $num if [ $num -eq 20 ];then break fi num=$((num+1)) done done ``` ## shell流程控制--case多条件分支语句 根据不同的条件执行不同的代码块 case语法: ``` case var in 条件1) 执行代码块1 ;; 条件2) 执行代码块2 ;; esac 注意:每个代码块执行完毕要以;;结尾代表结束,case结尾要以倒过来谢的esac来结束 实例: #!/bin/bash case $1 in zmn|ZMN) echo "伯母好" ;; lzr|LXR) echo "伯父好" ;; lnn|LNN) echo "奶奶好" ;; *) echo "USAGE:$0 zmn|lzr|lnn" ;; esac ``` ## shell特殊变量 ``` 实例: #!/bin/bash echo "脚本的名字是:$0" echo "脚本的参数是:$*" echo "传参数量:$#" echo "脚本执行进程号:$$" echo "最后执行的命令是:$_" echo "第二个参数是:$2" ``` ## shell函数 把代码模块化,一个模块实现实现一个功能,代码量少,可以改变执行顺序,排错简单。 函数的语法: ``` 语法1: 函数名(){ 代码块 return N } 实例1: #1/bin/bash #函数默认不会执行,除非你调用 #定义函数 start(){ echo "apache start .... [OK]" #return 0 #可写可不写! } stop(){ echo "apache stop.... [FAIL]" } #调用函数 start;stop 语法2: function 函数名{ 代码块 return N } 实例2: #1/bin/bash #函数默认不会执行,除非你调用 #定义函数 function start { echo "apache start .... [OK]" #return 0 #可写可不写! } #调用函数 start ``` ## nginx启动管理脚本 ``` #!/bin/bash #nginx service manage script #varables nginx_install_doc=/etc/nginx/ nginxd=/usr/sbin/nginx pid_file=/run/nginx.pid proc=nginx #Source function library. #调用系统函数库 if [ -f /etc/init.d/functions ];then . /etc/init.d/functions else echo "not found file /etc/init.d/functions" exit fi #查看PID并统计 if [ -f $pid_file ];then nginx_process_id=`cat $pid_file` nginx_process_num=`ps aux | grep $nginx_process_id | grep -v "grep"|wc -l` fi #function start (){ #如果nginx没有启动,直接启动,否则报错,已经启动。 if [ -f $pid_file ] && [ $nginx_process_num -ge 1 ];then echo "nginx running..." else if [ -f $pid_file ] && [ $nginx_process_num -lt 1 ];then rm -f $pid_file #echo " nginx start `daemon $nginxd` " #daemon来自系统函数库 action "nginx start" $nginxd #action来时系统函数库 fi #echo "nginx start `daemon $nginxd`" action "nginx start" $nginxd fi } stop (){ if [ -f $pid_file ] && [ $nginx_process_num -ge 1 ];then action "nginx stop" killall -s QUIT $proc rm -f $pid_file else action "nginx stop" killall -s QUIT $proc 2>/dev/null fi } restart (){ stop sleep 1 start } reload(){ if [ -f $pid_file ] && [ $nginx_process_num -ge 1 ];then action "nginx reload" killall -s HUP $proc else action "nginx reload" killall -s HUP $proc 2>/dev/null fi } status(){ if [ -f $pid_file ] && [ $nginx_process_num -ge 1 ];then echo "nginx running....." else echo "nginx stop" fi } ck(){ if [ -f $nginx_install_doc/nginx.conf ];then $nginxd -t else echo "配置文件不存在。。" fi } #callable case $1 in start) start;; stop) stop;; restart) restart;; reload) reload;; status) status;; check) ck;; *) echo "USAGE:$0 start|stop|restart|reload|status|check" ;; esac ``` ## 正则表达式 + 正则表达式是一种文本模式匹配,包括普通字符(例如,a-z之间的字母)和特殊字符。它是一种字符串匹配的模式,可以检查一个字符是否含有某种子串,将匹配的子串替换或者从某个字符串中取出某个条件的子串。 正则表达式就像数学公式一样,可以通过正则提供一些字符来生成一个匹配对应字符串的公式,用来从海量的数据中匹配出自己想要的数据。 正则表达式是一个三方产品,常被计算机语言广泛使用,比如:shell、python、java、js等! shell也支持正则表达式,但不是所有命令都支持正则表达式,常见的命令中只有grep、sed、awk支持正则表达式。 + 特殊字符 定位符使用技巧:同时锚定开头和结尾,做精确匹配;单一锚定开头或结尾,做模糊匹配。 |定位符|说明| |--|--| |^|锚定开头^a以a开头,默认锚定一个字符| |\$|锚定结尾a\$以a结尾,默认锚定一个字符| ``` [root@lianshou zhengze]# egrep "^a" file.txt #以A为开头匹配 ab abbc [root@lianshou zhengze]# egrep "c$" file.txt #以c为结尾匹配 abbc abcc [root@lianshou zhengze]# egrep "^ac$" file.txt #以a开头c结尾的精确匹配 ac ``` 匹配符:匹配字符串 是 | ``` [root@lianshou zhengze]# egrep "^a.c$" file.txt #.任意字符 acc abc [root@lianshou zhengze]# egrep "^a[0-9]c$" file.txt # [0-9]匹配0-9的任意字符 a3c [root@lianshou zhengze]# egrep "^a[^0-9]c$" file.txt #[^0-9]匹配除了0-9以外的字符 acc abc [root@lianshou zhengze]# egrep "^a*c$" file.txt #*需要转义才能匹配 ac [root@lianshou zhengze]# egrep "^a\*c$" file.txt #添加了转义符 a*c [root@lianshou zhengze]# egrep "^(a|b)c$" file.txt #以A开头或者以B开头的匹配,使用了字符串分组 ac bc ``` 限定符:对前面的字符或者字符串做限定说明 ``` [root@lianshou zhengze]# egrep "^ab*c$" file.txt #*表示bb ,匹配以a开头,b字符或者不出现,以C结尾的字符 abbc abbbc abbbbbc abc ac [root@lianshou zhengze]# egrep "^ab?c$" file.txt #?表示B字符出现一次或者不出现匹配。 abc ac [root@lianshou zhengze]# egrep "^ab+c$" file.txt #+表示出现一次或者多次,但必须出现一次的匹配。 abbc abbbc abbbbbc abc [root@lianshou zhengze]# egrep "^ab{1,3}c$" file.txt #{1,3}表示B出现后最少出现1次,最多出现3次匹配 abbc abbbc abc [root@lianshou zhengze]# egrep "^ab{3}c$" file.txt #{3}表示B出现次数必须是3个匹配 abbbc ``` POSIX特殊字符 ``` [root@lianshou zhengze]# egrep ^a[[:alnum:]]c$ file.txt #以a开头[[:alnum:]]匹配任意字母字符0-9-a-z-A-Z以c结尾的一个字符匹配 acc abc aZc a3c ``` ##shell对文件的操作--sed命令 + sed是linux中提供的一个外部命令,它是一个行(流)编辑器,非交互式的对文件内容进行增删改查的操作,使用者只能在命令行输入编辑命令、指定文件名,然后在屏幕上查看输出。它和文本编辑器有本质的区别。默认不会更改文本中的数据,需要加选项才能修改。 ``` 区别是: 文本编辑器:编辑对象是文件 行编辑器:编辑对象是文本中的行 ``` + sed数据处理原理 + sed命令语法 sed [options] ‘{command}[flags]’ [filename] ``` 命令选项 -e script 将脚本中指定的命令添加到处理输入时执行的命令中 多条件,一行中要有多个操作 -f script 将文件中指定的命令添加到处理输入时执行的命令中 -n 抑制自动输出 -i 编辑文件内容 -i.bak 修改时同时创建.bak备份文件。 -r 使用扩展的正则表达式 ! 取反 (跟在模式条件后与shell有所区别) sed常用内部命令 a 在匹配后面添加 i 在匹配前面添加 p 打印 d 删除 s 查找替换 c 更改 y 转换 N D P flags 数字 表示新文本替换的模式 g: 表示用新文本替换现有文本的全部实例 p: 表示打印原始的内容 w filename: 将替换的结果写入文件 ``` ``` [root@lianshou zhengze]# sed '3,5a\woaini' file.txt #在第三行,第五行添加 增 [root@lianshou zhengze]# sed -r '/(^#|^$|#)/d' nginx.conf #-r 使用正则,/匹配/ d删除 删 [root@lianshou zhengze]# sed 's/html/htm/' nginx.conf # s替换/源/更改后/ 文件 改 [root@lianshou zhengze]# sed '3,5c\woaini' file.txt #c更改,3,5表示把第三行第五行删 了,添加一行 ``` + [flags] 标记位 ``` [root@lianshou zhengze]# sed 's/dog/cat/' dog.txt #默认只会替换一行中的第一个 zhangzhang is cat.dog zhangzhang is cat.dog [root@lianshou zhengze]# sed 's/dog/cat/2' dog.txt #2,替换一行中的第二个 zhangzhang is dog.cat zhangzhang is dog.cat [root@lianshou zhengze]# sed 's/dog/cat/g' dog.txt #g,全局,替换一行中所有包含的字 zhangzhang is cat.cat zhangzhang is cat.cat [root@lianshou zhengze]# sed '2s/dog/cat/w test.txt' dog.txt #w,写入到另外一个文档 ``` + [options] 选项 ``` [root@lianshou zhengze]# sed -n '3s/dog/cat/p' dog.txt #-n,抑制内存输出,-p 打印 [root@lianshou zhengze]# sed -e 's/red/green/;s/dog/cat/g' dog.txt #-e,多条件处理 [root@lianshou zhengze]# cat xx.txt s/red/green/ /dog/cat/ [root@lianshou zhengze]# sed -f xx.txt dog.txt # -f 将文件中指定的命令添加到处理输入时执行。 [root@lianshou zhengze]# sed -i 's/dog/cat/g' dog.txt #-i,编辑文件,直接修改,不输出,不可逆 [root@lianshou zhengze]# sed -i.bak 's/cat/dog/g' dog.txt #-i.bak会帮你备份一份源文件,安全。 小技巧: [root@lianshou zhengze]# sed -n '$=' dog.txt #-n,抑制内存输出,'$=' 统计行数 [root@lianshou zhengze]# sed '=' dog.txt # ‘=’ 给每一行添加一个行号 ``` ##shell对输出流的处理--awk命令 + 在日常计算机管理中,总会有很多数据输出到屏幕或者文件,这些输出包含了标准输出、标准错误输出。默认情况下,这些信息全部输出到默认输出设备—-屏幕。然而,大量的数据输出中,只有一小部分是我们需要重点关注的,我们需要把我们需要的或者关注的这些信息过滤或者提取以备后续需要时调用。早先的学习中,我们学过使用grep来过滤这些数据,使用cut、tr命令提出某些字段,但是他们都不具备提取并处理数据的能力,都必须先过滤,再提取转存到变量,然后在通过变量提取去处理,比如: 内存使用率的统计步骤 1) 通过free -m提取出内存总量,赋值给变量 memory_totle 2)通过free -m提取出n内存使用量,赋值给变量memory_use 3)通过数学运算计算内存使用率 需要执行多步才能得到内存使用率,那么有没有一个命令能够集过滤、提取、运算为一体呢?当然,就是今天我要给大家介绍的命令:awk 平行命令还有gawk、pgawk、dgawk,awk是一个行编辑器 awk是一种可以处理数据、产生格式化报表的语言,功能十分强大。awk 认为文件中的每一行是一条记录 记录与记录的分隔符为换行符,每一列是一个字段 字段与字段的分隔符默认是一个或多个空格或tab制表符. awk的工作方式是读取数据,将每一行数据视为一条记录(record)每条记录以字段分隔符分成若干字段,然后输出各个字段的值. + awk语法 awk [options] [BEGIN]{program} [END][file] ``` 常用命令选项 -F fs 指定描绘一行中数据字段的文件分隔符 默认为空格 -f file 指定读取程序的文件名 -v var=value 定义awk程序中使用的变量和默认值 注意:awk 程序脚本由左大括号和右大括号定义。脚本命令必须放置在两个大括号之间。由于awk命令行假定脚本是单文本字符串,所以必须将脚本包 括在单引号内。 awk程序运行优先级是: 1)BEGIN: 在开始处理数据流之前执行,可选项 2)program: 如何处理数据流,必选项 3)END: 处理完数据流后执行,可选项 ``` + awk对字段(列)的提取 ``` 字段提取:提取一个文本中的一列数据并打印输出 $0 表示整行文本 [root@02 shell]# awk '{print $0}' test.txt $1 表示文本行中的第一个数据字段 [root@02 shell]# awk '{print $1}' test.txt $2 表示文本行中的第二个数据字段 [root@02 shell]# awk '{print $2}' test.txt $N 表示文本行中的第N个数据字段 $NF 表示文本行中的最后一个数据字段 [root@02 shell]# awk '{print $NF}' test.txt ``` + awk 对记录(行)的提取 ``` 提取方法有两种:a通过行号,b通过正则匹配 NR:指定行号 [root@02 shell]# awk 'NR==3{print $0 }' test.txt #NR指定行号 [root@02 shell]# awk -F ":" 'NR==1{ print $1 }' passwd #-F指定分割符 [root@02 shell]# awk -F ":" 'NR==1{print $1 "-" $3 "-" $4 }' passwd #默认输出是以空格分开,也可指定分割符 [root@02 shell]# awk -F ":" 'NR==1{print "user:"$1,"UID:"$3}' passwd #逗号输出是空格符号,也可以用" "输出空格 [root@02 shell]# head -3 /proc/meminfo |awk 'NR==2{print $2}' #截取内存 ``` + awk程序优先级 关于awk程序的执行优先级,BEGIN是优先级最高的代码块,是在执行PROGRAM之前执行的,不需要提供数据源,因为不涉及到任何数据的处理,也不依赖与PROGRAM代码块;PROGRAM是对数据流干什么,是必选代码块,也是默认代码块。所以在执行时必须提供数据源;END是处理完数据流后的操作,如果需要执行END代码块,就必须需要PROGRAM的支持,单个无法执行。 ``` [root@02 shell]# awk 'BEGIN{print "hello,world"}' #BEGIN不需要数据源 [root@02 shell]# awk 'BEGIN{print "welcom"}{print $0}END{print "byebye"}' test.txt ``` + awk高级用法--awk是一门语言,那么就会符合语言的特性,除了可以定义变量外,还可以定义数组,还可以进行运算,流程控制 + 定义数组 ``` [root@02 shell]# awk 'BEGIN{array[1]="oyh";array[2]=25;print array[1],array[2]}' ``` + 定义变量 ``` [root@02 shell]# head -2 /proc/meminfo |awk 'NR==1{t=$2}NR==2{f=$2;print (t-f)*100/t "%"}' #计算内存使用率 [root@02 shell]# awk 'BEGIN{name="oyh";print name}' ``` + awk运算: 赋值运算 = 比较运算 > >= == < <= != 数学运算 + - / % * ++ — 逻辑运算 && || 匹配运算 ~ !~ ``` 比较运算,如果比较的是字符串则按ascii编码顺序表比较。如果结果返回为真则用1表示,如果返回为假则用0表示 [root@02 shell]# awk 'BEGIN{print "a" >= "b" }' 0 [root@02 shell]# awk '$1>5{print $0}' num #打印 数学运算: [root@02 shell]# awk 'BEGIN{print 1+1}' 2 [root@02 shell]# awk 'BEGIN{print 1-1}' 0 [root@02 shell]# awk 'BEGIN{print 1*2}' 2 [root@02 shell]# awk 'BEGIN{print 1/2}' 0.5 [root@02 shell]# awk 'BEGIN{print 1%2}' 1 [root@02 shell]# awk 'BEGIN{print 3**2}' 9 [root@02 shell]# awk -v 'name=18' 'BEGIN{name--;print name}' #-v定义变量,“--”,减1 17 [root@02 shell]# awk -v 'name=18' 'BEGIN{name++;print name}' # ++ ,加1 19 逻辑运算: [root@02 shell]# awk 'BEGIN{print 100>=2 && 100>=3}' 1 [root@02 shell]# awk 'BEGIN{print 100>=2 || 100>=3}' 1 匹配运算: [root@02 shell]# awk -F: '$1 ~ "ro"{print $0}' passwd #~匹配带ro的字符,属于模糊匹配 root:x:0:0:root:/root:/bin/bash chrony:x:998:996::/var/lib/chrony:/sbin/nologin [root@02 shell]# awk -F: '$1 !~ "ro"{print $0}' passwd #!~取反 [root@02 shell]# awk -F: '$1=="root" {print $0}' passwd #精确匹配 ``` + awk环境变量 ``` [root@02 shell]# awk 'BEGIN{FIELDWIDTHS="5 2 8"}NR==1{print $1,$2,$3 }' /etc/passwd #指定每段字符的宽度,5对应$1 ,打印5个字符 root: x: 0:0:root [root@02 shell]# awk 'BEGIN{FS=":"}$1 ~ "ro" {print $0}' passwd #FS指定数据源分隔符,类似于-F [root@02 shell]# awk 'BEGIN{FS=":";OFS="-"}$1 == "root"{print $1,$3,$5}' passwd #OFS指定输出分隔符 root-0-root [root@02 shell]# awk 'BEGIN{RS=""}{print $1,$2,$3}' num #RS输入分隔符 1 2 3 ``` + awk流程控制 ``` if判断语句 for循环语句 while循环语句 do…while语句 循环控制 ``` ``` >>>>if判断: [root@02 shell]# awk '{if($1>5)print $0}' num # if $1大于5,打印全部。 6 7 8 9 10 [root@02 shell]# awk '{if($1>5)print $1*2;else print $1/2}' num # 嵌入else 0.5 1 1.5 2 2.5 12 14 16 18 20 [root@02 shell]# awk '{ >if ($1>5) > print $1*2 >else > print $1/2 >}' num >>>>for循环 [root@02 shell]# cat num2 60 50 100 150 30 10 70 100 40 [root@02 shell]# awk '{ #写法1 > for (i=1;i<4;i++) > sum+=$i >print sum}' num2 210 400 610 [root@02 shell]# awk '{sum=0;for (i=1;i<4;i++){sum+=$i}print sum}' num2 #写法2 210 190 210 >>>>while循环: [root@02 shell]# awk '{ #写法1 > sum=0 > i=1 > while (i<4) { > sum+=$i > i++ > } > print sum >}' num2 210 190 210 [root@02 shell]# awk '{sum=0;i=1;while(sum<150){sum+=$i;i++}print sum}' num2 #写法2 210 150 170 >>>>循环控制break: [root@02 shell]# awk '{ > sum=0 > i=1 > while (i<4){ > sum+=$i > if (sum>150) > break > i++ > } > print sum }' num2 210 180 170 ``` + awk使用小技巧 ``` [root@02 shell]# cat test.txt 1 the quick brown fox jumps over the lazy cat . dog 2 the quick brown fox jumps over the lazy cat . dog 3 the quick brown fox jumps over the lazy cat . dog 4 the quick brown fox jumps over the lazy cat . dog 5 the quick brown fox jumps over the lazy cat . dog >>>>统计行数 [root@02 shell]# awk 'END{print NR}' test.txt 5 >>>>打印最后一行 [root@02 shell]# awk 'END{print $0}' test.txt 5 the quick brown fox jumps over the lazy cat . dog >>>>打印文本的列数 [root@02 shell]# awk 'END{print NF}' test.txt 12 ```