wall 命令用于向所有已登录用户的终端发送广播消息。它是"write all"的缩写,通常用于系统管理员向所有用户发送系统通知、维护提醒、紧急警报等重要信息。wall消息会显示在所有用户的终端上,无论他们当前正在执行什么操作。
wall 是系统管理员的重要工具,用于发送系统范围的通知。消息会以Broadcast Message的形式显示,并且会中断用户的当前工作,因此应谨慎使用。
# 基本格式
wall [选项] [消息]
# 常用格式
wall "系统即将重启" # 发送简单消息
wall < message.txt # 从文件发送消息
echo "紧急通知" | wall # 通过管道发送消息
wall -n "测试消息" # 不显示标题头
wall -t 10 "10秒后显示" # 设置超时时间
wall 是util-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
使用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
在系统管理中使用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
企业环境中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 命令可以中断所有用户的工作,使用时需特别谨慎:
安全建议:
故障排查:
# 检查用户是否禁用了消息
# 查看用户的消息状态
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/{}
# 但注意这可能有安全风险
# 检查wall命令权限
ls -la $(which wall)
# 应该显示:-rwxr-xr-x 1 root root
# 检查执行者权限
# wall通常需要root或tty组权限
groups $USER
# 确保用户在tty或root组
# 检查sudo配置
sudo -l wall
# 检查用户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/*
# 注意:重启后权限会恢复
# 查看wall相关日志
sudo journalctl -u systemd-logind | grep -i wall
sudo dmesg | grep -i wall
# 或查看auth日志
sudo tail -f /var/log/auth.log
# 测试消息发送
echo "测试消息 $(date)" | sudo wall
# 检查是否收到
# 在另一个终端检查消息
# 测试特定用户
write $(whoami) $(tty | cut -d/ -f3-)
# 输入消息,按Ctrl+D发送
# 检查SELinux
getenforce
# 如果是Enforcing,检查SELinux日志
sudo ausearch -m avc -ts recent | grep wall
# 检查AppArmor
sudo aa-status | grep wall
# 临时禁用测试
sudo setenforce 0
# 测试wall
# 如果工作,需要调整SELinux策略
权限限制方案:
# 创建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选项
# 创建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
# 移除其他用户执行权限
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)
# 创建受控的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)
# 配置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
# 使用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
现代替代方案:
# 使用logger和systemd-journal
logger -p user.emerg "紧急系统通知"
# 用户可以通过journalctl查看
journalctl -f -p user.emerg
# 或发送到所有终端
systemd-cat -t SYSTEM-NOTICE echo "系统通知"
# 在终端显示
journalctl -f -t SYSTEM-NOTICE
# 使用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
# 使用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
# 使用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
# 在Kubernetes中
kubectl create configmap system-notice \
--from-literal=message="系统维护通知"
# 在Pod中挂载
# 或使用sidecar容器
# 或使用集群事件
kubectl get events -w
# Docker容器
docker events --filter 'type=container'
# 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