shell脚本编程 ②


目录

  • bash shell 配置文件
  • 流程控制 if 和 case
  • for 循环
  • while 循环
  • until 循环
  • continue
  • break
  • shift
  • while read
  • select
  • 函数

 bash shell 配置文件

按照bash shell的生效范围划分

1 全局配置:针对所有用户有效

  • /etc/profile
  • /etc/profile.d/*.sh
  • /etc/bashrc

2 个人配置:只对特定用户有效

  • ~/.bash_profile
  • ~/.bashrc

按照shell登录的两种方式分类

交互式登录,通过终端使用账号密码登录或者使用su - username切换的用户

交互式登录下,bash shell文件执行的顺序(命令在配置文件中位置不同,执行的顺序也不同)

# 命令放在放在每个配置文件最前面
/etc/profile
/etc/profile.d/*. sh
/etc/bashrc
~/ .bash_ profile
~/ .bashrc
/etc/bashrc

# 命令放在放在每个配置文件最后面
/etc/profile.d/*.sh
/etc/bashrc
/etc/profile
/etc/bashrc #此文件执行两次
~/.bashrc
~/.bash_profile

非交互式登录,如su username切换用户,图形界面下打开终端,执行脚本,执行顺序如下:

/etc/profile.d/*.sh
/etc/bashrc
~/.bashrc

按照bash shell配置文件的功能划分

  • profile类 为交互式登录的shell提供配置,功能在于定义环境变量,运行命令或脚本
  • bashrc类 为非交互式登录的shell提供配置,功能在于定义命令别名或函数,定义本地变量

bash  退出任务

bash 退出任务脚本是~/. bash_logout,在退出shell的时候,会执行这个脚本。主要功能是创建备份和清除临时文件

流程控制

if 流程控制

if 判断条件1;then
    条件为真执行代码
elif 判断条件2;then
    条件2为真执行代码
elif 判断条件3;then
    条件3为真执行代码
...
else
    以上条件都为假执行的分支代码
fi

例子:

#!/bin/bash
read -p "请输入你的身高(单位是M):" HIGH
echo $HIGH
if [[ ! "$HIGH" =~ ^[0-2](\.[0-9]{,2})?$ ]];then
    echo "输入错误"
    exit 1
fi
read -p "请输入你的体重(单位是kg)" WEIGHT
if [[ ! "$WEIGHT" =~ ^[0-9]{1,3}$ ]];then
    echo "输入错误"
    exit 1
fi
BMI=`echo $WEIGHT/$HIGH^2|bc`
if [ $BMI -le 18 ];then
    echo "太瘦了,多吃点"
elif [ $BMI -lt 24 ];then
    echo "身材很棒"
else
    echo "太胖了,注意节食"
fi

case流程控制

case 变量引用 in
PAT1)
    分支1
    ;;
PAT2)
    分支2
    ;;
...
*)
    默认分支
    ;;
esac

例子:

#!/bin/bash
echo -en "\E[$[RANDOM%7+31];1m"
cat << EOF
请选择:
1)备份数据库
2)清理日志
3)软件升级
4)软件回滚
5)删库跑路
EOF

echo -en "\E[0m"
read -p "请输入上边的数字1-5: " MENU
case $MENU in
1)
  echo "执行备份数据库"
  ;;
2)
  echo "清理日志"
  ;;
3)
  echo "软件升级"
  ;;
4)
  echo "软件回滚"
  ;;
5)
  echo "删库跑路"
  ;;
*)
  echo "输入错误"
esac

for循环

# 方式1
for 变量名 in 列表;do
    循环体
done

# 方式2
for 变量名 in 列表
do
     循环体
done

# 方式3
for (( for (( exp1; exp2; exp3 )); do COMMANDS; done

# 方式4
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
do
    循环体
done

例子:

for i in {1..10};do
useradd user$i
PASS=`cat /dev/urandom | tr -dc '[:alnum:]' |head -c12`
echo $PASS | passwd --stdin user$i &> /dev/null
echo user$i:$PASS >> /data/user.log
echo "user$i is created"
done

 九九乘法表

for i in {1..9};do
  for j in `seq $i`;do
    echo -e "\E[1;$[RANDOM%7+31]m${j}x${i}=$[j*i]\E[0m\t\c"
  done
  echo
done

 while循环

while COMMANDS; do COMMANDS; done
while CONDITION; do
  循环体
done

例1

sum=0
while ((i<=100));do
  let sum+=$i
  let i++
done
echo $sum

例2

WARNING=50
while true;do
  USE=`df | sed -rn '/^\/dev\/sd/s#.* ([0-9]+)%.*#\1#p' |sort -nr|head -n1`
  if [ $USE -gt $WARNING ];then
    echo disk will be full | mail -s "主机报警" 693007996@qq.com
  fi
  sleep 10
done

until循环

 until和while相似,不同的是until的进入条件是 until后接的条件结果是fasle

until COMMANDS; do COMMANDS; done
until CONDITION; do
  循环体
done

 循环控制语句continue

跳过本次循环,直接进入到下一次的循环

while CONDITION1; do
  CMD1
  ...
  if CONDITION2; then
    continue
  fi
  CMDn
  ...
done

 循环控制语句break

打断循环

while CONDITION1; do
  CMD1
  ...
  if CONDITION2; then
    break
  fi
  CMDn
  ...
done

shift

shitf [n] 用于将列表左移,默认左移一次。参量列表list一旦移动,最左端的那个参数就会从列表中删除。

while循环遍历位置参量列表时,经常会用到shift

举例:

#!/bin/bash
echo $*
shift
echo $*
shift
echo $*
shift
echo $*

#执行脚本传入多个参数,发现每一次shift都会删掉一个参数
if [ $# -eq 0 ];then
  echo "输入格式错误,必须有参数,参数为用户名"
  exit
fi

while [ "$1" ];do
  if id $1 &> /dev/null;then
    echo "用户 $1 已存在"  
  else 
    useradd $1
    echo "用户 $1 已经创建完成"
  fi
  shift
done
echo "所有用户已成功创建"

# 脚本后加要创建的用户名为参数,所有参数在一个列表,每次处理完一个用户shift,下一轮处理下一个参数

while read

while循环的特殊用法,遍历文件或文本的每一行做处理

举例:

while true;do
    WARNING=1
    df | sed -nr '/^\/dev\/sd/s/^([^ ]+) .*([0-9]+)%.*/\1 \2/p' | while read DEVICE USE;do
        if [ $USE -gt $WARNING ] ; then
            echo "$DEVICE的容量已经达到$USE"
        fi
    done
    sleep 5;
done

# 循环处理每一行

select菜单

select循环用于创建菜单,按照数字的顺序把列表内的元素显示在菜单项,并显示PS3提示符,等待用户输入

用户输入列表中的某个数字,执行对应的命令

用户输入被保存在内置变量REPLY中

select是一个无限循环,要用break或者exit 打断循环或退出循环

select经常和case使用

与for循环相似,如果不带 in list,则使用位置变量

select NAME [in WORDS ... ;] do COMMANDS; done

select variable in list ;do
    循环体命令
done

 举例:

#!/bin/bash
sum=0
PS3="请点菜(1-6): "
select MENU in 北京烤鸭 佛跳墙 小龙虾 羊蝎子 火锅 点菜结束;do
    case $REPLY in
        1)
            echo $MENU 价格是 100
            let sum+=100
            ;;
        2)
            echo $MENU 价格是 88
            let sum+=88
            ;;
        3)
            echo $MENU价格是 66
            let sum+=66
            ;;
        4)
            echo $MENU 价格是 166
            let sum+=166
            ;;
        5)
            echo $MENU 价格是 200
            let sum+=200
            ;;
        6)
            echo "点菜结束,退出"
            break
            ;;
        *)
            echo "点菜错误,重新选择"
            ;;
        esac
    done
echo "总价格是: $sum"
 

函数

定义函数

# 语法一:
func_name (){
...函数体...
}
# 语法二:
function func_name {
...函数体...
}
# 语法三:
function func_name () {
...函数体...
}

 查看函数

declare -F               # 查看当前已定义的函数名 

declare -f               # 查看当前已定义的函数定义

declare -f func_name     # 查看指定当前已定义的函数名

declare -F func_name     # 查看当前已定义的函数名定义

 删除函数

unset func_name

 在交互式环境下创建使用函数

[root@centos8 mnt]# get_version () {
> sed -nr "s/([a-z,A-Z]+) .* ([0-9]{1}).*/\1 \2/p" /etc/redhat-release
> }

[root@centos8 mnt]# get_version  # 直接函数名调用

 在脚本中定义使用函数

#!/bin/bash
hello(){
    echo "hello there today's date is `date "+%F %H:%M:%S"`"
}
echo "now going the function hello"
hello
echo "back from the function"