首页
恋爱日记
数据统计
留言板
更多
友情链接
Search
1
CentOS7安装部署weblogic12.1.1
3,130 阅读
2
Docker真的被Kubernetes放弃了吗?
2,825 阅读
3
一款可以自定义VScode背景的插件
2,684 阅读
4
Nginx搭建本地YUM仓库
2,352 阅读
5
CentOS 7安装fail2ban+Firewalld防止SSH爆破与CC攻击
2,158 阅读
Prometheus网站监控面板
Vscode
Typecho优化
Ops工具
Linux
Shell
Nginx
Weblogic
云原生
Kubernetes
Docker
Ceph
监控
Promethues
Zabbix
Grafana
数据库
MySQL
登录
Search
废柴阿尤
累计撰写
25
篇文章
累计收到
14
条评论
首页
栏目
Prometheus网站监控面板
Vscode
Typecho优化
Ops工具
Linux
Shell
Nginx
Weblogic
云原生
Kubernetes
Docker
Ceph
监控
Promethues
Zabbix
Grafana
数据库
MySQL
页面
恋爱日记
数据统计
留言板
友情链接
搜索到
25
篇与
的结果
2022-10-20
非常实用的常用Linux运维Shell脚本
运维可以根据实际情况进行修改 {message type="success" content="本文章长期更新常用脚本"/}{collapse}{collapse-item label="mysql备份脚本" open}#!/bin/bash set -e USER="backup" PASSWORD="backup" # 数据库数据目录 # DATA_DIR="/data/mysql" BIN_INDEX=$DATA_DIR"/mysql-bin.index" # 备份目录 # BACKUP_DIR="/data/backup/mysql" BACKUP_LOG="/var/log/mysql/backup.log" DATE=`date +"%Y%m%d"` TIME=`date +"%Y%m%d%H"` LOG_TIME=`date +"%Y-%m-%d %H:%M:%S"` DELETE_BINLOG_TIME="7 day" INCREMENT_INTERVAL="3 hour" note() { printf "[$LOG_TIME] note: $*\n" >> $BACKUP_LOG; } warning() { printf "[$LOG_TIME] warning: $*\n" >> $BACKUP_LOG; } error() { printf "[$LOG_TIME] error: $*\n" >> $BACKUP_LOG; exit 1; } full_backup() { local dbs=`ls -l $DATA_DIR | grep "^d" | awk -F " " '{print $9}'` for db in $dbs do local backup_dir=$BACKUP_DIR"/full/"$db local filename=$db"."$DATE local backup_file=$backup_dir"/"$filename".sql" if [ ! -d $backup_dir ] then mkdir -p $backup_dir || { error "创建数据库 $db 全量备份目录 $backup_dir 失败"; continue; } note "数据库 $db 全量备份目录 $backup_dir 不存在,创建完成"; fi note "full backup $db start ..." mysqldump --user=${USER} --password=${PASSWORD} --flush-logs --skip-lock-tables --quick $db > $backup_file || { warning "数据库 $db 备份失败"; continue; } cd $backup_dir tar -cPzf $filename".tar.gz" $filename".sql" rm -f $backup_file chown -fR mysql:mysql $backup_dir note "数据库 $db 备份成功"; note "full backup $db end." done } increment_backup() { local StartTime=`date "-d $INCREMENT_INTERVAL ago" +"%Y-%m-%d %H:%M:%S"` local DELETE_BINLOG_END_TIME=`date "-d $DELETE_BINLOG_TIME ago" +"%Y-%m-%d %H:%M:%S"` local dbs=`ls -l $DATA_DIR | grep "^d" | awk -F " " '{print $9}'` mysql -u$USER -p$PASSWORD -e "purge master logs before '$DELETE_BINLOG_END_TIME'" && note "delete $DELETE_BINLOG_TIME days before log"; filename=`cat $BIN_INDEX | awk -F "/" '{print $2}'` for i in $filename do for db in $dbs do local backup_dir=$BACKUP_DIR"/increment/"$db local filename=$db"."$TIME local backup_file=$backup_dir"/"$filename".sql" if [ ! -d $backup_dir ] then mkdir -p $backup_dir || { error "创建数据库 $db 增量备份目录 $backup_dir 失败"; continue; } note "数据库 $db 增量备份目录 $backup_dir 不存在,创建完成"; fi note "increment backup $db form time $StartTime start ..." mysqlbinlog -d $db --start-datetime="$StartTime" $DATA_DIR/$i >> $backup_file || { warning "数据库 $db 备份失败"; continue; } note "increment backup $db end." done done for db in $dbs do local backup_dir=$BACKUP_DIR"/increment/"$db local filename=$db"."$TIME local backup_file=$backup_dir"/"$filename".sql" cd $backup_dir tar -cPzf $filename".tar.gz" $filename".sql" rm -f $backup_file note "数据库 $db 备份成功"; done } case "$1" in full) full_backup ;; increment) increment_backup ;; *) exit 2 ;; esac exit 1{/collapse-item}{collapse-item label="Dos 攻击防范(自动屏蔽攻击 IP)"}#!/bin/bash DATE=$(date +%d/%b/%Y:%H:%M) LOG_FILE=/usr/local/nginx/logs/demo2.access.log ABNORMAL_IP=$(tail -n5000 $LOG_FILE |grep $DATE |awk '{a[$1]++}END{for(i in a)if(a[i]>10)print i}') for IP in $ABNORMAL_IP; do if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then iptables -I INPUT -s $IP -j DROP echo "$(date +'%F_%T') $IP" >> /tmp/drop_ip.log fi done{/collapse-item}{collapse-item label="Linux 系统发送告警脚本"}# yum install mailx # vi /etc/mail.rc set from=baojingtongzhi@163.com smtp=smtp.163.com set smtp-auth-user=baojingtongzhi@163.com smtp-auth-password=******* set smtp-auth=login{/collapse-item}{collapse-item label="MySQL 数据库备份单循环"}#!/bin/bash DATE=$(date +%F_%H-%M-%S) HOST=localhost USER=backup PASS=123.com BACKUP_DIR=/data/db_backup DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys") for DB in $DB_LIST; do BACKUP_NAME=$BACKUP_DIR/${DB}_${DATE}.sql if ! mysqldump -h$HOST -u$USER -p$PASS -B $DB > $BACKUP_NAME 2>/dev/null; then echo "$BACKUP_NAME 备份失败!" fi done{/collapse-item}{collapse-item label="MySQL 数据库备份多循环"}#!/bin/bash DATE=$(date +%F_%H-%M-%S) HOST=localhost USER=backup PASS=123.com BACKUP_DIR=/data/db_backup DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys") for DB in $DB_LIST; do BACKUP_DB_DIR=$BACKUP_DIR/${DB}_${DATE} [ ! -d $BACKUP_DB_DIR ] && mkdir -p $BACKUP_DB_DIR &>/dev/null TABLE_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "use $DB;show tables;" 2>/dev/null) for TABLE in $TABLE_LIST; do BACKUP_NAME=$BACKUP_DB_DIR/${TABLE}.sql if ! mysqldump -h$HOST -u$USER -p$PASS $DB $TABLE > $BACKUP_NAME 2>/dev/null; then echo "$BACKUP_NAME 备份失败!" fi done done{/collapse-item}{collapse-item label="Nginx 访问访问日志按天切割"}#!/bin/bash LOG_DIR=/usr/local/nginx/logs YESTERDAY_TIME=$(date -d "yesterday" +%F) LOG_MONTH_DIR=$LOG_DIR/$(date +"%Y-%m") LOG_FILE_LIST="default.access.log" for LOG_FILE in $LOG_FILE_LIST; do [ ! -d $LOG_MONTH_DIR ] && mkdir -p $LOG_MONTH_DIR mv $LOG_DIR/$LOG_FILE $LOG_MONTH_DIR/${LOG_FILE}_${YESTERDAY_TIME} done kill -USR1 $(cat /var/run/nginx.pid){/collapse-item}{collapse-item label="Nginx 访问日志分析脚本"}#!/bin/bash # 日志格式: $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" LOG_FILE=$1 echo "统计访问最多的10个IP" awk '{a[$1]++}END{print "UV:",length(a);for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr |head -10 echo "----------------------" echo "统计时间段访问最多的IP" awk '$4>="[01/Dec/2018:13:20:25" && $4<="[27/Nov/2018:16:20:49"{a[$1]++}END{for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr|head -10 echo "----------------------" echo "统计访问最多的10个页面" awk '{a[$7]++}END{print "PV:",length(a);for(v in a){if(a[v]>10)print v,a[v]}}' $LOG_FILE |sort -k2 -nr echo "----------------------" echo "统计访问页面状态码数量" awk '{a[$7" "$9]++}END{for(v in a){if(a[v]>5)print v,a[v]}}'{/collapse-item}{collapse-item label="查看网卡实时流量脚本"}#!/bin/bash NIC=$1 echo -e " In ------ Out" while true; do OLD_IN=$(awk '$0~"'$NIC'"{print $2}' /proc/net/dev) OLD_OUT=$(awk '$0~"'$NIC'"{print $10}' /proc/net/dev) sleep 1 NEW_IN=$(awk '$0~"'$NIC'"{print $2}' /proc/net/dev) NEW_OUT=$(awk '$0~"'$NIC'"{print $10}' /proc/net/dev) IN=$(printf "%.1f%s" "$((($NEW_IN-$OLD_IN)/1024))" "KB/s") OUT=$(printf "%.1f%s" "$((($NEW_OUT-$OLD_OUT)/1024))" "KB/s") echo "$IN $OUT" sleep 1 done{/collapse-item}{collapse-item label="服务器系统配置初始化脚本"}#/bin/bash # 设置时区并同步时间 ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime if ! crontab -l |grep ntpdate &>/dev/null ; then (echo "* 1 * * * ntpdate time.windows.com >/dev/null 2>&1";crontab -l) |crontab fi # 禁用selinux sed -i '/SELINUX/{s/permissive/disabled/}' /etc/selinux/config # 关闭防火墙 if egrep "7.[0-9]" /etc/redhat-release &>/dev/null; then systemctl stop firewalld systemctl disable firewalld elif egrep "6.[0-9]" /etc/redhat-release &>/dev/null; then service iptables stop chkconfig iptables off fi # 历史命令显示操作时间 if ! grep HISTTIMEFORMAT /etc/bashrc; then echo 'export HISTTIMEFORMAT="%F %T `whoami` "' >> /etc/bashrc fi # SSH超时时间 if ! grep "TMOUT=600" /etc/profile &>/dev/null; then echo "export TMOUT=600" >> /etc/profile fi # 禁止root远程登录 sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config # 禁止定时任务向发送邮件 sed -i 's/^MAILTO=root/MAILTO=""/' /etc/crontab # 设置最大打开文件数 if ! grep "* soft nofile 65535" /etc/security/limits.conf &>/dev/null; then cat >> /etc/security/limits.conf << EOF * soft nofile 65535 * hard nofile 65535 EOF fi # 系统内核优化 cat >> /etc/sysctl.conf << EOF net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_tw_buckets = 20480 net.ipv4.tcp_max_syn_backlog = 20480 net.core.netdev_max_backlog = 262144 net.ipv4.tcp_fin_timeout = 20 EOF # 减少SWAP使用 echo "0" > /proc/sys/vm/swappiness # 安装系统性能分析工具及其他 yum install gcc make autoconf vim sysstat net-tools iostat if{/collapse-item}{collapse-item label="监控 100 台服务器磁盘利用率脚本"}#!/bin/bash HOST_INFO=host.info for IP in $(awk '/^[^#]/{print $1}' $HOST_INFO); do USER=$(awk -v ip=$IP 'ip==$1{print $2}' $HOST_INFO) PORT=$(awk -v ip=$IP 'ip==$1{print $3}' $HOST_INFO) TMP_FILE=/tmp/disk.tmp ssh -p $PORT $USER@$IP 'df -h' > $TMP_FILE USE_RATE_LIST=$(awk 'BEGIN{OFS="="}/^\/dev/{print $NF,int($5)}' $TMP_FILE) for USE_RATE in $USE_RATE_LIST; do PART_NAME=${USE_RATE%=*} USE_RATE=${USE_RATE#*=} if [ $USE_RATE -ge 80 ]; then echo "Warning: $PART_NAME Partition usage $USE_RATE%!" fi done done{/collapse-item}{collapse-item label="mysqldump备份所有库脚本"}#!/bin/bash date=`date +%Y_%m_%d'___'%H_%M_%S` ####################################### project_path=$(cd `dirname $0`; pwd) ####################################### start_time=`date --date='0 days ago' "+%Y-%m-%d %H:%M:%S"` u="puser" p="!O2222n" ip="127.0.0.1" port="3306" pwd="/opt/Myslq_Backup" mysql -u$u -p$p "-e show databases;" |awk '{print $1}' |egrep -v -e "Database" -e "performance_schema" -e "information_schema" > $pwd/Database_text for i in `(cat $pwd/Database_text)` do mysqldump -u$u -p$p $i > $pwd/${i}_$date.sql gzip $pwd/${i}_$date.sql done find $pwd/ -mtime +30 -name "*.gz" -exec rm -rf {} \; finish_time=`date --date='0 days ago' "+%Y-%m-%d %H:%M:%S"` duration=$(($(($(date +%s -d "$finish_time")-$(date +%s -d "$start_time"))))) echo -e "\033[41m 本次执行脚本耗时: $duration秒 \033[0m"{/collapse-item}{/collapse}
2022年10月20日
1,346 阅读
0 评论
261 点赞
2022-05-08
此内容被密码保护
加密文章,请前往内页查看详情
2022年05月08日
1,867 阅读
0 评论
1,162 点赞
2021-12-19
Kubernetes Pod与宿主机时区不同步
{alert type="error"}在安装Kubernetes集群的过程中并没有注意到pod的时间问题,直到在Tomcat上部署应用后发现pod中的时间与Node上的时间不同步。针对时区不同文章有以下解决方案{/alert}问题在Kubernetes集群中运行的容器默认会使用UTC时间,即北京时间为凌晨3点时,容器时间为晚上7点,中间会有8小时时差。而有些分布式系统对于时间极为敏感,不允许出现时间误差这里我们构建一个Nginx镜像,查看构建前的时间apiVersion: v1 kind: Pod metadata: name: time-nginx spec: containers: - name: time-nginx image: nginx args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']创建完Pod后我们查看一下时间[root@k8s-01 test]# kubectl logs -f time 337: Fri Dec 1 19:01:30 UTC 2021 338: Fri Dec 1 19:01:31 UTC 2021 339: Fri Dec 1 19:01:32 UTC 2021 340: Fri Dec 1 19:01:33 UTC 2021 341: Fri Dec 1 19:01:34 UTC 2021 342: Fri Dec 1 19:01:35 UTC 2021查看一下宿主机时间[root@k8s-01 ~]# date Wed Dec 15 00:00:51 CST 2021解决首先要确保宿主机时间同步timedatectl set-timezone Asia/Shanghai #将当前的 UTC 时间写入硬件时钟 timedatectl set-local-rtc 0 #重启依赖于系统时间的服务 systemctl restart rsyslog systemctl restart crond目前解决Pod和宿主机时间不一致有以下集中解决方案通过定制Dockerfile添加时区通过将时区文件挂在到Pod中通过环境变量定义时区进入容器内修改时区网上资料还有通过PodPreset的方式,但是我测试完毕之后没有效果~ 这里就不进行整理了通过定制Dockerfile添加时区$ cat Dockerfile.date FROM centos RUN rm -f /etc/localtime \ && ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone # 构建容器镜像 $ docker build -t centos7-date:test -f Dockerfile.date . Sending build context to Docker daemon 4.426GB Step 1/2 : FROM centos ---> 1e1148e4cc2c Step 2/2 : RUN rm -f /etc/localtime && ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone ---> Running in fe2e931c3cf2 '/etc/localtime' -> '/usr/share/zoneinfo/Asia/Shanghai' Removing intermediate container fe2e931c3cf2 ---> 2120143141c8 Successfully built 2120143141c8 Successfully tagged centos7-date:test $ docker run -it centos7-date:test /bin/sh sh-4.2# date Wed Dec 6 16:40:01 CST 2021通过将时区文件挂在到Pod中[root@k8s-01 test]# cat time-mount.yaml apiVersion: v1 kind: Pod metadata: name: time spec: containers: - name: time image: nginx args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done'] volumeMounts: - name: timezone mountPath: /etc/localtime volumes: - name: timezone hostPath: path: /usr/share/zoneinfo/Asia/Shanghai我们可以通过命令查看,/etc/localtime的目录实际上就是个软连接如果需要系统修改时区,那么只需要将时区文件覆盖到/etc/localtime,前提是我们设置好上海的时区。[root@k8s-01 test]# ll /etc/localtime lrwxrwxrwx. 1 root root 35 Apr 20 00:11 /etc/localtime -> ../usr/share/zoneinfo/Asia/Shanghai通过环境变量定义时区[root@k8s-01 test]# cat time.yaml apiVersion: v1 kind: Pod metadata: name: time-nginx spec: containers: - name: time-nginx image: nginx args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done'] env: - name: TZ value: Asia/Shanghai
2021年12月19日
1,840 阅读
0 评论
635 点赞
2021-12-16
Duplicity:企业级的增量备份与数据恢复工具
在日常运维中,数据备份和恢复是一项至关重要的任务。使用 Duplicity 进行数据备份和恢复是一个非常高效的方式。它的增量备份能节省大量的存储空间和带宽,同时还能为恢复过程带来便利。在备份策略中加入定期的全量备份和删除过期备份,可以更有效地管理你的备份文件。在这篇文章中,我们将简单介绍如何使用 Duplicity 进行网站数据的备份和恢复。以下是在 Debian 或 Ubuntu 系统上使用 Duplicity 进行网站数据备份和恢复的详细步骤:安装Duplicity和配置GPG密钥首先,我们需要在源服务器(即你希望备份数据的服务器)上安装 Duplicity。以下命令适用于 Debian 或 Ubuntu 系统:apt-get update apt-get install duplicity接下来,在源服务器上,为了增加数据的安全性,我们需要创建 GPG 密钥:gpg --gen-key gpg --list-keys最后,我们需要在源服务器上导出 GPG 密钥,并将其安全地传输到任何可能需要恢复数据的服务器(例如备份服务器或其他服务器):gpg --export-secret-keys YOUR-KEY-ID > private.key gpg --export YOUR-KEY-ID > public.key scp private.key user@recovery.server:/path/to/keydir scp public.key user@recovery.server:/path/to/keydir这里,YOUR-KEY-ID是你的GPG 密钥 ID。user 是恢复服务器的用户名,recovery.server 是恢复服务器的地址,/path/to/keydir 是存放密钥文件的目录。数据备份增量备份 Duplicity 默认进行增量备份。这意味着在首次备份全部数据后,之后的备份只会备份自上次备份以来更改过的文件,大幅节省存储空间和网络带宽:duplicity /var/www/html scp://user@backup.server//backup这里,user和 backup.server 需替换为实际的用户名和备份服务器地址。{alert type="error"}需要注意:命令使用双斜杠是因为SCP路径的特殊性。//表示这是一个绝对路径,//backup指的是根目录下的"backup"文件夹,即/backup目录,如果这里用单斜杆/那么/home指的则是用户的home目录下的"backup"文件夹。这个规则在SCP和RSYNC中都适用。{/alert}定期全量备份 尽管增量备份很有用,但定期进行全量备份可以降低数据恢复的复杂性。以下命令会在距离上次全量备份超过 30 天时,自动执行全量备份:duplicity --full-if-older-than 30D /var/www/html scp://user@backup.server//backup定期删除过期备份 为有效管理存储空间,我们需要定期删除过期的备份。以下命令将删除 60 天前的所有备份:duplicity remove-older-than 60D scp://user@backup.server//backup --force数据恢复要从备份中恢复数据,首先你需要在源服务器(或者任何你打算恢复数据的服务器)上导入之前用于加密备份的 GPG 密钥对,包括公钥和私钥:gpg --import /path/to/keydir/private.key gpg --import /path/to/keydir/public.key接着,使用 Duplicity 进行数据恢复:duplicity scp://user@backup.server//backup /var/www/html这将从备份服务器的 /backup目录恢复数据到本地的 /var/www/html目录。写在最后为什么是 Duplicity 而不是 rsync ?我们知道 rsync 在文件同步方面优秀,但其在备份中缺乏版本控制和错误检查,不能有效防止数据丢失。因此,我们建议备份关键数据时,考虑使用具备增量备份和数据加密功能的 Duplicity、BorgBackup 或类似工具,实现更安全、更有效的数据保护。
2021年12月16日
1,521 阅读
0 评论
538 点赞
2021-11-17
Linux 服务器日常巡检脚本分享
Linux 系统日常巡检脚本,巡检内容包含了,磁盘,内存`cpu进程文件更改`用户登录等一系列的操作直接用就行了。报告以邮件发送到邮箱在log下生成巡检报告。#!/bin/bash # @Author: Luckly # @Date: 2021-11-16 09:56:57 # @Last Modified by: Luckly # @Last Modified time: 2022-06-21 11:06:31 # @E-mail: llswdhh@163.com #!/bin/bash #主机信息每日巡检 IPADDR=$(ifconfig eth0|grep 'inet '|awk '{print $2}') #环境变量PATH没设好,在cron里执行时有很多命令会找不到 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="2021-11-16" #日志相关 PROGPATH=`echo $0 | sed -e 's,[\\/][^\\/][^\\/]*$,,'` [ -f $PROGPATH ] && PROGPATH="." LOGPATH="$PROGPATH/log" [ -e $LOGPATH ] || mkdir $LOGPATH RESULTFILE="$LOGPATH/`date +%Y-%m-%d`-HostDailyCheck-${IPADDR}.txt" #定义报表的全局变量 report_DateTime="" #日期 ok report_Hostname="" #主机名 ok report_OSRelease="" #发行版本 ok report_Kernel="" #内核 ok report_Language="" #语言/编码 ok report_LastReboot="" #最近启动时间 ok report_Uptime="" #运行时间(天) ok report_CPUs="" #CPU数量 ok report_CPUType="" #CPU类型 ok report_Arch="" #CPU架构 ok report_MemTotal="" #内存总容量(MB) ok report_MemFree="" #内存剩余(MB) ok report_MemUsedPercent="" #内存使用率% ok report_DiskTotal="" #硬盘总容量(GB) ok report_DiskFree="" #硬盘剩余(GB) ok report_DiskUsedPercent="" #硬盘使用率% ok report_InodeTotal="" #Inode总量 ok report_InodeFree="" #Inode剩余 ok report_InodeUsedPercent="" #Inode使用率 ok report_IP="" #IP地址 ok report_MAC="" #MAC地址 ok report_Gateway="" #默认网关 ok report_DNS="" #DNS ok report_Listen="" #监听 ok report_Selinux="" #Selinux ok report_Firewall="" #防火墙 ok report_USERs="" #用户 ok report_USEREmptyPassword="" #空密码用户 ok report_USERTheSameUID="" #相同ID的用户 ok report_PasswordExpiry="" #密码过期(天) ok report_RootUser="" #root用户 ok report_Sudoers="" #sudo授权 ok report_SSHAuthorized="" #SSH信任主机 ok report_SSHDProtocolVersion="" #SSH协议版本 ok report_SSHDPermitRootLogin="" #允许root远程登录 ok report_DefunctProsess="" #僵尸进程数量 ok report_SelfInitiatedService="" #自启动服务数量 ok report_SelfInitiatedProgram="" #自启动程序数量 ok report_RuningService="" #运行中服务数 ok report_Crontab="" #计划任务数 ok report_Syslog="" #日志服务 ok report_SNMP="" #SNMP OK report_NTP="" #NTP ok report_JDK="" #JDK版本 ok 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 #CPU数量 report_CPUType=$CPU_Type #CPU类型 report_Arch=$CPU_Arch #CPU架构 } function getMemStatus(){ echo "" echo "" echo "############################ 内存检查 ############################" if [[ $centosVersion < 7 ]];then free -mo else free -h fi #报表信息 MemTotal=$(grep MemTotal /proc/meminfo| awk '{print $2}') #KB MemFree=$(grep MemFree /proc/meminfo| awk '{print $2}') #KB let MemUsed=MemTotal-MemFree MemPercent=$(awk "BEGIN {if($MemTotal==0){printf 100}else{printf \"%.2f\",$MemUsed*100/$MemTotal}}") report_MemTotal="$((MemTotal/1024))""MB" #内存总容量(MB) report_MemFree="$((MemFree/1024))""MB" #内存剩余(MB) report_MemUsedPercent="$(awk "BEGIN {if($MemTotal==0){printf 100}else{printf \"%.2f\",$MemUsed*100/$MemTotal}}")""%" #内存使用率% } 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}') #KB disktotal=$(echo "$diskdata" | awk '{total+=$3}END{print total}') #KB diskused=$(echo "$diskdata" | awk '{total+=$4}END{print total}') #KB diskfree=$((disktotal-diskused)) #KB 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" #硬盘总容量(GB) report_DiskFree=$((diskfree/1024/1024))"GB" #硬盘剩余(GB) report_DiskUsedPercent="$diskusedpercent""%" #硬盘使用率% report_InodeTotal=$((inodetotal/1000))"K" #Inode总量 report_InodeFree=$((inodefree/1000))"K" #Inode剩余 report_InodeUsedPercent="$inodeusedpercent""%" #Inode使用率% } 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 "############################ 服务检查 ############################" 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 #ip a for i in $(ip link | grep BROADCAST | awk -F: '{print $2}');do ip add show $i | grep -E "BROADCAST|global"| awk '{print $2}' | tr '\n' ' ' ;echo "" ;done fi GATEWAY=$(ip route | grep default | awk '{print $3}') DNS=$(grep nameserver /etc/resolv.conf| grep -v "#" | awk '{print $2}' | tr '\n' ',' | sed 's/,$//') echo "" echo "网关:$GATEWAY " echo " DNS:$DNS" #报表信息 IP=$(ip -f inet addr | grep -v 127.0.0.1 | grep inet | awk '{print $NF,$2}' | tr '\n' ',' | sed 's/,$//') MAC=$(ip link | grep -v "LOOPBACK\|loopback" | awk '{print $2}' | sed 'N;s/\n//' | tr '\n' ',' | sed 's/,$//') report_IP="$IP" #IP地址 report_MAC=$MAC #MAC地址 report_Gateway="$GATEWAY" #默认网关 report_DNS="$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 getHowLongAgo(){ # 计算一个时间戳离现在有多久了 datetime="$*" [ -z "$datetime" ] && echo "错误的参数:getHowLongAgo() $*" Timestamp=$(date +%s -d "$datetime") #转化为时间戳 Now_Timestamp=$(date +%s) Difference_Timestamp=$(($Now_Timestamp-$Timestamp)) days=0;hours=0;minutes=0; sec_in_day=$((60*60*24)); sec_in_hour=$((60*60)); sec_in_minute=60 while (( $(($Difference_Timestamp-$sec_in_day)) > 1 )) do let Difference_Timestamp=Difference_Timestamp-sec_in_day let days++ done while (( $(($Difference_Timestamp-$sec_in_hour)) > 1 )) do let Difference_Timestamp=Difference_Timestamp-sec_in_hour let hours++ done echo "$days 天 $hours 小时前" } function getUserLastLogin(){ # 获取用户最近一次登录的时间,含年份 # 很遗憾last命令不支持显示年份,只有"last -t YYYYMMDDHHMMSS"表示某个时间之间的登录,我 # 们只能用最笨的方法了,对比今天之前和今年元旦之前(或者去年之前和前年之前……)某个用户 # 登录次数,如果登录统计次数有变化,则说明最近一次登录是今年。 username=$1 : ${username:="`whoami`"} thisYear=$(date +%Y) oldesYear=$(last | tail -n1 | awk '{print $NF}') while(( $thisYear >= $oldesYear));do loginBeforeToday=$(last $username | grep $username | wc -l) loginBeforeNewYearsDayOfThisYear=$(last $username -t $thisYear"0101000000" | grep $username | wc -l) if [ $loginBeforeToday -eq 0 ];then echo "从未登录过" break elif [ $loginBeforeToday -gt $loginBeforeNewYearsDayOfThisYear ];then lastDateTime=$(last -i $username | head -n1 | awk '{for(i=4;i<(NF-2);i++)printf"%s ",$i}')" $thisYear" #格式如: Sat Nov 2 20:33 2015 lastDateTime=$(date "+%Y-%m-%d %H:%M:%S" -d "$lastDateTime") echo "$lastDateTime" break else thisYear=$((thisYear-1)) fi done } function getUserStatus(){ echo "" echo "" echo "############################ 用户检查 ############################" #/etc/passwd 最后修改时间 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="$RootUser,$user" fi done 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="$(echo "$userLastLogin" | tr ' ' '_')" '{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 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: 'ORS="";$3=='"$uid"'{print ":",$1}' /etc/passwd) echo "$r" echo "" USERTheSameUID="$USERTheSameUID $r," done #报表信息 report_USERs="$USERs" #用户 report_USEREmptyPassword=$(echo $USEREmptyPassword | sed 's/^,//') report_USERTheSameUID=$(echo $USERTheSameUID | sed 's/,$//') report_RootUser=$(echo $RootUser | sed 's/^,//') #特权用户 } 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 永不过期\n" $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天后过期\n" $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(){ #SNMP服务状态,配置等 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="$(getState snmpd)" } 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 #CentOS 7+ r="$(systemctl is-active $1 2>&1)" fi echo "$r" } function getSSHStatus(){ #SSHD服务状态,配置,受信任主机等 echo "" echo "" echo "############################ SSH检查 #############################" #检查受信任主机 pwdfile="$(cat /etc/passwd)" 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 '\n' ',' | 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" #默认是允许ROOT远程登录的 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" #SSH信任主机 report_SSHDProtocolVersion="$Protocol_Version" #SSH协议版本 report_SSHDPermitRootLogin="$PermitRootLogin" #允许root远程登录 } function getNTPStatus(){ #NTP服务状态,当前时间,配置等 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 uploadHostDailyCheckReport(){ json="{ \"DateTime\":\"$report_DateTime\", \"Hostname\":\"$report_Hostname\", \"OSRelease\":\"$report_OSRelease\", \"Kernel\":\"$report_Kernel\", \"Language\":\"$report_Language\", \"LastReboot\":\"$report_LastReboot\", \"Uptime\":\"$report_Uptime\", \"CPUs\":\"$report_CPUs\", \"CPUType\":\"$report_CPUType\", \"Arch\":\"$report_Arch\", \"MemTotal\":\"$report_MemTotal\", \"MemFree\":\"$report_MemFree\", \"MemUsedPercent\":\"$report_MemUsedPercent\", \"DiskTotal\":\"$report_DiskTotal\", \"DiskFree\":\"$report_DiskFree\", \"DiskUsedPercent\":\"$report_DiskUsedPercent\", \"InodeTotal\":\"$report_InodeTotal\", \"InodeFree\":\"$report_InodeFree\", \"InodeUsedPercent\":\"$report_InodeUsedPercent\", \"IP\":\"$report_IP\", \"MAC\":\"$report_MAC\", \"Gateway\":\"$report_Gateway\", \"DNS\":\"$report_DNS\", \"Listen\":\"$report_Listen\", \"Selinux\":\"$report_Selinux\", \"Firewall\":\"$report_Firewall\", \"USERs\":\"$report_USERs\", \"USEREmptyPassword\":\"$report_USEREmptyPassword\", \"USERTheSameUID\":\"$report_USERTheSameUID\", \"PasswordExpiry\":\"$report_PasswordExpiry\", \"RootUser\":\"$report_RootUser\", \"Sudoers\":\"$report_Sudoers\", \"SSHAuthorized\":\"$report_SSHAuthorized\", \"SSHDProtocolVersion\":\"$report_SSHDProtocolVersion\", \"SSHDPermitRootLogin\":\"$report_SSHDPermitRootLogin\", \"DefunctProsess\":\"$report_DefunctProsess\", \"SelfInitiatedService\":\"$report_SelfInitiatedService\", \"SelfInitiatedProgram\":\"$report_SelfInitiatedProgram\", \"RuningService\":\"$report_RuningService\", \"Crontab\":\"$report_Crontab\", \"Syslog\":\"$report_Syslog\", \"SNMP\":\"$report_SNMP\", \"NTP\":\"$report_NTP\", \"JDK\":\"$report_JDK\" }" #echo "$json" curl -l -H "Content-type: application/json" -X POST -d "$json" "$uploadHostDailyCheckReportApi" 2>/dev/null } function getchage_file_24h() { echo "############################ 文件检查 #############################" check2=$(find / -name '*.sh' -mtime -1) check21=$(find / -name '*.asp' -mtime -1) check22=$(find / -name '*.php' -mtime -1) check23=$(find / -name '*.aspx' -mtime -1) check24=$(find / -name '*.jsp' -mtime -1) check25=$(find / -name '*.html' -mtime -1) check26=$(find / -name '*.htm' -mtime -1) check9=$(find / -name core -exec ls -l {} \;) check10=$(cat /etc/crontab) check12=$(ls -alt /usr/bin | head -10) cat <<EOF ############################查看所有被修改过的文件返回最近24小时内的############################ ${check2} ${check21} ${check22} ${check23} ${check24} ${check25} ${check26} ${line} ############################检查定时文件的完整性############################ ${check10} ${line} ############################查看系统命令是否被替换############################ ${check12} ${line} EOF } 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"` 服务器巡检报告" | mail -a $RESULTFILE -s "服务器巡检报告" openai_ayou@163.com
2021年11月17日
1,466 阅读
0 评论
652 点赞
1
...
3
4
5
首页
复制
搜索
前进
后退
重载网页
和我当邻居