介绍
系统管理员经常会将重复性的检查工作转化为小型 Shell 脚本。RHCSA 风格的脚本编写并不在于编写大型程序,而在于如何安全地使用 Bash 来自动化常见任务、验证输入、遍历目标、返回有用的退出代码,并留下易于其他管理员理解的输出信息。
在本实验中,你将逐步构建一个目录摘要脚本。该脚本将接收目录路径,检查每个路径是否可用,收集基本的文件信息,编写可读的输出,并将相同的输出保存到日志文件中。
创建可执行脚本
在此步骤中,你将检查示例目录并创建管理脚本的第一个可执行版本。脚本应以 shebang 开头,以便系统知道使用哪个解释器。
进入项目目录。
cd /home/labex/project
检查示例目录树。find 命令用于列出文件和目录,sort 命令使输出顺序保持稳定。
find /home/labex/project/script-practice -maxdepth 2 -print | sort
创建 admin-summary.sh 的第一个版本。#!/bin/bash 这一行告诉 Linux 使用 Bash 运行该文件。set -u 选项使得脚本在引用未定义的变量时会报错,这有助于捕获许多拼写错误。
cat > /home/labex/project/admin-summary.sh <<'EOF'
#!/bin/bash
set -u
echo "RHCSA admin summary"
echo "RUN_AS=$(id -un)"
echo "HOST=$(hostname -s)"
EOF
使脚本具有可执行权限。如果没有执行权限,该文件仅为普通文本。
chmod 755 /home/labex/project/admin-summary.sh
运行脚本。
/home/labex/project/admin-summary.sh
你应该能看到脚本标题、当前用户以及简短的主机名。具体的主机名可能会有所不同。
接收目录参数
在此步骤中,你将添加位置参数。脚本使用 $# 来计算参数个数,并使用 "$@" 来表示所有按原样传递的参数。
将脚本替换为需要至少一个目录参数的版本。
cat > /home/labex/project/admin-summary.sh <<'EOF'
#!/bin/bash
set -u
if [ "$#" -eq 0 ]; then
echo "Usage: $0 DIRECTORY [DIRECTORY...]"
exit 2
fi
echo "RHCSA admin summary"
echo "RUN_AS=$(id -un)"
echo "HOST=$(hostname -s)"
for target in "$@"; do
echo "TARGET=$target"
done
EOF
保持脚本的可执行权限。
chmod 755 /home/labex/project/admin-summary.sh
在不带参数的情况下运行它。该命令应打印用法说明并返回退出状态 2。|| 运算符仅在左侧脚本失败时运行右侧命令,这让你能够有意地显示非零状态。
/home/labex/project/admin-summary.sh || echo "exit status: $?"
现在使用两个目录参数运行它。
/home/labex/project/admin-summary.sh /home/labex/project/script-practice/app /home/labex/project/script-practice/logs
输出应包含每个参数对应的 TARGET= 行。
测试每个目标并返回有用的状态
在此步骤中,你将为每个参数添加条件测试。测试 [ -d "$target" ] 仅在路径存在且为目录时才会成功。
将脚本替换为能够为目录报告 OK、为其他内容报告 MISSING 的版本。
cat > /home/labex/project/admin-summary.sh <<'EOF'
#!/bin/bash
set -u
if [ "$#" -eq 0 ]; then
echo "Usage: $0 DIRECTORY [DIRECTORY...]"
exit 2
fi
echo "RHCSA admin summary"
echo "RUN_AS=$(id -un)"
echo "HOST=$(hostname -s)"
exit_status=0
for target in "$@"; do
if [ -d "$target" ]; then
echo "OK $target"
else
echo "MISSING $target"
exit_status=1
fi
done
exit "$exit_status"
EOF
使用有效的目录运行脚本。最终的退出状态应为 0。
/home/labex/project/admin-summary.sh /home/labex/project/script-practice/app
echo "exit status: $?"
再次使用一个不存在的目录运行它。这一次脚本应打印 MISSING 并返回退出状态 1。
/home/labex/project/admin-summary.sh /home/labex/project/script-practice/missing || echo "exit status: $?"
收集实用的目录信息
在此步骤中,你将添加命令替换。命令替换会在 $() 内部运行命令,并将其输出存储在变量中。
将脚本替换为能够为每个有效目录报告文件数量、显示大小和所有者的版本。
cat > /home/labex/project/admin-summary.sh <<'EOF'
#!/bin/bash
set -u
if [ "$#" -eq 0 ]; then
echo "Usage: $0 DIRECTORY [DIRECTORY...]"
exit 2
fi
echo "RHCSA admin summary"
echo "RUN_AS=$(id -un)"
echo "HOST=$(hostname -s)"
exit_status=0
for target in "$@"; do
if [ -d "$target" ]; then
file_count="$(find "$target" -type f | wc -l)"
size="$(du -sh "$target" | awk '{print $1}')"
owner="$(stat -c '%U:%G' "$target")"
echo "OK $target FILES=$file_count SIZE=$size OWNER=$owner"
else
echo "MISSING $target"
exit_status=1
fi
done
exit "$exit_status"
EOF
针对三个准备好的目录运行脚本。
/home/labex/project/admin-summary.sh /home/labex/project/script-practice/app /home/labex/project/script-practice/logs /home/labex/project/script-practice/cache
app 目录应显示 FILES=3,logs 应显示 FILES=2,而 cache 应显示 FILES=1。
将输出保存到日志文件
在此步骤中,你将添加一个小的辅助函数和一个日志文件。函数可以避免代码重复,而 tee -a 可以在显示输出的同时将同一行追加到文件中。
将脚本替换为最终版本。
cat > /home/labex/project/admin-summary.sh <<'EOF'
#!/bin/bash
set -u
LOG="/home/labex/project/admin-summary.log"
: > "$LOG"
emit() {
echo "$*" | tee -a "$LOG"
}
if [ "$#" -eq 0 ]; then
emit "Usage: $0 DIRECTORY [DIRECTORY...]"
exit 2
fi
emit "RHCSA admin summary"
emit "RUN_AS=$(id -un)"
emit "HOST=$(hostname -s)"
exit_status=0
for target in "$@"; do
if [ -d "$target" ]; then
file_count="$(find "$target" -type f | wc -l)"
size="$(du -sh "$target" | awk '{print $1}')"
owner="$(stat -c '%U:%G' "$target")"
emit "OK $target FILES=$file_count SIZE=$size OWNER=$owner"
else
emit "MISSING $target"
exit_status=1
fi
done
exit "$exit_status"
EOF
使用两个有效目录和一个缺失目录运行最终脚本。
/home/labex/project/admin-summary.sh /home/labex/project/script-practice/app /home/labex/project/script-practice/logs /home/labex/project/script-practice/missing || echo "exit status: $?"
检查保存的日志。
sed -n '1,8p' /home/labex/project/admin-summary.log
终端输出和日志文件应包含相同的摘要行。由于有一个目标缺失,退出状态应为 1。
总结
你创建了一个实用的 Bash 管理脚本。你使用了 shebang、可执行权限、位置参数、参数计数、循环、目录测试、命令替换、显式退出状态、辅助函数以及日志文件。这些是小型 RHCSA 风格管理任务中最有用的脚本编写模式。


