Operations 24 min read

Comprehensive Linux Daily Inspection Script for System Health Monitoring

This article presents a Bash script that performs a full daily health check on a Linux server—covering disk usage, memory, CPU, processes, file changes, user logins, network settings, services, cron jobs, and security configurations—and then emails the generated report.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Comprehensive Linux Daily Inspection Script for System Health Monitoring

Linux系统日常巡检脚本,检查内容包括磁盘、内存、CPU、进程、文件更改、用户登录等一系列操作,直接使用即可,报告通过邮件发送并保存在log目录下。

#!/bin/bash
# @Author: HanWei
# @Date:   2020-03-16 09:56:57
# @Last Modified by:   HanWei
# @Last Modified time: 2020-03-16 11:06:31
# @E-mail: [email protected]
#!/bin/bash
#主机信息每日巡检

IPADDR=$(ifconfig eth0|grep 'inet addr'|awk -F '[ :]' '{print $13}')
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
source /etc/profile
[ $(id -u) -gt 0 ] && echo "请用root用户执行此脚本!" && exit 1
centosVersion=$(awk '{print $(NF-1)}' /etc/redhat-release)
VERSION="2020-03-16"

#日志相关
PROGPATH=`echo $0 | sed -e 's,[\/][^\/][^\/]*$,,'`
[ -f $PROGPATH ] && PROGPATH="."
LOGPATH="$PROGPATH/log"
[ -e $LOGPATH ] || mkdir $LOGPATH
RESULTFILE="$LOGPATH/HostDailyCheck-$IPADDR-$(date +%Y%m%d).txt"

#定义报表的全局变量
report_DateTime=""
report_Hostname=""
report_OSRelease=""
report_Kernel=""
report_Language=""
report_LastReboot=""
report_Uptime=""
report_CPUs=""
report_CPUType=""
report_Arch=""
report_MemTotal=""
report_MemFree=""
report_MemUsedPercent=""
report_DiskTotal=""
report_DiskFree=""
report_DiskUsedPercent=""
report_InodeTotal=""
report_InodeFree=""
report_InodeUsedPercent=""
report_IP=""
report_MAC=""
report_Gateway=""
report_DNS=""
report_Listen=""
report_Selinux=""
report_Firewall=""
report_USERs=""
report_USEREmptyPassword=""
report_USERTheSameUID=""
report_PasswordExpiry=""
report_RootUser=""
report_Sudoers=""
report_SSHAuthorized=""
report_SSHDProtocolVersion=""
report_SSHDPermitRootLogin=""
report_DefunctProsess=""
report_SelfInitiatedService=""
report_SelfInitiatedProgram=""
report_RuningService=""
report_Crontab=""
report_Syslog=""
report_SNMP=""
report_NTP=""
report_JDK=""

function version(){
  echo ""
  echo ""
  echo "系统巡检脚本:Version $VERSION"
}

function getCpuStatus(){
  echo ""
  echo ""
  echo "############################ CPU检查 #############################"
  Physical_CPUs=$(grep "physical id" /proc/cpuinfo| sort | uniq | wc -l)
  Virt_CPUs=$(grep "processor" /proc/cpuinfo | wc -l)
  CPU_Kernels=$(grep "cores" /proc/cpuinfo|uniq| awk -F ': ' '{print $2}')
  CPU_Type=$(grep "model name" /proc/cpuinfo | awk -F ': ' '{print $2}' | sort | uniq)
  CPU_Arch=$(uname -m)
  echo "物理CPU个数:$Physical_CPUs"
  echo "逻辑CPU个数:$Virt_CPUs"
  echo "每CPU核心数:$CPU_Kernels"
  echo " CPU型号:$CPU_Type"
  echo " CPU架构:$CPU_Arch"
  report_CPUs=$Virt_CPUs
  report_CPUType=$CPU_Type
  report_Arch=$CPU_Arch
}

function getMemStatus(){
  echo ""
  echo ""
  echo "############################ 内存检查 ############################"
  if [[ $centosVersion < 7 ]]; then
    free -mo
  else
    free -h
  fi
  MemTotal=$(grep MemTotal /proc/meminfo| awk '{print $2}')
  MemFree=$(grep MemFree /proc/meminfo| awk '{print $2}')
  let MemUsed=MemTotal-MemFree
  MemPercent=$(awk "BEGIN {if($MemTotal==0){printf 100}else{printf \"%.2f\",$MemUsed*100/$MemTotal}}")
  report_MemTotal="$((MemTotal/1024))MB"
  report_MemFree="$((MemFree/1024))MB"
  report_MemUsedPercent="$MemPercent%"
}

function getDiskStatus(){
  echo ""
  echo ""
  echo "############################ 磁盘检查 ############################"
  df -hiP | sed 's/Mounted on/Mounted/' > /tmp/inode
  df -hTP | sed 's/Mounted on/Mounted/' > /tmp/disk
  join /tmp/disk /tmp/inode | awk '{print $1,$2,"|",$3,$4,$5,$6,"|",$8,$9,$10,$11,"|",$12}' | column -t
  diskdata=$(df -TP | sed '1d' | awk '$2!="tmpfs"{print}')
  disktotal=$(echo "$diskdata" | awk '{total+=$3}END{print total}')
  diskused=$(echo "$diskdata" | awk '{total+=$4}END{print total}')
  diskfree=$((disktotal-diskused))
  diskusedpercent=$(echo $disktotal $diskused | awk '{if($1==0){printf 100}else{printf "%.2f",$2*100/$1}}')
  inodedata=$(df -iTP | sed '1d' | awk '$2!="tmpfs"{print}')
  inodetotal=$(echo "$inodedata" | awk '{total+=$3}END{print total}')
  inodeused=$(echo "$inodedata" | awk '{total+=$4}END{print total}')
  inodefree=$((inodetotal-inodeused))
  inodeusedpercent=$(echo $inodetotal $inodeused | awk '{if($1==0){printf 100}else{printf "%.2f",$2*100/$1}}')
  report_DiskTotal=$((disktotal/1024/1024))GB
  report_DiskFree=$((diskfree/1024/1024))GB
  report_DiskUsedPercent="$diskusedpercent%"
  report_InodeTotal=$((inodetotal/1000))K
  report_InodeFree=$((inodefree/1000))K
  report_InodeUsedPercent="$inodeusedpercent%"
}

function getSystemStatus(){
  echo ""
  echo ""
  echo "############################ 系统检查 ############################"
  if [ -e /etc/sysconfig/i18n ]; then
    default_LANG="$(grep LANG= /etc/sysconfig/i18n | grep -v '^#' | awk -F '"' '{print $2}')"
  else
    default_LANG=$LANG
  fi
  export LANG="en_US.UTF-8"
  Release=$(cat /etc/redhat-release 2>/dev/null)
  Kernel=$(uname -r)
  OS=$(uname -o)
  Hostname=$(uname -n)
  SELinux=$(/usr/sbin/sestatus | grep "SELinux status:" | awk '{print $3}')
  LastReboot=$(who -b | awk '{print $3,$4}')
  uptime=$(uptime | sed 's/.*up \([^,]*\), .*/\1/')
  echo " 系统:$OS"
  echo " 发行版本:$Release"
  echo " 内核:$Kernel"
  echo " 主机名:$Hostname"
  echo " SELinux:$SELinux"
  echo "语言/编码:$default_LANG"
  echo " 当前时间:$(date +'%F %T')"
  echo " 最后启动:$LastReboot"
  echo " 运行时间:$uptime"
  report_DateTime=$(date +"%F %T")
  report_Hostname="$Hostname"
  report_OSRelease="$Release"
  report_Kernel="$Kernel"
  report_Language="$default_LANG"
  report_LastReboot="$LastReboot"
  report_Uptime="$uptime"
  report_Selinux="$SELinux"
  export LANG=$default_LANG
}

function getServiceStatus(){
  echo ""
  echo ""
  echo "############################ 服务检查 ############################"
  if [[ $centosVersion > 7 ]]; then
    conf=$(systemctl list-unit-files --type=service --state=enabled --no-pager | grep "enabled")
    process=$(systemctl list-units --type=service --state=running --no-pager | grep ".service")
    report_SelfInitiatedService="$(echo "$conf" | wc -l)"
    report_RuningService="$(echo "$process" | wc -l)"
  else
    conf=$(/sbin/chkconfig | grep -E ":on|:启用")
    process=$(/sbin/service --status-all 2>/dev/null | grep -E "is running|正在运行")
    report_SelfInitiatedService="$(echo "$conf" | wc -l)"
    report_RuningService="$(echo "$process" | wc -l)"
  fi
  echo "服务配置"
  echo "--------"
  echo "$conf" | column -t
  echo ""
  echo "正在运行的服务"
  echo "--------------"
  echo "$process"
}

function getAutoStartStatus(){
  echo ""
  echo ""
  echo "############################ 自启动检查 ##########################"
  conf=$(grep -v "^#" /etc/rc.d/rc.local | sed '/^$/d')
  echo "$conf"
  report_SelfInitiatedProgram="$(echo $conf | wc -l)"
}

function getLoginStatus(){
  echo ""
  echo ""
  echo "############################ 登录检查 ############################"
  last | head
}

function getNetworkStatus(){
  echo ""
  echo ""
  echo "############################ 网络检查 ############################"
  if [[ $centosVersion < 7 ]]; then
    /sbin/ifconfig -a | grep -v packets | grep -v collisions | grep -v inet6
  else
    for i in $(ip link | grep BROADCAST | awk -F: '{print $2}'); do
      ip add show $i | grep -E "BROADCAST|global" | awk '{print $2}' | tr '
' ' '
      echo ""
    done
  fi
  GATEWAY=$(ip route | grep default | awk '{print $3}')
  DNS=$(grep nameserver /etc/resolv.conf | grep -v "#" | awk '{print $2}' | tr '
' ',' | sed 's/,$//')
  echo "网关:$GATEWAY "
  echo " DNS:$DNS"
  IP=$(ip -f inet addr | grep -v 127.0.0.1 | grep inet | awk '{print $NF,$2}' | tr '
' ',' | sed 's/,$//')
  MAC=$(ip link | grep -v "LOOPBACK\|loopback" | awk '{print $2}' | tr -d '
' | tr '
' ',' | sed 's/,$//')
  report_IP="$IP"
  report_MAC=$MAC
  report_Gateway="$GATEWAY"
  report_DNS="$DNS"
}

function getListenStatus(){
  echo ""
  echo ""
  echo "############################ 监听检查 ############################"
  TCPListen=$(ss -ntul | column -t)
  echo "$TCPListen"
  report_Listen="$(echo "$TCPListen" | sed '1d' | awk '/tcp/ {print $5}' | awk -F: '{print $NF}' | sort | uniq | wc -l)"
}

function getCronStatus(){
  echo ""
  echo ""
  echo "############################ 计划任务检查 ########################"
  Crontab=0
  for shell in $(grep -v "/sbin/nologin" /etc/shells); do
    for user in $(grep "$shell" /etc/passwd | awk -F: '{print $1}'); do
      crontab -l -u $user >/dev/null 2>&1
      status=$?
      if [ $status -eq 0 ]; then
        echo "$user"
        echo "--------"
        crontab -l -u $user
        let Crontab=Crontab+$(crontab -l -u $user | wc -l)
        echo ""
      fi
    done
  done
  find /etc/cron* -type f | xargs -i ls -l {} | column -t
  let Crontab=Crontab+$(find /etc/cron* -type f | wc -l)
  report_Crontab="$Crontab"
}

function getUserStatus(){
  echo ""
  echo ""
  echo "############################ 用户检查 ############################"
  pwdfile="$(cat /etc/passwd)"
  Modify=$(stat /etc/passwd | grep Modify | tr '.' ' ' | awk '{print $2,$3}')
  echo "/etc/passwd 最后修改时间:$Modify ($(getHowLongAgo $Modify))"
  echo ""
  echo "特权用户"
  echo "--------"
  RootUser=""
  for user in $(echo "$pwdfile" | awk -F: '{print $1}'); do
    if [ $(id -u $user) -eq 0 ]; then
      echo "$user"
      RootUser=",$user"
    fi
  done
  RootUser=$(echo $RootUser | sed 's/^,//')
  echo ""
  echo "用户列表"
  echo "--------"
  USERs=0
  echo "$(
    echo "用户名 UID GID HOME SHELL 最后一次登录"
    for shell in $(grep -v "/sbin/nologin" /etc/shells); do
      for username in $(grep "$shell" /etc/passwd | awk -F: '{print $1}'); do
        userLastLogin="$(getUserLastLogin $username)"
        echo "$pwdfile" | grep -w "$username" | grep -w "$shell" | awk -F: -v lastlogin="${userLastLogin// /_}" '{print $1,$3,$4,$6,$7,lastlogin}'
      done
      let USERs=USERs+$(echo "$pwdfile" | grep "$shell" | wc -l)
    done
  )" | column -t)
  echo ""
  echo "空密码用户"
  echo "----------"
  USEREmptyPassword=""
  for shell in $(grep -v "/sbin/nologin" /etc/shells); do
    for user in $(echo "$pwdfile" | grep "$shell" | cut -d: -f1); do
      r=$(awk -F: '$2=="!!"{print $1}' /etc/shadow | grep -w $user)
      if [ ! -z $r ]; then
        echo $r
        USEREmptyPassword="$USEREmptyPassword,$r"
      fi
    done
  done
  USEREmptyPassword=$(echo $USEREmptyPassword | sed 's/^,//')
  echo ""
  echo "相同ID的用户"
  echo "------------"
  USERTheSameUID=""
  UIDs=$(cut -d: -f3 /etc/passwd | sort | uniq -c | awk '$1>1{print $2}')
  for uid in $UIDs; do
    echo -n "$uid"
    USERTheSameUID="$uid"
    r=$(awk -F: -v uid="$uid" '$3==uid{print ":",$1}' /etc/passwd)
    echo "$r"
    USERTheSameUID="$USERTheSameUID $r"
  done
  report_USERs="$USERs"
  report_USEREmptyPassword="$USEREmptyPassword"
  report_USERTheSameUID="$(echo $USERTheSameUID | sed 's/ $//')"
  report_RootUser="$RootUser"
}

function getPasswordStatus(){
  echo ""
  echo ""
  echo "############################ 密码检查 ############################"
  pwdfile="$(cat /etc/passwd)"
  echo ""
  echo "密码过期检查"
  echo "------------"
  result=""
  for shell in $(grep -v "/sbin/nologin" /etc/shells); do
    for user in $(echo "$pwdfile" | grep "$shell" | cut -d: -f1); do
      get_expiry_date=$(/usr/bin/chage -l $user | grep 'Password expires' | cut -d: -f2)
      if [[ $get_expiry_date = ' never' || $get_expiry_date = 'never' ]]; then
        printf "%-15s 永不过期
" $user
        result="$result,$user:never"
      else
        password_expiry_date=$(date -d "$get_expiry_date" +%s)
        current_date=$(date +%s)
        diff=$((password_expiry_date-current_date))
        let DAYS=$((diff/(60*60*24)))
        printf "%-15s %s天后过期
" $user $DAYS
        result="$result,$user:$DAYS days"
      fi
    done
  done
  report_PasswordExpiry="$(echo $result | sed 's/^,//')"
  echo ""
  echo "密码策略检查"
  echo "------------"
  grep -v "#" /etc/login.defs | grep -E "PASS_MAX_DAYS|PASS_MIN_DAYS|PASS_MIN_LEN|PASS_WARN_AGE"
}

function getSudoersStatus(){
  echo ""
  echo ""
  echo "############################ Sudoers检查 #########################"
  conf=$(grep -v "^#" /etc/sudoers | grep -v "^Defaults" | sed '/^$/d')
  echo "$conf"
  echo ""
  report_Sudoers="$(echo $conf | wc -l)"
}

function getInstalledStatus(){
  echo ""
  echo ""
  echo "############################ 软件检查 ############################"
  rpm -qa --last | head | column -t
}

function getProcessStatus(){
  echo ""
  echo ""
  echo "############################ 进程检查 ############################"
  if [ $(ps -ef | grep defunct | grep -v grep | wc -l) -ge 1 ]; then
    echo ""
    echo "僵尸进程"
    echo "--------"
    ps -ef | head -n1
    ps -ef | grep defunct | grep -v grep
  fi
  echo ""
  echo "内存占用TOP10"
  echo "-------------"
  echo -e "PID %MEM RSS COMMAND
$(ps aux | awk '{print $2, $4, $6, $11}' | sort -k3rn | head -n 10)" | column -t
  echo ""
  echo "CPU占用TOP10"
  echo "------------"
  top -b -n1 | head -17 | tail -11
  report_DefunctProsess="$(ps -ef | grep defunct | grep -v grep | wc -l)"
}

function getJDKStatus(){
  echo ""
  echo ""
  echo "############################ JDK检查 #############################"
  java -version 2>/dev/null
  if [ $? -eq 0 ]; then
    java -version 2>&1
  fi
  echo "JAVA_HOME=\"$JAVA_HOME\""
  report_JDK="$(java -version 2>&1 | grep version | awk '{print $1,$3}' | tr -d '\"')"
}

function getSyslogStatus(){
  echo ""
  echo ""
  echo "############################ syslog检查 ##########################"
  echo "服务状态:$(getState rsyslog)"
  echo ""
  echo "/etc/rsyslog.conf"
  echo "-----------------"
  cat /etc/rsyslog.conf 2>/dev/null | grep -v "^#" | grep -v "^$" | sed '/^$/d' | column -t
  report_Syslog="$(getState rsyslog)"
}

function getFirewallStatus(){
  echo ""
  echo ""
  echo "############################ 防火墙检查 ##########################"
  if [[ $centosVersion < 7 ]]; then
    /etc/init.d/iptables status >/dev/null 2>&1
    status=$?
    if [ $status -eq 0 ]; then s="active"; elif [ $status -eq 3 ]; then s="inactive"; elif [ $status -eq 4 ]; then s="permission denied"; else s="unknown"; fi
  else
    s="$(getState iptables)"
  fi
  echo "iptables: $s"
  echo ""
  echo "/etc/sysconfig/iptables"
  echo "-----------------------"
  cat /etc/sysconfig/iptables 2>/dev/null
  report_Firewall="$s"
}

function getSNMPStatus(){
  echo ""
  echo ""
  echo "############################ SNMP检查 ############################"
  status="$(getState snmpd)"
  echo "服务状态:$status"
  echo ""
  if [ -e /etc/snmp/snmpd.conf ]; then
    echo "/etc/snmp/snmpd.conf"
    echo "--------------------"
    cat /etc/snmp/snmpd.conf 2>/dev/null | grep -v "^#" | sed '/^$/d'
  fi
  report_SNMP="$status"
}

function getState(){
  if [[ $centosVersion < 7 ]]; then
    if [ -e "/etc/init.d/$1" ]; then
      if [ `/etc/init.d/$1 status 2>/dev/null | grep -E "is running|正在运行" | wc -l` -ge 1 ]; then
        r="active"
      else
        r="inactive"
      fi
    else
      r="unknown"
    fi
  else
    r="$(systemctl is-active $1 2>&1)"
  fi
  echo "$r"
}

function getSSHStatus(){
  echo ""
  echo ""
  echo "############################ SSH检查 #############################"
  echo "服务状态:$(getState sshd)"
  Protocol_Version=$(cat /etc/ssh/sshd_config | grep Protocol | awk '{print $2}')
  echo "SSH协议版本:$Protocol_Version"
  echo ""
  echo "信任主机"
  echo "--------"
  authorized=0
  for user in $(echo "$pwdfile" | grep /bin/bash | awk -F: '{print $1}'); do
    authorize_file=$(echo "$pwdfile" | grep -w $user | awk -F: '{printf $6"/.ssh/authorized_keys"}')
    authorized_host=$(cat $authorize_file 2>/dev/null | awk '{print $3}' | tr '
' ',' | sed 's/,$//')
    if [ ! -z $authorized_host ]; then
      echo "$user 授权 \"$authorized_host\" 无密码访问"
    fi
    let authorized=authorized+$(cat $authorize_file 2>/dev/null | awk '{print $3}' | wc -l)
  done
  echo ""
  echo "是否允许ROOT远程登录"
  echo "--------------------"
  config=$(cat /etc/ssh/sshd_config | grep PermitRootLogin)
  firstChar=${config:0:1}
  if [ $firstChar == "#" ]; then
    PermitRootLogin="yes"
  else
    PermitRootLogin=$(echo $config | awk '{print $2}')
  fi
  echo "PermitRootLogin $PermitRootLogin"
  echo ""
  echo "/etc/ssh/sshd_config"
  echo "--------------------"
  cat /etc/ssh/sshd_config | grep -v "^#" | sed '/^$/d'
  report_SSHAuthorized="$authorized"
  report_SSHDProtocolVersion="$Protocol_Version"
  report_SSHDPermitRootLogin="$PermitRootLogin"
}

function getNTPStatus(){
  echo ""
  echo ""
  echo "############################ NTP检查 #############################"
  if [ -e /etc/ntp.conf ]; then
    echo "服务状态:$(getState ntpd)"
    echo ""
    echo "/etc/ntp.conf"
    echo "-------------"
    cat /etc/ntp.conf 2>/dev/null | grep -v "^#" | sed '/^$/d'
  fi
  report_NTP="$(getState ntpd)"
}

function check(){
  version
  getSystemStatus
  getCpuStatus
  getMemStatus
  getDiskStatus
  getNetworkStatus
  getListenStatus
  getProcessStatus
  getServiceStatus
  getAutoStartStatus
  getLoginStatus
  getCronStatus
  getUserStatus
  getPasswordStatus
  getSudoersStatus
  getJDKStatus
  getFirewallStatus
  getSSHStatus
  getSyslogStatus
  getSNMPStatus
  getNTPStatus
  getInstalledStatus
  getchage_file_24h
}

#执行检查并保存检查结果
check > $RESULTFILE

echo "检查结果:$RESULTFILE"

echo -e "$(date "+%Y-%m-%d %H:%M:%S") 阿里云PHP企业平台巡检报告" | mail -a $RESULTFILE -s "阿里云PHP企业平台巡检报告" [email protected]
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

system-monitoringDaily Inspection
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.