Shell脚本实战:10个高频面试题解析与避坑指南(附完整代码)
最近几年,无论是面试Linux运维、SRE还是DevOps工程师,Shell脚本能力几乎成了必考项。我作为面试官,看过太多候选人因为一些看似基础实则暗藏玄机的脚本问题而失分。更常见的情况是,候选人能写出“能跑”的脚本,但代码里充满了潜在的“坑”,比如无法处理带空格的文件名、错误处理机制缺失,或者性能上存在明显短板。这篇文章,我想从一个面试官和一线工程师的双重角度,和你聊聊那些高频出现的Shell脚本面试题。我不会仅仅给你一个标准答案,而是会拆解每一道题背后的考察意图,指出常见的错误写法,并提供一个经过生产环境检验、更健壮、更优雅的解决方案。希望这些内容能帮你不仅通过面试,更能写出真正可靠的脚本。
1. 变量与字符串处理:从“能用”到“可靠”的跨越
变量操作是Shell脚本的基石,但很多开发者在这里就埋下了隐患。面试中,关于变量引用、字符串比较和参数传递的问题,往往是为了考察你对Shell执行模型的理解深度。
一个典型的初级错误是直接使用未加引号的变量进行文件操作。比如,面试官可能会让你写一个重命名脚本。你可能会写出这样的代码:
for file in *.txt; do
mv $file ${file%.txt}.log
done
这段代码在大多数情况下能工作,但一旦遇到名为 my file.txt 的文件,就会彻底失败。因为 $file 展开后变成了两个词 my 和 file.txt,mv 命令会接收到错误的参数数量。正确的做法是始终用双引号包裹变量引用,尤其是在路径和文件名操作中:
for file in *.txt; do
mv "$file" "${file%.txt}.log"
done
这里有个更隐蔽的坑:如果当前目录没有 .txt 文件,*.txt 会保持原样,for 循环会执行一次,file 的值就是字面量的 *.txt。为了避免这种情况,可以设置 nullglob 选项:
shopt -s nullglob
for file in *.txt; do
mv "$file" "${file%.txt}.log"
done
关于字符串比较,很多人习惯使用 =,但在 [ ] 测试中,等号两边必须留有空格。更推荐使用双中括号 [[ ]],它在Bash中更安全,能自动处理变量中的空格,并且支持正则匹配:
# 传统写法,容易因空格出错
if [ "$name" = "John" ]; then
echo "Hello John"
fi
# 更健壮的现代写法
if [[ $name == "John" ]]; then
echo "Hello John"
fi
# 使用正则表达式匹配
if [[ $filename =~ \.txt$ ]]; then
echo "这是一个文本文件"
fi
注意:
[[ ]]是Bash的扩展语法,虽然现在绝大多数环境都支持,但如果你需要编写高度可移植的、符合POSIX标准的脚本,仍需使用[ ]。
下表总结了变量处理中的关键要点和常见陷阱:
| 场景 | 危险写法 | 安全写法 | 原因解析 |
|---|---|---|---|
| 文件操作 | rm $file |
rm "$file" |
防止单词拆分,正确处理带空格的文件名 |
| 字符串比较 | [ $var = "test" ] |
[[ $var == "test" ]] |
避免变量为空时报语法错误,更清晰的语法 |
| 命令替换 | `cmd` |
$(cmd) |
更好的嵌套支持,更易读 |
| 默认值设置 | echo $name |
echo ${name:-"Guest"} |
提供变量未定义时的默认值,防止空输出 |
| 数组迭代 | for i in ${array[@]} |
for i in "${array[@]}" |
保留数组元素中的空格 |
2. 条件判断与流程控制:避免逻辑漏洞
条件判断是脚本逻辑的核心,但 if、case 语句中的细节常常被忽略。面试官让你写一个判断文件是否存在的脚本,可能是在考察你对测试运算符的熟悉程度,以及是否考虑到了边缘情况。
先看一个看似正确但有问题的基础示例:
if [ -f $FILE_PATH ]; then
echo "文件存在"
else
echo "文件不存在"
fi
如果 FILE_PATH 变量未设置或为空,这个测试会变成 [ -f ],这会被解释为测试 -f 这个字符串是否非空,结果永远为真!正确的做法是:
if [[ -n "$FILE_PATH" ]] && [[ -f "$FILE_PATH" ]]; then
echo "文件存在且路径有效"
else
echo "文件不存在或路径为空"
fi
对于数值比较,新手常犯的错误是使用数学比较符 >、< 而不是 -gt、-lt。在单中括号 [ ] 中,前者表示重定向,会导致语法错误:
count=10
# 错误写法:会被解释为重定向
if [ $count > 5 ]; then
echo "大于5"
fi
# 正确写法
if [ $count -gt 5 ]; then
echo "大于5"
fi
# 双括号中的数学比较(推荐用于数值)
if (( count > 5 )); then
echo "大于5"
fi
case 语句在匹配模式时非常高效,比一连串的 if-elif 更清晰。但要注意它的匹配模式是通配符风格,不是正则表达式:
read -p "输入操作 (start/stop/restart/status): " action
case $action in
start|s)
echo "启动服务..."
# 启动命令
;;
stop|p)
echo "停止服务..."
# 停止命令
;;

479

被折叠的 条评论
为什么被折叠?



