Appearance
03|命令替换与退出码
上一篇用变量存了固定的值。但运维脚本里很多值是动态的——当前日期、磁盘使用率、某进程的 PID。这些值得先跑命令拿到,再存进变量。
把命令的输出存进变量,靠命令替换。判断命令成功没,靠退出码。本篇讲这两个。
一、命令替换
命令替换有两种写法:
bash
# 推荐写法
today=$(date +%F)
# 老写法(反引号)
today=`date +%F`两种效果一样,把 date +%F 的输出赋给 today。推荐用 $()——嵌套时清晰,反引号嵌套要转义很难读。
看实际用法:
bash
today=$(date +%F)
backup_dir="/data/backup/${today}"
echo "备份到: $backup_dir"
# 备份到: /data/backup/2026-06-23再比如拿到磁盘使用率做判断:
bash
usage=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
echo "根分区使用率: ${usage}%"命令替换里可以套管道,把一串处理结果存进变量。
二、命令替换里的引号
命令替换 $() 在双引号里会展开,在单引号里不展开:
bash
echo "今天是 $(date +%F)" # 双引号:展开
echo '今天是 $(date +%F)' # 单引号:原样输出text
今天是 2026-06-23
今天是 $(date +%F)要展开就用双引号。
三、退出码
每条命令执行完,Shell 都记一个退出码(exit code):0 表示成功,非 0 表示失败。退出码存在 $? 里:
bash
ls /etc/passwd
echo $? # 0,成功
ls /not-exist
echo $? # 2,失败不同的非 0 值代表不同失败原因,但日常用 0 和非 0 两种就够:0 成功,非 0 失败。
判断上一条命令成功没:
bash
mkdir /tmp/backup
if [ $? -eq 0 ]; then
echo "创建成功"
else
echo "创建失败"
exit 1
fi$? 要紧跟在命令后取——中间只要再跑一条命令(哪怕 echo),$? 就被覆盖了:
bash
mkdir /tmp/backup
echo "正在处理" # 这条命令会覆盖 $?
if [ $? -eq 0 ]; then # 这里的 $? 是 echo 的退出码,不是 mkdir 的更简洁的写法是直接用命令做条件,不存中间变量:
bash
if mkdir /tmp/backup; then
echo "创建成功"
fi四、&& 和 ||:逻辑运算符
&& 和 || 用退出码做短路逻辑,比 if 简洁:
bash
mkdir /tmp/backup && echo "创建成功"
mkdir /tmp/backup || echo "创建失败"命令A && 命令B:A 成功才执行 B命令A || 命令B:A 失败才执行 B
常见的"成功就继续、失败就退出"模式:
bash
mkdir /tmp/backup || { echo "创建失败"; exit 1; }注意 || 后面跟一组命令要加大括号 { },且大括号和命令间要有空格,最后要有分号。
另一个常见用法——给可能失败的命令一个默认值:
bash
# grep 没找到返回 1,用 || 让脚本不退出
result=$(grep "error" /var/log/messages) || result="没有错误记录"五、管道的退出码
管道默认只看最后一个命令的退出码:
bash
grep "error" /var/log/messages | head
echo $? # head 成功返回 0,即使 grep 没找到第 2 篇讲过,set -o pipefail 能让管道任一段失败都算失败。但要注意:grep 没匹配到返回 1 是预期行为,加了 pipefail 会让脚本退出。这种情况要 || true:
bash
set -euo pipefail
grep "error" /var/log/messages | head || true六、自定义退出码
脚本自己可以用 exit 返回退出码,让调用方判断:
bash
#!/usr/bin/env bash
set -euo pipefail
if [ ! -d /data ]; then
echo "错误: /data 不存在" >&2
exit 2 # 自定义失败码
fi
echo "检查通过"
exit 0 # 显式成功退出约定俗成的退出码:0 成功,1 一般失败,2 用法错误。具体数字不重要,重要的是脚本失败时返回非 0,让 &&、||、调用方、cron 能判断。
错误信息用 >&2 输出到 stderr,和正常输出分开:
bash
echo "错误: /data 不存在" >&2 # 进 stderr
echo "正常信息" # 进 stdout这样调用方可以 2>/dev/null 只看正常输出,或 2>error.log 单独存错误。
学会了之后
命令替换和退出码让脚本能动态取值、能判断成败、能根据成败决定下一步。$(date) 拿日期、$(pidof nginx) 拿 PID、$? 判断成败、&& || 做逻辑——这些是脚本从"一串命令"变成"有判断的程序"的基础。
下一篇讲位置参数——脚本怎么接收外部传进来的参数。