Shell 脚本
→ 返回 Linux
基本结构
#!/bin/bash
# 第一行 shebang 指定解释器
set -euo pipefail # e=遇错退出 u=未定义变量报错 o pipefail=管道错误传递
echo "Hello, $1"chmod +x script.sh # 添加执行权限
./script.sh arg1 # 执行
bash script.sh arg1 # 直接用 bash 执行(无需执行权限)变量
name="Alice"
echo $name
echo "${name}!" # 花括号消除歧义
readonly MAX=100 # 只读变量
# 命令替换
today=$(date +%Y-%m-%d)
# 算术
count=5
echo $((count + 3))
((count++))特殊变量
| 变量 | 说明 |
|---|---|
$0 | 脚本名称 |
$1 ~ $9 | 位置参数 |
$# | 参数个数 |
$@ | 所有参数(各自独立) |
$? | 上条命令退出码(0 成功) |
$$ | 当前进程 PID |
$! | 最近后台进程 PID |
条件判断
if [ "$1" == "start" ]; then
echo "Starting..."
elif [ "$1" == "stop" ]; then
echo "Stopping..."
else
echo "Unknown command"
fi
# 文件测试
[ -f "/etc/nginx/nginx.conf" ] && echo "文件存在"
[ -d "/opt/app" ] && echo "目录存在"
# 数值比较(-eq -ne -gt -ge -lt -le)
[ $count -gt 10 ] && echo "大于10"
# 字符串
[ -z "$var" ] && echo "空字符串"
[ -n "$var" ] && echo "非空字符串"
# 多条件([[ ]] 支持 && ||)
[[ $age -ge 18 && $age -lt 60 ]] && echo "工作年龄"循环
# for 遍历列表
for file in /var/log/*.log; do
echo "Processing $file"
done
# for 数字范围
for i in {1..5}; do echo $i; done
for ((i=0; i<10; i++)); do echo $i; done
# while
count=0
while [ $count -lt 5 ]; do
echo $count
((count++))
done
# 逐行读取文件
while IFS= read -r line; do
echo "$line"
done < /etc/hosts
# until(条件为假时执行)
until ping -c1 host &>/dev/null; do
sleep 5
done函数
log() {
local level=$1
local msg=$2
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $msg"
}
log INFO "服务启动"
log ERROR "连接失败"
# 返回值(整数 0-255)
is_running() {
pgrep -x "$1" > /dev/null
return $?
}
is_running nginx && echo "nginx 运行中"
# 返回字符串:用 echo + 命令替换
get_version() { echo "1.0.0"; }
ver=$(get_version)错误处理
set -euo pipefail
# 退出时清理
trap 'rm -f /tmp/myapp.lock' EXIT
trap 'echo "中断"; exit 1' INT TERM
# 自定义 die 函数
die() {
echo "ERROR: $1" >&2
exit "${2:-1}"
}
[ -f "$config" ] || die "配置文件不存在: $config"字符串操作
str="Hello, World!"
echo ${#str} # 长度
echo ${str:7:5} # 截取:World
echo ${str/World/Linux} # 替换一次
echo ${str//l/L} # 全局替换
echo ${str,,} # 转小写
echo ${str^^} # 转大写
# 前缀 / 后缀删除
file="archive.tar.gz"
echo ${file%.gz} # archive.tar
echo ${file%%.*} # archive
echo ${file##*.} # gz数组
arr=("apple" "banana" "cherry")
echo ${arr[0]} # 第一个元素
echo ${arr[@]} # 所有元素
echo ${#arr[@]} # 元素个数
arr+=("date") # 追加
for item in "${arr[@]}"; do echo "$item"; done
# 关联数组
declare -A map
map["name"]="Alice"
map["age"]=30
echo ${map["name"]}实用片段
# 检查 root 权限
[ "$(id -u)" -ne 0 ] && echo "需要 root 权限" && exit 1
# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 加锁防并发
LOCK="/tmp/$(basename $0).lock"
exec 9>"$LOCK"
flock -n 9 || { echo "脚本已在运行"; exit 1; }
# 带超时等待服务就绪
timeout 30 bash -c 'until curl -sf http://localhost:8080/health; do sleep 1; done'