📍 导航:返回目录 | 上一节:Python实战
#!/bin/bash
# 定义变量(等号两边不能有空格)
name="Alice"
age=30
# 使用变量
echo "Name: $name, Age: $age"
echo "Name: ${name}, Age: ${age}" # 推荐使用花括号
# 只读变量
readonly PI=3.14159
# 删除变量
unset name
# 环境变量
export PATH=/usr/local/bin:$PATH
# 特殊变量
# $0 脚本名称
# $1-$9 位置参数
# $# 参数个数
# $@ 所有参数
# $? 上一个命令的退出状态
# $$ 当前进程PID# if-else
if [ $age -gt 18 ]; then
echo "Adult"
elif [ $age -eq 18 ]; then
echo "Just 18"
else
echo "Minor"
fi
# 文件判断
if [ -f "file.txt" ]; then
echo "File exists"
fi
# 字符串判断
if [ "$str1" = "$str2" ]; then
echo "Equal"
fi
# 逻辑运算
if [ $a -gt 0 ] && [ $a -lt 10 ]; then
echo "0 < a < 10"
fi
# case 语句
case $1 in
start)
echo "Starting..."
;;
stop)
echo "Stopping..."
;;
restart)
echo "Restarting..."
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac常用判断符号:
| 符号 | 含义 |
|---|---|
| -eq | 等于 |
| -ne | 不等于 |
| -gt | 大于 |
| -lt | 小于 |
| -ge | 大于等于 |
| -le | 小于等于 |
| -f | 是否为文件 |
| -d | 是否为目录 |
| -e | 是否存在 |
| -r | 是否可读 |
| -w | 是否可写 |
| -x | 是否可执行 |
# for 循环
for i in 1 2 3 4 5; do
echo "Number: $i"
done
# for 循环(C风格)
for ((i=0; i<10; i++)); do
echo "i = $i"
done
# 遍历文件
for file in *.txt; do
echo "Processing $file"
done
# while 循环
count=0
while [ $count -lt 5 ]; do
echo "Count: $count"
((count++))
done
# until 循环
count=0
until [ $count -ge 5 ]; do
echo "Count: $count"
((count++))
done
# break 和 continue
for i in {1..10}; do
if [ $i -eq 5 ]; then
continue
fi
if [ $i -eq 8 ]; then
break
fi
echo $i
done# 定义函数
function greet() {
echo "Hello, $1!"
}
# 或简写为
greet() {
echo "Hello, $1!"
}
# 调用函数
greet "Alice"
# 返回值(0-255)
check_file() {
if [ -f "$1" ]; then
return 0
else
return 1
fi
}
# 使用返回值
if check_file "data.txt"; then
echo "File exists"
fi
# 函数返回字符串(通过 echo)
get_timestamp() {
echo $(date +%Y%m%d_%H%M%S)
}
timestamp=$(get_timestamp)
echo "Timestamp: $timestamp"# 定义数组
arr=(apple banana cherry)
# 访问元素
echo ${arr[0]} # apple
echo ${arr[1]} # banana
# 所有元素
echo ${arr[@]}
echo ${arr[*]}
# 数组长度
echo ${#arr[@]}
# 遍历数组
for fruit in "${arr[@]}"; do
echo $fruit
done
# 添加元素
arr+=(date)
# 关联数组(Bash 4.0+)
declare -A config
config[host]="localhost"
config[port]=8080
echo ${config[host]}
echo ${config[port]}str="Hello, World!"
# 字符串长度
echo ${#str} # 13
# 子串
echo ${str:0:5} # Hello
echo ${str:7} # World!
# 替换
echo ${str/World/Shell} # Hello, Shell!
echo ${str//o/0} # Hell0, W0rld! (全局替换)
# 删除
echo ${str#Hello} # , World! (删除前缀)
echo ${str%World!} # Hello, (删除后缀)
# 大小写转换
echo ${str^^} # HELLO, WORLD! (全部大写)
echo ${str,,} # hello, world! (全部小写)# 标准输出重定向
echo "hello" > output.txt # 覆盖
echo "world" >> output.txt # 追加
# 标准错误重定向
command 2> error.log
# 同时重定向标准输出和标准错误
command > output.log 2>&1
command &> output.log # 简写
# 管道
cat file.txt | grep "keyword" | wc -l
# Here Document
cat << EOF > config.txt
server {
listen 80;
server_name example.com;
}
EOF
# Here String
grep "keyword" <<< "$string"#!/bin/bash
set -e # 遇到错误立即退出
APP_NAME="myapp"
VERSION="1.0.0"
DEPLOY_DIR="/opt/app"
echo "=== 开始部署 $APP_NAME v$VERSION ==="
# 1. 备份旧版本
if [ -d "$DEPLOY_DIR" ]; then
echo "备份旧版本..."
mv $DEPLOY_DIR ${DEPLOY_DIR}_backup_$(date +%Y%m%d_%H%M%S)
fi
# 2. 创建目录
echo "创建部署目录..."
mkdir -p $DEPLOY_DIR
# 3. 解压文件
echo "解压应用..."
tar -xzf ${APP_NAME}-${VERSION}.tar.gz -C $DEPLOY_DIR
# 4. 安装依赖
echo "安装依赖..."
cd $DEPLOY_DIR
npm install --production
# 5. 启动服务
echo "启动服务..."
pm2 restart $APP_NAME || pm2 start app.js --name $APP_NAME
echo "=== 部署完成 ==="#!/bin/bash
LOG_DIR="/var/log/myapp"
MAX_DAYS=7
# 压缩旧日志
find $LOG_DIR -name "*.log" -mtime +1 -exec gzip {} \;
# 删除过期日志
find $LOG_DIR -name "*.gz" -mtime +$MAX_DAYS -delete
# 发送 HUP 信号,让进程重新打开日志文件
pkill -HUP myapp
echo "日志轮转完成"#!/bin/bash
# CPU 使用率
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
# 内存使用率
mem_usage=$(free | grep Mem | awk '{printf "%.2f", $3/$2 * 100}')
# 磁盘使用率
disk_usage=$(df -h / | tail -1 | awk '{print $5}' | cut -d'%' -f1)
# 告警阈值
CPU_THRESHOLD=80
MEM_THRESHOLD=85
DISK_THRESHOLD=90
# 检查并告警
if (( $(echo "$cpu_usage > $CPU_THRESHOLD" | bc -l) )); then
echo "ALERT: CPU 使用率过高: ${cpu_usage}%"
fi
if (( $(echo "$mem_usage > $MEM_THRESHOLD" | bc -l) )); then
echo "ALERT: 内存使用率过高: ${mem_usage}%"
fi
if [ $disk_usage -gt $DISK_THRESHOLD ]; then
echo "ALERT: 磁盘使用率过高: ${disk_usage}%"
fi#!/bin/bash
# 遇到错误立即退出
set -e
# 使用未定义变量时报错
set -u
# 管道命令任一失败即退出
set -o pipefail
# 组合使用
set -euo pipefail
# 调试模式
set -x#!/bin/bash
# 清理函数
cleanup() {
echo "清理临时文件..."
rm -f /tmp/temp_*
}
# 捕获退出信号
trap cleanup EXIT
# 捕获错误
trap 'echo "错误发生在第 $LINENO 行"' ERR
# 捕获中断(Ctrl+C)
trap 'echo "脚本被中断"; exit 1' INT
# 主逻辑
echo "执行任务..."
# ...#!/bin/bash
# 方式1:检查退出状态
if ! command; then
echo "命令执行失败"
exit 1
fi
# 方式2:使用 || 操作符
command || { echo "命令执行失败"; exit 1; }
# 方式3:捕获输出和错误
output=$(command 2>&1) || {
echo "错误信息: $output"
exit 1
}#!/bin/bash
#
# 脚本名称: deploy.sh
# 功能描述: 自动化部署脚本
# 作者: Alice
# 日期: 2024-01-01
#
set -euo pipefail
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查依赖
check_dependencies() {
local deps=("git" "docker" "kubectl")
for cmd in "${deps[@]}"; do
if ! command -v $cmd &> /dev/null; then
log_error "$cmd 未安装"
exit 1
fi
done
}
# 主函数
main() {
log_info "开始执行部署..."
check_dependencies
# 业务逻辑
log_info "部署完成"
}
# 执行主函数
main "$@"- 使用引号:防止空格和特殊字符问题
rm -rf "$dir" # 而不是 rm -rf $dir- 检查参数:
if [ $# -ne 2 ]; then
echo "Usage: $0 <arg1> <arg2>"
exit 1
fi- 使用绝对路径:
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)- 避免使用eval:存在注入风险
Shell 脚本是后台开发必备技能,用于自动化部署、系统监控、日志处理等场景。
关键要点:
- ✅ 掌握变量、条件、循环、函数基础语法
- ✅ 使用 set 和 trap 进行错误处理
- ✅ 熟悉管道、重定向等高级特性
- ✅ 编写可维护的脚本(注释、日志、错误处理)
- 《Linux Shell脚本攻略》
- ShellCheck - Shell 脚本静态分析工具
- Google Shell Style Guide
💡 思考题:
$@和$*有什么区别?set -e的作用是什么?什么时候需要用?- 如何在脚本中实现优雅的错误处理和清理?
⏮️ 上一节:Python实战 |
⏏️ 返回目录