linux wall命令 (write all)

命令简介

wall 命令用于向所有已登录用户的终端发送广播消息。它是"write all"的缩写,通常用于系统管理员向所有用户发送系统通知、维护提醒、紧急警报等重要信息。wall消息会显示在所有用户的终端上,无论他们当前正在执行什么操作。

系统广播工具:wall 是系统管理员的重要工具,用于发送系统范围的通知。消息会以Broadcast Message的形式显示,并且会中断用户的当前工作,因此应谨慎使用。

基本语法

# 基本格式
wall [选项] [消息]

# 常用格式
wall "系统即将重启"          # 发送简单消息
wall < message.txt           # 从文件发送消息
echo "紧急通知" | wall      # 通过管道发送消息
wall -n "测试消息"           # 不显示标题头
wall -t 10 "10秒后显示"     # 设置超时时间

常用选项

选项 描述
-n, --nobanner 不显示横幅标题("Broadcast Message")
-t, --timeout 秒数 设置超时时间(默认300秒)
-g, --group 组名 只发送给指定组的用户
-f, --file 文件 从文件读取消息
-V, --version 显示版本信息
-h, --help 显示帮助信息

安装和可用性

wallutil-linux软件包的一部分,几乎所有Linux发行版都预装了:

# 1. 检查是否已安装
which wall
wall --version
# 输出示例:wall from util-linux 2.36.2

# 2. 如果未安装,安装util-linux
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install util-linux

# RHEL/CentOS
sudo yum install util-linux
# 或
sudo dnf install util-linux

# 3. 查看util-linux版本
wall --version
# 或
lsblk --version
# 这些命令都来自util-linux包

# 4. 从源码编译util-linux
wget https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.36/util-linux-2.36.2.tar.gz
tar -xzf util-linux-2.36.2.tar.gz
cd util-linux-2.36.2
./configure
make
sudo make install

# 5. 验证安装
wall "测试消息"
# 应该显示:Broadcast Message from root@hostname

# 6. 权限说明
# wall通常需要root权限或tty组权限
# 检查权限
ls -la $(which wall)
# 通常为:-rwxr-xr-x 1 root root

# 7. 相关工具
# util-linux包含的其他有用工具:
# - write: 向特定用户发送消息
# - mesg: 控制消息接收
# - wall: 广播消息
# - logger: 系统日志工具
# - dmesg: 内核消息
# - lsblk: 列出块设备
# - mount: 挂载文件系统
# - fdisk: 磁盘分区工具

# 8. 在容器中的可用性
# 大多数容器镜像不包含wall命令
# 如果需要,可以在Dockerfile中添加
# RUN apt-get update && apt-get install -y util-linux

实际示例

示例1:基本广播消息

使用wall发送基本广播消息:

# 1. 发送简单消息
wall "系统将在5分钟后重启,请保存您的工作。"
# 所有用户会看到:
# Broadcast Message from root@server (tty1) at 10:00 ...
# 系统将在5分钟后重启,请保存您的工作。

# 2. 发送多行消息
wall "紧急通知:
系统检测到硬件故障。
请立即保存您的工作。
系统将在3分钟后自动关机。"

# 3. 从文件发送消息
echo "计划维护通知:
时间:今晚22:00-24:00
内容:系统升级
影响:服务将不可用" > /tmp/maintenance.txt
wall < /tmp/maintenance.txt

# 4. 通过管道发送消息
echo "服务器负载过高,请关闭不必要的程序。" | wall
# 或
cat /var/log/messages | grep error | wall

# 5. 不显示标题头
wall -n "这是不显示标题的消息"
# 用户只会看到消息内容,没有"Broadcast Message"标题

# 6. 设置超时时间
wall -t 10 "这条消息10秒后消失"
# 默认超时是300秒(5分钟)

# 7. 发送给特定组
# 创建测试组
sudo groupadd staff
# 添加用户到组
sudo usermod -a -G staff alice
sudo usermod -a -G staff bob
# 发送给组
wall -g staff "员工会议通知:下午2点在会议室"

# 8. 从文件读取并发送
cat > /tmp/alert.txt << 'EOF'
紧急警报!
检测到安全漏洞。
请立即:
1. 保存工作
2. 退出登录
3. 联系管理员
EOF
wall -f /tmp/alert.txt

# 9. 结合变量发送消息
MESSAGE="今天是 $(date)
服务器: $(hostname)
IP地址: $(hostname -I)
请确保工作已保存。"
wall "$MESSAGE"

# 10. 在脚本中使用wall
#!/bin/bash
# 系统维护脚本
if [ "$EUID" -ne 0 ]; then
    echo "请以root身份运行此脚本"
    exit 1
fi

# 发送预警
wall "警告:系统维护将在5分钟后开始"

sleep 300  # 等待5分钟

# 发送最终通知
wall "系统维护现在开始,请立即保存工作!"

# 执行维护任务
systemctl stop apache2
# ... 其他维护操作

# 11. 发送彩色消息(如果终端支持)
# 注意:不是所有终端都支持ANSI颜色
echo -e "\033[1;31m紧急通知:服务器即将重启!\033[0m" | wall

# 12. 发送带格式的消息
cat << 'EOF' | wall
=======================
      系统通知
=======================
时间: $(date)
主机: $(hostname)
内容: 例行维护
=======================
EOF

# 13. 测试消息接收
# 终端1:接收消息
mesg y
# 等待消息

# 终端2:发送测试消息
wall "测试消息 $(date)"

# 14. 查看谁收到了消息
# wall不会显示谁收到了消息
# 但可以通过查看登录用户来估计
who
# 这些用户应该能收到消息

# 15. 避免消息被截断
# 长消息可能被截断,可以分多次发送
wall "第一部分:这是一个很长的消息,"
wall "第二部分:它被分成了多段发送。"

# 16. 紧急情况使用
# 在紧急情况下,可以直接发送
wall "!!! 紧急 !!! 立即撤离服务器!检测到火灾!"

# 17. 定期通知
# 使用cron定时发送
# 每天9点发送每日提醒
echo "0 9 * * * root echo '每日站会时间:9:30' | wall" | sudo tee -a /etc/crontab

# 18. 系统启动/关闭消息
# 在/etc/rc.local中添加
echo "wall '系统正在启动...'" >> /etc/rc.local
# 在关机脚本中添加
echo "wall '系统正在关闭...'" >> /etc/rc6.d/K99message

# 19. 消息日志记录
# 记录所有发送的wall消息
logger -t wall "发送消息:系统通知"
echo "系统通知" | wall

# 20. 权限检查
# 普通用户可能无法使用wall
# 检查权限
sudo -l wall
# 如果需要,可以配置sudo权限
echo "$USER ALL=(ALL) NOPASSWD: /usr/bin/wall" | sudo tee /etc/sudoers.d/wall

示例2:系统管理应用

在系统管理中使用wall命令:

#!/bin/bash
# 系统管理中的wall应用

# 1. 系统维护通知脚本
system_maintenance_notice() {
    local minutes=$1
    local reason=$2

    echo "发送系统维护通知..."

    # 提前通知
    wall "系统维护通知:$reason
维护将在 $minutes 分钟后开始。
请保存您的工作并退出。"

    # 倒计时通知
    for i in $(seq $minutes -1 1); do
        if [ $i -le 5 ]; then
            wall "⚠️ 最后警告:系统维护将在 $i 分钟后开始!"
        fi
        sleep 60
    done

    # 最终通知
    wall "🚨 系统维护现在开始!立即保存工作!"

    # 执行维护
    perform_maintenance

    # 完成通知
    wall "✅ 系统维护完成。服务已恢复。"
}

# 2. 服务器监控警报
server_monitoring_alerts() {
    # 监控CPU使用率
    while true; do
        cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)

        if (( $(echo "$cpu_usage > 90" | bc -l) )); then
            wall "⚠️ 高CPU使用率警报:${cpu_usage}%
请检查运行进程:top"
        fi

        # 监控内存
        mem_free=$(free -m | awk 'NR==2{print $4}')
        if [ $mem_free -lt 100 ]; then
            wall "⚠️ 低内存警报:仅剩 ${mem_free}MB 可用内存
请关闭不必要的程序。"
        fi

        # 监控磁盘
        disk_usage=$(df -h / | awk 'NR==2{print $5}' | cut -d'%' -f1)
        if [ $disk_usage -gt 90 ]; then
            wall "⚠️ 磁盘空间不足:已使用 ${disk_usage}%
请清理磁盘空间。"
        fi

        sleep 60
    done
}

# 3. 用户会话管理
user_session_management() {
    # 通知空闲用户
    who | while read user tty time; do
        idle_time=$(echo "$time" | awk -F: '{print $1}')
        if [ "$idle_time" -gt 60 ]; then
            wall -n "用户 $user:您的会话已空闲超过1小时,即将被断开。"
            sleep 300
            pkill -KILL -t "$tty"
        fi
    done

    # 广播登录用户数
    user_count=$(who | wc -l)
    wall "当前在线用户:$user_count 人"
}

# 4. 安全警报系统
security_alert_system() {
    # 监控失败登录
    tail -f /var/log/auth.log | while read line; do
        if echo "$line" | grep -q "Failed password"; then
            ip=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+')
            wall "🚨 安全警报:来自 $ip 的失败登录尝试!"
        fi

        if echo "$line" | grep -q "Accepted password"; then
            user=$(echo "$line" | awk '{print $9}')
            ip=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+')
            wall "🔐 登录通知:用户 $user 从 $ip 登录"
        fi
    done
}

# 5. 备份状态通知
backup_status_notification() {
    local backup_type=$1

    echo "开始 $backup_type 备份..."
    wall "开始 $backup_type 系统备份,可能会影响性能。"

    # 执行备份
    perform_backup

    if [ $? -eq 0 ]; then
        wall "✅ $backup_type 备份完成,状态:成功"
    else
        wall "❌ $backup_type 备份失败,请检查日志!"
    fi
}

# 6. 网络状态广播
network_status_broadcast() {
    # 网络中断通知
    if ! ping -c 2 8.8.8.8 &> /dev/null; then
        wall "🌐 网络连接中断!无法访问外部网络。"
    fi

    # 网络恢复通知
    if ping -c 2 8.8.8.8 &> /dev/null; then
        wall "🌐 网络连接已恢复。"
    fi

    # IP地址变化通知
    current_ip=$(hostname -I | awk '{print $1}')
    if [ -f /tmp/last_ip ] && [ "$current_ip" != "$(cat /tmp/last_ip)" ]; then
        wall "IP地址已更改:$(cat /tmp/last_ip) → $current_ip"
    fi
    echo "$current_ip" > /tmp/last_ip
}

# 7. 服务状态通知
service_status_notification() {
    local service=$1
    local action=$2

    wall "正在 $action $service 服务..."

    if systemctl $action $service; then
        wall "✅ $service 服务已成功 $action"
    else
        wall "❌ $service 服务 $action 失败"
    fi
}

# 8. 计划任务通知
scheduled_task_notification() {
    # 每日提醒
    echo "0 9 * * * root /usr/local/bin/daily_reminder.sh" | sudo tee -a /etc/crontab

    # daily_reminder.sh
    cat > /usr/local/bin/daily_reminder.sh << 'EOF'
#!/bin/bash
wall "📅 每日提醒:
1. 检查系统更新
2. 查看日志文件
3. 备份重要数据
祝您有高效的一天!"
EOF
    chmod +x /usr/local/bin/daily_reminder.sh
}

# 9. 系统更新通知
system_update_notification() {
    echo "检查系统更新..."
    wall "开始检查系统更新,请稍候..."

    if apt-get update && apt-get upgrade -s; then
        updates=$(apt-get upgrade -s | grep ^Inst | wc -l)
        wall "发现 $updates 个可用更新。建议在维护窗口更新。"
    fi
}

# 10. 灾难恢复通知
disaster_recovery_notification() {
    # 系统崩溃恢复
    wall "🚨 检测到系统异常!
正在尝试自动恢复...
请勿关闭电源!"

    # 执行恢复操作
    fsck -y /
    systemctl daemon-reload

    wall "✅ 系统恢复完成。
请报告任何异常情况。"
}

# 11. 主菜单
main_menu() {
    while true; do
        clear
        echo "=== 系统管理wall工具 ==="
        echo ""
        echo "1. 发送系统维护通知"
        echo "2. 启动服务器监控"
        echo "3. 管理用户会话"
        echo "4. 启动安全警报"
        echo "5. 发送备份通知"
        echo "6. 网络状态广播"
        echo "7. 服务状态通知"
        echo "8. 配置计划任务"
        echo "9. 系统更新通知"
        echo "10. 灾难恢复通知"
        echo "0. 退出"
        echo ""

        read -p "请选择操作: " choice

        case $choice in
            1)
                read -p "维护时间(分钟): " minutes
                read -p "维护原因: " reason
                system_maintenance_notice "$minutes" "$reason"
                ;;
            2)
                echo "启动服务器监控 (Ctrl+C停止)..."
                server_monitoring_alerts
                ;;
            3) user_session_management ;;
            4)
                echo "启动安全警报系统 (Ctrl+C停止)..."
                security_alert_system
                ;;
            5)
                read -p "备份类型: " backup_type
                backup_status_notification "$backup_type"
                ;;
            6) network_status_broadcast ;;
            7)
                read -p "服务名: " service
                read -p "操作(start/stop/restart): " action
                service_status_notification "$service" "$action"
                ;;
            8) scheduled_task_notification ;;
            9) system_update_notification ;;
            10) disaster_recovery_notification ;;
            0)
                echo "退出"
                exit 0
                ;;
            *)
                echo "无效选择"
                ;;
        esac

        echo ""
        read -p "按回车键继续..."
    done
}

# 运行主菜单
main_menu

示例3:企业级消息系统

企业环境中wall的高级应用:

#!/bin/bash
# 企业级消息系统

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# 1. 企业消息分类
send_enterprise_message() {
    local level=$1
    local department=$2
    local message=$3

    case $level in
        "emergency")
            color=$RED
            prefix="🚨 紧急"
            ;;
        "alert")
            color=$YELLOW
            prefix="⚠️ 警报"
            ;;
        "critical")
            color=$MAGENTA
            prefix="🔴 严重"
            ;;
        "warning")
            color=$YELLOW
            prefix="⚠️ 警告"
            ;;
        "notice")
            color=$BLUE
            prefix="📢 通知"
            ;;
        "info")
            color=$GREEN
            prefix="ℹ️ 信息"
            ;;
        "debug")
            color=$CYAN
            prefix="🐛 调试"
            ;;
        *)
            color=$NC
            prefix="📝 消息"
            ;;
    esac

    # 构建格式化消息
    formatted_message="
========================================
$prefix | 部门: $department | 级别: $level
时间: $(date)
主机: $(hostname)
========================================
$message
========================================
"

    # 发送消息
    echo -e "${color}$formatted_message${NC}" | wall

    # 记录到日志
    logger -t "enterprise_wall" "级别=$level 部门=$department 消息=$message"
}

# 2. 部门定向消息
send_department_message() {
    local department=$1
    local message=$2

    # 获取部门成员
    case $department in
        "it")
            users=$(getent passwd | grep -E "(sysadmin|admin|root|network)" | cut -d: -f1)
            ;;
        "dev")
            users=$(getent passwd | grep -E "(dev|developer|coder)" | cut -d: -f1)
            ;;
        "ops")
            users=$(getent passwd | grep -E "(ops|operator)" | cut -d: -f1)
            ;;
        "all")
            users=$(getent passwd | grep -E "/bin/bash$" | cut -d: -f1)
            ;;
        *)
            users=$department
            ;;
    esac

    # 发送给每个用户
    echo "$users" | while read user; do
        if who | grep -q "^$user "; then
            # 获取用户的tty
            tty=$(who | grep "^$user " | awk '{print $2}' | head -1)
            if [ -n "$tty" ]; then
                echo "部门消息给 $user: $message" | write "$user" "$tty"
            fi
        fi
    done

    # 同时广播
    wall "[$department] $message"
}

# 3. 消息队列系统
message_queue_system() {
    local queue_dir="/var/spool/wall_queue"
    mkdir -p "$queue_dir"

    # 添加消息到队列
    add_to_queue() {
        local priority=$1
        local message=$2

        local timestamp=$(date +%s)
        local filename="${queue_dir}/${priority}_${timestamp}.msg"

        echo "$message" > "$filename"
        echo "消息已添加到队列: $filename"
    }

    # 处理队列消息
    process_queue() {
        while true; do
            # 按优先级处理消息
            for priority in emergency alert critical warning notice info debug; do
                for msg_file in "$queue_dir"/"$priority"_*.msg 2>/dev/null; do
                    [ -f "$msg_file" ] || continue

                    # 发送消息
                    wall < "$msg_file"

                    # 记录并删除
                    echo "已发送: $(basename "$msg_file")" >> /var/log/wall_queue.log
                    rm "$msg_file"

                    # 消息间延迟
                    sleep 2
                done
            done

            sleep 10
        done
    }

    # 查看队列状态
    queue_status() {
        echo "消息队列状态:"
        echo "总计: $(ls "$queue_dir"/*.msg 2>/dev/null | wc -l)"

        for priority in emergency alert critical warning notice info debug; do
            count=$(ls "$queue_dir"/"$priority"_*.msg 2>/dev/null | wc -l)
            [ $count -gt 0 ] && echo "  $priority: $count"
        done
    }
}

# 4. 消息审批系统
message_approval_system() {
    local pending_dir="/var/spool/wall_pending"
    local approved_dir="/var/spool/wall_approved"
    mkdir -p "$pending_dir" "$approved_dir"

    # 提交消息等待审批
    submit_for_approval() {
        local sender=$1
        local message=$2

        local msg_id=$(date +%s%N)
        local msg_file="${pending_dir}/${msg_id}.msg"

        cat > "$msg_file" << EOF
发送者: $sender
时间: $(date)
消息ID: $msg_id
状态: 待审批
---
$message
---
EOF

        echo "消息已提交,ID: $msg_id"
        echo "请等待管理员审批。"
    }

    # 审批消息
    approve_message() {
        local msg_id=$1
        local approver=$2

        local pending_file="${pending_dir}/${msg_id}.msg"
        local approved_file="${approved_dir}/${msg_id}.msg"

        if [ -f "$pending_file" ]; then
            # 添加审批信息
            echo "审批人: $approver" >> "$pending_file"
            echo "审批时间: $(date)" >> "$pending_file"
            echo "状态: 已批准" >> "$pending_file"

            # 发送消息
            wall < "$pending_file"

            # 移动文件
            mv "$pending_file" "$approved_file"

            echo "消息 $msg_id 已批准并发送"
        else
            echo "消息不存在: $msg_id"
        fi
    }

    # 拒绝消息
    reject_message() {
        local msg_id=$1
        local approver=$2
        local reason=$3

        local pending_file="${pending_dir}/${msg_id}.msg"
        local rejected_file="${approved_dir}/${msg_id}_rejected.msg"

        if [ -f "$pending_file" ]; then
            echo "审批人: $approver" >> "$pending_file"
            echo "审批时间: $(date)" >> "$pending_file"
            echo "状态: 被拒绝" >> "$pending_file"
            echo "原因: $reason" >> "$pending_file"

            mv "$pending_file" "$rejected_file"
            echo "消息 $msg_id 已被拒绝"
        fi
    }
}

# 5. 消息模板系统
message_template_system() {
    local template_dir="/etc/wall_templates"
    mkdir -p "$template_dir"

    # 创建模板
    create_template() {
        local name=$1
        local content=$2

        echo "$content" > "${template_dir}/${name}.tpl"
        echo "模板已创建: $name"
    }

    # 使用模板发送消息
    send_from_template() {
        local template_name=$1
        shift
        local variables=("$@")

        local template_file="${template_dir}/${template_name}.tpl"

        if [ -f "$template_file" ]; then
            # 读取模板
            message=$(cat "$template_file")

            # 替换变量
            for var in "${variables[@]}"; do
                key=$(echo "$var" | cut -d'=' -f1)
                value=$(echo "$var" | cut -d'=' -f2)
                message=${message//\$\{$key\}/$value}
            done

            # 发送消息
            wall "$message"
        else
            echo "模板不存在: $template_name"
        fi
    }

    # 预定义模板
    create_template "maintenance" "
========================================
系统维护通知
========================================
维护类型: \${type}
开始时间: \${start_time}
结束时间: \${end_time}
影响范围: \${scope}
备注: \${notes}
========================================
"

    create_template "security" "
========================================
安全警报
========================================
事件类型: \${event}
严重程度: \${severity}
影响系统: \${systems}
建议操作: \${actions}
联系人: \${contact}
========================================
"
}

# 6. 消息统计和报告
message_statistics() {
    local log_file="/var/log/wall_messages.log"

    # 记录消息
    log_message() {
        local sender=$1
        local level=$2
        local message=$3

        echo "$(date),$sender,$level,$(echo "$message" | wc -c)" >> "$log_file"
    }

    # 生成报告
    generate_report() {
        local start_date=$1
        local end_date=$2

        echo "消息统计报告"
        echo "期间: $start_date 到 $end_date"
        echo "================================"

        # 总消息数
        total=$(grep -c ",$start_date.*$end_date," "$log_file" 2>/dev/null || echo "0")
        echo "总消息数: $total"

        # 按级别统计
        echo -e "\n按级别统计:"
        for level in emergency alert critical warning notice info debug; do
            count=$(grep -c ",$level," "$log_file" 2>/dev/null || echo "0")
            [ $count -gt 0 ] && echo "  $level: $count"
        done

        # 按发送者统计
        echo -e "\n按发送者统计:"
        grep -o "^[^,]*,[^,]*" "$log_file" 2>/dev/null | cut -d, -f2 | sort | uniq -c | sort -rn

        # 消息长度统计
        echo -e "\n消息长度统计:"
        awk -F, '{sum+=$4} END {print "平均长度:", sum/NR, "字符"}' "$log_file" 2>/dev/null || echo "无数据"
    }
}

# 7. 消息加密传输
encrypted_messaging() {
    # 生成密钥对
    generate_keys() {
        local user=$1

        mkdir -p ~/.wall_keys
        openssl genrsa -out ~/.wall_keys/${user}_private.pem 2048
        openssl rsa -in ~/.wall_keys/${user}_private.pem -pubout -out ~/.wall_keys/${user}_public.pem

        echo "密钥对已生成: ~/.wall_keys/"
    }

    # 发送加密消息
    send_encrypted() {
        local recipient=$1
        local message=$2

        # 使用接收者的公钥加密
        echo "$message" | openssl rsautl -encrypt -pubin -inkey ~/.wall_keys/${recipient}_public.pem | base64 | wall

        echo "加密消息已发送"
    }

    # 接收加密消息
    receive_encrypted() {
        # 监听加密消息
        while read encrypted_message; do
            # 解码并解密
            echo "$encrypted_message" | base64 -d | openssl rsautl -decrypt -inkey ~/.wall_keys/$(whoami)_private.pem
        done
    }
}

# 8. 主菜单
main_menu() {
    while true; do
        clear
        echo -e "${BLUE}=== 企业级消息系统 ==="
        echo ""
        echo "1. 发送分类消息"
        echo "2. 部门定向消息"
        echo "3. 消息队列系统"
        echo "4. 消息审批系统"
        echo "5. 消息模板系统"
        echo "6. 消息统计报告"
        echo "7. 加密消息传输"
        echo "8. 消息系统状态"
        echo "0. 退出"
        echo ""

        read -p "请选择操作: " choice

        case $choice in
            1)
                echo "选择消息级别:"
                echo "1. emergency  2. alert  3. critical"
                echo "4. warning    5. notice 6. info"
                read -p "级别: " level_num

                case $level_num in
                    1) level="emergency" ;;
                    2) level="alert" ;;
                    3) level="critical" ;;
                    4) level="warning" ;;
                    5) level="notice" ;;
                    6) level="info" ;;
                    *) level="info" ;;
                esac

                read -p "部门: " department
                read -p "消息内容: " message
                send_enterprise_message "$level" "$department" "$message"
                ;;
            2)
                read -p "部门(it/dev/ops/all): " department
                read -p "消息内容: " message
                send_department_message "$department" "$message"
                ;;
            3)
                echo "消息队列系统"
                echo "1. 添加消息到队列"
                echo "2. 启动队列处理器"
                echo "3. 查看队列状态"
                read -p "选择: " queue_choice

                case $queue_choice in
                    1)
                        read -p "优先级: " priority
                        read -p "消息: " message
                        add_to_queue "$priority" "$message"
                        ;;
                    2)
                        echo "启动队列处理器 (Ctrl+C停止)..."
                        process_queue
                        ;;
                    3) queue_status ;;
                esac
                ;;
            4)
                echo "消息审批系统"
                echo "1. 提交消息"
                echo "2. 审批消息"
                echo "3. 拒绝消息"
                read -p "选择: " approval_choice

                case $approval_choice in
                    1)
                        read -p "发送者: " sender
                        read -p "消息: " message
                        submit_for_approval "$sender" "$message"
                        ;;
                    2)
                        read -p "消息ID: " msg_id
                        read -p "审批人: " approver
                        approve_message "$msg_id" "$approver"
                        ;;
                    3)
                        read -p "消息ID: " msg_id
                        read -p "审批人: " approver
                        read -p "拒绝原因: " reason
                        reject_message "$msg_id" "$approver" "$reason"
                        ;;
                esac
                ;;
            5)
                echo "消息模板系统"
                echo "1. 使用维护模板"
                echo "2. 使用安全模板"
                read -p "选择: " template_choice

                case $template_choice in
                    1)
                        read -p "维护类型: " type
                        read -p "开始时间: " start
                        read -p "结束时间: " end
                        read -p "影响范围: " scope
                        read -p "备注: " notes
                        send_from_template "maintenance" \
                            "type=$type" \
                            "start_time=$start" \
                            "end_time=$end" \
                            "scope=$scope" \
                            "notes=$notes"
                        ;;
                    2)
                        read -p "事件类型: " event
                        read -p "严重程度: " severity
                        read -p "影响系统: " systems
                        read -p "建议操作: " actions
                        read -p "联系人: " contact
                        send_from_template "security" \
                            "event=$event" \
                            "severity=$severity" \
                            "systems=$systems" \
                            "actions=$actions" \
                            "contact=$contact"
                        ;;
                esac
                ;;
            6)
                read -p "开始日期(YYYY-MM-DD): " start_date
                read -p "结束日期(YYYY-MM-DD): " end_date
                generate_report "$start_date" "$end_date"
                ;;
            7)
                echo "加密消息传输"
                echo "1. 生成密钥"
                echo "2. 发送加密消息"
                echo "3. 接收加密消息"
                read -p "选择: " encrypt_choice

                case $encrypt_choice in
                    1)
                        read -p "用户名: " user
                        generate_keys "$user"
                        ;;
                    2)
                        read -p "接收者: " recipient
                        read -p "消息: " message
                        send_encrypted "$recipient" "$message"
                        ;;
                    3)
                        echo "开始接收加密消息 (Ctrl+C停止)..."
                        receive_encrypted
                        ;;
                esac
                ;;
            8)
                echo "消息系统状态"
                echo "==============="
                systemctl status wall-queue 2>/dev/null || echo "队列服务: 未运行"
                echo "待审批消息: $(ls /var/spool/wall_pending/*.msg 2>/dev/null | wc -l)"
                echo "今日消息数: $(grep -c $(date +%Y-%m-%d) /var/log/wall_messages.log 2>/dev/null || echo 0)"
                ;;
            0)
                echo "退出"
                exit 0
                ;;
            *)
                echo "无效选择"
                ;;
        esac

        echo ""
        read -p "按回车键继续..."
    done
}

# 运行主菜单
main_menu

安全注意事项

wall命令安全警告

wall 命令可以中断所有用户的工作,使用时需特别谨慎:

  • 滥用风险:恶意使用可能导致服务拒绝攻击
  • 信息泄露:可能泄露敏感信息给所有用户
  • 工作中断:会打断用户的重要操作
  • 权限提升:普通用户不应有wall权限
  • 社交工程:可能被用于钓鱼攻击

安全建议:

  1. 限制wall命令的sudo权限
  2. 建立消息审批流程
  3. 记录所有wall消息发送日志
  4. 避免发送敏感信息
  5. 设置消息发送频率限制
  6. 监控wall命令使用情况
  7. 定期审计wall使用日志
  8. 考虑使用更安全的替代方案

常见问题

故障排查:

  1. 检查用户消息设置:
    # 检查用户是否禁用了消息
    # 查看用户的消息状态
    who
    # 检查每个用户的mesg设置
    for user in $(who | awk '{print $1}'); do
        echo -n "$user: "
        sudo -u "$user" mesg
    done
    # 如果显示"is n",用户禁用了消息
    
    # 临时启用所有用户消息
    who | awk '{print $2}' | xargs -I {} sudo chmod g+w /dev/{}
    # 但注意这可能有安全风险
  2. 检查wall命令权限:
    # 检查wall命令权限
    ls -la $(which wall)
    # 应该显示:-rwxr-xr-x 1 root root
    
    # 检查执行者权限
    # wall通常需要root或tty组权限
    groups $USER
    # 确保用户在tty或root组
    
    # 检查sudo配置
    sudo -l wall
  3. 检查tty设备权限:
    # 检查用户tty设备权限
    who | awk '{print $2}' | while read tty; do
        echo -n "$tty: "
        ls -la /dev/$tty
    done
    # 应该显示:crw--w---- 表示可写
    
    # 修复权限
    sudo chmod g+w /dev/pts/*
    # 注意:重启后权限会恢复
  4. 检查系统日志:
    # 查看wall相关日志
    sudo journalctl -u systemd-logind | grep -i wall
    sudo dmesg | grep -i wall
    # 或查看auth日志
    sudo tail -f /var/log/auth.log
  5. 测试消息发送:
    # 测试消息发送
    echo "测试消息 $(date)" | sudo wall
    # 检查是否收到
    # 在另一个终端检查消息
    
    # 测试特定用户
    write $(whoami) $(tty | cut -d/ -f3-)
    # 输入消息,按Ctrl+D发送
  6. 检查防火墙/SELinux:
    # 检查SELinux
    getenforce
    # 如果是Enforcing,检查SELinux日志
    sudo ausearch -m avc -ts recent | grep wall
    
    # 检查AppArmor
    sudo aa-status | grep wall
    
    # 临时禁用测试
    sudo setenforce 0
    # 测试wall
    # 如果工作,需要调整SELinux策略

权限限制方案:

  1. 使用sudo限制:
    # 创建sudoers配置文件
    sudo visudo -f /etc/sudoers.d/wall-restrict
    
    # 只允许特定用户组使用wall
    %admins ALL=(ALL) NOPASSWD: /usr/bin/wall
    # 或特定用户
    alice ALL=(ALL) NOPASSWD: /usr/bin/wall
    bob ALL=(ALL) NOPASSWD: /usr/bin/wall
    
    # 限制参数
    %ops ALL=(ALL) NOPASSWD: /usr/bin/wall -n *
    # 只允许使用-n选项
  2. 使用PAM模块限制:
    # 创建PAM配置
    sudo tee /etc/pam.d/wall << 'EOF'
    # 只允许wheel组
    auth required pam_wheel.so use_uid group=wheel
    # 或特定用户
    auth [success=1 default=ignore] pam_succeed_if.so user in alice:bob:charlie
    auth requisite pam_deny.so
    EOF
  3. 使用文件权限限制:
    # 移除其他用户执行权限
    sudo chmod o-x $(which wall)
    # 只允许root和特定组
    sudo chown root:admins $(which wall)
    sudo chmod 750 $(which wall)
    
    # 使用ACL进一步限制
    sudo setfacl -m u:alice:rx $(which wall)
    sudo setfacl -m u:bob:rx $(which wall)
  4. 创建包装脚本:
    # 创建受控的wall包装
    sudo mv $(which wall) $(which wall).real
    cat > $(which wall) << 'EOF'
    #!/bin/bash
    # 受控的wall包装
    ALLOWED_USERS=("root" "alice" "bob")
    MESSAGE_LOG="/var/log/wall_usage.log"
    
    # 检查用户权限
    if [[ ! " ${ALLOWED_USERS[@]} " =~ " $USER " ]]; then
        echo "错误: 您无权使用wall命令" >&2
        exit 1
    fi
    
    # 记录使用
    echo "$(date) - $USER: $*" >> "$MESSAGE_LOG"
    
    # 执行真正的wall
    /usr/bin/wall.real "$@"
    EOF
    sudo chmod 755 $(which wall)
  5. 使用系统审计:
    # 配置auditd审计wall命令
    sudo tee /etc/audit/rules.d/wall.rules << 'EOF'
    # 审计wall命令执行
    -a always,exit -F path=/usr/bin/wall -F perm=x -F auid>=1000 -F auid!=-1 -k wall_command
    EOF
    
    # 重新加载审计规则
    sudo auditctl -R /etc/audit/rules.d/wall.rules
    
    # 查看审计日志
    sudo ausearch -k wall_command
  6. 使用替代方案:
    # 使用logger记录到系统日志
    logger -p user.emerg "紧急消息"
    # 然后用户可以通过查看系统日志获取消息
    
    # 使用邮件系统
    echo "消息内容" | mail -s "系统通知" allusers@example.com
    
    # 使用Web通知系统
    curl -X POST -H "Content-Type: application/json" \
        -d '{"message":"系统通知"}' \
        https://notifications.example.com/api/send

现代替代方案:

  1. 系统日志通知:
    # 使用logger和systemd-journal
    logger -p user.emerg "紧急系统通知"
    # 用户可以通过journalctl查看
    journalctl -f -p user.emerg
    
    # 或发送到所有终端
    systemd-cat -t SYSTEM-NOTICE echo "系统通知"
    # 在终端显示
    journalctl -f -t SYSTEM-NOTICE
  2. 桌面通知系统:
    # 使用notify-send (需要X11)
    notify-send -u critical "系统通知" "服务器即将重启"
    # 或通过dbus
    dbus-send --session --type=method_call \
        --dest=org.freedesktop.Notifications \
        /org/freedesktop/Notifications \
        org.freedesktop.Notifications.Notify \
        string:"system" uint32:0 string:"" \
        string:"系统通知" string:"消息内容" \
        array:string:"" dict:string:string:"" \
        int32:5000
  3. Web-based通知:
    # 使用WebSocket广播
    # 服务器端
    websocketd --port=8080 ./notify_script.sh
    
    # 客户端JavaScript
    var ws = new WebSocket('ws://server:8080/');
    ws.onmessage = function(event) {
        showNotification(event.data);
    };
    
    # 或使用Server-Sent Events
    curl -X POST -H "Content-Type: application/json" \
        -d '{"message":"系统通知"}' \
        http://notification-server:3000/api/broadcast
  4. 消息队列系统:
    # 使用Redis Pub/Sub
    # 发送消息
    redis-cli PUBLISH notifications "系统通知"
    
    # 客户端订阅
    redis-cli SUBSCRIBE notifications
    # 或通过脚本
    while true; do
        message=$(redis-cli BLPOP notifications 0 2>/dev/null | tail -1)
        echo "收到: $message"
    done
  5. 容器环境通知:
    # 在Kubernetes中
    kubectl create configmap system-notice \
        --from-literal=message="系统维护通知"
    
    # 在Pod中挂载
    # 或使用sidecar容器
    # 或使用集群事件
    kubectl get events -w
    
    # Docker容器
    docker events --filter 'type=container'
  6. 企业消息平台集成:
    # Slack集成
    curl -X POST -H 'Content-type: application/json' \
        --data '{"text":"系统通知"}' \
        https://hooks.slack.com/services/xxx/xxx/xxx
    
    # Microsoft Teams
    curl -H "Content-Type: application/json" \
        -d '{"text":"系统通知"}' \
        https://outlook.office.com/webhook/xxx/IncomingWebhook/xxx
    
    # Mattermost
    curl -i -X POST \
        -H 'Content-Type: application/json' \
        -d '{"text":"系统通知"}' \
        https://mattermost.example.com/hooks/xxx