#!/bin/bash clear name_scr=${0##*/} name_scr=${name_scr%.*} readonly name_scr readonly title_scr="${name_scr} на \"${HOSTNAME}\"" readonly IFS_OLD=$IFS if [[ -n $@ ]]; then for var in "$@"; do [[ ${var} == *'='* ]] && eval ${var}; done fi if [ -z "$(command -v whiptail)" ]; then echo "Не установлен пакет \"whiptail\"!" exit 0 fi function whiptail_msgbox { [[ -z "$@" ]] && return if [[ -n ${stat_key} ]]; then echo -e "$@" return fi local strings="$@" local lines=$(echo -e "${strings}" | wc -l) local height=7 local height_max=12 [[ "${lines}" -gt "1" ]] && height=$((height + ${lines})) local width=$((6 + ${#title_scr})) local width_max=60 IFS=$'\n' for string in $(echo -e ${strings}); do [[ "${#string}" -gt "${width}" ]] && width=${#string} done IFS=${IFS_OLD} [[ "${width}" -gt "${width_max}" ]] && width=${width_max} if [ "${height}" -gt "${height_max}" ]; then whiptail --scrolltext --title "${title_scr}" --msgbox "${strings}" ${height_max} $((8 + ${width})) else whiptail --title "${title_scr}" --msgbox "${strings}" ${height} $((8 + ${width})) fi } if [ $(whoami) != "root" ]; then whiptail_msgbox "Запуск только под рутом!" exit 0 fi readonly tmpl_name='????-??-??' readonly bin_ls=$(command -v ls) readonly bin_grep=$(command -v grep) readonly bin_lnav=$(command -v lnav) readonly bin_fail2ban_client=$(command -v fail2ban-client) if [ -n "${bin_fail2ban_client}" ]; then readonly logtarget=$(fail2ban-client get logtarget 2> /dev/null | ${bin_grep} -v "Current logging target is" | sed 's/`- //g') readonly logs_fail2ban=${logtarget}\* fi readonly DirScript="$(cd -- "$(dirname -- "${0}")" &> /dev/null && pwd)" readonly CfgScript="${DirScript}/${name_scr}.cfg" if ! [ -f "${CfgScript}" ]; then touch "${CfgScript}" if ! [ $? -eq 0 ]; then whiptail_msgbox "Не удается создать cfg-файл:\n\"${CfgScript}\"" exit fi echo '# Массив параметров для сбора статистики' >> "${CfgScript}" echo '# strings - количество строк в списке попыток подключений' >> "${CfgScript}" echo '# значения strings: число или слово "all" (без кавычек)' >> "${CfgScript}" echo '# stat_num_files - количество сохраняемых файлов' >> "${CfgScript}" echo '# stat_to_file - запись статистики в файл, yes = записывать' >> "${CfgScript}" echo "statistics[\"01\"]=\"name='Статистика за 1 день' days=1 strings=30 stat_to_file='yes' stat_num_files=10\"" >> "${CfgScript}" echo "statistics[\"03\"]=\"name='Статистика за 3 дня' days=3 strings=20 stat_to_file='yes' stat_num_files=5\"" >> "${CfgScript}" echo "statistics[\"07\"]=\"name='Статистика за неделю' days=7 strings=20 stat_to_file='no'\"" >> "${CfgScript}" echo "statistics[\"14\"]=\"name='Статистика за две недели' days=14 strings=20\"" >> "${CfgScript}" echo "statistics[\"30\"]=\"name='Статистика за 30 дней' days=30 strings=all stat_to_file='no'\"" >> "${CfgScript}" whiptail_msgbox "Создан cfg-файл скрипта:\n\"${CfgScript}\"\nОтредактируйте его под свои нужды." fi if [ -z "$(${bin_grep} 'sort_banned_ips=' "${CfgScript}")" ]; then echo -e "" >> "${CfgScript}" echo '# Сортировка списка забаненых IP. Значения: "ip" или "date"' >> "${CfgScript}" echo 'sort_banned_ips="date"' >> "${CfgScript}" fi if [ -z "$(${bin_grep} 'journal_days_ago=' "${CfgScript}")" ]; then echo -e "" >> "${CfgScript}" echo '# Количество дней для запроса у journalctl (если используется journal для сбора логов)' >> "${CfgScript}" echo 'journal_days_ago=3' >> "${CfgScript}" fi readonly DirStatistics="${DirScript}/Statistics" if ! [ -d "${DirStatistics}" ]; then mkdir "${DirStatistics}" if ! [ -d "${DirStatistics}" ]; then whiptail_msgbox "Не удается создать каталог для сохранения статистик:\n\"${DirStatistics}\"" fi fi function press_enter { set +x if [ -z "$@" ]; then read -p "\"Enter\" - продолжить, \"Ctrl+c\" - прервать" else read -p "$@" fi } function arr_keys_sort { [[ -z "$1" ]] && return declare -n arr_keys_declare="$1" if [[ ${#arr_keys_declare[@]} == 0 ]]; then press_enter "$FUNCNAME: Массив \"$1\" не существует или пуст!" return fi local sorted_arr_keys IFS=$'\n' sorted_arr_keys=($(sort <<< "${!arr_keys_declare[*]}")) IFS=${IFS_OLD} echo "${sorted_arr_keys[@]}" } function seconds_to_dhms { [[ -z "$1" ]] && return local seconds=${1%.*} local string='' local d=$((seconds/60/60/24)) local h=$((seconds/60/60%24)) local m=$((seconds/60%60)) local s=$((seconds%60)) if [ $d -gt 0 ]; then string=$(printf "%dd, %dh, %dm" "$d" "$h" "$m") elif [ $h -gt 0 ]; then string=$(printf "%dh, %dm, %ds" "$h" "$m" "$s") elif [ $m -gt 0 ]; then string=$(printf "%dm, %ds" "$m" "$s") else string=$(printf "%ds" "$s") fi echo "${string}" } function menu_name { [[ -z "$@" ]] && return echo "$(echo "$@" | awk -F'=' '{print $1}')" } function menu_function { [[ -z "$@" ]] && return echo "$(echo "$@" | awk -F'=' '{print $2}')" } function menu_search_name { [[ -z "$@" ]] && return local name for item in "${menu_top[@]}"; do if [ "$(menu_function ${item})" == "$@" ]; then name="$(menu_name ${item})" break fi done if [ -z "${name}" ]; then for item in "${menu_bottom[@]}"; do if [ "$(menu_function ${item})" == "$@" ]; then name="$(menu_name ${item})" break fi done fi echo "${name}" } function nano_cfg { if [ -z "$(command -v nano)" ]; then whiptail_msgbox "Не установлен пакет \"nano\"" return fi nano "${CfgScript}" } function lnav_logs { if [ -z "${bin_lnav}" ]; then whiptail_msgbox "Не установлен пакет \"lnav\"" return fi if [ -z "${bin_fail2ban_client}" ]; then whiptail_msgbox "Не установлен пакет \"fail2ban-client\"" return fi local heading=$(menu_search_name "$FUNCNAME") local height=7 local width=6 local width=$((width + ${#title_scr})) local menu='' local tag='' local default_tag local logfiles if [[ -n ${logtarget} ]]; then menu=("fail2ban" "logs fail2ban") fi local jails=$(fail2ban-client status | ${bin_grep} " Jail list:" | sed 's/`- Jail list://g' | sed 's/^[ \t]*//' | sed 's/,//g') for jail in ${jails}; do if [[ -n "$(fail2ban-client get ${jail} logpath | ${bin_grep} 'No file is currently monitored')" ]]; then menu+=("journal_${jail}" "for jail ${jail}") continue else menu+=("${jail}" "for jail ${jail}") fi [[ $((${#jail} + 10)) -gt ${width} ]] && width=$((${#jail} + 10)) done while true;do tag=$(whiptail --title "${title_scr}" --menu --default-item "${default_tag}" --notags "${heading}" $((height + 8)) $((width + 8)) ${height} "${menu[@]}" 3>&1 1>&2 2>&3) if [ $? -eq 0 ]; then clear default_tag=${tag} case ${tag} in fail2ban) ${bin_lnav} ${logs_fail2ban} ;; journal_sshd) if [[ -z "${journal_strings}" ]]; then local journal_strings=500 elif [[ ${journal_strings} =~ ^[0-9]+$ ]]; then local journal_strings=${journal_strings} else local journal_strings=500 fi [[ ${journal_days_ago} =~ ^[0-9]+$ ]] || journal_days_ago=1 [[ ${journal_days_ago} -gt 0 ]] || journal_days_ago=1 journalctl -f --since "${journal_days_ago} days ago" -u ssh | ${bin_lnav} ;; *) logfiles=() for file in $(fail2ban-client get ${tag} logpath | ${bin_grep} -v 'Current monitored log file' | sed 's/`- //g' | sed 's/^|- //g'); do [[ $(du -b "$file" | cut -f 1) -eq 0 ]] && continue logfiles+=("${file}*") done [[ -n ${logfiles[@]} ]] && ${bin_lnav} ${logfiles[@]} ;; esac clear else clear break fi done } function status_all_jails { if [ -z "${bin_fail2ban_client}" ]; then whiptail_msgbox "Не установлен пакет \"fail2ban-client\"" return fi local uptime="$(seconds_to_dhms $(cat /proc/uptime))" local result="${title_scr} (uptime: ${uptime})\n$(menu_search_name "$FUNCNAME") на $(date +"%F %R")\n" echo -e "${result}" local jails=$(fail2ban-client status | ${bin_grep} " Jail list:" | sed 's/`- Jail list://g' | sed 's/^[ \t]*//' | sed 's/,//g') for jail in $jails; do result+="\n"'=== '${jail}' ===' local findtime="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'findtime'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${findtime} ]] && result+="\nfindtime: ${findtime}" local maxmatches="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'maxmatches'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${maxmatches} ]] && result+="\nmaxmatches: ${maxmatches}" local maxretry="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'maxretry'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${maxretry} ]] && result+="\nmaxretry: ${maxretry}" local bantime="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'bantime'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${bantime} ]] && result+="\nbantime: ${bantime}" local bantime_rndtime="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'bantime.rndtime'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${bantime_rndtime} ]] && result+="\nbantime.rndtime: ${bantime_rndtime}" local bantime_increment="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'bantime.increment'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${bantime_increment} ]] && result+="\nbantime.increment: ${bantime_increment}" local bantime_factor="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'bantime.factor'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${bantime_factor} ]] && result+="\nbantime.factor: ${bantime_factor}" local bantime_formula="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'bantime.formula'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${bantime_formula} ]] && result+="\nbantime.formula: ${bantime_formula}" local bantime_multipliers="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'bantime.multipliers'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${bantime_multipliers} ]] && result+="\nbantime.multipliers: ${bantime_multipliers}" local bantime_maxtime="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'bantime.maxtime'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${bantime_maxtime} ]] && result+="\nbantime.maxtime: ${bantime_maxtime}" local addaction="$(fail2ban-client -d | ${bin_grep} "'set', '${jail}', 'addaction'" | sed 's/^\[\(.*\)\]$/\1/' | awk '{print $4}')" [[ -n ${addaction} ]] && result+="\naddaction: ${addaction}" local ignoreip=$(fail2ban-client get ${jail} ignoreip | ${bin_grep} -v 'These IP addresses/networks are ignored:' | sed 's/^[\|\`]*//' | sed 's/-//g') result+="\nignoreip:\n${ignoreip[@]}" result+="\n\n$(fail2ban-client status ${jail} | ${bin_grep} -v "Banned IP list:")\n" done clear echo -e "${result}" press_enter 'Press ENTER to continue' } function get_banned_ips { [[ -z "${bin_fail2ban_client}" ]] && return local uptime="$(seconds_to_dhms $(cat /proc/uptime))" local heading="${title_scr} (uptime: ${uptime})\n$(menu_search_name "$FUNCNAME") на $(date +"%F %R")" if [ "${sort_banned_ips}" == "ip" ]; then heading+=" (сортировка по ip)\n" else heading+=" (сортировка по дате)\n" fi local banned local ip_list='' local jails=$(fail2ban-client status | ${bin_grep} " Jail list:" | sed 's/`- Jail list://g' | sed 's/^[ \t]*//' | sed 's/,//g') for jail in ${jails}; do if [[ -z "$@" ]]; then banned=$(fail2ban-client status ${jail} | ${bin_grep} "Currently banned" | sed 's/|- Currently banned://g' | sed 's/^[ \t]*//') if [[ ${banned} -gt 0 ]]; then ip_list+='\n=== '${jail}\ \(${banned}\)' ====\n' if [ "${sort_banned_ips}" == "ip" ]; then ip_list+=$(fail2ban-client get ${jail} banip --with-time | awk '{print $1"\t(до "$7" "$8")"}' | sort -k1 -V) else ip_list+=$(fail2ban-client get ${jail} banip --with-time | awk '{print $1"\t(до "$7" "$8")"}') fi ip_list+="\n\n" else ip_list+='=== '${jail}\ \(${banned}\)' ====\n' fi else ip_list+=$(fail2ban-client get ${jail} banip | sed 's/^[ \t]*//' | sed 's/ /\n/g') fi done if [ -z "$@" ]; then if [ -z "${bin_lnav}" ]; then whiptail_msgbox "Не установлен пакет \"lnav\"" return fi echo -e "${heading}\n${ip_list}" > ${DirStatistics}/${HOSTNAME}_banned_ips.tmp ${bin_lnav} ${DirStatistics}/${HOSTNAME}_banned_ips.tmp rm ${DirStatistics}/${HOSTNAME}_banned_ips.tmp 2>/dev/null else echo $(echo "${ip_list}" | sort | uniq) fi } function del_old_files { local full_path local count local prefix local suffix for var in "$@"; do [[ ${var} == *'='* ]] && eval ${var}; done [[ -d "${full_path}" ]] || return [[ -z "${count}" ]] || [[ "${count}" -lt "1" ]] && return local files=$(${bin_ls} -1r ${full_path}/${prefix}${tmpl_name}${suffix} 2> /dev/null) if [ -n "${files}" ]; then for file in ${files[@]}; do [[ -f "${file}" ]] || continue let "count -= 1" if [ "${count}" -lt "0" ]; then rm ${file} [[ $? -ne 0 ]] && whiptail_msgbox "Ошибка удаления файла:\n${file}" fi done fi } function for_statistics { local date_string=$(echo "${string}" | awk '{print $1" " $2}') date_string=$(date --date="${date_string}" +%s) [[ ${date_string} -lt ${date_start} ]] && return case "$(echo "${string}" | awk '{print $7}')" in Unban) let "num_unban += 1" ;; Ban) let "num_ban += 1" ;; Restore) let "num_restore += 1" ;; Found) [[ -z ${found_first} ]] && found_first=${date_string} found_last=${date_string} found_ip+=("$(echo "${string}" | awk '{print $8}')") ;; Increase) let "num_increase += 1" ;; esac } function StatisticsLastDays { if [ -z "${bin_fail2ban_client}" ]; then whiptail_msgbox "Не установлен пакет \"fail2ban-client\"" return fi local key="$1" if [[ -z ${key} ]]; then whiptail_msgbox "Вызов функции \"$FUNCNAME\" без параметра!" return fi if [[ -z ${statistics[${key}]} ]]; then whiptail_msgbox "Не найден элемент \"${key}\" в массиве \"statistics\"!" return fi local name='Статистика за 1 день' local days=1 local strings=10 local stat_to_file='no' local stat_num_files=10 eval "${statistics[${key}]}" if [[ -n ${stat_key} ]]; then if ! [[ ${strings} == 'all' ]]; then if ! [[ ${strings} =~ ^[0-9]+$ ]]; then exit fi fi [[ ${days} =~ ^[0-9]+$ ]] || exit [[ ${stat_num_files} =~ ^[0-9]+$ ]] || exit fi [[ -n ${stat_key} ]] && stat_to_file='yes' if [[ ${stat_to_file} == "yes" ]]; then stat_to_file=" с записью в файл" else stat_to_file='' local height=10 local width=20 local width=$((width + ${#title_scr})) if ! [[ ${days} =~ ^[0-9]+$ ]]; then whiptail_msgbox "Параметр \"days\" должен быть числом:\n"${statistics[${key}]}"" return fi while true; do strings=$(whiptail --title "${title_scr}" --inputbox "${name}\nКоличество строк в списке попыток подключений или \"all\" (без кавычек):" ${height} ${width} "${strings}" 3>&1 1>&2 2>&3) if [ $? -eq 0 ]; then if [[ ${strings} == 'all' ]]; then break elif [[ ${strings} =~ ^[0-9]+$ ]]; then break else whiptail_msgbox "Необходимо ввести число или \"all\" (без кавычек)!" fi else return fi done fi local date_start=$(date --date="-${days} day" +%s) local found_ip=() local found_first='' local found_last='' local time_start=$(date +"%F %R:%S") local num_logs=0 local num_ban=0 local num_restore=0 local num_unban=0 local num_increase=0 local result='' echo -e "${title_scr}\n${name}${stat_to_file}\n\nНачало обработки файлов: ${time_start}\n" IFS=$'\n' for file in $(${bin_ls} -1 -r ${logs_fail2ban}); do [[ ${date_start} -gt $(date -r ${file} +%s) ]] && continue let "num_logs += 1" if [ "${file##*.}" == "gz" ]; then echo "Обработка файла ${file##*/}" for string in $(gunzip -c "${file}" | ${bin_grep} -E "filter.*Found|actions.*Unban|actions.*Ban|observer.*Increase Ban"); do for_statistics done else echo "Обработка файла ${file##*/}" for string in $(${bin_grep} -E "filter.*Found|actions.*Unban|actions.*Ban|observer.*Increase Ban" ${file}); do for_statistics done fi done IFS=${IFS_OLD} local time_diff=$(seconds_to_dhms "$(($(date +%s) - $(date --date="${time_start}" +%s)))") local uptime="$(seconds_to_dhms $(cat /proc/uptime))" result="${title_scr} (uptime: ${uptime})\n${name}" result+=" на $(date +"%F %R")" result+="\n\nОбработано log-файлов fail2ban: ${num_logs}" result+="\nДлительность обработки файлов: ${time_diff}" result+="\n\nВсего попыток подключений: ${#found_ip[@]}" [[ ${days} -gt 1 ]] && result+=" (среднее за 1 день: $((${#found_ip[@]} / ${days})))" result+="\nПервая попытка: $(date --date=@${found_first} +"%F %R:%S")" result+="\nПоследняя попытка: $(date --date=@${found_last} +"%F %R:%S")" result+="\n\nПолучили \"Ban\": ${num_ban}" result+="\nПолучили \"Unban\": $((${num_unban} - ${num_restore}))" result+="\nПолучили \"Increase Ban\": ${num_increase}\n" local banned_ip_arr='' local banned_ip_list='' local jails=$(fail2ban-client status | ${bin_grep} " Jail list:" | sed 's/`- Jail list://g' | sed 's/^[ \t]*//' | sed 's/,//g') for jail in ${jails}; do banned_ip_arr='' banned_ip_arr=($(fail2ban-client status ${jail} | ${bin_grep} "Banned IP list:" | sed 's/`- Banned IP list://g' | sed 's/^[ \t]*//')) banned_ip_list+="Забанено в jail \"${jail}\": ${#banned_ip_arr[@]}\n" done result+="\n$(echo -e "${banned_ip_list}" | column -t)" local found_num_ip=$(echo "${found_ip[@]}" | sed 's/^[ \t]*//' | sed 's/ /\n/g' | sort | uniq -c | sort -k1,1nr -k2) local cound_num_ip="$(echo -n "${found_num_ip[@]}" | ${bin_grep} -c '^')" result+="\n\nКоличество попыток подключений " if [[ ${strings} == 'all' ]]; then result+="(всего ${cound_num_ip} IP, среднее на IP: $((${#found_ip[@]} / ${cound_num_ip}))):" elif [[ ${strings} =~ ^[0-9]+$ ]]; then if [[ ${cound_num_ip} -gt ${strings} ]]; then result+="(первые ${strings} из ${cound_num_ip} IP, среднее на IP: $((${#found_ip[@]} / ${cound_num_ip}))):" else result+="(всего ${cound_num_ip} IP, среднее на IP: $((${#found_ip[@]} / ${cound_num_ip}))):" fi else if [[ -z ${stat_key} ]]; then whiptail_msgbox "Ошибка параметра \"${strings}\"" return else exit fi fi local i=0 local banned='' local list_banned_ips=$(get_banned_ips list) IFS=$'\n' for num_ip in ${found_num_ip[@]}; do let "i += 1" if ! [[ ${strings} == 'all' ]]; then [[ ${i} -gt ${strings} ]] && break fi banned="$(echo ${list_banned_ips} | ${bin_grep} -w "$(echo ${num_ip} | sed 's/^[ \t]*//' | awk '{print $2}')")" [[ -n ${banned} ]] && banned='\t (banned)' result+="\n${num_ip}${banned}" done IFS=${IFS_OLD} if [[ -n ${stat_to_file} ]]; then echo -e "${result}\n==========\n" > ${DirStatistics}/${HOSTNAME}_${key}_$(date +"%F").txt del_old_files "full_path=${DirStatistics}" "count=${stat_num_files}" "prefix=${HOSTNAME}_${key}_" "suffix=.txt" fi if [[ -z ${stat_key} ]]; then clear echo -e "${result}" > ${DirStatistics}/${HOSTNAME}_${key}.tmp if [ -z "${bin_lnav}" ]; then less ${DirStatistics}/${HOSTNAME}_${key}.tmp else ${bin_lnav} ${DirStatistics}/${HOSTNAME}_${key}.tmp fi rm ${DirStatistics}/${HOSTNAME}_${key}.tmp 2>/dev/null fi } function StatisticsDays { local heading=$(menu_search_name "$FUNCNAME") local height=5 local width=6 local width=$((width + ${#title_scr})) local menu='' local tag='' local default_tag local tags='' local name='' local days='' local strings='' local stat_to_file='' for key in $(arr_keys_sort "statistics"); do eval "${statistics[${key}]}" if [ -z "${menu}" ]; then menu=("${key}" "${name}") else menu+=("${key}" "${name}") fi done while true;do tag=$(whiptail --title "${title_scr}" --menu --default-item "${default_tag}" --notags "${heading}" $((height + 8)) $((width + 12)) ${height} "${menu[@]}" 3>&1 1>&2 2>&3) if [ $? -eq 0 ]; then clear default_tag=${tag} StatisticsLastDays ${tag} clear else clear break fi done } function lnav_stat_files { if [ -z "${bin_lnav}" ]; then whiptail_msgbox "Не установлен пакет \"lnav\"" return fi local heading=$(menu_search_name "$FUNCNAME") local height=5 local width=6 local width=$((width + ${#title_scr})) local menu='' local tag='' local default_tag local logfiles local tags='' local name='' local days='' local strings='' local stat_to_file='' tags=$(${bin_ls} -1 ${DirStatistics}/${HOSTNAME}_*_${tmpl_name}.txt | awk -F'_' '{print $2}' | uniq) for tag in ${tags}; do name='' [ -n "${statistics["${tag/d/}"]}" ] && eval "${statistics[${tag/d/}]}" [[ -z ${name} ]] && name="Статистика за ${tag}" if [ -z "${menu}" ]; then menu=("${tag}" "${name}") else menu+=("${tag}" "${name}") fi done while true;do tag=$(whiptail --title "${title_scr}" --menu --default-item "${default_tag}" --notags "${heading}" $((height + 8)) $((width + 12)) ${height} "${menu[@]}" 3>&1 1>&2 2>&3) if [ $? -eq 0 ]; then clear default_tag=${tag} cat $(${bin_ls} ${DirStatistics}/${HOSTNAME}_${tag}_${tmpl_name}.txt) > ${DirStatistics}/${HOSTNAME}_${tag}_all.tmp ${bin_lnav} ${DirStatistics}/${HOSTNAME}_${tag}_all.tmp rm ${DirStatistics}/${HOSTNAME}_${tag}_all.tmp 2>/dev/null clear else clear break fi done } function script_info { if ! [ -f "${DirScript}/${name_scr}Info.txt" ]; then whiptail_msgbox "Не найден файл:\n${DirScript}/${name_scr}Info.txt" return fi local text='' local height=30 local width=100 local stat_01='' if [ -n "${statistics["01"]}" ]; then stat_01="Пример элемента массива statistics из файла ${name_scr}.cfg:\n" stat_01+=${statistics["01"]} fi source ${DirScript}/${name_scr}Info.txt whiptail --scrolltext --title "${title_scr}" --msgbox "${text}" ${height} ${width} } if [[ -n ${stat_key} ]]; then declare -A statistics . "${CfgScript}" StatisticsLastDays ${stat_key} exit fi declare -a menu_main height=7 width=6 width=$((width + ${#title_scr})) while true;do menu_top=('Просмотр лог-файлов (lnav)'=lnav_logs 'Текущее состояние jails'=status_all_jails) menu_bottom=('Список забаненых IP (lnav)'=get_banned_ips 'Сбор статистик'=StatisticsDays) [[ $(${bin_ls} -1 ${DirStatistics}/${HOSTNAME}_*.txt 2>/dev/null | wc -l) -gt 0 ]] && menu_bottom+=('Просмотр файлов статистик (lnav)'=lnav_stat_files) menu_bottom+=('Редактирование cfg-файла скрипта (nano)'=nano_cfg) menu_bottom+=('Информация о скрипте'=script_info) unset menu_main declare -A statistics sort_banned_ips="date" . "${CfgScript}" for item in "${menu_top[@]}"; do if [[ $(declare -F $(menu_function ${item})) ]]; then name="$(menu_name ${item})" menu_main+=("$(menu_function ${item})" "${name}") ((${#name} > width)) && width=${#name} fi done for item in "${menu_bottom[@]}"; do if [[ $(declare -F $(menu_function ${item})) ]]; then name="$(menu_name ${item})" menu_main+=("$(menu_function ${item})" "${name}") ((${#name} > width)) && width=${#name} fi done if [ ${#menu_main[@]} -eq 0 ]; then whiptail_msgbox "Список главного меню пуст!" break fi tag=$(whiptail --title "${title_scr}" --menu --default-item "${default_tag}" --notags "Главное меню" $((height + 8)) $((width + 10)) ${height} "${menu_main[@]}" 3>&1 1>&2 2>&3) if [ $? -eq 0 ]; then default_tag=${tag} clear ${tag} clear else clear break fi done