Shell编程-高级部分

98 阅读4分钟

变量的替换和测试

语法说明
${变量名#匹配规则}从变量开头进行规则匹配,将符合最短的数据进行删除
${变量名##匹配规则}从变量开头进行规则匹配,将符合最长的数据进行删除
${变量名$匹配规则}从变量尾部进行规则匹配,将符合最短的数据进行删除
${变量名$$匹配规则}从变量尾部进行规则匹配,将符合最短的数据进行删除
${变量名/旧字符串/新字符串}变量内容符合旧字符串规则,则第一个旧字符串会被新字符串取代
${变量名//旧字符串/新字符串}变量内容符合旧字符串规则,则全部的旧字符串会被新字符串取代

例子1:

* 匹配前面任意字符 0次或多次 . 匹配任意字符1次

$variable="I love you,Do you love me"
$echo $variable
I love you,Do you love me
$var1=${variable#*ov}
$echo $var1
e you,Do you love me

$var2=${variable##*ov}
$echo $var2
e me

$var3=${variable%ov*}
$echo $var3
I love you,Do you l

$var4=${variable%%ov*}
$echo $var4
I l


$echo $PATH
/home/admin/apache-maven-3.8.5/bin:/opt/taobao/java/bin/:/home/admin/bin/obclient/bin:/opt/taobao/java/bin/:/home/admin/apache-maven-3.8.5/bin:/opt/taobao/java/bin/:/sbin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/usr/X11R6/bin:/home/admin/hadoop-current/bin/:/home/admin/hadoop-current:/home/admin/guxuan/apache-hive-1.2.1-bin/bin:/usr/local/git/bin:/usr/local/git/bin:/home/chenjitong.cjt/.local/bin:/home/chenjitong.cjt/bin:/usr/lib/oracle/11.2/client64/bin:/home/admin/hadoop3/hadoop-3.1.2/bin:/opt/taobao/java/bin:/bin:/opt/mssql-tools/bin:/home/admin/hadoop-current/bin/:/home/admin/hadoop-current:/home/admin/guxuan/apache-hive-1.2.1-bin/bin:/usr/local/git/bin

$var5=${PATH/bin/BIN}

$echo $var5
/home/admin/apache-maven-3.8.5/BIN:/opt/taobao/java/bin/:/home/admin/bin/obclient/bin:/opt/taobao/java/bin/:/home/admin/apache-maven-3.8.5/bin:/opt/taobao/java/bin/:/sbin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/usr/X11R6/bin:/home/admin/hadoop-current/bin/:/home/admin/hadoop-current:/home/admin/guxuan/apache-hive-1.2.1-bin/bin:/usr/local/git/bin:/usr/local/git/bin:/home/chenjitong.cjt/.local/bin:/home/chenjitong.cjt/bin:/usr/lib/oracle/11.2/client64/bin:/home/admin/hadoop3/hadoop-3.1.2/bin:/opt/taobao/java/bin:/bin:/opt/mssql-tools/bin:/home/admin/hadoop-current/bin/:/home/admin/hadoop-current:/home/admin/guxuan/apache-hive-1.2.1-bin/bin:/usr/local/git/bin


$var6=${PATH//bin/BIN}
$echo $var6
/home/admin/apache-maven-3.8.5/BIN:/opt/taobao/java/BIN/:/home/admin/BIN/obclient/BIN:/opt/taobao/java/BIN/:/home/admin/apache-maven-3.8.5/BIN:/opt/taobao/java/BIN/:/sBIN:/usr/local/BIN:/usr/BIN:/usr/local/sBIN:/usr/sBIN:/usr/X11R6/BIN:/home/admin/hadoop-current/BIN/:/home/admin/hadoop-current:/home/admin/guxuan/apache-hive-1.2.1-BIN/BIN:/usr/local/git/BIN:/usr/local/git/BIN:/home/chenjitong.cjt/.local/BIN:/home/chenjitong.cjt/BIN:/usr/lib/oracle/11.2/client64/BIN:/home/admin/hadoop3/hadoop-3.1.2/BIN:/opt/taobao/java/BIN:/BIN:/opt/mssql-tools/BIN:/home/admin/hadoop-current/BIN/:/home/admin/hadoop-current:/home/admin/guxuan/apache-hive-1.2.1-BIN/BIN:/usr/local/git/BIN

字符串处理

获取字符串长度

语法说明
方法一${#string}
方法二expr length "${string}"string有空格,则必须加双引号

例子

$var1="Hello World"
$len=${#var1}
$echo $len
11

len=`expr length "${var1}"`
$echo $len
11

获取子串在字符串中的索引位置

语法说明
expr index "${string}" "${substring}"
$var1="quickstart is a app"
$ind=`expr index "${var1}" "start"`
$echo $ind
6

$var1="quickstart is a app"
$ind=`expr index "${var1}" "kc"`
$echo $ind
4

抽取子串

语法说明
方法一${string:position}从string中的position开始
方法二${string:position:length}从position开始,匹配长度为length
方法三expr substr "${string}" $position $length从position开始,匹配长度为length

例子

$var1="kafka hadoop yarn zookeeper"
$substr=${var1:10}
$echo ${substr}
op yarn zookeeper

$sub_str=${var1:10:5}
$echo $sub_str
op ya

$sub_str=`expr substr "${var1}" 10 5`
$echo $sub_str
oop y

注意expr索引是从1开始计数的

变量以及字符串部分简单测试

需求描述
变量 string="Bigdata process framework is Hadoop,Hadoop is an open source project", 执行脚本后,打印输出string字符串变量,并给用户以下选项:

(1)、打印string长度

(2)、删除字符串中的所有 Hadoop

(3)、替换第一个Hadoop为Mapreduce

(4)、替换全部Hadoop为Mapreduce

用户输入数字1|2|3|4, 可以执行对应项的功能,输入 q|Q则退出应用


#!/bin/bash
string="Bigdata process framework is Hadoop,Hadoop is an open source project"


function print_tips {
 echo "***********************"
 echo "(1) 打印string长度"
 echo "(2) 删除字符串中的所有 Hadoop"
 echo "(3) 替换第一个Hadoop为Mapreduce"
 echo "(4) 替换全部Hadoop为Mapreduce"
 echo "***********************"
}

function len_of_string {
 len=${#string}
 echo $len
}

function del_hadoop {
  str_del_hadoop=${string//Hadoop/}
  echo $str_del_hadoop
}

function rep_hadoop_mapreduce {
 echo "${string/Hadoop/Mapreduce}"
}

function rep_hadoop_mapreduce_all {
 echo "${string//Hadoop/Mapreduce}"
}


while true
do
   echo "[string=${string}]"
   echo
   print_tips
   read -p "Pls input your choice (1|2|3|4|q|Q): " choice
   case $choice in
   1)
       len_of_string;;
   2)
       del_hadoop;;
   3)
       rep_hadoop_mapreduce;;
   4)
       rep_hadoop_mapreduce_all;;
   q|Q)
         exit ;;
 esac
done

参考内容:www.runoob.com/linux/linux…

命令替换

方法一 : 反单引号 `` command
方法二 : 圆括号 $(command)

例子一
获取系统的所有用户并输出

$cat /etc/passwd |  cut -d ":" -f 1
-d 以什么切分, -f 配合 -d 一起使用,取第几个 field字段

cat /etc/passwd | awk -F ":"  '{print $1}'

输出

root
bin
daemon
adm

如果想遍历,脚本如下

#!/bin/bash
#****************************************************************#
# ScriptName: getLinuxUser
# Author: $xiaochen
# Create Date: 2023-07-23 15:35
# Modify Date: 2023-07-23 15:35
# Function:
#***************************************************************#
index=1
for user in `cat /etc/passwd | cut -d ":" -f 1`
do
	echo "This is the ${index} user: ${user}"
  # 两个()是运算
	index=$((${index}+1))
done

例子二

根据系统时间计算明年

#!/bin/sh
#****************************************************************#
# ScriptName: cal this year and next year
# Create Date: 2023-07-23 15:46
# Modify Date: 2023-07-23 15:46
# Function:
#***************************************************************#
echo "This is `date +%Y`  year, the next year is $(($(date +%Y) + 1)) year"

This is 2023  year, the next year is 2024 year

例子三

根据系统时间获取今年还剩多少星期,已经过去了多少星期

#!/bin/sh
#****************************************************************#
# ScriptName: cal date
# Create Date: 2023-07-23 16:20
# Modify Date: 2023-07-23 16:20
# Function:
#***************************************************************#
echo "This year has passed $(date +%j) days"
echo "This year has passed $(($(date +%j)/7)) weeks"
echo "This year has $((365-$(date +%j))) days left"
echo "This year has $(((365-$(date +%j))/7)) weeks left"


This year has passed 204 days
This year has passed 29 weeks
This year has 161 days left
This year has 23 weeks left

例子四

编写 nginx 保活脚本

#!/bin/sh
#****************************************************************#
# ScriptName: nginx_keepalive.sh
# Create Date: 2023-07-23 16:32
# Modify Date: 2023-07-23 16:32
# Function:
#***************************************************************#
nginx_process_num=$(ps -ef | grep nginx | grep -v nginx | wc -l)

if [ ${nginx_process_num} -eq 0 ]; then
	systemctl start nginx
fi

总结:`` 和 $() 都是等价的,但是初学者推荐使用$(), 易于掌握

$(()) 主要用来做整数运算,包括加减乘除

有类型变量

declare 命令参数表

参数含义
-r将变量设为只读
-i将变量设为整数
-a将变量设为数组
-f显示此脚本前定义过的所有函数及内容
-F仅显示此脚本前定义过的函数名
-x将变量声明为环境变量

例子

$declare -r var="hello world"
$var="hello1"
bash: var: readonly variable


$num1=10
$num2=${num1}+20
$echo $num2
10+20


declare -i num3=10
$num3=$num1+20
$echo $num3
30



$declare -a array
$array=("jones" "mike" "kobe" "jordan")

输出数组内容
echo ${array[@]}  输出全部内容
echo ${array[1]}  输出下标索引为1的内容

$echo ${array[@]}
jones mike kobe jordan

$echo ${array[1]}
mike

获取数组长度

$echo ${#array[@]}
4

$echo ${#array[2]}
4

给数组某个下标赋值

array[0]="lily"   给数组下标索引为1的元素赋值为lily
array[20]="hanmeimei"  在数组尾部添加一个新元素


$echo ${array[@]}
lily mike kobe jordan hanmeimei

$echo ${array[20]}
hanmeimei


删除元素

unset array[2] 清除元素
unset array 清空整个数组

分片访问

${array[@]:1:4}

$echo ${array[@]:1:4}
mike jordan hanmeimei


内容替换

${array[@]/an/AN} 将数组中所有元素内含有 an的字符串替换成AN

echo ${array[@]/an/AN}
lily mike jordAN hANmeimei


数组遍历

for v in ${array[@]}
do 
    echo ${v}
done


declare -x 
 声明为环境变量,可以在脚本中直接使用
 
 
 取消声明变量
 
 declare +x 
 +a 
 +i 
 +r

Bash数学运算之expr (只支持整数)

语法
方法一expr $num1 operator $num2
方法二$(($num1 operator $num2))

expr 操作符对照表 (上)

操作符含义
num1或(竖线)num2num1不为空且非0,返回num1;否则返回num2
num1&num2num1不为空且非0,返回num1;否则返回num2
num1<num2num1小于num2,返回1,否则返回0
num1<=num2num1小于等于num2,返回1,否则返回0
num1=num2num1等于num2,返回1,否则返回0
num1!=num2num1不等于num2,返回1,否则返回0
num1>num2num1大于num2,返回1,否则返回0
num1>=num2num1大于等于num2,返回1,否则返回0

注意上述符号在linux都是保留字,需要加\转义使用

$num1=30
$num2=50

$expr $num1 \> $num2
0

$expr $num1 \< $num2
1
$expr $num1 \& $num2
30

$expr $num1 \| $num2
30

$expr $num1 \% $num2
30

$expr $num1 + $num2
80

$num3=$(($num1+$num2))
$echo $num3
80

例子:

输入一个整数 num, 校验是否为大于1的正整数,并且求 1+2+3+....+num 的和


#!/bin/bash
#****************************************************************#
# ScriptName: sum.sh
# Create Date: 2023-07-23 18:44
# Modify Date: 2023-07-23 18:44
# Function:
#***************************************************************#
read -p "Pls input a postive number: " num

expr $num + 1 &> /dev/null
if [ $? -eq 0 ]; then
 if [ `expr $num \> 0` -eq 1 ]; then
	 echo "Yes,positive number"
	 for((i=1;i<=$num;i++))
	 do
		 sum=`expr $sum + $i`
	 done
	 echo "1+2+3+...+$num = $sum"
 else
	 echo "error,input number is $num"
	 exit
 fi
fi

bc (浮点类型计算)


$echo "23+38" | bc
61

$echo "scale=4;23/4" | bc
5.7500

例子

#!/bin/sh
#****************************************************************#
# ScriptName: bc.sh
# Create Date: 2023-07-23 19:33
# Modify Date: 2023-07-23 19:33
# Function:
#***************************************************************#
read -p "num1: " num1
read -p "num2: " num2

echo "scale=4;$num1*$num2" | bc

结果
$sh bc.sh
num1: 1.2
num2: 2.4
2.88

函数定义和使用

语法格式

格式
第一种格式name() {command1,command2.....commandn}
第二种格式function name {command1,command2.....commandn}

如何调用函数

  • 直接使用函数名调用,可以想象成Shell中的一条命令
  • 函数内部可以直接使用参数 11、2....$n
#!/bin/bash
#****************************************************************#
# ScriptName: nginx_daemon.sh
# Create Date: 2023-07-23 19:50
# Modify Date: 2023-07-23 19:50
# Function:
#***************************************************************#
#获取当前保活脚本pid,过滤的时候可以过滤掉
this_pid=$$
ps -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/null
if [ $? -eq 0 ]; then
	echo "nginx is running well"
else
	echo "nginx is down, Start it ..."
    systemctl start nginx
fi
home_dir=`echo $0 |/usr/bin/xargs /usr/bin/dirname`
[ ${home_dir} == "." ] && home_dir=`/bin/pwd`
如果`home_dir`的值为`.`,则将`home_dir`的值设为当前工作目录的绝对路径。