#!/bin/bash # Цвета и стили RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' WHITE='\033[1;37m' NC='\033[0m' # No Color BOLD='\033[1m' # Функция для создания прогресс-бара create_progress_bar() { local used_percent=$1 local bar_length=50 local filled=$(echo "scale=0; $used_percent * $bar_length / 100" | bc 2>/dev/null || echo "0") local empty=$((bar_length - filled)) # Ограничиваем значения if [ $filled -gt $bar_length ]; then filled=$bar_length; fi if [ $empty -lt 0 ]; then empty=0; fi printf "[" printf "${RED}%*s${NC}" $filled | tr ' ' '=' printf "${GREEN}%*s${NC}" $empty | tr ' ' '=' printf "]" } # ОДНОКРАТНЫЙ СБОР ВСЕХ ДАННЫХ echo -e "${YELLOW}Сбор информации о системе...${NC}" # Uptime uptime_full=$(uptime) # Информация о памяти (один раз) mem_info=$(free -b | grep "^Mem:") swap_info=$(free -b | grep "^Swap:") # Информация о дисках (один раз) disk_info=$(df -h 2>/dev/null) # Информация о процессах (один раз) process_data=$(ps aux --no-headers 2>/dev/null) # Информация о сети и ошибках (один раз) if command -v ss &> /dev/null; then port_info=$(ss -tulpn 2>/dev/null) fi net_dev_info=$(cat /proc/net/dev 2>/dev/null) # Информация о нагрузке CPU (iowait и другие метрики) if command -v mpstat &> /dev/null; then mpstat_info=$(mpstat 1 1 2>/dev/null | tail -1) else # Fallback на чтение из /proc/stat cpu_stats=$(cat /proc/stat 2>/dev/null | grep "^cpu " | head -1) fi # Информация о дисковом вводе-выводе if command -v iostat &> /dev/null; then iostat_info=$(iostat -x 1 2 2>/dev/null | grep -A 100 "Device" | tail -n +3) fi # Информация о системных ограничениях if [ -f /proc/sys/fs/file-nr ]; then file_handles=$(cat /proc/sys/fs/file-nr 2>/dev/null) fi # Информация о загрузке системы load_avg=$(echo "$uptime_full" | awk -F'load average:' '{print $2}' | sed 's/^[ \t]*//') load_1min=$(echo $load_avg | awk -F',' '{print $1}' | tr -d ' ') # Количество CPU cpu_count=$(nproc) echo -e "${GREEN}✓ Данные собраны${NC}\n" # Парсим uptime if [[ $uptime_full =~ up\ (.*),\ *([0-9]+)\ users?,\ *load\ average:\ (.*) ]]; then current_time=$(echo "$uptime_full" | awk '{print $1}') uptime_part="${BASH_REMATCH[1]}" users="${BASH_REMATCH[2]}" elif [[ $uptime_full =~ up\ (.*),\ *load\ average:\ (.*) ]]; then current_time=$(echo "$uptime_full" | awk '{print $1}') uptime_part=$(echo "$uptime_full" | sed -n 's/.*up \(.*\),.*load.*/\1/p') users=$(who | wc -l) else current_time=$(date +"%H:%M:%S") uptime_part=$(echo "$uptime_full" | awk -F'up ' '{print $2}' | awk -F',' '{print $1}') users=$(who | wc -l) fi uptime_part=$(echo "$uptime_part" | sed 's/^[ \t]*//;s/[ \t]*$//') # Парсим память mem_total=$(echo "$mem_info" | awk '{print $2}') mem_used=$(echo "$mem_info" | awk '{print $3}') mem_available=$(echo "$mem_info" | awk '{print $7}') mem_percent=$(echo "scale=0; $mem_used * 100 / $mem_total" | bc 2>/dev/null || echo "0") swap_total=$(echo "$swap_info" | awk '{print $2}') swap_used=$(echo "$swap_info" | awk '{print $3}') if [ $swap_total -gt 0 ]; then swap_percent=$(echo "scale=0; $swap_used * 100 / $swap_total" | bc 2>/dev/null || echo "0") else swap_percent=0 fi # Форматируем для вывода mem_total_h=$(numfmt --to=iec --suffix=B $mem_total 2>/dev/null || echo "${mem_total}KB") mem_used_h=$(numfmt --to=iec --suffix=B $mem_used 2>/dev/null || echo "${mem_used}KB") mem_available_h=$(numfmt --to=iec --suffix=B $mem_available 2>/dev/null || echo "${mem_available}KB") if [ $swap_total -gt 0 ]; then swap_total_h=$(numfmt --to=iec --suffix=B $swap_total 2>/dev/null || echo "${swap_total}KB") swap_used_h=$(numfmt --to=iec --suffix=B $swap_used 2>/dev/null || echo "${swap_used}KB") swap_free_h=$(numfmt --to=iec --suffix=B $((swap_total - swap_used)) 2>/dev/null || echo "$((swap_total - swap_used))KB") fi # Анализируем iowait из mpstat или /proc/stat iowait_value=0 if [ -n "$mpstat_info" ]; then iowait_value=$(echo "$mpstat_info" | awk '{print $6}') elif [ -n "$cpu_stats" ]; then # Парсим /proc/stat для получения iowait user=$(echo $cpu_stats | awk '{print $2}') nice=$(echo $cpu_stats | awk '{print $3}') system=$(echo $cpu_stats | awk '{print $4}') idle=$(echo $cpu_stats | awk '{print $5}') iowait=$(echo $cpu_stats | awk '{print $6}') irq=$(echo $cpu_stats | awk '{print $7}') softirq=$(echo $cpu_stats | awk '{print $8}') total=$((user + nice + system + idle + iowait + irq + softirq)) iowait_value=$(echo "scale=2; $iowait * 100 / $total" | bc 2>/dev/null || echo "0") fi # Анализируем ошибки на интерфейсах declare -A interface_errors if [ -n "$net_dev_info" ]; then while read line; do if [[ $line =~ ^[[:space:]]*([a-zA-Z0-9]+): ]]; then interface="${BASH_REMATCH[1]}" # Пропускаем loopback if [ "$interface" = "lo" ]; then continue; fi # Получаем ошибки при приеме и передаче receive_errors=$(echo $line | awk '{print $4}') transmit_errors=$(echo $line | awk '{print $12}') receive_drops=$(echo $line | awk '{print $5}') transmit_drops=$(echo $line | awk '{print $13}') total_errors=$((receive_errors + transmit_errors + receive_drops + transmit_drops)) if [ $total_errors -gt 0 ]; then interface_errors[$interface]="$receive_errors,$transmit_errors,$receive_drops,$transmit_drops" fi fi done <<< "$net_dev_info" fi # Анализируем дисковый ввод-вывод high_iowait_disks=() if [ -n "$iostat_info" ]; then while read line; do if [[ $line =~ ^([a-zA-Z0-9]+) ]]; then device="${BASH_REMATCH[1]}" util=$(echo $line | awk '{print $NF}') if (( $(echo "$util > 80" | bc -l 2>/dev/null) )); then high_iowait_disks+=("$device ($util%)") fi fi done <<< "$iostat_info" fi # Анализируем файловые дескрипторы file_handles_warning=0 if [ -n "$file_handles" ]; then allocated=$(echo $file_handles | awk '{print $1}') maximum=$(echo $file_handles | awk '{print $3}') if [ $maximum -gt 0 ]; then file_handle_percent=$(echo "scale=0; $allocated * 100 / $maximum" | bc 2>/dev/null || echo "0") if [ $file_handle_percent -gt 80 ]; then file_handles_warning=1 fi fi fi # ВЫВОД ИНФОРМАЦИИ echo -e "${BOLD}${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" echo -e "${BOLD}${BLUE}║ SYSTEM INFO ║${NC}" echo -e "${BOLD}${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" # Имя сервера echo -e "${BOLD}Server Name:${GREEN} $(hostname)${NC}" # OS if [ -f /etc/os-release ]; then . /etc/os-release echo -e "${BOLD}OS:${NC} $PRETTY_NAME" else echo -e "${BOLD}OS:${RED} Unknown${NC}" fi # Внутренние IP echo -e "${BOLD}IP:${NC}" ip -4 addr show 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | while read ip; do echo " - $ip" done # Uptime информация echo -e "${BOLD}Time:${NC} $current_time" echo -e "${BOLD}Uptime:${NC} $uptime_part" echo -e "${BOLD}Logged in users:${NC} $users" # CPU RAM SWAP echo -e "${BOLD}CPU count:${NC} $cpu_count" echo -e "${BOLD}RAM total:${NC} $$mem_total_h" if [ $swap_total -gt 0 ]; then echo -e "${BOLD}RAM total:${NC} $$swap_total" fi echo -e "${BOLD}${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" echo -e "${BOLD}${BLUE}║ SYSTEM STATE ║${NC}" echo -e "${BOLD}${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" # Load average if (( $(echo "$load_1min > $cpu_count" | bc -l 2>/dev/null) )); then echo -e "${BOLD}Load:${NC} ${RED}$load_avg${NC}" else echo -e "${BOLD}Load:${NC} $load_avg" fi # IOWait if (( $(echo "$iowait_value > 10" | bc -l 2>/dev/null) )); then echo -e "${BOLD}IOWait:${NC} ${RED}${iowait_value}%${NC} (high)" else echo -e "${BOLD}IOWait:${NC} ${iowait_value}%" fi echo "" # Оперативная память и Swap echo -e "${BOLD}${BLUE}═══════════════════════════ RAM/SWAP ════════════════════════${NC}" echo -e "${CYAN}RAM${NC}: ${WHITE}$mem_total_h${NC} total, ${WHITE}$mem_used_h${NC} used, ${WHITE}$mem_available_h${NC} free" create_progress_bar $mem_percent echo "" # Swap if [ $swap_total -gt 0 ]; then echo -e "${CYAN}SWAP${NC}: ${WHITE}$swap_total_h${NC} total, ${WHITE}$swap_used_h${NC} used, ${WHITE}$swap_free_h${NC} free" create_progress_bar $swap_percent echo "" fi echo "" # Дисковое пространство echo -e "${BOLD}${BLUE}═════════════════════════════ DISK ═══════════════════════════${NC}" # Исключенные типы файловых систем excluded_types=( "devtmpfs" "ecryptfs" "squashfs" "tmpfs" "udev" "overlay" ) # Формируем строку исключений для grep exclude_pattern=$(printf "|%s" "${excluded_types[@]}") exclude_pattern=${exclude_pattern:1} # Массив для хранения информации о дисках для резюме declare -A disk_usage echo "$disk_info" | tail -n+2 | grep -vE "^($exclude_pattern)" | while read line; do filesystem=$(echo $line | awk '{print $1}') size=$(echo $line | awk '{print $2}') used=$(echo $line | awk '{print $3}') available=$(echo $line | awk '{print $4}') mountpoint=$(echo $line | awk '{print $6}') used_percent=$(echo $line | awk '{print $5}' | sed 's/%//') # Сохраняем для резюме disk_usage["$mountpoint"]=$used_percent echo -e "${CYAN}$mountpoint${NC} (${YELLOW}$filesystem${NC}): ${WHITE}$size${NC} total, ${WHITE}$used${NC} used, ${WHITE}$available${NC} free" create_progress_bar $used_percent echo "" done echo "" # Количество открытых портов echo -e "${BOLD}${BLUE}═════════════════════════ LISTEN PORTS ═══════════════════════${NC}" if [ -n "$port_info" ]; then port_count=$(echo "$port_info" | grep -v "127.0.0.1" | grep -v "::1" | tail -n+2 | wc -l) echo -e "${BOLD}Всего открытых портов (слушающих):${NC} $port_count" echo "" echo -e "${CYAN}Список портов и процессов:${NC}" echo "$port_info" | grep -v "127.0.0.1" | grep -v "::1" | tail -n+2 | while read line; do protocol=$(echo $line | awk '{print $1}') address=$(echo $line | awk '{print $5}') port=$(echo $address | grep -oP ':\K\d+$') process=$(echo $line | grep -oP 'users:\(\("\K[^"]+' || echo "unknown") if [ -n "$port" ]; then printf " ${YELLOW}%-5s${NC} ${WHITE}%-8s${NC} - %s\n" "$protocol" "$port" "$process" fi done else echo -e "${RED}Не удалось получить информацию о портах${NC}" fi echo "" # Процессы echo -e "${BOLD}${BLUE}════════════════════════ PROCESSES INFO ══════════════════════${NC}" if [ -n "$process_data" ]; then process_count=$(echo "$process_data" | wc -l) echo -e "${BOLD}Всего процессов:${NC} $process_count" zombie_count=$(echo "$process_data" | awk '{if ($8 == "Z") print}' | wc -l) if [ $zombie_count -gt 0 ]; then echo -e "${BOLD}Zombie процессы:${NC} ${RED}$zombie_count${NC}" else echo -e "${BOLD}Zombie процессы:${NC} $zombie_count" fi # TOP 5 процессов по памяти echo -e "${BOLD}${BLUE}═══════════════════ TOP 5 PROCESSES (MEMORY) ═════════════════${NC}" echo "$process_data" | awk '{ cmd = $11 gsub(/^.*\//, "", cmd) if (cmd == "") cmd = "[unknown]" mem[cmd] += $6 } END { for (cmd in mem) { printf "%.2f|%s\n", mem[cmd]/1024, cmd } }' | sort -rn | head -5 | nl -w2 -s'. ' | while read line; do number=$(echo $line | cut -d'.' -f1) data=$(echo $line | cut -d'.' -f2-) mem=$(echo $data | cut -d'|' -f1) cmd=$(echo $data | cut -d'|' -f2-) printf "%2d. ${WHITE}%.2f MB${NC} - %s\n" $number $mem "$cmd" done # TOP 5 процессов по CPU echo -e "${BOLD}${BLUE}═════════════════════ TOP 5 PROCESSES (CPU) ══════════════════${NC}" echo "$process_data" | awk '{ cmd = $11 gsub(/^.*\//, "", cmd) if (cmd == "") cmd = "[unknown]" cpu[cmd] += $3 } END { for (cmd in cpu) { printf "%.1f|%s\n", cpu[cmd], cmd } }' | sort -rn | head -5 | nl -w2 -s'. ' | while read line; do number=$(echo $line | cut -d'.' -f1) data=$(echo $line | cut -d'.' -f2-) cpu=$(echo $data | cut -d'|' -f1) cmd=$(echo $data | cut -d'|' -f2-) printf "%2d. ${WHITE}%.1f%%${NC} - %s\n" $number $cpu "$cmd" done fi echo "" # Docker контейнеры (быстрая проверка) if command -v docker &> /dev/null && docker ps &> /dev/null; then echo -e "${BOLD}${BLUE}══════════════════════ DOCKER CONTAINERS ═════════════════════${NC}" docker_not_running=() while read line; do name=$(echo $line | awk '{print $1}') status=$(echo $line | awk '{print $2}') if [[ $status == "Up"* ]]; then echo -e "$name: ${GREEN}▲${NC} $status" else echo -e "$name: ${RED}▼${NC} $status" docker_not_running+=("$name") fi done < <(docker ps --format "table {{.Names}}\t{{.Status}}" 2>/dev/null | tail -n+2) echo "" fi # РЕЗЮМЕ echo -e "${BOLD}${BLUE}════════════════════════════ RESUME ══════════════════════════${NC}" echo "" issues_found=0 # Проверка дисков (< 5% свободного места) for mountpoint in "${!disk_usage[@]}"; do used_percent=${disk_usage["$mountpoint"]} free_percent=$((100 - used_percent)) if [ $free_percent -lt 5 ]; then echo -e "${RED}⚠ ДИСК:${NC} На разделе ${CYAN}$mountpoint${NC} осталось менее 5% свободного места (${RED}${used_percent}% занято${NC})" echo -e " ${YELLOW}Рекомендация:${NC} Очистите диск или увеличьте его размер" issues_found=1 fi done # Проверка RAM (< 5% свободной) free_ram_percent=$((100 - mem_percent)) if [ $free_ram_percent -lt 5 ]; then echo -e "${RED}⚠ ПАМЯТЬ:${NC} Осталось менее 5% свободной RAM (${RED}${mem_percent}% занято${NC})" echo -e " ${YELLOW}Рекомендация:${NC} Проверьте процессы, потребляющие память, и увеличьте RAM при необходимости" issues_found=1 fi # Проверка использования swap (> 5%) if [ $swap_total -gt 0 ] && [ $swap_percent -gt 5 ]; then echo -e "${YELLOW}⚠ SWAP:${NC} Используется более 5% swap (${YELLOW}${swap_percent}%${NC})" echo -e " ${YELLOW}Рекомендация:${NC} Активное использование swap замедляет работу системы. Возможно, не хватает оперативной памяти." issues_found=1 fi # Проверка load average (> количество ядер) if (( $(echo "$load_1min > $cpu_count" | bc -l 2>/dev/null) )); then echo -e "${RED}⚠ CPU:${NC} Load average (${RED}$load_1min${NC}) превышает количество ядер CPU (${WHITE}$cpu_count${NC})" echo -e " ${YELLOW}Рекомендация:${NC} Требуется увеличить количество CPU, возможно их не хватает" issues_found=1 fi # Проверка IOWait (> 10%) if (( $(echo "$iowait_value > 10" | bc -l 2>/dev/null) )); then echo -e "${RED}⚠ IOWAIT:${NC} Высокий IOWait (${RED}${iowait_value}%${NC})" if [ ${#high_iowait_disks[@]} -gt 0 ]; then echo -e " Проблемные диски: ${YELLOW}${high_iowait_disks[*]}${NC}" fi echo -e " ${YELLOW}Рекомендация:${NC} Проверьте дисковую подсистему, возможно медленные диски или проблемы с вводом-выводом" issues_found=1 fi # Проверка ошибок на интерфейсах if [ ${#interface_errors[@]} -gt 0 ]; then echo -e "${RED}⚠ СЕТЕВЫЕ ОШИБКИ:${NC} Обнаружены ошибки на сетевых интерфейсах:" for interface in "${!interface_errors[@]}"; do IFS=',' read -r rx_err tx_err rx_drop tx_drop <<< "${interface_errors[$interface]}" echo -e " ${CYAN}$interface${NC}: RX errors: ${RED}$rx_err${NC}, TX errors: ${RED}$tx_err${NC}, RX drops: ${YELLOW}$rx_drop${NC}, TX drops: ${YELLOW}$tx_drop${NC}" done echo -e " ${YELLOW}Рекомендация:${NC} Проверьте сетевые подключения и кабели" issues_found=1 fi # Проверка файловых дескрипторов if [ $file_handles_warning -eq 1 ]; then echo -e "${YELLOW}⚠ ФАЙЛОВЫЕ ДЕСКРИПТОРЫ:${NC} Использовано более 80% доступных файловых дескрипторов (${file_handle_percent}%)" echo -e " ${YELLOW}Рекомендация:${NC} Проверьте утечки файловых дескрипторов в приложениях" issues_found=1 fi # Проверка Docker контейнеров if [ ${#docker_not_running[@]} -gt 0 ]; then echo -e "${RED}⚠ DOCKER:${NC} Следующие контейнеры не запущены:" for container in "${docker_not_running[@]}"; do echo -e " - ${RED}$container${NC}" done issues_found=1 fi if [ $issues_found -eq 0 ]; then echo -e "${GREEN}✓ Система работает в штатном режиме. Проблем не обнаружено.${NC}" fi echo -e "${BOLD}${BLUE}══════════════════════════════════════════════════════════════${NC}"