ShellScript脚本编程
语法基础
脚本结构
我们先从这个小demo程序来窥探一下我们shell脚本
的程序结构
#!/bin/bash# 注释信息echo_str="hello world"test(){echo $echo_str
}test echo_str
首先我们可以通过文本编辑器(在这里我们使用linux自带文本编辑神器vim),新建一个文件demo.sh
,文件扩展名sh
代表shell
,表明该文件是一个shell脚本文件
,并不影响脚本的执行,然后将上述代码片段写入文件中,保存退出
然后使用bash -n demo.sh
命令可以检测刚才脚本文件的语法是否错误,如果没有回显结果就代表脚本文件没有语法错误
- 脚本都以
#!/bin/bash
开头,#
称为sharp
,!
在unix行话里称为bang
,合起来简称就是常见的shabang
。#!/bin/bash
指定了shell脚本解释器bash的路径,即使用bash
程序作为该脚本文件的解释器,当然也可以使用其它的解释器/bin/sh
等,根据具体环境进行相应选择 echo_str
是字符串变量,通过$
进行引用变量的值,test
是自定义函数名,通过函数名 传入参数
格式进行函数的调用echo
是shell命令,相对于python中的print
#
字符用来注释shell脚本的
最后可以使用下列两种方式执行上述脚本
-
将脚本作为bash解释器的参数执行:此时首行的
#!/bin/bash
可以不用写bash demo.sh
:直接将脚本文件作为bash命令的参数bash -x demo.sh
:使用-x
参数可以查看脚本的详细执行过程
-
将脚本作为独立的可执行文件执行:此时首行的
#!/bin/bash
必须写,用来指定shell解释器路径;同时脚本必须可执行权限chmod +x demo.sh
:给脚本添加执行权限./demo.sh
:执行脚本文件,在这里需要使用./demo.sh
表明当前目录下脚本,因为PATH
环境变量中没有当前目录,写成demo.sh
系统会去/sbin、/sbin
等目录下查找该脚本,无法找到该脚本文件执行,造成报错
数据结构
数据类型的本质:固定内存大小的别名
据类型的作用:
- 确定对应变量分配的内存大小
- 确定对应变量所能支持的运算或操作
shell脚本是弱类型解释型的语言,在脚本运行时由解释器进行解释变量在什么时候是什么数据类型
在bash中,变量默认都是字符串类型,都是以字符串方式存储,所以在本章主要是介绍各数据类型变量所支持的运算或操作
虽说变量默认都是字符串类型,但是按照其使用场景可将数据类型分为以下几种类型:
- 数值型
- 字符串型
- 数组型
- 列表型
数值型
首先我们来声明定义一个数值型变量:declare -i Var_Name
- 虽说声明是一个数值型变量,但是存储依然是按照字符串的形式进行存储
- 该种方式声明,变量默认是本地全局变量,可以通过
local Var_Name
关键字将变量修改为局部变量,可以通过export Var_Name
关键字将变量导出为环境变量 - 除了使用
declare -i
显式声明变量数据类型为数值型,还可以像Var_Name=1
由解释器动态执行隐式声明该变量数据类型为数值型
数值型变量一般支持以下运算操作
- 算术运算
- 比较运算
- 数组索引
算术运算
算数运算代码示例如下
#!/bin/bashdeclare -i val=5 # 显式声明数值变量
num=2 # 隐式声明数值变量# 使用[]运算符执行算术表达式$val+$num
# 使用$引用表达式执行结果
echo "val+num=$[$val+$num]"
echo "val++: $[val++]" # 这里不需要加$,不是引用变量的值,而是修改变量的值
echo "val--: $[val--]" # 这里不需要加$,不是引用变量的值,而是修改变量的值
echo "++val: $[++val]" # 这里不需要加$,不是引用变量的值,而是修改变量的值
echo "--val: $[--val]" # 这里不需要加$,不是引用变量的值,而是修改变量的值# 使用(())运算符执行算术表达式
# 使用$引用表达式执行结果
echo "val-num=$(($val-$num))"
echo "val%num=$(($val%$num))"# 使用let关键字执行算术表达式$val*$num
# 使用=运算符将执行结果赋值给变量
let ret=$val*$num
echo "var*num=$ret"# 使用expr命令执行算术表达式$val/$num但是$val / $num之间需要用空格隔开
# 此时该表达式中的各个部分将作为参数传递给expr命令,最后使用``运算符引用命令的执行结果
# 使用=运算符将命令引用结果赋值给变量
ret=`expr $val / $num`
echo "val/num=$ret"# 使用let关键字执行算术表达式+=、-=、*=、/=、%=
let val+=$num
echo "var+=num:$val"
let val-=$num
echo "var-=num:$val"
let val*=$num
echo "val*=num:$val"
let val/=$sum # 貌似let不支持/=运算符
echo "val/=num:$val"
let val%=$num
echo "val%=num:$val"
运行结果为:
val+num=7
val++: 5
val--: 6
++val: 6
--val: 5
val-num=3
val%num=1
var*num=10
val/num=2
var+=num:7
var-=num:5
val*=num:10
test.sh: line 37: let: val/=: syntax error: operand expected (error token is "/=")
val/=num:10
val%=num:0
let
关键字用于执行算术运算。它主要用于对变量进行数学计算,并且可以在表达式中直接对变量进行操作,而不需要使用 $
符号来引用变量值。
作用
-
执行算术运算:
let
可以对变量进行加、减、乘、除等基本运算。 -
更新变量值:
let
会根据运算结果更新变量的值。 -
支持复合运算符:
let
支持如+=
、-=
、*=
、/=
等复合运算符
比较运算
比较运算有以下几种类型
- 用于条件测试
- 用于for循环
用于条件测试的示例代码如下
#!/bin/bashdeclare -i val=5 # 显式声明数值变量
num=2 # 隐式声明数值变量# -eq:判断val变量的值是否等于5
# []运算符用来执行条件测试表达式,其执行结果要么为真,要么为假
# []运算符和条件测试表达式之间前后有空格
if [ $val -eq 5 ]; thenecho "the value of val variable is 5"
fi# -ne:判断num变量的值是否不等于5
# [[]]运算符用来执行条件测试表达式,其执行结果要么为真,要么为假
# [[]]运算符和条件测试表达式之间前后有空格
if [[ $num -ne 5 ]];thenecho "the value of num variable is not 5"
fi# -le:判断num变量的值是否小于或等于val变量的值
# test命令关键字用来执行条件测试表达式,其执行结果要么为真,要么为假
if test $num -le $val ;thenecho "the value of num variable is lower or equal than val variable"
fi# -ge:判断val变量的值是否大于或等于num变量的值
# [[]]运算符用来执行条件测试表达式,其执行结果要么为真,要么为假
# [[]]运算符和条件测试表达式之间前后有空格
if [[ $val -ge $num ]];thenecho "the value of val variable is growth or equal than num variable"
fi# -gt:判断val变量的值是否大于5
# []运算符用来执行条件测试表达式,其执行结果要么为真,要么为假
# []运算符和条件测试表达式之间前后有空格
if [ $val -gt 5 ];thenecho "the value of val variable is growth than 5"
fi# -lt:判断num变量的值是否小于5
# [[]]运算符用来执行条件测试表达式,其执行结果要么为真,要么为假
# [[]]运算符和条件测试表达式之间前后有空格
if [[ $num -lt 5 ]];thenecho "the value of num variable is lower than 5"
fi
gt 的作用是,greater than
大于的意思
then
的作用
-
表示条件满足后的执行起点:在
if
语句中,then
是一个分隔符,用于区分条件判断部分和条件满足时的执行部分。当条件表达式(如[ $val -eq 5 ]
)的值为真(即条件满足)时,then
后面的语句将被执行。 -
语法结构的必要组成部分:在 Shell 脚本的
if
语句中,then
是必须的,它标志着条件判断之后的代码块的开始。如果没有then
,脚本将无法正确解析if
语句的结构。
fi
的作用
-
表示
if
语句的结束:fi
是if
的反向拼写,用于明确地标识if
语句的结束。它告诉 Shell 解释器,if
语句的逻辑已经完成,后续的代码将不再属于这个if
语句的范围。 -
确保语法完整性和正确性:在 Shell 脚本中,
if
语句必须以fi
结尾,否则脚本会报错。fi
是确保脚本语法完整性和正确性的关键部分。
val+num=7
val++: 5
val--: 6
++val: 6
--val: 5
val-num=3
val%num=1
var*num=10
val/num=2
var+=num:7
var-=num:5
val*=num:10
test.sh: line 37: let: val/=: syntax error: operand expected (error token is "/=")
val/=num:10
val%=num:0
[root@localhost ~]# vim test.sh
[root@localhost ~]# bash test.sh
val+num=7
val++: 5
val--: 6
++val: 6
--val: 5
val-num=3
val%num=1
var*num=10
val/num=2
var+=num:7
var-=num:5
val*=num:10
test.sh: line 37: let: val/=: syntax error: operand expected (error token is "/=")
the value of val variable is 5
the value of num variable is not 5
the value of num variable is lower or equal than val variable
the value of val variable is growth or equal than num variable
the value of num variable is lower than 5
用于用于for循环的示例代码如下
#!/bin/bash# ==判断变量i的值是否等于1
for ((i=1; i==1; i++));doecho $i
done# !=判断变量i的值是否不等于3
for ((i=1; i!=3; i++)); doecho $i
done# <=判断变量i的值是否小于等于4
for ((i=1; i<=4; i++)); doecho $i
done# >=判断变量i的值是否大于等于1
for ((i=5; i>=1; i--));doecho $i
done# <判断变量i的值是否小于7
# >判断变量i的值是否大于0
# &&表示逻辑与
# ||表示逻辑或
# !表示逻辑非
# 非的优先级大于与,与的优先级大于或
for ((i=1; i>0 && i<7; i++)); doecho $i
done
运行结果为:
test.sh: line 1: 的值是否等于1: command not found
1
1
2
1
2
3
4
5
4
3
2
1
1
2
3
4
5
6
数组索引
数组是一种数据结构,也可以叫做数据序列,它是一段连续的内容空间,保存了连续的多个数据(数据类型可以不相同),可以使用数组index索引来访问操作数组元素
根据数组index索引的不同可将数组分为
- 普通数组:数组index索引为整数型
- 关联数组:数组index索引为字符串
普通数组
普通数组也可以称为整型索引数组,它的声明定义方式有以下几种
#!/bin/bash# 使用declare -a显式声明变量数据类型为整型索引数组型
# 数组中各元素间使用空白字符分隔
# 字符串类型的元素使用引号
declare -a array1=(1 'b' 3 'a')
# 依次引用数组的第一、二、三、四个元素
# 不加下标时默认引用第一个元素
# 引用时必须加上{},否则$array1[0]的值为1[0]
echo "the first element of array1 is ${array1[0]}"
echo "the second element of array1 is ${array1[1]}"
echo "the third element of array1 is ${array1[2]}"
echo "the fourth element of array1 is ${array1[3]}"
# 查看数组所有元素
echo "all elements of array1 is ${array1[*]}"
echo "all elements of array1 is ${array1[@]}"# 由解释器动态解释变量数据类型为整型索引数组型
# 如果数组中各元素间使用逗号,则它们将作为一个整体,也就是数组索引0的值
array2=(1,'b',3,'a')
echo "the first element of array2 is ${array2[0]}"# 由解释器动态解释变量数据类型为整型索引数组型
# 数组元素使用自定义下标赋值
# 以下数组定义中,第一个元素是1,第二个元素是'b',第3个元素为空,第4个元素为'a'
array3=(1 'b' [3]='a')
# 依次引用数组的第一、二、三、四个元素
# 不加下标时默认引用第一个元素
echo "the first element of array3 is ${array3[0]}"
echo "the second element of array3 is ${array3[1]}"
echo "the third element of array3 is ${array3[2]}"
echo "the fourth element of array3 is ${array3[3]}"
# 查看数组中所有有效元素(不为空)的整型索引号
echo "the index of effective element is ${!array3[*]}"
echo "the index of effective element is ${!array3[@]}"
# 查看数组中的有效元素个数(只统计值不为空的元素)
echo "the num of array3 is ${#array3[*]}"
echo "the num of array3 is ${#array3[@]}"
结果为:
the first element of array1 is 1
the second element of array1 is b
the third element of array1 is 3
the fourth element of array1 is a
all elements of array1 is 1 b 3 a
all elements of array1 is 1 b 3 a
the first element of array2 is 1,b,3,a
the first element of array3 is 1
the second element of array3 is b
the third element of array3 is
the fourth element of array3 is a
the index of effective element is 0 1 3
the index of effective element is 0 1 3
the num of array3 is 3
the num of array3 is 3
在 Bash 脚本中,${#array4[1]}
中的 #
符号的作用是获取数组中指定元素的长度。
另外普通数组还支持以下运算操作
-
返回数组长度(即有效元素的个数,不包括空元素)
${#Array_Name[*]}
${#Array_Name[@]}
-
数组元素消除,该操作不会修改原数组元素,操作执行结果用数组来接收
Array_Name1=${Array_Name[*]#*word}
:功能同下Array_Name1=${Array_Name[*]##*word}
:自左而右查找Array_Name
数组中所有被匹配到的word
匹配到的元素,并将所有匹配到的元素删除(并不会删除原数组中的元素),最后返回剩余的数组元素Array_Name1=${Array_Name[*]%word*}
:功能同下Array_Name1=${Array_Name[*]%%word*}
:自右而左查找Array_Name
数组中所有被匹配到的word
匹配到的元素,并将所有匹配到的元素删除(并不会删除原数组中的元素),最后返回剩余的数组元素
-
数组元素提取,该操作不会修改原数组元素,操作执行结果用数组来接收
Array_Name1=${Array_Name[*]:offset}
:返回Array_Name
数组中索引为offset
的数组元素以及后面所有元素;其中offset
为整型数Array_Name1=${Array_Name[*]:offset:length}
:返回Array_Name
数组中索引为offset
的数值元素以及后面length-1
个元素;其中offset
和length
都为整型数
代码示例如下
#!/bin/basharray_test=(/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin)# 返回数组长度(即有效元素的个数,不包括空元素)
echo "the length of array_test is ${#array_test[*]}"
echo "the length of array_test is ${#array_test[@]}"# 数组元素消除,该操作不会修改原数组元素,操作执行结果用数组来接收
array_test1=${array_test[*]#*/usr/apache/bin}
echo "array_test:${array_test[*]}"
echo "array_test1:${array_test1[@]}"
array_test2=${array_test[*]##*/usr/apache/bin}
echo "array_test:${array_test[*]}"
echo "array_test2:${array_test2[@]}"
array_test3=${array_test[*]%/usr/apache/bin*}
echo "array_test:${array_test[*]}"
echo "array_test3:${array_test3[@]}"
array_test4=${array_test[*]%%/usr/apache/bin*}
echo "array_test:${array_test[*]}"
echo "array_test4:${array_test4[@]}"# 数组元素提取,该操作不会修改原数组元素,操作执行结果用数组来接收
array_test5=${array_test[*]:2}
echo "array_test:${array_test[*]}"
echo "array_test5:${array_test5[@]}"
array_test6=${array_test[*]:2:2}
echo "array_test:${array_test[*]}"
echo "array_test6:${array_test6[@]}"# 数组元素替换,该操作不会修改原数组元素,操作执行结果用数组来接收
array_test7=${array_test[*]/\/usr\/apache\/bin/} # 需要用\对/进行转义,替换值为空表示删除前面匹配到的
echo "array_test:${array_test[*]}"
echo "array_test7:${array_test7[@]}"
array_test8=${array_test[*]//\/usr\/apache\/bin/} # 需要用\对/进行转义,替换值为空表示删除前面匹配到的
echo "array_test:${array_test[*]}"
echo "array_test8:${array_test8[@]}"
执行结果如下
the length of array_test is 5
the length of array_test is 5
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test1:/usr/bin /root/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test2:/usr/bin /root/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test3:/usr/bin /root/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test4:/usr/bin /root/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test5:/usr/apache/bin /usr/mysql /usr/apache/bin
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test6:/usr/apache/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test7:/usr/bin /root/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test8:/usr/bin /root/bin /usr/mysql
同时普通数组也可用于for循环遍历
代码示例如下
#!/bin/bash# 获取家目录下文件列表,转换成普通数组
array_test=(`ls ~`)
echo ${array_test[@]}
echo "----------------"# 以数组元素值的方式直接遍历数组
for i in ${array_test[*]};doecho $i
done
echo "----------------"# 以数组index索引的方式遍历数组
for i in ${!array_test[*]};doecho ${array_test[$i]}
done
echo "----------------"# 以数组元素个数的方式遍历数组
for ((i=0;i<${#array_test[*]};i++));doecho ${array_test[$i]}
done
执行结果如下
anaconda-ks.cfg crontest.txt ln1 test.sh
----------------
anaconda-ks.cfg
crontest.txt
ln1
test.sh
----------------
anaconda-ks.cfg
crontest.txt
ln1
test.sh
----------------
anaconda-ks.cfg
crontest.txt
ln1
test.sh
关联数组
关联数组也可以称为字符索引数组,它的声明定义方式有以下几种
#!/bin/bash# 声明定义字符索引数组时必须使用declare -A
# 数组中各元素间使用空白字符分隔
declare -A array1=([name1]=jack [name2]=anony)
# 依次引用name1和name2对应的值
echo "the value of name1 element is ${array1[name1]}"
echo "the value of name2 element is ${array1[name2]}"# 声明定义字符索引数组时必须使用declare -A
# 如果数组中各元素间使用逗号,则它们将作为一个整体
declare -A array2=([name1]=jack,[name2]=anony)
echo "the value of name1 element is ${array2[name1]}"
# 查看name1对应值的字符长度
echo "the length of name1 element is ${#array2[name1]}"# 声明定义字符索引数组时必须使用declare -A
declare -A array3=([name1]=jack [name2]=anony)
echo "the value of name1 element is ${array3[name1]}"
echo "the value of name2 element is ${array3[name2]}"
# 通过字符索引进行赋值
array3[name3]=zhangsan
echo "the value of name3 element is ${array3[name3]}"
# 通过字符索引进行赋值
array3[name5]=lisi
# 查看数组所有元素
echo "the all effective element is ${array3[*]}"
echo "the all effective element is ${array3[@]}"
# 查看数组中所有有效元素(不为空)的字符索引号,默认是对应值的排列顺序
echo "the index of all effective element is ${!array3[*]}"
echo "the index of all effective element is ${!array3[@]}"
# 查看数组中的有效元素个数(只统计值不为空的元素)
echo "the length of array is ${#array3[*]}"
echo "the length of array is ${#array3[@]}"
执行结果如下
the value of name1 element is jack
the value of name2 element is anony
the value of name1 element is jack,[name2]=anony
the length of name1 element is 18
the value of name1 element is jack
the value of name2 element is anony
the value of name3 element is zhangsan
the all effective element is zhangsan anony jack lisi
the all effective element is zhangsan anony jack lisi
the index of all effective element is name3 name2 name1 name5
the index of all effective element is name3 name2 name1 name5
the length of array is 4
the length of array is 4
和普通数组一样,关联数组也支持以下运算操作
-
返回数组长度(即有效元素的个数,不包括空元素)
${#Array_Name[*]}
${#Array_Name[@]}
-
数组元素消除,该操作不会修改原数组元素,操作执行结果用数组来接收
declare -A Array_Name1=${Array_Name[*]#*word}
:功能同下declare -A Array_Name1=${Array_Name[*]##*word}
:自左而右查找Array_Name
数组中所有被匹配到的word
匹配到的元素,并将所有匹配到的元素删除(并不会删除原数组中的元素),最后返回剩余的数组元素declare -A Array_Name1=${Array_Name[*]%word*}
:功能同下declare -A Array_Name1=${Array_Name[*]%%word*}
:自右而左查找Array_Name
数组中所有被匹配到的word
匹配到的元素,并将所有匹配到的元素删除(并不会删除原数组中的元素),最后返回剩余的数组元素
-
数组元素提取,该操作不会修改原数组元素,操作执行结果用数组来接收
declare -A Array_Name1=${Array_Name[*]:offset}
:返回Array_Name
数组中索引为offset
的数组元素以及后面所有元素;其中offset
为整型数declare -A Array_Name1=${Array_Name[*]:offset:length}
:返回Array_Name
数组中索引为offset
的数值元素以及后面length-1
个元素;其中offset
和length
都为整型数
#!/bin/bashdeclare -A array_test=([ele1]=/usr/bin [ele2]=/root/bin [ele3]=/usr/apache/bin [ele4]=/usr/mysql [ele5]=/usr/apache/bin)# 返回数组长度(即有效元素的个数,不包括空元素)
echo "the length of array_test is ${#array_test[*]}"
echo "the length of array_test is ${#array_test[@]}"# 数组元素消除,该操作不会修改原数组元素,操作执行结果用数组来接收
declare -A array_test1=${array_test[*]#*/usr/apache/bin}
echo "array_test:${array_test[*]}"
echo "array_test1:${array_test1[@]}"
declare -A array_test2=${array_test[*]##*/usr/apache/bin}
echo "array_test:${array_test[*]}"
echo "array_test2:${array_test2[@]}"
declare -A array_test3=${array_test[*]%/usr/apache/bin*}
echo "array_test:${array_test[*]}"
echo "array_test3:${array_test3[@]}"
declare -A array_test4=${array_test[*]%%/usr/apache/bin*}
echo "array_test:${array_test[*]}"
echo "array_test4:${array_test4[@]}"# 数组元素提取,该操作不会修改原数组元素,操作执行结果用数组来接收
declare -A array_test5=${array_test[*]:2}
echo "array_test:${array_test[*]}"
echo "array_test5:${array_test5[@]}"
declare -A array_test6=${array_test[*]:2:2}
echo "array_test:${array_test[*]}"
echo "array_test6:${array_test6[@]}"# 数组元素替换,该操作不会修改原数组元素,操作执行结果用数组来接收
declare -A array_test7=${array_test[*]/\/usr\/apache\/bin/}
echo "array_test:${array_test[*]}"
echo "array_test7:${array_test7[@]}"
declare -A array_test8=${array_test[*]//\/usr\/apache\/bin/}
echo "array_test:${array_test[*]}"
echo "array_test8:${array_test8[@]}"
执行结果如下
the length of array_test is 5
the length of array_test is 5
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test1:/usr/mysql /usr/bin /root/bin
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test2:/usr/mysql /usr/bin /root/bin
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test3:/usr/mysql /usr/bin /root/bin
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test4:/usr/mysql /usr/bin /root/bin
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test5:/usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test6:/usr/apache/bin /usr/bin
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test7:/usr/mysql /usr/bin /root/bin
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test8:/usr/mysql /usr/bin /root/bin
关联数组和普通数组一样,也可用于for循环遍历
先创建test.log
文件,内容如下
[root@localhost ~]# cat test.log
portmapper
portmapper
portmapper
portmapper
portmapper
portmapper
status
status
mountd
mountd
mountd
mountd
mountd
mountd
nfs
nfs
nfs_acl
nfs
nfs
nfs_acl
nlockmgr
nlockmgr
nlockmgr
nlockmgr
nlockmgr
nlockmgr
代码示例如下:统计文件中重复行的次数
#!/bin/bashdeclare -A array_testfor i in `cat ~/test.log`;dolet ++array_test[$i] # 修改数组元素值
donefor j in ${!array_test[*]};doprintf "%-15s %3s\n" $j :${array_test[$j]}
done
执行结果如下
status :2
nfs :4
portmapper :6
nlockmgr :6
nfs_acl :2
mountd :6
列表型
列表型变量常用来for循环遍历,但是一般是在for循环中直接使用,当然也可以通过变量进行引用
代码示例如下
#!/bin/bash# 生成数字列表:使用{}运算符
for i in {1..4};doecho $i
done
echo "-------------------"# 生成数字列表:使用seq命令
for i in `seq 1 2 7`;doecho $i
done
echo "-------------------"# 生成文件列表:直接给出列表
for fileName in /etc/init.d/functions /etc/rc.d/rc.sysinit /etc/fstab;doecho $fileName
done
echo "-------------------"# 生成文件列表:使用文件名通配机制生成列表
dirName=/etc/rc.d
for fileName in $dirName/*.d;doecho $fileName
done
echo "-------------------"# 生成文件列表:使用``运算符引用相关命令的执行结果
for fileName in `ls ~`;doecho $fileName
done
代码执行结果
1
2
3
4
-------------------
1
3
5
7
-------------------
/etc/init.d/functions
/etc/rc.d/rc.sysinit
/etc/fstab
-------------------
/etc/rc.d/init.d
/etc/rc.d/rc0.d
/etc/rc.d/rc1.d
/etc/rc.d/rc2.d
/etc/rc.d/rc3.d
/etc/rc.d/rc4.d
/etc/rc.d/rc5.d
/etc/rc.d/rc6.d
-------------------
anaconda-ks.cfg
crontest.txt
ln1
test.log
test.sh
字符串型
首先我们来声明定义一个字符串型变量:Var_Name="anony"
- 在bash中,变量默认都是字符串类型,也都是以字符串方式存储,所以字符串可以不需要使用
""
,除非特殊声明,否则都会解释成字符串 - 该种方式声明,变量默认是本地全局变量,可以通过
local Var_Name
关键字将变量修改为局部变量,可以通过export Var_Name
关键字将变量导出为环境变量 - 该种声明定义方式是由shell解释器动态执行隐式声明该变量数据类型为字符串型
字符串型变量一般支持以下运算操作
-
返回字符串长度:
${#Var_Name}
(长度包括空白字符) -
字符串消除
-
${var#*word}
:查找var
中自左而右第一个被word
匹配到的串,并将此串及向左的所有内容都删除;此处为非贪婪匹配${var##*word}
:查找var
中自左而右最后一个被word
匹配到的串,并将此串及向左的所有内容都删除;此处为贪婪匹配${var%word*}
:查找var
中自右而左第一个被word
匹配到的串,并将此串及向右的所有内容都删除;此处为非贪婪匹配${var%%word*}
:查找var
中自右而左最后一个被word
匹配到的串,并将此串及向右的所有内容都删除;此处为贪婪匹配
-
字符串提取
${var:offset}
:自左向右偏移offset
个字符,取余下的字串;例如:name=jerry,${name:2}结果为rry
${var:offset:length}
:自左向右偏移offset
个字符,取余下的length
个字符长度的字串。例如:``name=’hello world’ ${name:2:5}结果为llo w``
函数
在编程语言中,函数是能够实现模块化编程的工具,每个函数都是一个功能组件,但是函数必须被调用才能执行
函数存在的主要作用在于:最大化代码重用,最小化代码冗余
在shell中,函数可以被当做命令一样执行,它的本质是命令的组合结构体,即可以将函数看成一个普通命令或一个小型脚本。接下来本章内容将从以下几个方面来介绍函数
- 函数定义
- 函数调用
- 函数退出
- 示例代码
0x00 函数定义
在shell中函数定义的方法有两种(使用help function
命令可以查看)
# 方法一 function FuncName {COMMANDS_LIST } [&>/dev/null]# 方法二 FuncName() {COMMANDS_LIST } [&>/dev/null]
上面两种函数定义方法定义了一个名为FuncName
的函数
- 方法一中:使用了
function
关键字,此时函数名FuncName
后面的括号可以省略 - 方法二中:省略了
function
关键字,此时函数名FuncName
后面的括号不能省略
COMMANDS_LIST
是函数体,它与以下特点
- 函数体通常使用大括号
{}
包围,由于历史原因,在shell中大括号本身也是关键字,所以为了不产生歧义,函数体和大括号之间必须使用空格、制表符、换行符
分隔开来;一般我们都是通过换行符进行分隔 - 函数体中的每一个命令必须使用
;
或换行符
进行分隔;如果使用&
结束某条命令,则表示该条命令会放入后台执行
需要注意的是
&>/dev/null
表示将函数体执行过程中可能输出的信息重定向至/dev/null
中,该功能可选- 定义函数时,还可以指定可选的函数重定向功能,这样当函数被调用的时候,指定的重定向也会被执行
- 当前shell定义的函数只能在当前shell使用,子shell无法继承父shell的函数定义,除非使用
export -f
将函数导出为全局函数;如果想取消函数的导出可以使用export -n
- 定义了函数后,可以使用
unset -f
移除当前shell中已定义的函数 - 可以使用
typeset -f [func_name]
或declare -f [func_name]
查看当前shell已定义的函数名和对应的定义语句;使用typeset -F
或declare -F
则只显示当前shell中已定义的函数名 - 只有先定义了函数,才可以调用函数;不允许函数调用语句在函数定义语句之前
- 在shell脚本中,函数没有形参的概念,使用方法二定义函数时,括号里什么都不用写,只需要在函数体内使用相关的调用机制调用接收参数即可
0x01 函数调用
函数的调用格式如下
FuncName ARGS_LIST
其中
FuncName
:表示被调用函数的函数名,需要注意的是在shell中函数调用时函数名后面没有()
操作符ARGS_LIST
:表示被调用函数的传入参数,在shell中给函数传入参数和脚本接收参数的方法相似,直接在函数名后面加上需要传入的参数即可
函数调用时需要注意以下几点
- 如果函数名和命令名相同,则优先执行函数,除非使用
command
命令。例如:定义了一个名为rm
的函数,在bash中输入rm
执行时,执行的是rm函数
,而非/bin/rm命令
,除非使用command rm ARGS
,表示执行的是/bin/rm命令
- 如果函数名和命令别名相同,则优先执行命令别名,即在优先级方面:
别名别名>函数>命令自身
当函数调用函数被执行时,它的执行逻辑如下
-
接收参数:shell函数也接受位置参数变量,但函数的位置参数是调用函数时传递给函数的,而非传递给脚本的参数,所以脚本的位置变量和函数的位置变量是不同的;同时shell函数也接收特殊变量。函数体内引用位置参数和特殊变量方式如下
-
位置参数
$0
:和脚本位置参数一样,引用脚本名称$1
:引用函数的第1个传入参数$n
:引用函数的第n个传入参数
-
特殊变量
-
$?
:引用上一条命令的执行状态返回值,状态用数字表示0-255
0
:表示成功1-255
:表示失败;其中1/2/127/255
是系统预留的,写脚本时要避开与这些值重复
-
$$
:引用当前shell的PID。除了执行bash命令和shell脚本时,$$不会继承父shell的值,其他类型的子shell都继承 -
$!
:引用最近一次执行的后台进程PID,即运行于后台的最后一个作业的PID -
$#
:引用函数所有位置参数的个数 -
$*
:引用函数所有位置参数的整体,即所有参数被当做一个字符串 -
$@
:引用函数所有单个位置参数,即每个参数都是一个独立的字符串
-
-
-
执行函数体:在函数体执行时,需要注意的是
-
函数内部引用变量的查找次序:
内层函数自己的变量>外层函数的变量>主程序的变量>bash内置的环境变量
-
函数内部引用变量的作用域
- 本地变量:函数体引用本地变量时,重新赋值会覆盖原来的值,如果不想覆盖值,可以使用
local
进行修饰 - 局部变量:函数体引用局部变量时,函数退出,将会被撤销
- 环境变量:函数体引用环境变量时,重新赋值会覆盖原来的值,如果不想覆盖值,可以使用
local
进行修饰 - 位置变量:函数体引用位置变量表示引用传递给函数的参数
- 特殊变量
- 本地变量:函数体引用本地变量时,重新赋值会覆盖原来的值,如果不想覆盖值,可以使用
-
-
函数返回:函数返回值可分为两类
-
执行结果返回值:正常的执行结果返回值有以下几种
- 函数中的打印语句:如
echo
、print
等 - 最后一条命令语句的执行结果值
- 函数中的打印语句:如
-
执行状态返回值:执行状态返回值主要有以下几种
- 使用
return
语句自定义返回值,即return n,n表示函数的退出状态码,不给定状态码时默认状态码为0 - 取决于函数体中最后一条命令语句的执行状态返回值
- 使用
-
在shell中不仅可以调用本脚本文件中定义的函数,还可以调用其它脚本文件中定义的函数
- 先使用
. /path/to/shellscript
或source /path/to/shellscript
命令导入指定的脚本文件 - 然后使用相应的函数名调用函数即可
0x02 函数退出命令
函数退出命令有
return [n]
:可以在函数体内的任何地方使用,表示退出整个函数;数值n表示函数的退出状态码exit [n]
:可以在脚本的任何地方使用,表示退出整个脚本;数值n表示脚本的退出状态码
此处需要注意的是:return
并非只能用于function内部
- 如果
return
在function之外
,但在.
或者source
命令的执行过程中,则直接停止该执行操作,并返回给定状态码n(如果未给定,则为0) - 如果
return
在function之外
,且不在source
或.
的执行过程中,则这将是一个错误用法
可能有些人不理解为什么不直接使用exit
来替代这时候的return
。下面给个例子就能清楚地区分它们
先创建一个脚本文件proxy.sh
,内容如下,用于根据情况设置代理的环境变量
#!/bin/bashproxy="http://127.0.0.1:8118" function exp_proxy() {export http_proxy=$proxyexport https_proxy=$proxyexport ftp_proxy=$proxyexport no_proxy=localhost }case $1 inset) exp_proxy;;unset) unset http_proxy https_proxy ftp_proxy no_proxy;;*) return 0 esac
首先我们来了解下source
的特性:即source
是在当前shell而非子shell执行指定脚本中的代码
当进入bash
- 需要设置环境变量时:使用
source proxy.sh set
即可 - 需要取消环境变量时:使用
source proxy.sh unset
即可
此时如果不清楚该脚本的用途或者一时手快直接输入source proxy.sh
,就可以区分exit
和return
- 如果上述脚本是
return 0
,那么表示直接退出脚本而已,不会退出bash - 如果上述脚本是
exit 0
,则表示退出当前bash,因为source
是在当前shell而非子shell执行指定脚本中的代码
可能你想象不出在source执行中的return有何用处:从source来考虑,它除了用在某些脚本中加载其他环境,更主要的是在bash环境初始化脚本中使用,例如/etc/profile
、~/.bashrc
等,如果你在/etc/profile
中用exit
来替代function外面
的return
,那么永远也登陆不上bash
0x03 示例代码
- 随机生成密码
#!/bin/bashgenpasswd(){local l=$1[ "$l" == "" ]&& l=20tr -dc A-Za-z0-9_</dev/urandom | head -c ${l} | xargs }genpasswd $1 # 将脚本传入的位置参数传递给函数,表示生成的随机密码的位数
-
写一个脚本,完成如下功能:
-
1、脚本使用格式:
mkscript.sh [-D|--description "script description"] [-A|--author "script author"] /path/to/somefile
-
2、如果文件事先不存在,则创建;且前几行内容如下所示:
- #!/bin/bash
- # Description: script description
- # Author: script author
-
3、如果事先存在,但不空,且第一行不是
#!/bin/bash
,则提示错误并退出;如果第一行是#!/bin/bash
,则使用vim打开脚本;把光标直接定位至最后一行 -
4、打开脚本后关闭时判断脚本是否有语法错误;如果有,提示输入y继续编辑,输入n放弃并退出;如果没有,则给此文件以执行权限
-
#!/bin/bash read -p "Enter a file: " filename declare authname declare descroptions(){ if [[ $# -ge 0 ]];thencase $1 in-D|--description)authname=$4descr=$2;;-A|--author)descr=$4authname=$2;;esac fi }command(){ if bash -n $filename &> /dev/null;thenchmod +x $filename elsewhile true;doread -p "[y|n]:" optioncase $option iny)vim + $filename;;n)exit 8;;esacdone fi exit 6 }oneline(){ if [[ -f $filename ]];thenif [ `head -1 $filename` == "#!/bin/bash" ];thenvim + $filenameelseecho "wrong..."exit 4fi elsetouch $filename && echo -e "#!/bin/bash\n# Description: $descr\n# Author: $authname" > $filenamevim + $filename fi command }options $* oneline
-
写一个脚本,完成如下功能:
- 1、提示用户输入一个可执行命令
- 2、获取这个命令所依赖的所有库文件(使用ldd命令)
- 3、复制命令至
/mnt/sysroot/
对应的目录中;如果复制的是cat
命令,其可执行程序的路径是/bin/cat
,那么就要将/bin/cat
复制到/mnt/sysroot/bin/
目录中,如果复制的是useradd
命令,而useradd
的可执行文件路径为/usr/sbin/useradd
,那么就要将其复制到/mnt/sysroot/usr/sbin/
目录中 - 4、复制各库文件至
/mnt/sysroot/
对应的目录中
#!/bin/bashoptions(){for i in $*;dodirname=`dirname $i`[ -d /mnt/sysroot$dirname ] || mkdir -p /mnt/sysroot$dirname[ -f /mnt/sysroot$i ]||cp $i /mnt/sysroot$dirname/done }while true;doread -p "Enter a command : " pidname[[ "$pidname" == "quit" ]] && echo "Quit " && exit 0bash=`which --skip-alias $pidname`if [[ -x $bash ]];thenoptions `/usr/bin/ldd $bash |grep -o "/[^[:space:]]\{1,\}"`options $bashelseecho "PLZ a command!"fi done# 说明 # 将bash命令的相关bin文件和lib文件复制到/mnt/sysroot/目录中后 # 使用chroot命令可切换根目录,切换到/mnt/sysroot/后可当做bash执行复制到该处的命令,作为bash中的bash
- 写一个脚本,用来判定172.16.0.0网络内有哪些主机在线,在线的用绿色显示,不在线的用红色显示
#!/bin/bash Cnetping(){for i in {1..254};doping -c 1 -w 1 $1.$iif [[ $? -eq 0 ]];thenecho -e -n "\033[32mping 172.16.$i.$j ke da !\033[0m\n"elseecho -e -n "\033[31mping 172.16.$i.$j bu ke da !\033[0m \n"fidone }Bnetping(){for j in {0..255};doCnetping $1.$jdone }Bnetping 172.16
- 写一个脚本,用来判定随意输入的ip地址所在网段内有哪些主机在线,在线的用绿色显示,不在线的用红色显示
#!/bin/bash Cnetping(){for i in {1..254};doping -c 1 -w 1 $1.$iif [[ $? -eq 0 ]];thenecho -e -n "\033[32mping 172.16.$i.$j ke da !\033[0m\n"elseecho -e -n "\033[31mping 172.16.$i.$j bu ke da !\033[0m \n"fidone }Bnetping(){for j in {0..255};doCnetping $1.$jdone }Anetping(){for m in {0.255};doBnetping $1.$mdone }netType=`echo $1 | cut -d'.' -f1`if [ $netType -gt 0 -a $netType -le 126 ];thenAnetping $1 elif [ $netType -ge 128 -a $netType -le 191 ];thenBnetping $1 elif [ $netType -ge 192 -a $netType -le 223 ];thenCnetping $1 elseecho "Wrong"exit 3 fi
相关文章:
ShellScript脚本编程
语法基础 脚本结构 我们先从这个小demo程序来窥探一下我们shell脚本的程序结构 #!/bin/bash# 注释信息echo_str"hello world"test(){echo $echo_str }test echo_str 首先我们可以通过文本编辑器(在这里我们使用linux自带文本编辑神器vim),新建一个文件…...
【leetcode100】整数拆分
1、题目描述 给定一个正整数 n ,将其拆分为 k 个 正整数 的和( k > 2 ),并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入: n 2 输出: 1 解释: 2 1 1, 1 1 1。 示例 2: 输入: n 10 输出: 36…...
leetcode:2899. 上一个遍历的整数(python3解法)
难度:简单 给你一个整数数组 nums ,其中 nums[i] 要么是一个正整数,要么是 -1 。我们需要为每个 -1 找到相应的正整数,我们称之为最后访问的整数。 为了达到这个目标,定义两个空数组:seen 和 ans。 从数组 …...
Mysql读写分离(2)-中间件mycat和实践方案
系统环境要求 Mysql版本5.5版本以上jdk1.7Mycat1.6 mycat使用Java开发,因为用到了JDK 7的部分功能,所以在使用前请确保安装了JDK 7.0,并设置了正确的Java环境变量(可在命令行窗口输入:“java –version”获知是否安装…...
QT之在多线程中如何优雅的处理资源泄漏
概述 在多线程编程中,资源泄漏是一个常见且需要特别关注的问题。资源泄漏通常指的是程序未能正确释放分配给它的资源(如内存、文件句柄、数据库连接等),这可能导致系统性能下降甚至崩溃。尤其是在多线程环境中,由于多个线程可能同时访问相同的资源,增加了管理这些资源的…...
SPA 收入支出/技师提成自动统计系统——仙盟共创平台——未来之窗
支出 spa服务 使用开始:https://mp.weixin.qq.com/s/Ok3wuSYAPhd-6N8DrK7jwg 收入清晰呈现:自动整合 SPA 门店各类服务项目收入数据,包括面部护理、身体按摩、特色疗程等。通过对接收银系统,实时记录每笔消费金额,按不…...
Linux的应用领域,测试与Linux,Linux的介绍,VirtualBox和Ubuntu的安装,VMware的安装和打开虚拟机CentOS
目录 Linux的应用领域 测试人员在Linux的工作 测试人员需要掌握Linux的程度 Linux的介绍 Linux的介绍 Linux发行版 Unix和Linux的渊源 虚拟机和Linux的安装 VirtualBox和Ubuntu的安装 安装VirtualBox 安装Ubuntu 下载Ubuntu操作系统的镜像文件 创建虚拟机 虚拟机…...
《Not All Tokens Are What You Need for Pretraining》全文翻译
《Not All Tokens Are What You Need for Pretraining》 不是所有的词元都是预训练所需 摘要 先前的语言模型预训练方法通常对所有训练词元均匀地应用下一词预测损失。对此常规做法提出挑战,我们认为“语料库中的并非所有词元对于语言模型训练同等重要”。我们的…...
vscode终端运行windows服务器的conda出错
远程windows服务器可以运行,本地vscode不能。 打开vscode settings.json文件 添加conda所在路径...
使用基数树优化高并发内存池(替代加锁访问的哈希表和红黑树)
前言: 本篇旨在熟悉 基于tcmalloc的高性能并发内存池项目之后,对于最后的优化进行的笔记梳理,项目完整代码 可点击:项目代码 进行查看。 优化思想风暴: 为了方便根据页号查找到对应的span, 这里我们可以使用红黑树或…...
【bash】.bashrc
查看当前路径文件数量 alias file_num"ls -l | grep ^- | wc -l"查看文件大小 alias file_size"du -sh"alias ll alias ll"ls -ltrh"cd的同时执行ll alias cdcdls; function cdls() {builtin cd "$1" && ll }自定义prompt…...
自我生成,自我训练:大模型用合成数据实现“自我学习”机制实战解析
目录 自我生成,自我训练:大模型用合成数据实现“自我学习”机制实战解析 一、什么是自我学习机制? 二、实现机制:如何用合成数据实现自我训练? ✅ 方式一:Prompt强化生成 → 自我采样再训练 ✅ 方式二…...
Linux的命令格式,运行级别,找回root密码,Linux用户的分类,绝对路径和相对路径,硬链接和软链接,实用按键
目录 Linux的命令格式 运行级别 运行级别说明 切换运行级别 指定默认的运行级别 找回root密码 找回root密码 可能会出现的问题 Linux的用户分类 绝对路径和相对路径 硬链接和软链接 实用按键 Linux的命令格式 Linux的命令格式: command [-options] [par…...
C# JSON
在C#中,你可以使用System.Text.Json或Newtonsoft.Json库来解析JSON字符串。以下是使用这两种库分别解析你提供的JSON字符串的示例。 1. 使用 System.Text.Json System.Text.Json 是 .NET Core 3.0 及以上版本中包含的内置JSON库。以下是如何使用它来解析你的JSON字…...
入门-C编程基础部分:6、常量
飞书文档https://x509p6c8to.feishu.cn/wiki/MnkLwEozRidtw6kyeW9cwClbnAg C 常量 常量是固定值,在程序执行期间不会改变,可以让我们编程更加规范。 常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字…...
数字时代的AI与大数据:用高级AI开发技术革新大数据管理
李升伟 编译 在当今数字时代,数据的爆炸式增长令人惊叹 从社交媒体互动到物联网设备的传感器数据,企业正被海量信息淹没。但如何将这种无序的数据洪流转化为有价值的洞察?答案在于人工智能(AI)开发技术的革新&#x…...
数据结构与算法入门 Day 0:程序世界的基石与密码
🌟数据结构与算法入门 Day 0:程序世界的基石与密码🔑 ps:接受到了不少的私信反馈,说应该先把前置的知识内容做一个梳理,所以把昨天的文章删除了,重新开启今天的博文写作 Hey 小伙伴们ÿ…...
20250416在荣品的PRO-RK3566开发板的Android13下编译native C的应用程序的步骤
mm编译的简略步骤以及详细LOG,仅供参考: rootrootrootroot-X99-Turbo:~/hailuo_temp/Android13.0$ source build/envsetup.sh rootrootrootroot-X99-Turbo:~/hailuo_temp/Android13.0$ lunch 57. rk3566_t-userdebug Pick from common choices abo…...
Pikachu靶场——Cross-Site Scripting
使用ubantu-linux虚拟机通过docker镜像本地搭建 一,反射型xss(get) 1,观察靶场环境,功能是提交你最喜欢的NBA球星 2,可以通过burp suite抓包分析一下 通过GET请求提交输入的姓名,这是及其危险的 3,尝试使用…...
ArkTS组件的三个通用(通用事件、通用属性、通用手势)
文章目录 通用事件点击事件 onClick触摸事件 onTouch挂载、卸载事件拖拽事件按键事件 onKeyEvent焦点事件鼠标事件悬浮事件组件区域变化事件 onAreaChange组件尺寸变化事件组件可见区域变化事件组件快捷键事件自定义事件分发自定义事件拦截 通用属性尺寸设置位置设置布局约束边…...
双token实现无感刷新
一、方案说明 1. 核心流程 用户登录 提交账号密码 → 服务端验证 → 返回Access Token(前端存储) Refresh Token(HttpOnly Cookie) 业务请求 请求头携带Access Token → 服务端验证有效性 → 有效则返回数据 Token过…...
UE5游戏分辨率设置和窗口模式
第一种方法: 在项目配置Config文件夹下新建 DefaultGameUserSettings.ini 输入代码 [/Script/Engine.GameUserSettings] bUseVSyncFalse ResolutionSizeX1960 ResolutionSizeY1080 LastUserConfirmedResolutionSizeX800 LastUserConfirmedResolutionSizeY600 WindowPosX-1 …...
Java 线程中断 Interrupted
线程中断是 Java 中的一种协作机制,用于通知线程应该停止当前工作并退出。 中断就好比其它线程跟当前线程打了个招呼,告诉他可以执行中断操作。其他线程通过调用该线程的interrupt()方法对其进行中断操作。 中断并不会直接终止线程,而是设置…...
Android Jetpack是什么与原生android 有什么区别
Android Jetpack是什么 Android Jetpack是Google推出的一套开发组件工具集,旨在帮助开发者更高效地构建高质量的Android应用。它包含多个库和工具,被分为架构、用户界面、行为和基础四大类。以下是一些Android Jetpack的示例: 架构组件 ViewModel:用于以生命周期的方式管理…...
从0~1写一个starer启动器
从0到1编写一个Spring Boot Starter 前言 使用过Spring框架的伙伴都知道,虽然Spring在一定程度上帮助我们简化了集成其他框架,但在集成框架的同时仍少不了大量的XML配置,这些繁琐的工作无疑会加重我们的工作任务。而Spring Boot相较于Sprin…...
prime-2 靶场笔记(vuInhub靶场)
前言: 在本次靶场环境中涉及的知识点,主要包含LFI和SMB以及Lxd组提权,具体内容包括主机探测、端口扫描、目录扫描、wpscan扫描、反弹shell、一句话木马、容器、linux各种提权和维持。 环境介绍: 本靶场使用了kali(192…...
Node.js 中的 Buffer(缓冲区)
下面是关于 Node.js 中的 Buffer(缓冲区) 的系统总结,涵盖了定义、创建、读取修改、溢出处理、中文编码问题以及字符串转换等关键用法👇 🧱 一、什么是 Buffer? Buffer 是 Node.js 提供的用于处理二进制数…...
如何学习嵌入式
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.16 请各位前辈能否给我提点建议,或者学习路线指导一下 STM32单片机学习总…...
高版本Android (AIDL HAL) 使用HIDL方法
目录 修改步骤和编译方法 注意事项 Android 11 引入了使用 AIDL 实现 HAL 的功能。 后续Android新版本,HAL默认切到了使用AIDL. 因此当导入旧HIDL实现方式时,需要做一些修改。 1.将HAL HIDL模块拷贝到相应目录,进行编译 source build/envsetup.sh lunch xxx mmm 模块路径 1.…...
Cribl (实验) vpc-flow 数据抽样
先看文档: Firewall Logs: VPC Flow Logs, Cisco ASA, Etc. | Cribl Docs Firewall Logs: VPC Flow Logs, Cisco ASA, Etc. Recipe for Sampling Firewall Logs Firewall logs are another source of important operational (and security) data. Typical examples include Ama…...
RK3568 更换显示logo
文章目录 1、环境介绍2、替换logo 1、环境介绍 硬件:飞凌ok3568-c开发板 软件:原厂rk356x sdk 屏幕:1024*600 hdmi屏 2、替换logo 这是一件提无语的事。本来替换logo是很平常的一件事。即替换kernel目录下的logo图片即可: 但…...
修改wsl中发行版Ubuntu的主机名
我wsl2中装了两个ubuntu的发行版本,默认下主机名和我的windows主机名都一样,而且包含大写字母,在配置其他应用时经常会出问题,按照下面的顺序修改了一下: 1、打开ubuntu发行版 现在显示包含大写字母和数字的主机名。 …...
Python学习之路(三)
将 Python 与数据库对接是开发过程中常见的任务,可以使用多种数据库(如 SQLite、MySQL、PostgreSQL、Oracle、MongoDB 等)。以下是一些常见的数据库及其与 Python 的对接方法,包括安装库、连接数据库、执行查询和操作数据的示例。…...
多功能门禁系统的设计
本课题为多功能门禁系统的设计,其系统架构如图2.1所示,整个系统由STM32F103单片机和MaixBit开发板两部分构成,其中MaixBit是基于K210芯片的开发板,在此主要负责人脸的录入,识别,液晶显示等功能,…...
C/C++---头文件保护机制
在 C 和 C 编程里,头文件保护机制是一种防止头文件被重复包含的技术,它主要借助 #ifndef、#define 和 #endif 这些预处理指令来达成,也可以使用 #pragma once 这一编译器特定指令。下面详细阐述这一机制: 1. 头文件重复包含的问题…...
双指针算法(一)
目录 一、力扣——283、移动零 二、力扣——1089、复写零 三、力扣——11、盛最多的水 四、力扣——202、快乐数 一、力扣——283、移动零 题目如下: 这里我们用双指针算法,用的是双指针的思想,我们在这道题在数组下操作可以用数组下标。…...
LNMP架构部署论坛
目录 1.安装Nginx服务 1.系统初始化 2.安装工具包及依赖包 3.创建运行用户 4.编译安装 5.优化路径 6.添加 Nginx 系统服 2.安装MySQL服务 1.确定GLIBC版本 2.上传二进制压缩包并解压 3. 创建运行用户 4. 创建 mysql 配置文件 5.更改mysql安装目录和配…...
微信小程序边框容器带三角指向
效果图 .wxml <view class"tb"><view class"tb-pointer" style"--n:{{n}}rpx;" /> </view> <button bind:tap"addPixel">增加三角一个像素</button>.js Page({data: {n:16,},addPixel(){this.setData…...
RISCV Hardware Performance Monitor 和 Sscofpmf 扩展
文章目录 前言RISCV的HPMSscofpmf 扩展总结 前言 Perf 全名是 Performance Event,应用可以利用 PMU (Performance Monitoring Unit)、tracepoint 和核心内部的特殊计数器(counter)来进行统计,另外还能同时分析运行中的核心代码&a…...
MATLAB脚本实现了一个三自由度的通用航空运载器(CAV-H)的轨迹仿真,主要用于模拟升力体在不同飞行阶段(初始滑翔段、滑翔段、下压段)的运动轨迹
%升力体:通用航空运载器CAV-H %读取数据1 升力系数 alpha = [10 15 20]; Ma = [3.5 5 8 10 15 20 23]; alpha1 = 10:0.1:20; Ma1 = 3.5:0.1:23; [Ma1, alpha1] = meshgrid(Ma1, alpha1); CL = readmatrix(simulation.xlsx, Sheet, Sheet1, Range, B2:H4); CL1 = interp2(…...
GIS开发笔记(4)结合osg及osgEarth实现地图选点功能
一、实现效果:在地球上点击某个点后,显示该点的坐标。 二、实现原理: viewer添加事件处理器类,类中响应鼠标左键事件,获取坐标点显示。 三、参考代码: #pragma once#include <osgGA/GUIEventHandler> #include...
halcon模板匹配(五)find_shape_model_clutter
目录 一、find_shape_model_clutter例程目的二、默认模板匹配的过程三、定义杂波区域四、设置模型的杂波区域 一、find_shape_model_clutter例程目的 如下图所示,这个例程是想找到左图所示区域内的目标,要求上下临近区域无目标。 默认参数匹配结果 二…...
openGauss使用指南与SQL转换注意事项
openGauss 使用指南与SQL转换注意事项 基本说明 openGauss数据库内核基于PostgreSQL(pgsql),因此可以将SQL Server语句转换为pgsql语句。可以使用AI工具辅助转换,但需注意以下关键差异点。 数据类型转换注意事项 字符串类型处理 nvarchar转换&#…...
前端基础之《Vue(5)—组件基础》
一、什么是组件化 1、理解组件化 组件是HTML的扩展,使用粒度较小的HTML元素封装成粒度更大的标签(Vue组件)。可以实现快速开发、代码复用、提升可维护性。 相当于盖房子,用预制板,不是用一块块砖,一天可以…...
责任链模式(Chain of Responsibility Pattern)
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许将请求沿着处理者链进行传递,直到有一个处理者能够处理该请求为止。在这个模式中,多个处理者对象会形成一个链条,每个处理者都有机会处理请求,或者将请求传递给链条中的下一个处理者。这种模式将…...
C++算法(9):数组作为函数参数,注意事项与实践
C编程中,数组作为函数参数传递是一个常见但容易出错的操作。本文将详细介绍数组作为函数参数时需要注意的关键问题,帮助开发者避免常见的陷阱。 主要注意事项 1. 数组作为参数的本质 参数声明形式实际传递内容大小信息int arr[]数组首地址丢失int arr[…...
特性(Attribute)
特性(Attribute)的概念 定义 特性是用于向代码元素(类、方法、属性等)添加元数据的类,继承自 System.Attribute。 元数据提供程序化的描述信息,供运行时或工具(如编译器、反射)使…...
使用CubeMX新建SysTick延时函数工程——使用中断,不使用HAL_Delay
具体操作步骤看这里:STM32CubeMX学习笔记(4)——系统延时使用_cubemx systick-CSDN博客 1、SysTick 初始化函数 SysTick 初始化函数由用户编写,里面调用了 SysTick_Config() 这个固件库函数,通过设置该固件 库函数的形…...
从零开始实现 MobileViT 注意力机制——轻量级Transformer Vision Model 的新思路
从零开始实现 MobileViT 注意力机制——轻量级Transformer Vision Model 的新思路 近年来,计算机视觉领域中 Transformer 模型的崛起为图像处理带来了新的活力。特别是在 ViT(Vision Transformer)模型提出之后,Transformer 在图像…...
Doris部署生产集群最低要求的部署方案
Doris生产集群最低部署方案(2025年4月版) 一、节点规划与数量 1. FE节点(Frontend) 数量:至少 3个节点(1个Follower 2个 Observer),确保高可用(HA)。角色分…...