str="Hello, World!"
echo ${#str} # 13 (长度)
echo ${str:7} # World! (从第7位截取)
echo ${str:0:5} # Hello (截取5个字符)
echo ${str/World/Linux} # Hello, Linux! (替换第一个)
echo ${str//l/L} # HeLLo, WorLd! (替换所有)
# 默认值
echo ${UNSET:-default} # default (变量未设置则用默认值)
echo ${EMPTY:=default} # default (变量为空则赋值)
echo ${MISSING:+set} # 空 (变量设置了则用替代值)
# 普通数组
fruits=("apple" "banana" "cherry")
echo ${fruits[0]} # apple
echo ${fruits[@]} # 所有元素
echo ${#fruits[@]} # 3 (元素个数)
echo ${!fruits[@]} # 0 1 2 (索引)
# 添加元素
fruits+=("date")
# 遍历
for f in "${fruits[@]}"; do
echo "水果: $f"
done
# 关联数组(Bash 4+)
declare -A config
config[host]="server1"
config[port]="8080"
echo ${config[host]} # server1
| 操作符 | 含义 |
|---|---|
| -f | 普通文件 |
| -d | 目录 |
| -e | 存在 |
| -r/-w/-x | 可读/写/执行 |
| -s | 大小>0 |
| -L | 符号链接 |
| 操作符 | 含义 |
|---|---|
| -z | 为空 |
| -n | 非空 |
| == | 相等 |
| != | 不等 |
| =~ | 正则匹配(仅[[ ]]) |
| 操作符 | 含义 |
|---|---|
| -eq | 等于 |
| -ne | 不等于 |
| -gt/-ge | 大于/大于等于 |
| -lt/-le | 小于/小于等于 |
# 基本if
if [[ -f /etc/passwd ]]; then
echo "文件存在"
fi
# if-else
if [[ $EUID -eq 0 ]]; then
echo "root用户"
else
echo "普通用户"
fi
# if-elif-else
if [[ $score -ge 90 ]]; then
echo "优秀"
elif [[ $score -ge 80 ]]; then
echo "良好"
elif [[ $score -ge 60 ]]; then
echo "及格"
else
echo "不及格"
fi
# 逻辑组合
if [[ -f "$file" ]] && [[ -r "$file" ]]; then
echo "文件存在且可读"
fi
case "$1" in
start) systemctl start "$SERVICE" ;;
stop) systemctl stop "$SERVICE" ;;
restart) systemctl restart "$SERVICE" ;;
status) systemctl status "$SERVICE" ;;
*) echo "用法: $0 {start|stop|restart|status}"; exit 1 ;;
esac
# 模式匹配
case "$ext" in
jpg|jpeg|png|gif) echo "图片" ;;
mp4|avi|mkv) echo "视频" ;;
*) echo "未知: $ext" ;;
esac
# 退出码约定
# 0: 成功 1: 一般错误 127: 命令未找到
# 128+N: 信号N导致退出
if [[ -z "$1" ]]; then
echo "需要参数" >&2
exit 1
fi
# 短路语法
mkdir -p /tmp/test && echo "成功" || echo "失败"
#!/bin/bash
# 解析 KEY=VALUE 格式配置文件
CONFIG="$1"
while IFS='=' read -r key value; do
[[ "$key" =~ ^[[:space:]]*# ]] && continue
[[ -z "$key" ]] && continue
key=$(echo "$key" | xargs)
value=$(echo "$value" | xargs)
declare -g "$key=$value"
echo "$key = $value"
done < "$CONFIG"
#!/bin/bash
# check-file.sh
target="$1"
[[ -z "$target" ]] && echo "用法: $0 <路径>" && exit 1
if [[ ! -e "$target" ]]; then
echo "不存在: $target"; exit 1
elif [[ -f "$target" ]]; then
echo "文件: $target"
elif [[ -d "$target" ]]; then
echo "目录: $target"
fi
[[ -r "$target" ]] && echo "可读"
[[ -w "$target" ]] && echo "可写"
[[ -x "$target" ]] && echo "可执行"
echo "大小: $(stat -c '%s' "$target") bytes"✅ 掌握变量与字符串操作
✅ 理解数组
✅ 掌握条件操作符
✅ 学会if/case分支
✅ 理解退出码
# 多条件组合
if [[ -f "$file" && -r "$file" && -s "$file" ]]; then
echo "文件存在、可读、非空"
fi
# 嵌套条件
if [[ $EUID -eq 0 ]]; then
if [[ -f /etc/shadow ]]; then
echo "root且shadow文件存在"
fi
fi
# 条件赋值
[[ -z "$PORT" ]] && PORT=8080
[[ -z "$HOST" ]] && HOST="localhost"
# 一次性判断多个
if [[ $status == "running" || $status == "active" ]]; then
echo "服务正常"
fi
# 需要shopt -s extglob
shopt -s extglob
# 删除所有.log和.tmp文件
rm -+(*.log|*.tmp)
# 匹配不是.conf的文件
ls !(*.conf)
# 匹配一个或多个数字
echo "${path/+([0-9])/NUM}"
# 匹配除v1 v2外的版本
case "$ver" in
v[!12]*) echo "新版本" ;;
esac
#!/bin/bash
while getopts "hvd:f:" opt; do
case $opt in
h) echo "Usage: $0 [-h] [-v] [-d dir] [-f file]"; exit 0 ;;
v) VERBOSE=1 ;;
d) DIR="$OPTARG" ;;
f) FILE="$OPTARG" ;;
:) echo "选项 -$OPTARG 需要参数" >&2; exit 1 ;;
\?) echo "无效选项: -$OPTARG" >&2; exit 1 ;;
esac
done
shift $((OPTIND - 1))
echo "DIR=$DIR FILE=$FILE VERBOSE=$VERBOSE"
echo "剩余参数: $@"
| 书名 | 作者 | 重点 |
|---|---|---|
| Linux命令行与Shell脚本编程大全 | Blum | Shell脚本全面覆盖 |
| UNIX/Linux系统管理技术手册 | Nemeth | 系统管理圣经 |
| Ansible: Up and Running | Lintner | Ansible实战 |
| 鸟哥的Linux私房菜 | 鸟哥 | 中文经典入门 |
| 认证 | 机构 | 级别 |
|---|---|---|
| LFCS | Linux Foundation | 基础系统管理 |
| LFCE | Linux Foundation | 高级系统工程师 |
| RHCSA | Red Hat | Red Hat管理员 |
| RHCE | Red Hat | Red Hat工程师 |
| CKA/CKAD | CNCF | Kubernetes管理员/开发者 |
# 文本处理速查
grep -E 'pattern' file # 扩展正则搜索
sed -i 's/old/new/g' file # 替换
awk '{print $1}' file # 提取列
sort | uniq -c | sort -rn # 频次统计
cut -d: -f1 file # 切列
tr 'A-Z' 'a-z' # 转小写
# 系统管理速查
systemctl status/start/stop/restart service
journalctl -u service -f # 跟踪日志
df -h / du -sh * # 磁盘使用
ps aux --sort=-%mem # 内存排序
ss -tlnp # 监听端口
iptables -L -n # 防火墙规则
crontab -e # 编辑定时任务
useradd -m -s /bin/bash user # 创建用户
# 网络诊断速查
ip addr / ip route # 网络配置
ping / traceroute # 连通测试
dig / nslookup # DNS查询
curl -I url # HTTP头检查
nc -zv host port # 端口测试
tcpdump -i eth0 port 80 # 抓包
$ [[ -f /etc/passwd ]] && echo "存在" || echo "不存在"
存在
$ [[ -d /tmp ]] && echo "是目录" || echo "不是"
是目录
$ test 5 -gt 3 && echo "5>3" || echo "5<=3"
5>3
$ id
uid=0(root) gid=0(root) groups=0(root)
#!/bin/bash
# safe-restart.sh - 安全重启服务
SERVICE="$1"
[[ -z "$SERVICE" ]] && echo "用法: $0 service_name" >&2 && exit 1
# 检查服务是否存在
if ! systemctl list-unit-files "$SERVICE.service" &>/dev/null; then
echo "服务不存在: $SERVICE" >&2; exit 1
fi
# 检查当前状态
if systemctl is-active "$SERVICE" &>/dev/null; then
echo "服务正在运行,准备重启..."
systemctl restart "$SERVICE"
sleep 2
if systemctl is-active "$SERVICE"; then
echo "✅ 重启成功"
else
echo "❌ 重启后服务未运行!" >&2; exit 1
fi
else
echo "服务未运行,尝试启动..."
systemctl start "$SERVICE"
if systemctl is-active "$SERVICE"; then
echo "✅ 启动成功"
else
echo "❌ 启动失败!" >&2; exit 1
fi
fi
#!/bin/bash
# safe-restart.sh
SERVICE="$1"
[[ -z "$SERVICE" ]] && echo "Usage: $0 service" >&2 && exit 1
if ! systemctl list-unit-files "$SERVICE.service" &>/dev/null; then
echo "服务不存在: $SERVICE" >&2; exit 1
fi
if systemctl is-active "$SERVICE" &>/dev/null; then
echo "重启 $SERVICE..."
systemctl restart "$SERVICE"
sleep 2
systemctl is-active "$SERVICE" && echo "OK" || echo "FAIL" >&2
else
systemctl start "$SERVICE"
systemctl is-active "$SERVICE" && echo "OK" || echo "FAIL" >&2
fi
在实际生产环境中,变量作用域与条件表达式是系统管理员必须深入掌握的核心能力。本节将探讨常见场景、最佳实践和避坑指南。
开发环境和生产环境的差异是脚本出错的常见原因。建议:
优化策略:
改善方法:
#!/bin/bash
# 变量作用域与条件表达式最佳实践模板
set -euo pipefail
# 1. 参数校验
[[ $# -lt 1 ]] && echo "Usage: $0 <arg>" >&2 && exit 1
# 2. 环境检查
require_cmd() {
command -v "$1" >/dev/null || { echo "需要: $1" >&2; exit 1; }
}
# 3. 清理机制
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
# 4. 日志记录
log() { echo "[$(date +%T)] $*"; }
err() { log "ERROR: $*" >&2; exit 1; }
# 5. 主逻辑
main() {
log "开始处理: $1"
# 业务逻辑
log "处理完成"
}
main "$@"