创建简单的管理脚本

ShellBeginner
立即练习

介绍

系统管理员经常会将重复性的检查工作转化为小型 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 风格管理任务中最有用的脚本编写模式。