title: shell技巧 #标题tags: shell #标签
categories: shell # 分类
date: 2021-02-09

用于记录下提高shell脚本逼格的指令。

shell变量状态赋值

  • ${VAR:-string} 如果VAR变量为空则返回string
  • ${VAR:+string} 如果VAR变量不为空则返回string
  • ${VAR:=string} 如果VAR变量为空则重新赋值VAR变量值为string
  • ${VAR:?string} 如果VAR变量为空则将string输出到stderr

getopts使用

  1. [root@mysql nginx]# vim test.sh #脚本内容如下
  2. #!/usr/bin/env bash
  3. while getopts ":h:p:" optname;do
  4. case "$optname" in
  5. "h")
  6. host_ip=$OPTARG
  7. ;;
  8. "p")
  9. host_port=$OPTARG
  10. ;;
  11. "?" )
  12. echo "不知道此选项"
  13. ;;
  14. esac
  15. done
  16. echo "IP是${host_ip},端口是${host_port}"
  17. #执行效果如下
  18. [root@mysql nginx]# sh test.sh -h 192.168.20.2 -p 3306
  19. IP192.168.20.2,端口是3306
  20. [root@mysql nginx]# sh test.sh -p 22 -h 192.168.20.3
  21. IP192.168.20.3,端口是22

h2标记

  1. $ cat a.sh # 脚本内容如下
  2. #!/usr/bin/env bash
  3. item=1 # 定义初始值
  4. h2() {
  5. printf "\n${underline}${bold}${white}%s${reset}\n" "$@"
  6. }
  7. # 定义h2函数,以便下面调用
  8. h2 "[Step $item]: 第一阶段..."; let item+=1
  9. echo one
  10. h2 "[Step $item]: 第二阶段..."; let item+=1
  11. echo two
  12. h2 "[Step $item]: 第三阶段..."; let item+=1
  13. echo three

执行效果如下:

shell技巧 - 图1

使用数组

  1. #!/usr/bin/env bash
  2. set -e
  3. yum_list=(
  4. gcc
  5. gcc-c++
  6. autoconf
  7. automake
  8. pcre
  9. pcre-devel
  10. openssl
  11. openssl-devel
  12. patch
  13. net-tools
  14. )
  15. for i in ${yum_list[@]}
  16. do
  17. yum install --downloadonly --downloaddir=/tmp/rpm/${i}/ ${i}
  18. done
  19. # @表示调用数组中的所有元素
  20. # 若要调用数组中的某个元素,使用以下指令:
  21. echo ${yum_list[-3]}
  22. echo ${yum_list[3]}
  23. # 注:正向是从 0 开始,倒向是从-1开始。

获取当前脚本路径

  1. cur_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

shell脚本固定格式

  1. #!/usr/bin/env bash
  2. << COMMENT
  3. Author : 吕建钊
  4. Date : 2020-07-31
  5. Email : lvjianzhao@aspirecn.com
  6. COMMENT
  7. set -e
  8. item=1
  9. h2() {
  10. printf "\n${underline}${bold}${white}%s${reset}\n" "$@"
  11. }
  12. cur_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
  13. cur_date=$(date +%F_%H%M)
  14. cd ${cur_dir}
  15. h2 "[Step $item]: 第一阶段..."; let item+=1
  16. # 依据实际情况来定,是否需要root执行此脚本
  17. if [[ ${USER} != root ]];then
  18. echo -e "\033[31m
  19. 此脚本必须使用 root 执行
  20. 当前用户为 ${USER}
  21. 正在退出脚本...
  22. \033[0m"
  23. sleep 1 && exit 1
  24. fi
  25. h2 "[Step $item]: 第二阶段..."; let item+=1
  26. echo two
  27. h2 "[Step $item]: 第三阶段..."; let item+=1
  28. echo three
  29. ......................
  30. echo -e "\033[33m
  31. 结束提示语!!!
  32. \033[0m"

tr指令

  1. free -h | grep -i mem | tr -s " "| cut -d " " -f7
  2. 1.5G
  3. # tr -s : 将多个连续的字符合并为一个。

控制分隔符—— IFS

shell中默认以空格为分隔符,有时需要改变它,示例如下:

  1. $ OLD_IFS=${IFS} # 先备份当前分隔符
  2. $ IFS=":" # 更改默认分隔符为冒号
  3. $ read -p "请输入3个数据: " x y z
  4. 请输入3个数据: a:b:c
  5. [12::root@lv::~]# >>$ echo $x
  6. a
  7. [13::root@lv::~]# >>$ echo $y
  8. b
  9. [14::root@lv::~]# >>$ echo $z
  10. c

中断与退出控制

  • continue:用于结束此次循环,也可以continue后面加 数字,指定跳出几次循环(默认为1)。
  • break:用于结束整个循环体,后面可以指定数字,来控制跳出几层循环(默认为1)。
  • exit:用于退出整个脚本,后面可以追加数字,但这个数字定义的是退出状态码。

文件属性判断与比较

操作符 功能
-e file 判断文件或目录是否存在,存在返回true,反之为false
-f file 判断存在且为普通文件
-d file 判断存在且为目录
-b file 判断存在且为块设备文件,如磁盘、U盘等
-c file 判断存在且为字符设备文件,如键盘、鼠标等
-L file 判断存在且为软链接文件
-r file 判断存在且当前用户有可读权限
-w file 判断存在且当前用户有可写权限
-x file 判断存在且当前用户有可执行权限
-s file 判断文件是否存在并且文件大小非空
file1 -ef file2 两个文件使用相同设备、相同inode编号,则返回true,否则返回false
file1 -nt file2 file1 比file2 更新时返回true,或者file1存在而file2不存在则返回真
file1 -ot file2 file1 比file2 更旧时返回true,或者file2存在而file1不存在则返回真

记录脚本执行时长

  1. #!/usr/bin/env bash
  2. starttime=$(date +'%Y-%m-%d %H:%M:%S')
  3. # .........命令体
  4. endtime=$(date +'%Y-%m-%d %H:%M:%S')
  5. start_seconds=$(date --date="$starttime" +%s);
  6. end_seconds=$(date --date="$endtime" +%s);
  7. echo "${log_path} 目录下的日志已排查完成,共耗时"$((end_seconds-start_seconds))"s" > /tmp/log_delete.log

创建菜单

使用select实现:

  1. #!/usr/bin/env bash
  2. # Description: 根据用户选择的菜单实现对应的功能
  3. echo "请根据提示选择您的操作: "
  4. select item in "CPU" "IP" "MEM" "exit"
  5. do
  6. case $item in
  7. "CPU")
  8. uptime;;
  9. "IP")
  10. ip a s;;
  11. "MEM")
  12. free -h;;
  13. "exit")
  14. exit;;
  15. *)
  16. echo "error";;
  17. esac
  18. done

使用while实现:

  1. function install_menu() {
  2. while true
  3. do
  4. cd ${cur_dir}
  5. echo ""
  6. echo -e "\e[1;36m [ Deployment Menu ] \e[0m"
  7. echo -e "\e[1;34m ------------------------------ \e[0m"
  8. echo -e "\e[1;32m 1) Deployment Nginx \e[0m"
  9. echo ""
  10. echo -e "\e[1;34m 2) Deployment Redis \e[0m"
  11. echo ""
  12. echo -e "\e[1;33m 3) Deployment MySQL \e[0m"
  13. echo ""
  14. echo -e "\e[1;35m q) Quit Deployment Task \e[0m"
  15. echo -e "\e[1;34m ------------------------------ \e[0m"
  16. echo ""
  17. read -p "$view_name" var
  18. echo ""
  19. case $var in
  20. 1)
  21. echo -e "\e[1;33mStart Deployment Nginx \e[0m"
  22. tar zxf install_nginx-1.18.0.tgz && cd nginx_install
  23. chmod +x install_nginx.sh && ./install_nginx.sh
  24. echo -e "\e[1;32mDeployment Complete Nginx \e[0m"
  25. ;;
  26. 2)
  27. echo -e "\e[1;33mStart Deployment Redis \e[0m"
  28. tar zxf install_redis-5.0.5.tgz && cd install_redis-5.0.5
  29. chmod +x install.sh && ./install.sh
  30. echo -e "\e[1;32mDeployment Complete Redis \e[0m"
  31. ;;
  32. 3)
  33. echo -e "\e[1;33mStart Deployment Mysql \e[0m"
  34. tar zxf install_mysql-5.7.31.tgz && cd install_mysql-5.7.31
  35. chmod +x install.sh && ./install.sh
  36. echo -e "\e[1;32mDeployment Complete Mysql \e[0m"
  37. ;;
  38. q )
  39. echo -e "\e[1;32m ------------------------ \e[0m"
  40. echo -e "\e[1;32m | Quit Deployment Task | \e[0m"
  41. echo -e "\e[1;32m ------------------------ \e[0m"
  42. echo ""
  43. exit 0
  44. ;;
  45. * )
  46. echo -e "\e[1;31m ********************************** \e[0m"
  47. echo -e "\e[1;31m * Input Error,Please try again * \e[0m"
  48. echo -e "\e[1;31m ********************************** \e[0m"
  49. ;;
  50. esac
  51. done
  52. }
  53. clear
  54. install_menu