【问答】Shell脚本编程20问:从基础到进阶

阿里云推广

Shell脚本编程高频问题20问

Shell脚本是运维自动化的核心工具。本文整理了最常见的问题和解决方案。

Q1: 如何安全地写Shell脚本?

A: 开头加上这三行:

#!/bin/bash
set -euo pipefail
# -e: 任何命令失败立即退出
# -u: 使用未定义变量报错
# -o pipefail: 管道中任一命令失败都算失败

Q2: 如何传递和处理参数?

#!/bin/bash
# 脚本名: backup.sh
# 用法: ./backup.sh /source /dest

SOURCE="$1"      # 第一个参数
DEST="$2"        # 第二个参数
shift 2          # 移走前两个参数
EXTRA=("$@")     # 剩余所有参数

# 参数检查
if [ $# -lt 2 ]; then
    echo "用法: $0 <源目录> <目标目录>"
    exit 1
fi

Q3: 如何读取用户输入?

# 简单读取
read -p "请输入用户名: " username
echo "你好, $username"

# 隐藏输入(密码)
read -s -p "请输入密码: " password
echo

# 带默认值
read -p "请输入端口 [默认8080]: " port
port=${port:-8080}

Q4: 如何进行条件判断?

# 字符串比较
if [ "$var" = "value" ]; then ... fi
if [ -z "$var" ]; then echo "变量为空"; fi  # -z 长度为0
if [ -n "$var" ]; then echo "变量非空"; fi  # -n 长度非0

# 数字比较
if [ "$num" -eq 10 ]; then ... fi  # 等于
if [ "$num" -gt 10 ]; then ... fi  # 大于
if [ "$num" -lt 10 ]; then ... fi  # 小于

# 文件判断
if [ -f "file.txt" ]; then ... fi   # 文件存在
if [ -d "directory" ]; then ... fi  # 目录存在
if [ -r "file.txt" ]; then ... fi   # 可读
if [ -w "file.txt" ]; then ... fi   # 可写
if [ -x "script.sh" ]; then ... fi  # 可执行

Q5: 如何写循环?

# for循环(列表)
for i in 1 2 3 4 5; do
    echo $i
done

# for循环(范围)
for i in {1..10}; do
    echo $i
done

# for循环(命令输出)
for file in $(ls *.txt); do
    echo "处理: $file"
done

# while循环
while IFS= read -r line; do
    echo "$line"
done < file.txt

# 无限循环
while true; do
    echo "运行中..."
    sleep 60
done

Q6: 如何定义函数?

# 定义函数
log() {
    local level="$1"    # local声明局部变量
    shift
    local message="$*"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message"
}

# 调用函数
log INFO "开始备份"
log ERROR "备份失败"

# 带返回值的函数
get_cpu_usage() {
    local usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}')
    echo "$usage"  # 用echo返回
}

cpu=$(get_cpu_usage)
echo "CPU使用率: $cpu%"

Q7: 如何处理错误?

# 检查命令返回值
if ! mkdir -p /backup/data; then
    echo "创建目录失败"
    exit 1
fi

# 或者简写
mkdir -p /backup/data || { echo "创建目录失败"; exit 1; }

# 使用trap捕获错误
trap 'echo "脚本在第 $LINENO 行出错"' ERR

# 清理函数
cleanup() {
    echo "清理临时文件..."
    rm -f /tmp/temp_*.txt
}
trap cleanup EXIT  # 脚本退出时执行清理

Q8: 如何操作字符串?

str="Hello World"

# 长度
${#str}  # 11

# 截取
${str:0:5}    # Hello(从0开始,取5个字符)
${str:6}      # World(从6开始到结尾)
${str: -5}    # World(最后5个字符,注意空格)

# 替换
${str/World/Bash}     # Hello Bash(第一个匹配)
${str//l/L}           # HeLLo WorLd(全部匹配)
${str/#Hello/Hi}      # Hi World(开头匹配)
${str/%World/Earth}   # Hello Earth(结尾匹配)

# 删除匹配
${str#Hello }    # World(删除最短匹配的前缀)
${str##*l}       # d(删除最长匹配的前缀)
${str% World}    # Hello(删除最短匹配的后缀)
${str%% *}       # Hello(删除最长匹配的后缀)

更多问题速查

  • Q9: 数组怎么用? → arr=(a b c); echo ${arr[0]}
  • Q10: 如何并发执行? → command & 后台执行
  • Q11: 如何等待所有后台任务? → wait
  • Q12: 如何重定向输出? → >覆盖 >>追加 2>&1合并错误
  • Q13: 如何读取配置文件? → source config.sh
  • Q14: 如何生成随机数? → $RANDOM
  • Q15: 如何获取脚本路径? → $(dirname "$0")
  • Q16: 如何调试脚本? → bash -x script.sh
  • Q17: 如何比较版本号? → sort -V
  • Q18: 如何发送HTTP请求? → curl 或 wget
  • Q19: 如何解析JSON? → jq工具
  • Q20: 如何发送邮件? → mail 或 sendmail

总结

Shell脚本的核心是熟练运用变量、条件、循环、函数。记住set -euo pipefail,养成良好的脚本编写习惯。

发表评论