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=exprvar=“”var=$str
var=${str:-expr}var=exprvar=exprvar=$str
var=${str+expr}var=var=exprvar=expr
var=${str:+expr}var=var=“”var=expr
var=${str=expr}var=exprvar=“”var=$str
var=${str:=expr}var=exprvar=exprvar=$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)}从左开始匹配
方法5expr 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`
		  > 4
				
	4、抽取字符串中的子串
			
			方法一: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}" 
      > 4
      sub_len=`expr match "$var3" quic.*`
      echo "${sub_len}"
      > 18
      sub_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=1
			
			for user in `cat /etc/passwd | cut -d ":" -f 1`
			do
				echo "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 +%j
			echo "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 ];then
					systemctl start nginx
			fi
			
	总结:``$()两者是等价的,但推荐初学者使用$(),易于掌握;缺点是极少数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 variable
			
		2、declare -i	#声明变量类型为整型
		
			num1=2001
			num2=$num1+1
			echo $num2
			
			declare -i num2
			num2=$num1+1
			echo $num2
		
		3、declare -f		在脚本中显示定义的函数和内容		
		4、declare -F		在脚本中显示定义的函数
		5、declare -a
		
			array=("jones" "mike" "kobe" "jordan")
			
			输出数组内容:											
			
						echo ${array[@]}	输出全部内容
						echo ${array[1]}	输出下标索引为1的内容
			
			获取数组长度:											
						
						echo ${#array}		数组内元素个数
						echo ${#array[2]}	数组内下标索引为2的元素长度
						
			给数组某个下标赋值:									
			
						array[0]="lily"				给数组下标索引为1的元素赋值为lily
						array[20]="hanmeimei"		在数组尾部添加一个新元素
						
			删除元素:												
			
						unset array[2]		清除元素
						unset array			清空整个数组
						
			分片访问:												
			
						${array[@]:1:4}		显示数组下标索引从1开始到3的3个元素,不显示索引为4的元素
						
			内容替换:												
			
						${array[@]/an/AN}	将数组中所有元素内包含kobe的子串替换为mcgrady
						
			数组遍历:
					for v in ${array[@]}
					do
							echo $v
					done
														
		
		6、declare -x
		
			声明为环境变量,可以在脚本中直接使用
		
	取消声明的变量:
	
		declare +r
		declare +i
		declare +a
		declare +X

bash 数学运算

expr

语法
1expr $num1 operator $num2
2result= ( ( (( ((num1 operator $num2))

相等推荐expr

常和命令替换搭配使用 包裹在``中

操作符列表

操作符意义
+加法
-减法
*乘法
/除法
%取模
=等于
!=不等于
>大于
>=大于等于
<小于
<=小于等于
:正则表达式匹配
||逻辑或
&&逻辑与
( )用于分组
	bash数学运算之expr:
		num1=20
		num2=100
		
		expr $num1 \| $num2
		expr $num1 \& $num2
		expr $num1 \< $num2
		expr $num1 \< $num2
		expr $num1 \<= $num2
		expr $num1 \> $num2
		expr $num1 \>= $num2
		expr $num1 = $num2
		expr $num1 != $num2
		expr $num1 + $num2
		expr $num1 - $num2
		expr $num1 \* $num2
		expr $num1 / $num2
		expr $num1 % $num2
		
		
		练习例子:
		
			提示用户输入一个正整数num,然后计算1+2+3+...+num的值;必须对num是否为正整数做判断,不符合应当允许再此输入
			
			#!/bin/bash
			#

			while true
			do
				read -p "Pls enter a positive integer(num>0): " num

				expr $num + 1 &> /dev/null
				if [ $? -ne 0 ];then
					echo "Error,You must input a interger"
					continue
				else
					if [ `expr $num \> 0` -ne 1 ];then
						echo "Error,You must input a postive interger"
						continue
					else
						sum=0
						for((i=0;i<=$num;i++))
						do
							sum=`expr $sum + $i`
						done
						echo "1+2+3+4+5+...+$num=$sum"
					fi
				fi
			done
			

bc

	bash数学运算之bc:
	
		脚本中使用bc运算的语法:
			echo "options;expression" | bc
			
			num1=23.5
			num2=50
			
			var1=`echo "scale=2;$num1 * $num2" | bc`

函数

linux shell的函数和大多数编程语言的函数一样——复用代码

函数定义和使用

	函数定义和使用:
		函数定义的两种语法:
			第一种:
					name()
					{
						command1
						command2
						.....
						commandn
					}
					
			第二种:
					function name
					{
						command1
						command2
						.....
						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++))
				do
					echo -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 ];then
					systemctl start nginx && echo "Start Nginx Successful" || echo "Failed To Start Nginx"
				else
					echo "Nginx is RUNNING Well"
					sleep 5
				fi
			}

			while true
			do
				nginx_daemon
			done

		可选:在终端命令行定义函数:
		
			在脚本中定义好disk_usage函数,然后直接使用. test.sh,再使用declare -F查看,是否可以列出disk_usage函数
			
			function disk_usage
			{
				if [ $# -eq 0 ];then
					df
				else
					case $1 in
						-h)
							df -h
							;;
						-i)
							df -i
							;;
						-ih|-hi)
							df -ih
							;;
						-T)
							df -T
							;;
						*)
							echo "Usage: $0 { -h|-i|-ih|-T }"
							;;
					esac
				fi
			}		

向函数传递参数

调用函数的方式:

  • 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>&1
				if [ $? -eq 0 ];then # 正常存在nginx
					return 0
				else
					return 1
				fi
			}

			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=1
			for user in `get_users`;do
				echo "The $index user is $user"
				index=$(expr $index + 1)
			done	

			echo
			echo "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_func

			echo "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 ];then
					echo "1"
					return 0
				fi

				local temp=`expr $1 - 1`
				local pre=`factial $temp`

				result=`expr $1 \* $pre`

				echo $result
				return 0
			}

			read -p 'Please input a number: ' NUM

			factial $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=UNKNOW

				case "$osname" in
					"FreeBSD")
						PLATFORM="FreeBSD"
						;;
					"SunOS")
						PLATFORM="Solaris"
						;;
					"Linux")
						PLATFORM="Linux"
						;;
				esac
				return 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"
          echo
          free -m
          echo

          echo "Disk Usage"
          echo
          df -h
          echo
      }
> 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 {} ;对搜索到的文件执行特定命令
-print输出搜索到的文件名
-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 d
				c		字符设备文件		find . -type c
				b		块设备文件			find . -type b
				l		链接文件			find . -type l
				p		管道文件			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目录,但属主为hdfs
					find . -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/commandnum,//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替换old
			4、/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.txt
	hadAAp is a bigdata frame
  Spark hadBBp Kafka
  Skill on hadCCp
  Paper Of hadDDp
  Google hadFFp

# 将符合hadxxp的单词变为 hadxxps 此时不是简单的查找替换,而是在原基础上修改 引用
sed -i 's/had..p/&s/g' str.txt
# 此时的 & 指匹配到的单词 word 
# &s 拼接s
> hadAAps is a bigdata frame
  Spark hadBBps Kafka
  Skill on hadCCps
  Paper Of hadDDps
  Google hadFFps
  
# 反向引用符号 & 可以用 \1 替换 表示用匹配到的第几部分替换引用 
# () 又需要用\(\) 转意
sed -i 's/\(had..ps\)/\1O/g' str.txt
> hadAApsO is a bigdata frame
  Spark hadBBpsO Kafka
# 只作部分替换 
sed -i 's/\(had\)...../\1doop/g' str.txt
sed -i 's/l\(..e\)/L\1/g' str.txt # 将 lxxe 改为Lxxe

old_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.cnf

function 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=1
  for item in $items
  do
    index=`expr $index + 1`
  done
  echo ${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.txt
    zhang,24,90,85,88,94
    wang,22,70,80,75,85
    li,31,80,90,60,55
    mike,22,70,80,75,85
    han,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+=i
    i++
  }
  print sum
}
awk -f while.awk

>vim do-while.awk
BEGIN{
  do{
    sum+=i
    i++
  }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 +=$2
  score_2 +=$3
  score_3 +=$4
  score_4 +=$5
  score_5 +=$6
  printf "%-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_5
  printf "%-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=1
  while(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))
	# 日期秒数+ 纳秒数的拼接:1681026501723177880
	num=$(date +%s%s)
	# 返回随机数 [函数的返回值两种类型:整数 或者 用echo拼接一个复杂的字符串返回]
	# $(()) 双括号内做数学计算 -> result=$(($num1 operator $num2))
	# 数值过大溢出 再次取模 排除负数情况
	echo $(( $(( $num % $max + $max )) % $max ))
}

INDEX=1

while [ $INDEX -le 2000 ]
do
	# 数组内容直接展开 arr=["allen" "mike" "jerry" "tracy" "han" "lilei"]
	for user in allen mike jerry tracy han lilei
	do
		# shell内置随机数 echo ${RANDOM}
		COUNT=$RANDOM
		NUM1=`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]+=$8
  SUCCESS[$6]+=$14
  FAIL[$6]+=$17
  # 统计总数
  totalSum +=$8
  successSUm +=$14
  failedSum +=$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" ];then
	echo "The file does not exit"
	exit 1
fi
if [ -r "$filename" ];then
	echo "this is readable."
fi

if [ -w "$filename" ];then
	echo "this is writeable."
fi

if [ -x "$filename" ];then
	echo "this is executable."
fi

有错误的地方欢迎指出!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值