shell学习心得笔记系列一 文本处理三剑客
理解
整理自网络资料,非原创版权,只用于学习理解的笔记和资料,禁止侵权
shell语言的理解:重点在于它是一个解释型语言,学习的shell语法写出的shell脚本,最终由linux服务器的解释器逐句解释运行
1.编程工具,脚本语言,解释型语言,执行时翻译机器码,翻译一句执行一句,跨平台,使用posix定义的规范
2.shell 命令行解释器,用户和操作系统间通信提供的一种接口,转换为一系列的系统调用送到内核执行
通俗的理解:
Bash 的语法在一些地方是不够严谨的,需要硬记,但是大部分的语法是可以用编译原来来进行理解。
一行命令被解释器读取后,它会去链接到相关的code,构成一段代码,并为这段代码初始化它运行的上下文,所以理解每一行命令的时候,可以假设它有你不知道的隐含在背后的参数,环境变量,code等。
命令就像call(bash_cmd,arg1,arg2) , 由内核+bash解释器去执行对应的
bash_cmd ==> callFunction(arg1,arg2)
所以脚本的第一行是
#!/bin/bash => 这是为了找到当前脚本执行的解释器bash(二进制可执行文件)
文本处理三剑客grep、sed、awk在文章后面均有讲解
变量替换
操作符 | 意义 |
---|---|
${var} | 变量替换,返回变量 var 的值。 |
${var:-word} | 如果变量 var 存在且非空,则返回变量 var 的值;否则返回 word。 |
${var:=word} | 如果变量 var 存在且非空,则返回变量 var 的值;否则将变量 var 赋值为 word,并返回 word。 |
${var:?message} | 如果变量 var 存在且非空,则返回变量 var 的值;否则输出错误信息 message,并退出脚本。 |
${var:+word} | 如果变量 var 存在且非空,则返回 word;否则返回空字符串。 |
${var#pattern} | 从变量 var 的开头开始匹配 pattern,并将匹配的最短部分删除。 |
${var##pattern} | 从变量 var 的开头开始匹配 pattern,并将匹配的最长部分删除。 |
${var%pattern} | 从变量 var 的结尾开始匹配 pattern,并将匹配的最短部分删除。 |
${var%%pattern} | 从变量 var 的结尾开始匹配 pattern,并将匹配的最长部分删除。 |
${var/pattern/string} | 匹配变量 var 中的 pattern,并将其替换为 string。只替换第一个匹配项。 |
${var//pattern/string} | 匹配变量 var 中的 pattern,并将其替换为 string。替换所有匹配项。 |
${#var} | 返回变量 var 的字符长度。 |
${var:offset:length} | 返回从变量 var 的 offset 位置开始,长度为 length 的子字符串。 |
${var: -length} | 返回变量 var 的末尾 length 个字符。 |
${!prefix*} 或 ${!prefix@} | 返回所有以 prefix 开头的变量名列表。 |
# 删除动作 从头或从尾
${var#规则} |${var##规则} |${var%规则} |${var%%规则}|
# 替换动作
|${var/旧字符串/新字符串} |${var//旧字符串/新字符串} |
变量替换总结
贪婪模式
1、${变量#匹配规则} # 从头开始匹配,最短删除2、${变量##匹配规则} # 从头开始匹配,最长删除3、${变量%匹配规则} # 从尾开始匹配,最短删除4、${变量%%匹配规则} # 从尾开始匹配,最长删除5、${变量/旧字符串/新字符串} # 替换变量内的旧字符串为新字符串,只替换第一个6、${变量//旧字符串/新字符串} # 替换变量内的旧字符串为新字符串,全部替换
例子1:
variable_1="I love you,Do you love me"var1=${variable_1#*ov}var2=${variable_1##*ov}var3=${variable_1%ov*}var4=${variable_1%%ov*}var5=${PATH/bin/BIN}var6=${PATH//bin/BIN}
变量测试
expr声明为字符串
变量的配置方式 | str没有配置 | str字符为空串 | str字符配置且非空 |
---|---|---|---|
var=${str-expr} | var=expr | var=“” | var=$str |
var=${str:-expr} | var=expr | var=expr | var=$str |
var=${str+expr} | var= | var=expr | var=expr |
var=${str:+expr} | var= | var=“” | var=expr |
var=${str=expr} | var=expr | var=“” | var=$str |
var=${str:=expr} | var=expr | var=expr | var=$str |
开发中用的少,源码shell脚本中出现的多 现查现用:
只有+ 会用expr替换非空字符串,其他的多为
=> 处理空串或者未被赋值过的变量, 即怎么赋初始值或者空串用什么替换
字符串处理
获取子串 字符位置等
语法 | 说明 | |
---|---|---|
字符串长度 | ${#string} | 无 获取字符串长度 |
字符串长度 | expr length “$string” | expr命令 str有空格,则必须加双引号 |
获取子串的索引位置 | expr index $string %substring | 见注解 |
计算子串长度 | expr match $string substring | 匹配到的子串长度 |
注:当sub为字符串时,会将sub拆开为单个字符进行匹配,返回第一个匹配到字符的位置,并非完整匹配子串
string="hello world"
substring="world"result=$(expr index "$string" "$substring")echo "$result"
> 3 # 第一个找到的是l 字母
抽取子串
语法 | 说明 | |
---|---|---|
方法1 | ${string:position} | 从string中的position开始 |
方法2 | ${string:position:length} | 从position开始,匹配长度length |
方法3 | ${string: -position} | 从右开始匹配 |
方法4 | ${string:(position)} | 从左开始匹配 |
方法5 | expr substr $str $pos $length | 从position开始,匹配长度length |
字符串处理总结:1、计算字符串长度方法一:${#string}方法二:expr length $string例子:var1="Hello World"len=${#var1}len=`expr length "$string"`2、获取字符索引位置方法:expr index "$string" substr例子:var1="quicstart is a app"ind=`expr index "$var1" start`3、获取子串长度方法:expr match "$string" substr例子:var1="quicstart is a app"sub_len=`expr match "$var1" app` > 0 必须从头开始匹配,从中间匹配不到sub_len=`expr match "$var1" quic`> 44、抽取字符串中的子串方法一:index从0开始(1)、${string:position}(2)、${string:position:length}(3)、${string: -position} 或者 ${string:(position)}方法二:index从1开始expr substr $string $position $length 例子:var1="kafka hadoop yarn mapreduce"substr1=${var1:10}substr2=${var1:10:6}substr3=${var1: -5}substr4=${var1: -10:4}substr5=`expr substr "$var1" 5 10`> a hadoop y注意:使用expr,索引计数是从1开始计算;使用${string:position},索引计数是从0开始计数
执行脚本
var1="Hello World"len1=${#var1}len2=`expr length "$string"`echo "${len1} ${len2}"var2="quicstart is a app"ind=`expr index "$var2" start`echo "${ind}"var3="quicstart is a app"sub_len=`expr match "$var3" quic`echo "${sub_len}" > 4sub_len=`expr match "$var3" quic.*`echo "${sub_len}"> 18sub_len=`expr match "$var3" quicstart`echo "${sub_len}"> 9 var4="kafka hadoop yarn mapreduce"substr1=${var4:10}substr2=${var4:10:6}substr3=${var4: -5}substr4=${var4: -10:4}
命令替换
语法格式 | 注释 | |
---|---|---|
1 | `command` | 需要用``标志出这是一个命令替换 |
2 | $(command) |
命令替换总结:有两种方法:方法一:`command`方法二:$(command)例子1:获取系统得所有用户并输出 #!/bin/bash#index=1for user in `cat /etc/passwd | cut -d ":" -f 1`doecho "This is $index user: $user"index=$(($index + 1))done例子2:根据系统时间计算今年或明年echo "This is $(date +%Y) year"echo "This is $(($(date +%Y) + 1)) year"例子3:根据系统时间获取今年还剩下多少星期,已经过了多少星期date +%jecho "This year have passed $(date +%j) days"echo "This year have passed $(($(date +%j)/7)) weeks"echo "There is $((365 - $(date +%j))) days before new year"echo "There is $(((365 - $(date +%j))/7)) days before new year"例子4:判定nginx进程是否存在,若不存在则自动拉起该进程#!/bin/bash#nginx_process_num=$(ps -ef | grep nginx | grep -v grep | wc -l)if [ $nginx_process_num -eq 0 ];thensystemctl start nginxfi总结:``和$()两者是等价的,但推荐初学者使用$(),易于掌握;缺点是极少数UNIX可能不支持,但``都是支持的$(())主要用来进行整数运算,包括加减乘除,引用变量前面可以加$,也可以不加$$(( (100 + 30) / 13 ))num1=20;num2=30((num++));((num--))$(($num1+$num2*2))
变量声明
declare 和 typeset 命令
- declare 和 typeset 命令等价
- 定义变量类型
有类型变量总结:1、declare -r #声明变量为只读类型declare -r var="hello"var="world" -bash: var: readonly variable2、declare -i #声明变量类型为整型num1=2001num2=$num1+1echo $num2declare -i num2num2=$num1+1echo $num23、declare -f 在脚本中显示定义的函数和内容 4、declare -F 在脚本中显示定义的函数5、declare -aarray=("jones" "mike" "kobe" "jordan")输出数组内容: echo ${array[@]} 输出全部内容echo ${array[1]} 输出下标索引为1的内容获取数组长度: echo ${#array} 数组内元素个数echo ${#array[2]} 数组内下标索引为2的元素长度给数组某个下标赋值: array[0]="lily" 给数组下标索引为1的元素赋值为lilyarray[20]="hanmeimei" 在数组尾部添加一个新元素删除元素: unset array[2] 清除元素unset array 清空整个数组分片访问: ${array[@]:1:4} 显示数组下标索引从1开始到3的3个元素,不显示索引为4的元素内容替换: ${array[@]/an/AN} 将数组中所有元素内包含kobe的子串替换为mcgrady数组遍历:for v in ${array[@]}doecho $vdone6、declare -x声明为环境变量,可以在脚本中直接使用取消声明的变量:declare +rdeclare +ideclare +adeclare +X
bash 数学运算
expr
语法 | |
---|---|
1 | expr $num1 operator $num2 |
2 | result= ( ( (( ((num1 operator $num2)) |
相等推荐expr
常和命令替换搭配使用 包裹在``中
操作符列表
操作符 | 意义 |
---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ | 除法 |
% | 取模 |
= | 等于 |
!= | 不等于 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
: | 正则表达式匹配 |
|| | 逻辑或 |
&& | 逻辑与 |
( ) | 用于分组 |
bash数学运算之expr:num1=20num2=100expr $num1 \| $num2expr $num1 \& $num2expr $num1 \< $num2expr $num1 \< $num2expr $num1 \<= $num2expr $num1 \> $num2expr $num1 \>= $num2expr $num1 = $num2expr $num1 != $num2expr $num1 + $num2expr $num1 - $num2expr $num1 \* $num2expr $num1 / $num2expr $num1 % $num2练习例子:提示用户输入一个正整数num,然后计算1+2+3+...+num的值;必须对num是否为正整数做判断,不符合应当允许再此输入#!/bin/bash#while truedoread -p "Pls enter a positive integer(num>0): " numexpr $num + 1 &> /dev/nullif [ $? -ne 0 ];thenecho "Error,You must input a interger"continueelseif [ `expr $num \> 0` -ne 1 ];thenecho "Error,You must input a postive interger"continueelsesum=0for((i=0;i<=$num;i++))dosum=`expr $sum + $i`doneecho "1+2+3+4+5+...+$num=$sum"fifidone
bc
bash数学运算之bc:脚本中使用bc运算的语法:echo "options;expression" | bcnum1=23.5num2=50var1=`echo "scale=2;$num1 * $num2" | bc`
函数
linux shell的函数和大多数编程语言的函数一样——复用代码
函数定义和使用
函数定义和使用:函数定义的两种语法:第一种:name(){command1command2.....commandn}第二种:function name{command1command2.....commandn}函数使用:调用函数直接使用函数名即可,相当于一条命令,但不显示指定参数 * 函数内部直接使用参数$1 $2 ... $n* function $1 $2定义第一个函数:function hello ==> hello() { echo "xxxxxx"} hello{echo "Hello,Zhangsan"}hello定义第二个函数:function print_num{for((i=0;i<=10;i++))doecho -n "$i "done}定义第3个函数:需求描述:写一个监控nginx的脚本;如果Nginx服务宕掉,则该脚本可以检测到并将进程启动;如果正常运行,则不做任何处理#!/bin/bash#this_pid=$$function nginx_daemon{status=$(ps -ef | grep -v $this_pid | grep nginx | grep -v grep &> /dev/null)if [ $? -eq 1 ];thensystemctl start nginx && echo "Start Nginx Successful" || echo "Failed To Start Nginx"elseecho "Nginx is RUNNING Well"sleep 5fi}while truedonginx_daemondone可选:在终端命令行定义函数:在脚本中定义好disk_usage函数,然后直接使用. test.sh,再使用declare -F查看,是否可以列出disk_usage函数function disk_usage{if [ $# -eq 0 ];thendfelsecase $1 in-h)df -h;;-i)df -i;;-ih|-hi)df -ih;;-T)df -T;;*)echo "Usage: $0 { -h|-i|-ih|-T }";;esacfi}
向函数传递参数
调用函数的方式:
- int num =func(n1,n2);
- int num; num = func(n1,n2);
- func n1 n2
向函数传递参数:函数传参和给脚本传参类似,都是使用$1 $2 $3 $4 $5 $6 $7这种方式例子1:需求描述:写一个脚本,该脚本可以实现计算器的功能,可以进行+-*/四种计算。例如:sh calculate.sh 30 + 40 | sh calculate.sh 30 - 40 | sh calculate.sh 30 * 40实现:#!/bin/bash#function calculate{case "$2" in+)echo "$1 + $3 = $(expr $1 + $3)";;-)echo "$1 + $3 = $(expr $1 - $3)";;\*) echo "$1 * $3 = $(expr $1 \* $3)";;/)echo "$1 / $3 = $(expr $1 / $3)";;esac}calculate $1 $2 $3
函数返回值
两种返回值
- return
只能返回1-255的整数
函数使用return返回值,通常只是用来供其他地方调用获取状态,通常仅返回0或1;0:成功,1:失败 - echo
使用echo返回任何字符串结果
用于返回数据,比如一个字符串值或者列表值
函数返回值:使用return返回值:例子:测试nginx是否在运行 is_nginx_running.sh#!/bin/bash#this_pid=$$function is_nginx_running{ps -ef | grep nginx | grep -v $this_pid | grep -v grep > /dev/null 2>&1if [ $? -eq 0 ];then # 正常存在nginxreturn 0elsereturn 1fi}is_nginx_running && echo "Nginx is running" || echo "Nginx is stopped"使用echo返回值:例子1:两数字相加 add.sh#!/bin/bash#function add{echo "`expr $1 \+ $2`"}sum=`add $1 $2`echo "$1 + $2 = $sum"例子2:返回Linux上所有的不可登陆用户 unlogin.sh#!/bin/bash#function get_users{echo `cat /etc/passwd | awk -F: '/\/sbin\/nologin/{print $1}'`}index=1for user in `get_users`;doecho "The $index user is $user"index=$(expr $index + 1)done echoecho "System have $index users(do not login)"
局部变量和全局变量
- 全局变量
Shell脚本中,默认所有变量都是全局变量
即使函数内部定义的变量,一旦被调用后,改变了就将一直存在,直到脚本执行完毕 - 局部变量
定义局部变量,使用local关键字
函数内外若同时存在同名变量,函数内部变量覆盖外部变量 编程习惯原则:
1、尽量在函数内部使用local关键字,将变量的作用于限制在函数内部
2、命名变量名时尽可能遵循实义性的,尽量做到见名知意
例子1:#!/bin/bash#variable_1="Global Variable"function local_func{variable_2="Local Variable"}echo "variable_1=$variable_1"echo "variable_2=$variable_2"local_funcecho "variable_1=$variable_1"echo "variable_2=$variable_2"function test_local{echo "variable_2=$variable_2"}test_local
函数的递归调用
函数递归调用:经典案例:求数字阶乘,例如5!思路分析:5!= 5 * 4! = 5 * 4 * 3!= 5 * 4 * 3 * 2!= 5 * 4 * 3 * 2 * 1!= 5 * 4 * 3 * 2 * 1代码如下:#!/bin/bash#function factial{if [ $1 -eq 1 ];thenecho "1"return 0filocal temp=`expr $1 - 1`local pre=`factial $temp`result=`expr $1 \* $pre`echo $resultreturn 0}read -p 'Please input a number: ' NUMfactial $NUM
库函数
将常用的重复代码封装成函数文件
一般不直接执行,而是由其他脚本调用
- 一般使用.lib
- 库文件通常没有可执行选项
- 库文件无需和脚本在同级目录,只需要在脚本中引用时指定
- 第一行一般使用#!/bin/echo,输出警告信息,避免用户执行
> vim base_function#!/bin/echo Warning:This is a library which should not be executed,only be sourced in you scripts#function print_platform{local osname=`uname -s`PLATFORM=UNKNOWcase "$osname" in"FreeBSD")PLATFORM="FreeBSD";;"SunOS")PLATFORM="Solaris";;"Linux")PLATFORM="Linux";;esacreturn 0}function add{echo `expr $1 + $2` }function reduce{echo `expr $1 - $2`}function multiple{echo `expr $1 \* $2`}function divide{echo `expr $1 / $2`}function sys_load {echo "Memory Info"echofree -mechoecho "Disk Usage"echodf -hecho}
> vim cal.sh # 和 base_function 在同一级目录
#!/bin/bash
#
. base_function # 默认搜索路径 . 有指定路径
. /xx/xx/base_function # 使用绝对路径
add 12 23
reduce 90 30
sys_load
find命令
语法格式: find [路径] [选项] [操作]
选项 | 意义 |
---|---|
-name pattern | 按照文件名查找 区分大小写 |
-iname pattern | 按照文件名查找 不区分大小写 |
-type type | 按照文件类型查找 |
-size n[ckMG] | 按照文件大小查找 |
-mtime -n | +n | 按照文件修改时间查找 |
-user name | 按照文件属主查找 |
-group name | 按照文件所属组查找 |
-perm mode | 按照文件权限查找 |
-exec command {} ; | 对搜索到的文件执行特定命令 |
输出搜索到的文件名 | |
-depth | 按深度优先搜索 |
-maxdepth levels | 最大深度 最多搜索到n级子目录 |
-mindepth levels | 最小深度 从几级子目录开始搜索 |
-newer file | 查找比指定文件更新的文件 |
-not | 反转匹配条件 |
-or | 匹配条件之间的逻辑或 |
-and | 匹配条件之间的逻辑与 |
-regex pattern | 按照正则表达式匹配查找 |
-nogroup | 无效属组查找 |
-nouser | 无效属主查找 |
-newer f1 ! f2 | 查找更改时间比file1新但是比f2旧的文件 |
find命令总结:常用选项:-name 查找/etc目录下以conf结尾的文件 find /etc -name '*conf'-iname 查找当前目录下文件名为aa的文件,不区分大小写 find . -iname aa-user 查找文件属主为hdfs的所有文件 find . -user hdfs-group 查找文件属组为yarn的所有文件 find . -group yarn -type f 文件 find . -type f d 目录 find . -type dc 字符设备文件 find . -type cb 块设备文件 find . -type bl 链接文件 find . -type lp 管道文件 find . -type p-size-n 大小大于n的文件+n 大小小于n的文件n 大小等于n的文件 很少用例子1:查找/etc目录下小于10000字节的文件 find /etc -size -10000c例子2:查找/etc目录下大于1M的文件 find /etc -size +1M-mtime -n n天以内修改的文件+n n天以外修改的文件n 正好n天修改的文件例子1:查找/etc目录下5天之内修改且以conf结尾的文件 find /etc -mtime -5 -name '*.conf'例子2:查找/etc目录下10天之前修改且属主为root的文件 find /etc -mtime +10 -user root-mmin-n n分钟以内修改的文件+n n分钟以外修改的文件例子1:查找/etc目录下30分钟之前修改的文件 find /etc -mmin +30例子2:查找/etc目录下30分钟之内修改的目录 find /etc -mmin -30 -type d-mindepth n 表示从n级子目录开始搜索 过滤掉一些目录例子:在/etc下的3级子目录开始搜索 find /etc -mindepth 3 find /etc -mindepth 3 -type f-maxdepth n 表示最多搜索到n-1级子目录例子1:在/etc下搜索符合条件的文件,但最多搜索到2级子目录 find /etc -maxdepth 3 -name '*.conf'例子2:find ./etc/ -type f -name '*.conf' -size +10k -maxdepth 2了解选项:-nouser 查找没有属主的用户例子:find . -type f -nouser-nogroup 查找没有属组的用户例子:find . -type f -nogroup-perm 根据文件权限查找例子:find . -perm 664-prune 该选项可以排除某些查找目录搭配 -path 一起使用 [-path ./test -prune] 排除test 目录 -o 链接别的参数 显示指定或or通常和-path一起使用,用于将特定目录排除在搜索条件之外例子1:查找当前目录下所有普通文件,但排除test目录find . -path ./etc -prune -o -type f例子2:查找当前目录下所有普通文件,但排除etc和opt目录find . -path ./etc -prune -o -path ./opt -prune -o -type f例子3:查找当前目录下所有普通文件,但排除etc和opt目录,但属主为hdfsfind . -path ./etc -prune -o -path ./opt -prune -o -type f -a -user hdfs例子4:查找当前目录下所有普通文件,但排除etc和opt目录,但属主为hdfs,且文件大小必须大于500字节find . -path ./etc -prune -o -path ./opt -prune -o -type f -a -user hdfs -a -size +500c-newer file1 例子:find /etc -newer a操作:-prin 打印输出-exec 对搜索到的文件执行特定的操作,格式为-exec 'command' {} \;例子1:搜索/etc下的文件(非目录),文件名以conf结尾,且大于10k,然后将其删除find ./etc/ -type f -name '*.conf' -size +10k -exec rm -f {} \;例子2:将/var/log/目录下以log结尾的文件,且更改时间在7天以上的删除find /var/log/ -name '*.log' -mtime +7 -exec rm -rf {} \;例子3:搜索条件和例子1一样,只是不删除,而是将其复制到/root/conf目录下find ./etc/ -size +10k -type f -name '*.conf' -exec cp {} /root/conf/ \;-ok 和exec功能一样,只是每次操作都会给用户提示逻辑运算符:-a 与-o 或-not|! 非例子1:查找当前目录下,属主不是hdfs的所有文件 find . -not -user hdfs | find . ! -user hdfs例子2:查找当前目录下,属主属于hdfs,且大小大于300字节的文件find . -type f -a -user hdfs -a -size +300c例子3:查找当前目录下的属主为hdfs或者以conf结尾的普通文件find . -type f -a -user hdfs -o -name '*.conf'观察find . -type f -a -user hdfs -o -name '*.conf' -exec ls -rlt {} \;find . -type f -a \( -user hdfs -o -name '*.conf' \) -exec ls -rlt {} \;完整脚本练习:需求描述:提示用户输入一个目录,然后继续提示用户输入一个搜索文件的查询条件(文件名、文件大小),然后脚本可以将符合搜索条件的文件打印出来继续提示用户是拷贝或删除这些文件,如果删除,则执行删除操作,同时将删除的文件记录到一个remove.list文件中;如果是拷贝,则继续提示用户输入一个目标目录,然后执行拷贝动作
其他文件查找命令
locate
文件查找命令 所属软件包mlocate
不同于find命令是在整块磁盘中搜索,locate命令在数据库文件中查找
- 数据库文件定时更新 ——延迟查询到
- find 默认全部匹配,locate 是默认部分匹配
updatedb - 用户更新/var/lib/mlocate/mlocate.db
- 使用配置文件 /etc/updatedb.conf
- 该命令在后台cron计划任务中定期执行
updatedb # 用户更新/var/lib/mlocate/mlocate.db
locate file_name
whereis
选项 | 含义 |
---|---|
-b | 只返回二进制文件 |
-m | 只返回帮助文档文件 |
-s | 只返回源代码文件 |
whereis mysql
whereis -b mysql
which
仅查找二进制程序文件
-b 只返回二进制文件
which mysql
find 功能最强大 最慢; locate 快功能单一; which 查程序绝对路径; whereis 不常用
grep和egrep
过滤器
grep语法格式:
> grep [option] [pattern] [file1,file2…]
> command | grep [option] [pattern]
必须掌握的选项:-v 显示不匹配pattern的行-i 搜索时忽略大小写-n 显示行号-E 支持扩展的正则表达式-F 不支持正则表达式,按字符串的字面意思进行匹配-r 递归搜索需了解的选项:-c 只输出匹配行的数量,不显示具体内容-w 匹配整词 前后必须有空格-x 匹配整行-l 只列出匹配的文件名,不显示具体匹配行内容grep和egrep:grep默认不支持扩展正则表达式,只支持基础正则表达式使用grep -E可以支持扩展正则表达式使用egrep可以支持扩展正则表达式,与grep -E等价
grep -E "A|a" file
grep -F "py.*" file
grep -r like # 递归在当前文件查找like
sed
stream editor 流编辑器
对标准输出或文件进行处理
语法:
stdout | sed [option] “pattern command”
sed [option] “pattern command” file
**sed 的选项 **
选项 | 含义 |
---|---|
-n | 禁止自动输出模式空间内容 只打印匹配输出行 |
-e script | 在处理输入时将 script 应用到每一行 理解为and |
-f script-file | 在处理输入时将指定的脚本文件应用到每一行 |
-i | 直接修改文件内容,而不是输出到屏幕 |
-r | 启用扩展正则表达式 |
-s | 静默模式,不产生错误或诊断信息 |
-h | 不在输出中显示文件名 |
-V | 显示版本信息 |
sed 默认会打印一边原行信息
sed的内置命令
选项 | 含义 |
---|---|
a\ | 在匹配行后面追加一行文本 |
c\ | 用新文本替换匹配的行 |
d | 删除匹配的行 |
i\ | 在匹配行前面插入一行文本 |
p | 打印模式空间内容 |
s/regexp/replacement/ | 用 replacement 替换模式空间中第一个匹配的 regexp |
s/regexp/replacement/g | 用 replacement 替换模式空间中所有匹配的 regexp |
y/source-chars/dest-chars/ | 将模式空间中所有出现在 source-chars 中的字符替换成 dest-chars 中的对应字符 |
内置命令可以叠加组合 |
sed -n 'p' sed.txt
s/regexp 匹配模式或字符串/replacement 内置命令/
sed '/python/p' sed.txt # 匹配到python的打印
sed -n -e '/python/p' -e '/PYTHON/p' sed.txt> vim edit.sed
> /python/p
sed -n -f edit.sed sed.txt
sed -n '/python|PYTHON/p' sed.txt # 不行 默认不支持正则 -r 启用扩展
sed -n -r '/python|PYTHON/p' sed.txt
sed -n 's/love/like/g;p' sed.txt # 完整编辑命令 每行处理
sed -i 's/love/like/g;p' sed.txt
# 在原文件内替换修改 可以理解为 vim-i s-search g-global
sed 中的pattern
在sed命令中,pattern模式是用来匹配文本的正则表达式。pattern模式可以用来过滤、选取和修改文本中的内容。
在sed中,pattern模式可以使用基本正则表达式(BRE)或扩展正则表达式(ERE)语法,具体取决于是否使用了选项参数-r或-E。
常用的pattern模式示例:
^pattern:以pattern开头的行。
pattern$:以pattern结尾的行。
/pattern/:包含pattern的行。
!pattern:不包含pattern的行。
n,m:n到m行。
n~m:从第n行开始,每m行执行一次。
除了这些基本的pattern模式外,还可以使用正则表达式中的元字符和修饰符,例如.、*、+、?、[…]、{n,m}等。
匹配模式 | 含义 |
---|---|
10command | 匹配到第10行 |
10,20command | 匹配从第10行,到第20行结束 |
10,+5command | 匹配从第10行,到第15行结束 |
/pattern1/,/parttern2/command | //,//cmd 匹配到p1的行开始,到匹配到p2的行结束 |
10,/parttern1/command | num,//CMD 10行开始,到匹配到p1的行结束,没有匹配到会打到结尾 |
/parttern1/, 10command | //,numCMD 匹配到p1的行开始,到10行结束 |
/parttern1/command | //cmd 对所有行进行匹配 |
sed -n "17p" file # 打印文件到17行
sed -n "10,20p" file # 打印文件10到20行
sed -n "10,+5p" file # 打印文件10到15行
sed -n "/^root/p" file # 打印文件以root开头的行
sed -n "/\/sbin\/nologin/p" file # 匹配 /sbin/nologin 需要转意 //p 中'\/'
sed -n "/^hdfs/,/^yarn/p" /etc/passwd # 从hdfs匹配到yarn匹配结尾
sed中的编辑命令
混合匹配容易出错,不建议使用
| 类别 | 编辑命令 | 含义 |
| ---- | ---- | ---- |
| 查询 | p | 打印 |
| 增加 | a | 行后追加 |
| 增加 | i | 行前追加 |
| 增加 | r | 外部文件读入,行后追加 |
| 增加 | w | 匹配行导出到外部文件 |
| 删除 | d | 删除 |
| 修改 | s/old/new/ | 将行内第一个old替换为new |
| 修改 | s/old/new/g | 将行内全部old替换为new |
| 修改 | s/old/new/2g | 将行内从第2个到最后的old替换为new |
| 修改 | s/old/new/ig | 忽略大小写后,将行内全部old替换为new |
| 显示行号 | s/pattren/= | |
sed -i '1d' passwd # 删除第一行
sed -i '1,3d' passwd # 删除第一到第三行
sed -i '1d' passwd # 删除第一行
# sed -i '//d' file 根据匹配模式删除
sed -i '/\/sbin\/nologin/d' passwd
# sed -i '//a [append_string 有空格也不影响]' file 行后追加
sed -i '/\/bin\/bash/a appending string' passwd
# sed -i '/root/r list[当前路径下的list文件]' passwd
sed '/\/bin\/bash/w /tmp/user_login.txt' passwd# 替换 sed -i '///g' file
sed -i '/\/bin\/bash/\/BIN\/BASH/g' passwd
sed -i '/hadoop/HADOOP/ig' passwd
sed -i '/hadoop/=' passwd# 删除空行和注释行
sed -i '/^#/d;/^$/d' xx.conf
# 删除多个空格+# 的注释
sed - '/[:blank:]*#/d' xx.conf
# 在非#开头的行前添加*
sed -i 's/^[^#]/\*&/g' nginx.conf# 修改用法总结:1、1s/old/new/2、5,10s/old/new/3、10,+10s/old/new/# 将匹配到的行,在进行new替换old4、/pattern1/s/old/new/5、/pattern1/,/pattern2/s/old/new/6、/pattern1/,20s/old/new/7、15,/pattern1/s/old/new/
# 修改/etc/passwd中从匹配到以root开头的行,到匹配到行中包含mail的所有行。修改内为将这些所有匹配到的行中的bin改为HADOOP
# sed -i '//,//s/ / /g' /etc/passwd 从框架开始填充
sed -i '/^root/,/mail/s/bin/hadoop/g' /etc/passwd
# 删除数字
sed -i 's/[0-9]*//g' file.txt## 追加用法总结:1、a 在匹配行后面追加 2、i 在匹配行前面追加3、r 将文件内容追加到匹配行后面4、w 将匹配行写入指定文件
# 将passwd文件从第10行开始,到匹配到hdfs开头的所有行内容追加到/tmp/sed-1.txt
sed -i '10,/^hdfs/w /tmp/sed-1.txt' passwd
sed中的反向引用
在sed中,反向引用是指在替换命令中使用正则表达式捕获组中的内容,然后在替换文本中引用它们。
使用反向引用,可以将模式空间中的一个字符串替换为另一个字符串,并将其中一个字符串的一部分保留下来。
> vim str.txthadAAp is a bigdata frameSpark hadBBp KafkaSkill on hadCCpPaper Of hadDDpGoogle hadFFp# 将符合hadxxp的单词变为 hadxxps 此时不是简单的查找替换,而是在原基础上修改 引用
sed -i 's/had..p/&s/g' str.txt
# 此时的 & 指匹配到的单词 word
# &s 拼接s
> hadAAps is a bigdata frameSpark hadBBps KafkaSkill on hadCCpsPaper Of hadDDpsGoogle hadFFps# 反向引用符号 & 可以用 \1 替换 表示用匹配到的第几部分替换引用
# () 又需要用\(\) 转意
sed -i 's/\(had..ps\)/\1O/g' str.txt
> hadAApsO is a bigdata frameSpark hadBBpsO Kafka
# 只作部分替换
sed -i 's/\(had\)...../\1doop/g' str.txt
sed -i 's/l\(..e\)/L\1/g' str.txt # 将 lxxe 改为Lxxeold_str=hadoop
new_str=HADOOP
sed -i 's/'$old_str'/'$new_str'/g' str.txt
sed -i "s/$old_str/$new_str/g" str.txt
- 存在变量时用双引号
- 单引号内 ,自定义变量则也必须要使用单引号
- & 只能引用整个字符串
- \1 可以用()进行部分匹配到的字符串
统计配置文件段参数
#!/bin/bash
#FILE_NAME=my.cnffunction get_all_segments {echo "`sed -n '/\[.*\]/p' ${FILE_NAME} | sed -e 's/\[//g' -e 's/\]//g' `"
}function count_items_in_segment {# 过滤出[seg1] [seg2] 之间的数据,再grep 掉必须得 # 空白行 [seg]items=`sed -n '/\['$1'\]/,/\[.*\]/p' ${FILE_NAME} | grep -v "^#" | grep -v "^$" | grep -v "\[.*\]"`index=1for item in $itemsdoindex=`expr $index + 1`doneecho ${index}
}num=0
for seg in `get_all_segments`
do
num=`expr num + 1`item_count=`count_items_in_segment ${seg}`echo "${num}: ${seg} ${item_count}"
done
awk
awk 工作模式
可以做很复杂的编程,做很精细的结果控制
awk是一个文本处理工具,通常用于处理数据并生成结果报告
语法格式
awk ‘BEGIN{} pattern{commands} END{}’ file_name
standard output | awk ‘BEGIN{} pattern{commands} END{}’
- BEGIN: 类似于初始化, 正式数据处理之前执行
- pattern : 匹配模式
- {commands}: 处理命令,可能多行
- END: 处理完所有匹配数据后执行
awk的内置变量
变量名 | 意义 |
---|---|
$0 | 当前记录整行的文本内容。 |
$1 - $n | 当前记录的第一个到n字段的文本内容。 |
NF number field | 当前行的字段个数,有多少列;每行数据不一定列数相同 |
NR number row | 当前行的行号 从1开始计数,多文件累计计数 |
FNR file number row | 多文件处理时,每个文件的行号单独计数, 从0开始计数 |
FS field separator | 输入字段分隔符 不指定默认 空格或者tab |
RS row separator | 输入行分隔符 默认回车 |
OFS output field separator | 输出字段分隔符,默认 空格 |
ORS output row separator | 输出记录分隔符, 默认回车 |
FILENAME | 当前输入的文件名字 |
ARGC | 命令行参数个数 |
ARGV | 命令行参数数组 |
awk 'BEGIN{} patern {command} END{}'
# 输出每一行数据 省略:BEGIN patern END
awk '{print $0}' /etc/passwd
# 指定分隔符
awk 'BEGIN{FS=":"}{print $3}'/etc/passwd
# 打印每行字NR
awk '{print NF}' list
# 打印行号
awk '{print NR}' list1 list2
awk '{print FNR}' list1 list2
awk 'BEGIN{FS=":";RS="--";ORS="&";OFS=":"}{print $1,$3}'/etc/passwd
printf的格式说明符
格式符 | 含义 |
---|---|
%s | 字符串 |
%d | 十进制整数 |
%f | 浮点数 |
%c | 字符 ascii码 |
%e | 科学计数法 |
%g | 自动选择合适的计数法 |
%o | 八进制整数 |
%x | 十六进制整数(小写字母) |
%X | 十六进制整数(大写字母) |
%% | 百分号 |
- | 左对齐 |
+ | 右对齐 |
# | 显示8进制前面加0,16进制0x |
# 强制指定第一个字段占20个字符,不足补齐,默认右对齐
awk 'BEGIN{FS=":"}{printf "%20s %s\n",$1,$7}' /etc/passwd
# %-20s 左对齐
awk 'BEGIN{FS=":"}{printf "%20s %s\n",$1,$7}' /etc/passwd
awk 'BEGIN{FS=":"}{printf "%s\n",$7}' /etc/passwd
# 16进制加标志 # "%e\n" 科学计数法
awk 'BEGIN{FS=":"}{printf "%#x\n",$3}' /etc/passwd
awk的模式匹配
parren部分的语法
语法格式 | 含义 |
---|---|
RegExp | 按正则表达式匹配 |
关系运算 | 按关系运算匹配 |
关系运算: < > <= >= == ~ 匹配正则表达式 !~ 不符合正则表达式 != || && !
# 只要包含root的行
awk 'BEGIN{FS=":"}/root/{print $0}' /etc/passwd
# yarn 开头的
awk 'BEGIN{FS=":"}/^yarn/{print $0}' /etc/passwd
# uid < 50
awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd
# == "/bin/bash"
awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' /etc/passwd
# uid包含3个数字以上的 : ~ 匹配上 0-9 3次以上
awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/"/bin/bash"{print $0}' /etc/passwd
# 同时包含 hdfs 和yarn的
awk 'BEGIN{FS=":"}$1=="hdfs" ||$1=="yarn" {print $0}' /etc/passwd
# 3字段<50 4字段>50
awk 'BEGIN{FS=":"}$3<50 && $4>50{print $0}' /etc/passwd
# 3字段<50 并 是 /bin/bash 登录的 => 先填充 $7~// => $7~/ /bin/bash /
# 在转义 /bin/bash => \/bin\/bash/
awk 'BEGIN{FS=":"}$3>50 && $7~/\/bin\/bash/ {print $0}' /etc/passwd
awk动作中的表达式用法
动作部分action通常是由一个或多个表达式和操作符组成的:
变量和常量;算术运算符; 关系运算符;逻辑运算符;正则表达式; 函数调用;条件语句;
算术运算符: + - * / % ^或** 乘方 ++x x++
# 可以把BEGIN理解为awk 函数中的初始化代码块,会在遍历每行数据之前执行一次
awk 'BEGIN{var=20;var1="hello";print var,var1}'
awk 'BEGIN{num1=20;num2 +=num1;print num1,num2}'
awk 'BEGIN{num1=20;num2 =30;printf "%0.2f\n", num1/num2}' # 后置自增 i++ && 后置自减 i-- : 先将变量值传递出去,再修改变量值
# 前置自增 ++i && 前置自减 --i:首先修改变量的值,再将值传递出去
# x++ 是x先赋值,x再++
awk 'BEGIN{x=20;y=x++;print x,y}'
> 21 20
awk 'BEGIN{x=20;y=++x;print x,y}'
> 21 21
# 统计/etc/services的空白行
# 空白行 ^$
# 变量默认初始值为0
awk '/^$/{sum++}END{print sum}' /etc/services
> vim student.txtzhang,24,90,85,88,94wang,22,70,80,75,85li,31,80,90,60,55mike,22,70,80,75,85han,31,80,90,60,55
# 计算每个学生的平均分
awk 'BEGIN{FS=","}{total=$2+$3+$4+$5+$6;AVG=total/5;printf "%s,%d,%d,%d,%d,%d,%f\n",$1,$2,$3,$4,$5,$6,AVG}' student.txt
# 调整格式
awk 'BEGIN{FS=","}{total=$2+$3+$4+$5+$6;AVG=total/5;printf "%-8s%-5d%-5d%-5d%-5d%-8d%0.2f\n",$1,$2,$3,$4,$5,$6,AVG}' student.txt
# 加标题
awk 'BEGIN{FS=",";printf "%-8s%-8s%-8s%-8s%-8s%-8s%s\n","姓名","科1","科2","科3","科4","科5","平均分"}{total=$2+$3+$4+$5+$6;AVG=total/5;printf "%-8s%-8d%-8d%-8d%-8d%-8d%0.2f\n",$1,$2,$3,$4,$5,$6,AVG}' student.txt
在上面的基础上增加条件语句
借鉴了c语言语法风格
变量会自动初始化,无需专门定义
代码块用{ } 包裹;每一句语句之间 ; 分割 其他的和常规的语言语法相差不大
条件语句: if(条件表达式) 动作1 else if(条件表达式) 动作2 else 动作3
# uid <50
# 模式匹配
awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd
# 使用条件表达式,省略pattern 部分 过滤掉# 开头的行
awk 'BEGIN{FS=":"}/^[^#]/{if($3<50){printf "%-15s%-15s%-5d\n","小于50的uid",$1,$3}}' /etc/passwd
# 增加对小于100的逻辑
awk 'BEGIN{FS=":"}/^[^#]/{if($3<50){printf "%-15s%-15s%-5d\n","小于50的uid",$1,$3}else if($3<100){printf "%-15s%-15s%-5d\n","50~100的uid",$1,$3}}' /etc/passwd
> vim scripts.awk
BEGIN{FS=":"}
/^[^#]/{if($3<50){printf "%-30s%-30s%-5d\n","小于50的uid",$1,$3}else if($3<100){printf "%-30s%-30s%-5d\n","50~100的uid",$1,$3}else {printf "%-30s%-30s%-5d\n","大于100的uid",$1,$3}
}
awk -f scripts.awk /etc/passwd
循环语句 do-while
do while
do
动作
while(条件表达式)
循环语句 for
for(初始化计数器;测试计数器;计数器变更)
动作
# 计算1+2+3+4+...+100的和,用while、do while、 for 实现
> vim while.awk
BEGIN{while(i<=100){sum+=ii++}print sum
}
awk -f while.awk>vim do-while.awk
BEGIN{do{sum+=ii++}while(i<=100)print sum
}
awk -f do-while.awk> vim for.awk
BEGIN{for(i=0;i<=100;i++){sum+=i}print sum
}
awk -f for.awk
# 只打印平均分>=65的信息
> vim student.awk
BEGIN{FS=",";printf "%-8s%-8s%-8s%-8s%-8s%-8s%s\n","姓名","科1","科2","科3","科4","科5","平均分"
}
{total=$2+$3+$4+$5+$6;AVG=total/5;if(AVG>=65){printf "%-8s%-8d%-8d%-8d%-8d%-8d%0.2f\n",$1,$2,$3,$4,$5,$6,AVG}
}
awk -f student.awk student.txt
# 统计每个科目的平均分
> vim student_score.awk
BEGIN{FS=",";printf "%-8s%-8s%-8s%-8s%-8s%-8s%s\n","姓名","科1","科2","科3","科4","科5","平均分"
}
{total=$2+$3+$4+$5+$6;AVG=total/5;score_1 +=$2score_2 +=$3score_3 +=$4score_4 +=$5score_5 +=$6printf "%-8s%-8d%-8d%-8d%-8d%-8d%0.2f\n",$1,$2,$3,$4,$5,$6,AVG
}
END{printf "%-8s%-8s%-8s%-8s%-8s%-8s\n","科目总分",score_1,score_2,score_3,score_4,score_5printf "%-8s%-8s%-8s%-8s%-8s%-8s\n","科目平均分",score_1/NR,score_2/NR,score_3/NR,score_4/NR,score_5/NR
}
awk -f student_score.awk student.txt
awk中的字符串函数
内置的字符串函数意味着,在awk的语句中可以直接使用,无须额外定义function
awk字符串函数对照表:
函数名 | 解释 | 函数返回值 |
---|---|---|
length(string) | 字符串的长度 | |
index(str1, str2) | 在str1中查找str2的位置 | 返回str1中位置的索引计数,从1开始 |
substr(str, m, n) | 在ste的m个字符开始,截取n位 | 截取后的子字符串 |
split(string, arr, fs) | 将字符串按fs分隔,存放在数组arr中 | 分隔后的子字符串个数 arr数组下标从1开始 |
tolower(str) | 转为小写 | |
toupper(str) | 转为大写 | |
sub(regexp, RepStr, str) | 在str中搜索符合RE的字串,将其替换为RepStr,只替换第一个 | 被替换的字符串个数 1/0 |
gsub(regexp, RepStr, str) | 在str中搜索符合RE的字串,将其全部替换为RepStr | 被替换的字符串个数 0~N |
match(string, regexp) | 在字符串中按照RE查找,并返回匹配的位置 | 返回索引位置数组(位置和长度) |
# 返回每个字段的长度
> vim field.awk
BEGIN{FS=":"}
{i=1while(i<=NF){if(i==NF){printf "%d",length($i)}else{printf "%d:",length($i)}i++}printf "\n"
}
awk -f field.awk /etc/passwd
# 搜索’ea‘子串的位置
awk 'BEGIN{str="I have a dream";location=index(str,"ea");print location;}'
awk 'BEGIN{str="I have a dream";location=match(str,"ea");print location;}'
# 转大小写
awk 'BEGIN{str="I Have a Dream";print tolower(str);}'
awk 'BEGIN{str="I have a dream";print toupper(str);}'
# 分割字符并保存到array中 index 是乱序
awk 'BEGIN{str="Hadoop Kafka Spark Storm HDFS YARN Zookeeper";split(str,arr," ");for(idx in arr) print arr[idx];}'
# 第一个数字出现的位置 /[0-9]/ 标志这是一个正则匹配
awk 'BEGIN{str="Tranction 2345 Start";location=match(str,/[0-9]/);print location;}'
# 截取子串
awk 'BEGIN{str="Tranction 2345 Start";print substr(str,4,5);}'
# 将第一个匹配到的数字串替换为"$"
# /[0-9]+/ 匹配多个数字
awk 'BEGIN{str="Tranction 243 Start,Event ID:9002";sub(/[0-9]+/,"$",str);print str}
# 全部数字替换
awk 'BEGIN{str="Tranction 243 Start,Event ID:9002";gsub(/[0-9]+/,"$",str);print str}'
awk中的常用选项
选项 | 解释 |
---|---|
-v | 定义或引用变量 |
-f | 引入指定awk命令文件 |
-F | 指定列的分隔符 |
-V | 查看awk的版本号 |
awk并不能访问到环境变量或者自定义变量,需要用-v 引入
-F “:” 等价于 BEGIN{ FS=“:”}
> num1=100
> var="hello world"
awk 'BEGIN {print num1,var}' > 打印不出来
# -v 后 ${变量名} 能够获取到变量值; num1=xxx 则是定义一个awk上下文内的一个变量num1
awk -v num1=$num1 -v var=$var 'BEGIN {print num1,var}'
awk -F ":" '/root/{print $0}' /etc/passwd
awk中的数组用法
awk 的数组用法和array相差不大
在shell 中数组的用法:
array=("Allen" "Mike" "Messi" "Jerry" "Hanmeimei" "Wang")
# 打印元素:
echo ${array[2]}
# 打印元素个数: 可以把 # 理解为计算长度的符号 @理解为展开数组中的所有元素
echo ${#array[@]}
echo ${#str} # 字符串长度
# 打印元素的长度: 第三个元素 messi的长度
echo ${#array[3]}
# 给元素赋值:
array[3]="Li" => echo ${#array[3]} > 3
# 删除元素:
unset array[2]
# 删除数组
unset array
# 分片访问:下标从0开始 => 第1个元素开始取3个
echo ${array[@]:1:3}
# 只替换每个元素的第一个e;
${array[@]/e/E}
# 类比: 在sed 命令中 s/old/new/g 替换全部;s/old/new/ 只替换一个
# 每个元素的内容,替换所有的e
${array[@]//e/E}
# 数组的遍历:
for a in ${array[@]//e/E}
do
echo $a
done
awk的数组最重要的特点是:元素下标支持字符串,其实可以理解为兼容数组操作的Map
awk使用demo
模拟日常工作中的日志的处理
思路: 制造假数据log日志 ==> awk 统计计算出结果
vim insert.sh
#!/bin/bash
#function create_random()
{min=$1# 传入的随机数max=$(($2-$min+1))# 日期秒数+ 纳秒数的拼接:1681026501723177880num=$(date +%s%s)# 返回随机数 [函数的返回值两种类型:整数 或者 用echo拼接一个复杂的字符串返回]# $(()) 双括号内做数学计算 -> result=$(($num1 operator $num2))# 数值过大溢出 再次取模 排除负数情况echo $(( $(( $num % $max + $max )) % $max ))
}INDEX=1while [ $INDEX -le 2000 ]
do# 数组内容直接展开 arr=["allen" "mike" "jerry" "tracy" "han" "lilei"]for user in allen mike jerry tracy han lileido# shell内置随机数 echo ${RANDOM}COUNT=$RANDOMNUM1=`create_random 1 $COUNT`NUM2=`expr $COUNT - $NUM1` echo "`date '+%Y-%m-%d %H:%M:%S'` $INDEX Batches: user $user insert $COUNT records into database:product table:detail, insert $NUM1 records successfully,failed $NUM2 records" >> ./db.log.`date +%Y%m%d`INDEX=`expr $INDEX + 1`done
done
awk的计算样例
> vim log.awk
BEGIN{printf "%+10s%+10s%+10s%+10s\n","USER","TOTAL","SUCCESS","FAIL"
}
{ # 按名字统计TOTAL[$6]+=$8SUCCESS[$6]+=$14FAIL[$6]+=$17# 统计总数totalSum +=$8successSUm +=$14failedSum +=$17
}
END{for(u in TOTAL){printf "%+10s%+10s%+10s%+10s\n",u,TOTAL[u],SUCCESS[u],FAIL[u]}printf "%+10s%+10s%+10s%+10s\n","",totalSum,successSUm,failedSum
}
awk -f log.awk db.log.20230409
# 输出总数!=成功+失败的 手动改一些
awk '{if($8!=($14+$17))print NR,$0}' db.log.20230409
测试和判断
命令执行为0真,非0为假 => 判断行为称为测试
测试结构
test expression 或
[ 空格 expression 空格] => 以”[” 启动一个测试 ,执行expression ,再以”]”结束一个测试
必须严格的写空格
通常与 if case while 条件判断连用更方便
文件测试
test file_operator file/dir
[空格file_operator空格file/dir空格 ]
[空格 !空格 -e空格"$filename"空格 ]
文件测试符 file_operator
符号 | 说明 |
---|---|
-e | 文件存在 |
-f | 普通文件 |
-d | 目录 |
-h | 符号链接 |
-r | 可读 |
-w | 可写 |
-x | 可执行 |
-s | 文件大小不为0 |
-G | 文件属于当前用户组 |
-O | 文件属于当前用户 |
-nt | 新于某个文件 |
-ot | 旧于某个文件 |
-ef | 与某个文件指向相同的设备和节点号 |
test -e sed.txt
> 0
-e 是否存在
-s 文件是否为空
-nt f1 是否比 f2 新 newer than
-ot f1 是否比 f2 旧 older than
# 可以通过判断文件新旧来增量更新或备份文件# 判断文件权限脚本
> vim rwx.sh
#! /bin/bash
# 读入屏幕输入数据存储到变量filename中
read -p "input file test:" filename
if [ ! -e "$filename" ];thenecho "The file does not exit"exit 1
fi
if [ -r "$filename" ];thenecho "this is readable."
fiif [ -w "$filename" ];thenecho "this is writeable."
fiif [ -x "$filename" ];thenecho "this is executable."
fi
有错误的地方欢迎指出!!!
shell学习心得笔记系列一 文本处理三剑客相关推荐
- 深度学习入门笔记系列(三)——感知器模型和 tensorboard 的使用方法
本系列将分为 8 篇 .今天是第三篇 .主要讲讲感知器模型和 tensorboard 的基本使用方法 . 1. 感知器模型 因为小詹之前写过一篇感知器模型的介绍 ,这里就不赘述了 .有需要巩固的点击如 ...
- 深度学习入门笔记系列 ( 二 )——基于 tensorflow 的一些深度学习基础知识
本系列将分为 8 篇 .今天是第二篇 .主要讲讲 TensorFlow 框架的特点和此系列笔记中涉及到的入门概念 . 1.Tensor .Flow .Session .Graphs TensorFlo ...
- 2.7mnist手写数字识别之训练调试与优化精讲(百度架构师手把手带你零基础实践深度学习原版笔记系列)
2.7mnist手写数字识别之训练调试与优化精讲(百度架构师手把手带你零基础实践深度学习原版笔记系列) 目录 2.7mnist手写数字识别之训练调试与优化精讲(百度架构师手把手带你零基础实践深度学习原 ...
- 3.1 计算机视觉的发展和卷积神经网络概要(百度架构师手把手带你零基础实践深度学习原版笔记系列)
3.1 计算机视觉的发展和卷积神经网络(百度架构师手把手带你零基础实践深度学习原版笔记系列) 概要 计算机视觉作为一门让机器学会如何去"看"的科学学科,具体的说,就是让机器去识别摄 ...
- 深度学习入门笔记系列(一)——深度学习框架 tensorflow 的介绍与安装
本系列将分为 8 篇 .今天是第一篇 ,工欲善其事必先利其器 ,先简单讲讲当前的主流深度学习框架 TensorFlow 及其安装方法 . 我们知道 ,深度学习研究的热潮持续高涨 ,许多的开源深度学习框 ...
- shell学习整理笔记
1.shell脚本是一个以.sh问扩展名的文件. "#!"是一个约定的标记,是告诉系统需要什么解释器来执行,echo命令用于向窗口输出文本. 如: #!/bin/bash echo ...
- linux里shell的心得,Shell学习心得(一):变量
1.begin 1 #!/bin/bash 2 echo "hello world !" #! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 shell. ...
- 1.1机器学习和深度学习综述(百度架构师手把手带你零基础实践深度学习原版笔记系列)
人工智能.机器学习.深度学习的关系 近些年人工智能.机器学习和深度学习的概念十分火热,但很多从业者却很难说清它们之间的关系,外行人更是雾里看花.在研究深度学习之前,我们先从三个概念的正本清源开始. 概 ...
- js犀牛书,学习心得笔记(一)
最近每天都抽出时间看犀牛书,明显可以感觉到和以前看的时候有差别,阅读能力和心得有了很大的提升,以前不明白的一些知识点,还有一些隐藏在细节中的知识,现在都可以领悟到了. 1.包装对象 暂时性的包装对象 ...
最新文章
- 求助贴:人工智能offer,阿里or腾讯,选哪个?
- 面试官:说说什么是Java内存模型?
- extern C __declspec(dllexport) __declspec(dllimport) 和 def
- VC小技巧(三)视图
- kettle插入更新流程
- Hexo部署出现错误err-Error-Spawn-failed解决方式
- Android自定义View实战:影院在线选座
- 阿里云datav看板然后设置密码
- 社交鼻祖人人网被卖 曾意气风发比肩Facebook 一代人的回忆终结了
- 元图地图开放平台正式发布 --- 首款基于CAD图形的地图平台
- Setuptools(Python打包工具)
- 如何使用ContentProvider打造自己的本地图片库
- 日志异常检测-机器学习
- 转载——神经网络中mAP相关概念
- opencv之图像矩 image moments
- 自学MATLAB(四):特征值与特征向量
- 软件测试人还知道大名鼎鼎的compuware性能调优工具吗?该公司撤离中国!
- r软件自动化测试,App自动化测试工具Airtest
- 证券基金行业本地异地容灾备份查询一体化方案
- MYSQL 1045 - Access denied for user ‘root‘@‘localhost‘ (using password: YES)