Shell编程语法及应用
简介
Shell脚本与Windows/Dos下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比Windows下的批处理更强大,比用其他编程程序编辑的程序效率更高,它使用了Linux/Unix下的命令
变量
变量类型 本地变量:当前用户进程 环境变量:当前用户进程和子进程(env/set) 全局变量:所有用户程序都能调用 系统变量:内置bash变量 $?:上一条命令执行返回状态;0表示执行正常,非0表示执行不正常 $#:表示脚本接的参数个数 $*:表示脚本后面所有参数 :表示脚本后面所有参数 $0:运行脚本的名称 ${1}-${9}:表示脚本后面的位置参数 $$:当前所在进程的进程号 $!:最后一个放在后台运行的进程号 !$:调用最后一条命令的参数
数组
普通数组(整数作为下标) 分别定义:array[0]=v1 array[1]=v2 ... 连续定义:array=(var1 var2 ... varn) array=(`cat /etc/passwd`)通过空格分隔 查看单个元素:${array[0]} 查看所有元素: ${array[*]} ${array[@]} 截取部分元素:${array[*]:1:3} 查看元素个数:${#array[*]} 获取元素下标: ${!array[*]} ${!array[@]} 关联数组(可使用字符串作为下标,先声明在定义) 定义:declare -A array 查看关联数组 declare -A 分别定义:array[a]=v1 array[b]=v2 ... 连续定义:array=([name1]=var1 [name2]=var2 ... [namen]=varn) 查看单个元素:${array[a]} 查看所有元素: ${array[*]} ${array[@]} 截取部分元素:${array[*]:1:3} 查看元素个数:${#array[*]} 获取元素下标: ${!array[*]} ${!array[@]} 运算(默认为0): let array[name1]++ let array[name1]+=num 清空数组 unset array
用法
魔法字节(通配)
#!/bin/env bash
查看运行过程
[ ~]# bash -x my.sh
查看进程ID
[ ~]# pgrep 进程名称 &> /dev/null
查看语法问题
[ ~]# bash -n my.sh
date工具
前一分钟(日周月年) date -d ‘-1 minute‘ 后一分钟 date -d ‘1 minute‘ 设置格式 date +%d/%b%Y:%H%M
语法
调用变量某部分
A=123456 echo ${A:2:3}=>345
删除字符串的一部分
从后往前删 ${array%xxx}
从文件读取变量
read -p "Input:" name < filename
定义有类型变量,对变量做限制
declare [options] 变量名=变量值 常用选项 -i:声明一个整型 -r:声明一个readonly变量,该变量的值无法改变,并且不能为unset -a:声明一个数组 -x:声明环境变量
四则运算(仅整数)
$((1+1)) $[10-5] expr 1 + 1(不可求幂) n=1;let n=n+1;echo $n(需先定义变量)
shift
使位置参数左移(默认1位),也可以设定为多位
取出当前文件的目录和名称
dirname $A basename $A
shift
#输入参数one two three four five six #shift就是右移拿掉多少个参数的意思 echo "The script name is ==> ${0} " echo "Total parameter number is ==> $# " echo "Your whole parameter is ==> ‘‘ " shift #进行一个变量的shift echo "Total parameter number is ==> $# " echo "Your whole parameter is ==> ‘‘ " shift 3 #第二次进行三个变量的shift echo "Total parameter number is ==> $# " echo "Your whole parameter is ==> ‘‘ "
变量内容删除和替换
url=www.haha.com 获取长度:${$url} 左往右去掉一个key:${url#*.}=>haha.com 左往右去掉最大程度去掉:${url##*.}=>com 右往左去掉一个key:${url%*.}=>www.haha 右往左去掉最大程度去掉:${url%%*.}=>www
并发执行
用{}&包住函数体,加入wait关键字
实现输出
cat << -EOF xx EOF
随机数(0-32767)
$RANDOM 产生0-n-1之间随机数 $[$RANDOM%n] 产生10-99 $[$RANDOM%90+10]
expect(实现自动应答)
#位置参数定义变量 set ip xxx set pass xxx #开启一个程序 spawn ssh $ip #捕获相应内容 #exp_continue参数表示可忽略此捕获 expect { "(yes/no)?" { send "yes\r";exp_continue } "password:" { send "$pass\r";exp_continue } } #进行操作 expect "#" send "rm -rf /tmp/*\r" send "hostname\r" send "date +%F\r" send "touch file{1..3}\r" send "ls /tmp/\r" expect eof
条件判断
语法 test 条件 [ 条件 ] [[ 条件 ]] 类C风格 数值比较:(( 条件 )) []和[[]]区别: 判断空字符串时,[]需要对变量加"";[[]]不需要 &&和||时,[]要分开多个条件,[[]]不需要
流程控制
if结构
语法 if [[ condition1 ]];then command1 elif [[ condition2 ]];then command2 else command3 fi
for结构
语法 带列表: for variable in {list} do command done 不带列表(由用户输入的参数决定,$1$2): for variable [in ""] 类C风格: for (( expr1;expr2;expr3 ))
while结构
语法 while 表达式 do command done
until结构
语法 until expression do command done
case语句
语法 case var in pattern 1) command ;; pattern 2) command ;; *)#相当于default command ;; esac
select循环(方便输出菜单,无限循环)
语法 #定义提示符,$PS1,$PS2,$PS3 PS3="Your choice is:" select choice in xxx xxx xxx do case "$choice" in xxx) esac done
函数
语法 [function] 函数名(){ 函数体 打印传给函数的第一个参数:echo $1 } 调用 终端临时调用:source function.sh;function_name 环境变量:函数写入/etc/bashrc(用户在家目录.bashrc) 脚本中调用:function_name(脚本中定义|source function.sh)
应用
需求:随机产生1000个139开头的电话号码,并抽取五位幸运观众
n1=0 n2=0 n3=0 n4=0 n5=0 n6=0 n7=0 n8=0 file=/tmp/phonenum.txt for ((i=1;i<=1000;i++)) do for ((j=1;j<=8;j++)) do let n$j=$[$RANDOM%10] done echo "139$n1$n2$n3$n4$n5$n6$n7$n8" >> $file done
#!/bin/env bash #抽取五个幸运观众 phone=/tmp/phonenum.txt for ((i=1;i<=5;i++)) do line=`wc -l $phone|cut -d ‘ ‘ -f1` lucky_lines=$[$RANDOM%$line+1] #取出号码 luck_num=`head -$lucky_lines $phone |tail -1` #替换显示到屏幕 echo "139****${luck_num:7:4}" echo $luck_num >> /tmp/luck.txt #删除已抽取的号码,sed用shell变量要用双引号 sed -i "/$luck_num/d" $phone done
需求:保留最近3天的日志
#!/bin/bash #实现一: #定期删除目录下修改时间大于7天的文件,使用绝对路径 #脚本加上i权限防止误操作 #方法一: `find /path -mtime +7 -exec rm -r {} \;` #方法二: `find /path -mtime +7 |xargs rm -rf ` #实现二: #一直保留前两个工作日的备份文件,使用绝对路径 #方法一: `ls -t /path/*.tar.gz | awk ‘NR>2‘ |xargs rm -rf ` #方法二: `ls -t /path/*.tar.gz|awk ‘NR>2 {print "rm -f "$0""}‘|bash`
需求:统计网站连接状态
#!/bin/bash declare -A state_array states=`ss -ant|grep :80 |cut -d ‘ ‘ -f1` for i in $states do let state_array[$i]++ done for j in ${!state_array[*]} do echo $j:${state_array[$j]} done
需求:脚本查看系统性能
#!/bin/bash PS3="Your choice is:" #判断系统 os_check(){ if [ -e /etc/redhat-release ];then REDHAT=`cat /etc/redhat-release|cut -d ‘ ‘ -f1` else DEBIAN=`cat /etc/issue|cut -d ‘ ‘ -f1` fi if [ "$REDHAT" == "Centos" -o "$REDHAT" == "Red" ];then P_M=yum elif [ "$DEBIAN" == "Ubuntu" -o "$DEBIAN" == "ubuntu" ];then P_M=apt-get else echo "Operating system does not support." exit 1 fi } if [ $LOGNAME != root ];then echo "Please use the root account operation." exit 1 fi instll_software(){ if ! which $1 &> /dev/null;then echo $1 "command not found,now the install." sleep 1 os_check $P_M install $2 -y echo "--------------------" fi } while true do select input in cpu_load disk_load disk_use disk_inode mem_use tcp_status cpu_top10 mem_top10 traffic quit do case $input in cpu_load) #CPU利用率和负载 echo "-------------------------" i=1 while [[ $i -le 3 ]] do #定义颜色 echo -e "\033[32m 参考值${i}\033[0m" UTIL=`vmstat|awk ‘{if(NR==3)print 100-$15"%"}‘` USER=`vmstat|awk ‘{if(NR==3)print $13"%"}‘` SYS=`vmstat|awk ‘{if(NR==3)print $14"%"}‘` IOWAIT=`vmstat|awk ‘{if(NR==3)print $16"%"}‘` echo "Util:$UTIL" echo "User use:$USER" echo "System use:$SYS" echo "I/O wait:$IOWAIT" let i++ sleep 1 done echo "-------------------------" break ;; disk_load) #硬盘I/O负载 echo "-------------------------" i=1 while [[ $i -le 3 ]] do echo -e "\033[32m 参考值${i}\033[0m" UTIL=`iostat -x -k|awk ‘/^[v|s]da/{print $1,$NF"%"}‘` READ=`iostat -x -k|awk ‘/^[v|s]da/{print $1,$4"KB"}‘` WRITE=`iostat -x -k|awk ‘/^[v|s]da/{print $1,$5KB"%"}‘` IOWAIT=`vmstat|awk ‘{if(NR==3)print $16"%"}‘` echo "Util:$UTIL" echo "Read:$READ" echo "Write:$WRITE" echo "I/O wait:$IOWAIT" let i++ sleep 1 done echo "-------------------------" break ;; disk_use) echo "------------------" #硬盘利用率 DISK_TOTAL=`fdisk -l|awk ‘/dev\/sda/&& /^Disk.*字节/{print $2"GB"}‘` USE_RATE=`df |awk ‘/\/dev\/mapper/{print $5}‘` for i in $USE_RATE do flag=`awk -v num1="$i" -v num2=90% ‘BEGIN{print (num1<=num2)?"0":"1" }‘` if [ $flag -eq 1 ];then PART=`df -h|awk ‘{if(int($5)==‘‘‘$i‘‘‘) print $6}‘` echo "$PART=${i}%" fi done echo "Disk total:${DISK_TOTAL}" echo "Use rate:${USE_RATE}" echo "--------------------" break ;; disk_inode) echo "------------------" #硬盘inode利用率 USE_RATE=`df -i |awk ‘/\/dev\/mapper/{print $5}‘` for i in $USE_RATE do flag=`awk -v num1="$i" -v num2=90% ‘BEGIN{print (num1<=num2)?"0":"1" }‘` if [ $flag -eq 1 ];then PART=`df -h|awk ‘{if(int($5)==‘‘‘$i‘‘‘) print $6}‘` echo "$PART=${i}%" else echo "UseRate:"${USE_RATE} echo "Inode use rate no than 90% of the partition." fi done echo "------------------" break ;; mem_use) echo "------------------" MEM_TOTAL=`free -m|awk ‘{if(NR==2)printf"%.1f",$2/1024}END{print"G"}‘` USE=`free -m|awk ‘{if(NR==2)printf"%.1f",$3/1024}END{print"G"}‘` FREE=`free -m|awk ‘{if(NR==2)printf"%.1f",$4/1024}END{print"G"}‘` CACHE=`free -m|awk ‘{if(NR==2)printf"%.1f",$6/1024}END{print"G"}‘` echo "Total:${MEM_TOTAL}" echo "Use:${USE}" echo "Free:${FREE}" echo "Cache:${CACHE}" echo "------------------" break ;; tcp_status) #网络连接状态 echo "------------------" COUNT=`ss -ant|awk ‘!/State/{status[$1]++}END{for (i in status)print i,status[i]}‘` echo "Tcp connect status:\n$COUNT" echo "------------------" break ;; cpu_top10) #CPU占用率前10进程 echo "------------------" CPU=`ps -axu|awk ‘{if($3>0.1) print "PID: "$2" CPU: "$3"% --> "$NF"\n"}‘|sort -k4 -nr|head -10` num=0 for i in $CPU do echo -n "$i" let num++ if [ $num -eq 6 ];then echo let num=0 fi done echo "------------------" break ;; mem_top10) #内存占用前10进程 echo "------------------" MEM=`ps -axu|awk ‘{if($4>0.1){print "PID: "$2" Memory: "$4"% --> "$NF""}}‘|sort -k4 -nr|head -10` num=0 for i in $MEM do echo -n "$i" let num++ if [ $num -eq 6 ];then echo let num=0 fi done echo "------------------" break ;; traffic) #网络流量 while true do read -p "Input network cat name (ens[33/37]):" ens #判断是否存在 if [ `ifconfig |grep -c "\<$ens\>"` -eq 1 ];then break else echo "Input error,please input again." fi done echo "---------------------------" OLD_RX=`ifconfig ens33 |awk ‘{if(NR==5)print $5}‘` OLD_TX=`ifconfig ens33 |awk ‘{if(NR==7)print $5}‘` sleep 1 NEW_RX=`ifconfig ens33 |awk ‘{if(NR==5)print $5}‘` NEW_TX=`ifconfig ens33 |awk ‘{if(NR==7)print $5}‘` IN=`awk ‘BEGIN{printf "%.1f\n",‘$((${NEW_RX}-${OLD_RX}))‘/1024/1024}‘` OUT=`awk ‘BEGIN{printf "%.1f\n",‘$((${NEW_TX}-${OLD_TX}))‘/1024/1024}‘` echo "IN:${IN}MB/s OUT:${OUT}MB/s" echo "---------------------------" break ;; quit) exit ;; *) echo "---------------------------" echo "Input number" break echo "---------------------------" ;; esac done done
相关推荐
Yyqingmofeige 2020-08-18
Jieen 2020-06-18
CARBON 2020-05-18
yoshubom 2020-07-18
fendou00sd 2020-06-16
Zaratustra 2020-07-29
shelleymyl 2020-08-14
applecarelte 2020-06-04
zhushixia 2020-05-04
liujianhua 2020-04-22
Jieen 2020-04-18
伏雌摘星阁 2020-04-15
pimshell 2020-02-03
onetozero 2019-12-06
Sabrina 2019-12-08
SciRui 2019-12-02