Shell变量处理大全:这是我踩过的坑

  • 约866字
  • 技术
  • 2026年4月16日

你有没有遇到过这种情况:本地测试正常的脚本,一到服务器上就报错?

去年帮同事排查一个凌晨失败的定时任务,光定位问题就花了2小时。最后发现是一个变量未定义的细节导致的。这类问题不算复杂,但足以让人深夜抓狂。

变量未定义:默认值的正确写法

最常见的坑是变量为空时导致脚本失败:

#!/bin/bash
# 错误写法
echo "用户名是: $username"

如果username变量未定义,脚本可能会输出空值,或者在后续操作中报错。

正确做法是使用默认值:

#!/bin/bash
# 正确写法:使用 ${var:-default}
echo "用户名是: ${username:-root}"
# 或者使用 := 赋值
${db_host:='localhost'}

这里的区别是:-只负责默认值输出,=则会实际赋值。

引号陷阱:空格不是你想的那样

看这个例子:

#!/bin/bash
files="a.txt b.txt c.txt"
# 错误写法
for f in $files; do
    echo $f
done

输出会是三行,但每次循环处理的是a.txtb.txtc.txt三个独立的词,而不是一个包含空格的文件名。

正确做法:

#!/bin/bash
files="a.txt b.txt c.txt"
# 加引号
for f in "$files"; do
    echo "$f"
done
# 或者用数组
arr=(a.txt "b file.txt" c.txt)
for f in "${arr[@]}"; do
    echo "$f"
done

引号是Shell的生命线——宁可多写一对,不要少写一个。

命令结果赋值:容易被忽略的细节

把命令输出存到变量时,也容易出错:

#!/bin/bash
# 错误写法
current_date=`date +%Y-%m-%d`
# 或者
current_date=$(date +%Y-%m-%d)

这两种写法在简单场景下没问题,但如果命令输出包含空格,就会出问题:

#!/bin/bash
# 错误:输出多行时会被拆开
result=$(ls -la)
# 正确:保留换行
result="$(ls -la)"

更安全的做法是用数组或逐行处理:

#!/bin/bash
while IFS= read -r line; do
    echo "Line: $line"
done < <(ls -la)

变量作用域:local不是摆设

函数里变量全局污染是另一个常见问题:

#!/bin/bash
name="global"

set_name() {
    name="modified"
    echo "函数内: $name"
}

set_name
echo "函数外: $name"  # 输出 modified

正确做法:

#!/bin/bash
name="global"

set_name() {
    local name="local"
    echo "函数内: $name"
}

set_name
echo "函数外: $name"  # 输出 global

local关键字把变量限定在函数内部,避免意外修改全局状态。

总结

Shell变量这4个坑,踩一个就影响一片:

  1. 变量未定义——用${var:-default}设置默认值
  2. 引号丢失——凡是变量引用都加引号
  3. 命令输出——用双引号包住命令替换结果
  4. 作用域——函数内用local

这些问题单个都不难,但组合在一起足以让人debug到怀疑人生。我的经验是:写Shell脚本时宁可"冗余"一点,多写引号和默认值检查,也不要侥幸跳过。

相关文章

为什么你的Redis总崩?5个血泪教训

Redis缓存加了但还是慢?雪崩、击穿、穿透……这些问题我全踩过。本文总结5个真实踩坑场景,给出可落地的解决方案,帮助开发者避免缓存失效导致的系统崩溃。

查看更多

5个 Terminal 高效操作

每天在命令行敲相同指令?本文整理5个被忽视但超实用的Terminal操作,包含具体命令和配置步骤,让你的命令行效率翻倍。

查看更多

AI 应用开发入门工具简介

随着ChatGPT的出现,各种 AI 工具层出不穷。本文介绍了 LangChain、dify 和 Coze 三款热门 AI 开发工具,详细分析了它们的特点和应用场景,帮助开发者快速搭建高效的 AI 应用。

查看更多