Создание простых административных скриптов

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.