shell脚本在linux使用用的十分广泛,写篇总结学习性的文章做记录。
这个运维手册写的比较详细,可以做参考。
另一个比较全的参考
基本语法
- if else:
# then 与 if 同一行时要加 ; if [ `whoami` != "root" ];then echo "Please run it as a superuser" exit 0 elif $something -gt 2 ; then echo "else if" else echo "else" fi
- switch:
read -p $'Please input a number... \n1 means icmp,2 means udp ,3 means tcp ' case $n in 1) echo "you will accept icmp data" tcpdump icmp -c 5 -i ens33 -l -w./aaa.cap & ;; 2) echo "you will accept udp data" tcpdump udp -c 5 -i ens33 ;; 3) echo "you will accept tcp data" tcpdump tcp -c 5 -i ens33 ;; *) echo "invail command" ;; esac
- for:
datetime=`date +%F-%H:%M:%S`
i=1
while [ $i -lt 5 ];do
echo "start NO.$i capture data"
# sudo tcpdump icmp -i ens33 -w ./$datetime.cap &
# sudo tcpdump icmp -i ens33 -w ./`date +%F-%H:%M:%S` &
tdid=`pgrep tcpdump`
sleep 10s
echo "$tdid"
kill -9 $tdid
((i++))
done
for i in ${!IdArry[@]}
do
echo ${IdArry[i]:1}
# echo ${IdArry[i]:i:j} 表示打印第i位到第j位数据,j省略表示第i位到最后一位
done
关系运算符,如下:
注意: 使用 [] 就可以使用c中常用的关系符, # [ ]符号旁必须有空格,否则会被shell认为是命令执行
- -gt:大于,greater than。
- -eq:等于,equal。
- -lt:小于,less than。
- -ge:大于等于,greater than or equal。
- -le:小于等于,less than or equal。
- -ne:不等于,not equal。
连接符,如下:
- -a:且,and。
- -o:或,or。
条件判断,逻辑运算符,如下:
- &&:用来执行条件成立后执行的命令。
- ||:用来执行条件不成立后的执行命令。
函数、传参、返回值
给定的参数以$1,$2,$3,...$n的形式访问,对应于函数名后参数的位置。$0变量的值是函数的名称。
$? 表示上次运行的结果,非0表示异常
$# 变量用于保存赋予函数的位置自变量/参数的数量。其中 $* 和 $@ 变量用于保存赋予函数的所有参数。
传参时,若$cmd中带空格需要加"" , 不加双引号会自动以空格为分割符号传参
数组传参数使用 ${Mymap[*]} 或 ${Mymap[@]},区别为${Mymap[*]} 是传入一个参数,
例如“1 2 3”${Mymap[@]} 是传入多个参数,例如"1","2","3"
# 声明函数的语法有两种格式定义:
# 第一种方法:以函数名称开头,后跟括号。这是最优选且最常用的方法,语法如下:
function_name () {
commands
}
# 单行语法如下:
function_name () { commands; }
# 第二种方法:以函数保留字开头,后跟函数名称:
function function_name {
commands
}
# 单行语法如下:
function_name () { commands; }
数组、关联数组(字典)变量
索引-1是最后一个元素的参考
declare -a ARRAY_NA 声明数组 declare -A ARRAY_NAME 声明关联数组 local temp 声明局部变量
注意脚本中哪怕函数内定义变量默认是全局的,在函数内定义的local变量会结束作用域后销毁。
关联数组用法示例:
# 访问元素类似数组
Mymap[${NameArry}]
# 添加元素
Mymap[${NameArry}] = 12
# 删除元素
unset Mymap[$findkey] 删除操作
# 遍历元素
for i in ${IdArry[@]}
do
echo i
done
# ${!Mymap[@]}为数组或字典全部index ${Mymap[@]}为全部value
#
&() 与 ``区别
在操作上,这两者都是达到相应的效果。在bash中,$( )与``(反引号,博客格式有问题,这里打中文的代替)都是用来作命令替换的。命令替换与变量替换差不多,都是用来重组命令行的,先完成引号里的命令行,然后将其结果替换出来,再重组成新的命令行。
$ echo today is $(date "+%Y-%m-%d")
today is 2021-08-01
在多层次的复合替换中,``必须要额外的跳脱处理(反斜线),而$( )比较直观。 最后,$( )的弊端是,并不是所有的类unix系统都支持这种方式,但反引号是肯定支持的。
# 将cmd1执行结果作为cmd2参数,再将cmd2结果作为cmd3的参数
cmd3 $(cmd2 $(cmd1))
# 如果是用反引号,直接引用是不行的,还需要作跳脱处理
cmd3 `cmd2 \`cmd1\``
trap
详细trap介绍
在shell中,使用内置命令trap(中文就翻译为陷阱、圈套)也可以布置所谓的陷阱,这个陷阱当然不是捕老鼠的,而是捕捉信号。
通常trap都在脚本中使用,主要有2种功能:
(1).忽略信号。当运行中的脚本进程接收到某信号时(例如误按了CTRL+C),可以将其忽略,免得脚本执行到一半就被终止 (2).捕捉到信号后做相应处理。主要是清理一些脚本创建的临时文件,然后退出
进程结束临时文件销毁示例
# XXX会被随即字符代替保证唯一,-d生成目录,-t表示生成在/temp中,
# 脚本临时文件全部存在此处,程序捕获到EXIT后执行finish删除临时文件夹
scratch=$(mktemp -d -t coretmp.XXX)
function finish {
rm -rf "$scratch"
}
trap finish EXIT
调用core api示例
awk grep sed 是处理文本的三大利器,后面示例用到了用到了awk,直接将其返回一个变量会传输到数组中。
#!/bin/bash
scratch=$(mktemp -d -t coretmp.XXX)
function finish {
rm -rf "$scratch"
}
trap finish EXIT
function ApiCall {
local nodeId=$1;
local cmd=$2;
# tee一边重定向到文件一边打印,防止等待response卡死,也方便打印报错信息
coresendmsg execute flags=tty node=$nodeId number=1001 command="$cmd" -l | tee $scratch/core_msg
res=$(awk -F ': ' '{if($1 ~ /RESULT/) print $2}' $scratch/core_msg)
if [ "$res" == "" ]; then
exit 0
else
echo -e "excute core api command: \n$res\n"
fi
eval $res
}
function SetMap {
file=$1
Mymap=$2
local IdArry=(`awk '$1=="node" {print $2}' $file`)
local NameArry=(`awk '$1=="hostname" {print $2}' $file`)
for i in ${!IdArry[@]}
do
Mymap[${NameArry[i]}]=${IdArry[i]:1}
done
# echo ${!Mymap[@]} ${Mymap[@]}
}
# 默认命令、场景文件参数
nodeId='1'
protocol='icmp'
interface='eth0'
imnPwd=$(echo $HOME/.core/configs/)
scene='sample1'
declare -A Mymap
# 读取参数
if [ $# == 0 ]; then
echo -e "The required parameters are imn scenario name and node name\n\
When \$3 is CMD, \$4 is the command to execute...
Otherwise, \$3 indicates the NIC ID and \$4 indicates the packet capture protocol (optional).\n\
!! default: nodename=n1, interface=$interface, protocol=$protocol(options) !!
sense file: echo $imnPwd$scene.imn"
else
scene=$1
file=$(echo $imnPwd$scene.imn)
echo -e "sense file: $file"
SetMap $file ${Mymap[*]}
# echo "场景节点名: ${!Mymap[@]} \n 场景节点id: ${Mymap[@]}"
nodeId=${Mymap[$2]}
interface=$3
protocol=$4
if [ ! -n "$nodeId" ]; then
echo "node name error!"
exit 0
fi
fi
if [ "$3" == "cmd" ] ; then
ApiCall $nodeId "$4"
elif [ $# -ge 3 ] || [ $# == 0 ]; then
cmd=$(echo tcpdump $protocol -i $interface -l)
ApiCall $nodeId "$cmd"
else
echo "Invalid input parameter"
exit 0
fi