作者:Chancel Yang, 创建:2024-07-22, 字数:6448, 已阅:307, 最后更新:2024-07-22
服务器上的备份脚本是好几年前写的,前段时间发现有一些小问题,正好趁这个机会重写一下顺便回顾以下Bash
语法
以下内容是从头搜集整理的Bash
语法基础,若有错误欢迎指出
shell是一种统称符合其语法规则语言的简称
shell是一个命令行解释器,为类Unix操作系统提供一个命令行用户界面
命令行用户界面也称之为Command Line Interface(
CLI
)
在计算机领域,shell通常代指Bash
是因为Bash在原始的shell(burne again shell,即SH
)程序上增强了许多功能,提供了现代操作系统的非常多基础设施如环境变量、进程管理等
所以通常说shell时都会代指Bash,除了Bash外,现在也有许多其他shell如Cshell、Kshell等
Linux发行版都支持sh以及bash环境,无需安装,下面是Bash语法入门
Bash
的语法简单,但毕竟是一门较老的语言了,在许多特点上是比较反直觉的,下面直接将一些语法点整理出来,以供参考
首先,Bash
的脚本一般有开头标记来告诉环境需要什么脚本解释器,linux下script大部分情况下都是由Bash解释器来执行的
编辑一个hello.sh
文件,内容如下:
#!/bin/Bash
echo "Hello World! "
赋予权限,并执行,你就可以得到一个输出:"Hello World"
chmod +x hello.sh
# 执行方法1. 使用指定解释器执行
/bin/Bash hello.sh
# 执行方法2. 因为文件开头已经写了执行器类型,直接调用(./指当前目录,如有不理解请自行搜索)
./hello.sh
编辑hello.sh
文件,内如如下:
#!/bin/Bash
# 变量声明
var_hello_str='Hello World!'
# 使用1. 不带花括号
echo $pick_hero
# 使用2. 带花括号(推荐写法)
echo ${pick_hero}
变量命名规则如下:
Bash保留关键字如下
类型 | 关键字 |
---|---|
判断 | if、then、else、elif、fi |
循环 | for、do、done、while、until、break、continue、in |
选择 | case、esac |
函数 | function、return、exit |
其他 | select、time、{}、[[]]、(())、! |
保留字相对比较多,更具体可以参考Bash手册
声明变量参考如下:
#!/bin/Bash
# 定义并设置只读变量,只读变量不能被重新定义或删除
readonly my_name="chancel"
# 拼接字符串
str01="hello"
str02="world"
echo "${str01} ${str02}" # 用空格拼接两个字符串
# 定义数组
myArray=("x" "y" "z")
echo "${myArray[0]}" #取出第一个元素
echo "${myArray[*]}" # 取出所有元素
echo "${myArray[@]}" # 取出所有元素
# 遍历数组
for var in "${myArray[@]}"; do
echo "$var"
done
# 遍历数组并打印索引和元素
for i in "${!myArray[@]}"; do
printf "%s\t%s\n" "$i" "${myArray[$i]}"
done
# 使用while循环遍历数组
i=0
while [ $i -lt ${#myArray[@]} ]; do
echo "${myArray[$i]}"
((i++))
done
在写脚本时传递参数是很常见的做法:
./demo.sh -name chancel
接收参数并声明为变量:
#!/bin/Bash -e
show_help() {
echo "$0 [-h|-?|--help] [--who me] [--why hhh]"
echo "-h|-?|--help 显示帮助"
echo "--who 输入你是谁"
}
while [[ $# -gt 0 ]]; do
case $1 in
-h | -\? | --help)
show_help
exit 0
;;
--who)
WHO="${2}"
shift
;;
*)
echo -e "Error: $0 invalid option '$1'\nTry '$0 --help' for more information.\n" >&2
exit -1
;;
esac
shift
done
使用效果
$ ./demo.sh -h
./demo.sh [-h|-?|--help] [--who me] [--why hhh]
-h|-?|--help 显示帮助
--who 输入你是谁
控制流程方法如下:
# if写法
if condition
then
command1
command2
...
commandN
fi
# if-else写法
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
参考示例:
#!/bin/Bash -e
x=100
y=200
if [ $x == $y]
then
echo "x = y"
elif [ $x -gt $y ]
then
echo "x > y"
else
echo "x < y"
Bash的运算符比较简单,拢共如下几个
参数 | 说明 |
---|---|
-eq | = |
-ne | != |
-gt | > |
-ge | >= |
-lt | =< |
-le | <= |
-z(字符串) | 字符串长度为零 |
-n(字符串) | 字符串长度不为零 |
运算符例子如下:
#!/bin/Bash
# 加减乘除运算
x=100
y=200
$z=$[x+y] #这语法有点奇怪,且实测等号两侧不可空格(写惯了c#可能很不习惯这种写法)
echo $z
# 字符串判断
x="hello"
y="hallo"
if test $x = $y
then
echo "字符串内容相同"
else
echo "字符串内容不同"
fi
除以上语法外,常见的语法还包括:
例子如下:
#!/bin/bash
# 定义一个函数
greet() {
printf "Hello, %s!\n" "$1"
}
# 输入输出重定向
ls > files.txt
# 调用函数并传递参数
greet "John"
# 判断文件是否存在
if [ -f "files.txt" ]; then
printf "文件files.txt存在\n"
else
printf "文件files.txt不存在\n"
fi
# 引入其他脚本文件
source helper.sh
# 调用引入的函数并传递参数
greet "Alice"
我的需求主要有以下2点
/opt
目录下的所有程序基于以上语法,可实现脚本如下:
#!/bin/bash
# author: chancel
# url: www.chancel.me
show_help() {
echo "$0 [-h|-?|--help] [--temp /tmp/_backup] [--target /opt/backup/] [--dbuser root] [--dbpasswd passwd] [--extra /opt]"
echo "-h|-?|--help 显示帮助"
echo "--temp 设置备份文件时的缓存目录"
echo "--target 设置备份文件的目标(存放)路径"
echo "--dbuser 设置mysql数据库用户名称"
echo "--dbpasswd 设置mysql数据库用户密码"
echo "--extra 额外需要备份的目录,以空格分开不同目录"
}
create_folders() {
echo "创建必要的文件夹"
mkdir -p "$mysql_backup_dir"
}
backup_mysql_databases() {
echo "备份mysql数据库"
databases=$(mysql -u"$dbuser" -p"$dbpasswd" -e "SHOW DATABASES;" | tr -d "| " | grep -v Database)
for db in $databases; do
if [[ "$db" != "sentry" ]] && [[ "$db" != "information_schema" ]] && [[ "$db" != "performance_schema" ]] && [[ "$db" != "mysql" ]] && [[ "$db" != _* ]]; then
echo "正在导出数据库$db"
mysqldump -u"$dbuser" -p"$dbpasswd" --databases "$db" > "$mysql_backup_dir/$(date +%Y%m%d)-$db.sql"
fi
done
}
delete_previous_backup() {
echo "正在删除上一次产生的备份包"
rm -f "$old_backup_file_path"
}
create_backup_file() {
echo "创建备份文件 $new_backup_file_path"
tar -zcvf "$new_backup_file_path" "$mysql_backup_dir" $extra
mv "$new_backup_file_path" "$target"
}
delete_temp_folder() {
echo "删除临时文件夹 $temp"
rm -rf "$temp"
echo "备份结束"
}
# 解析命令行参数
while [[ $# -gt 0 ]]; do
case $1 in
-h | -\? | --help)
show_help
exit 0
;;
--temp)
temp="$2"
shift
;;
--target)
target="$2"
shift
;;
--dbuser)
dbuser="$2"
shift
;;
--dbpasswd)
dbpasswd="$2"
shift
;;
--extra)
extra="$2"
shift
;;
--)
shift
break
;;
*)
echo -e "错误: $0 无效操作 '$1'\n可输入命令 '$0 --help' 获取更多帮助.\n" >&2
exit -1
;;
esac
shift
done
# 设置变量
mysql_backup_dir="$temp/mysql_backup"
new_backup_file_path="$temp/$(date +%Y%m%d).tar.gz"
old_backup_file_path="$target/$(date -d -1day +%Y%m%d).tar.gz"
# 执行备份操作
create_folders
backup_mysql_databases
delete_previous_backup
create_backup_file
delete_temp_folder
参考这份文档,根据需要可自定修改,你就可以快速得到一份备份脚本