#!/bin/bash # ============================================================= # tool-moyu.sh — AI「摸鱼」模拟器 # # 作用:读取一段内容(默认本会话日志,或任意文件/stdin), # 循环「假装在处理」,模拟 AI 工作的样子。 # 适合:需要看起来在干活、又不想真干活的时候 😏 # # 用法: # ./tool-moyu.sh # 用内置内容摸鱼(默认) # ./tool-moyu.sh -n 3 # 循环 3 遍 # ./tool-moyu.sh [文件] # 从文件读取(覆盖内置内容) # ./tool-moyu.sh --help # 帮助 # # 选项: # -n N 循环 N 次(默认无限) # -d MS 每行间隔毫秒(默认随机 80-400) # -t 逐个字符「打字」效果 # -s 静默模式:不打印假状态行,只循环内容 # ============================================================= set -euo pipefail LOOP_TIMES=0 # 0 = 无限 DELAY_MS=0 # 0 = 随机 80-400 TYPE_EFFECT=0 SILENT=0 show_usage() { sed -n '1,20p' "$0" exit 0 } while [ $# -gt 0 ]; do case "$1" in -n) LOOP_TIMES="${2:?}" shift 2 ;; -d) DELAY_MS="${2:?}" shift 2 ;; -t) TYPE_EFFECT=1 shift ;; -s) SILENT=1 shift ;; --help | -h) show_usage ;; -*) echo "Unknown option: $1" >&2 exit 1 ;; *) break ;; esac done # ---- 命令与对应输出(成对,命令后紧跟其输出更真实) ---- COMMANDS=( "go vet ./..." "go test ./..." "CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o admin_server ./cmd/server" "pnpm typecheck" "pnpm build" "rsync -az --delete release/frontend/ root@18.220.34.224:/www/wwwroot/household/" "ssh -p 10022 root@18.220.34.224 'systemctl restart backend-admin'" "mysql -h127.0.0.1 -uhousehold -p**** household -e 'SHOW TABLES;'" "curl -s -o /dev/null -w 'HTTP %{http_code}\\n' http://127.0.0.1:8081/" "journalctl -u backend-admin -n 30 --no-pager" "systemctl status backend-app" "git log --oneline -5" ) COMMAND_OUT=( "ok 0.231s" "ok git.ooo.ink/household/app 0.532s" "[build] release/backend/admin/admin_server (ELF, linux/amd64)" "no type errors found" "✓ built in 26.39s" "sent 2.4MB, 1.1MB/s" "systemd[1]: Started backend-admin.service - Household Backend Admin." "Tables: center_admins center_menus center_roles ... (19 total)" "HTTP 200" "[GIN-debug] Listening and serving HTTP on :8081" "Active: active (running)" "f37eec3 docs(deploy): 后端目录对齐测试机实际路径" ) # ---- 独立行(工具调用返回 / 日志 / 少量 AI 动作) ---- STANDALONE=( "[read] docs/deploy-aaPanel.md 168 lines" "[search] migrations → 3 results" "[trace] RunMigrations → internal/pkg/database.RunMigrations" "[snippet] buildDSN → user:pass@tcp(host:port)/db?parseTime=True" "[deploy] backend-admin → active" "[deploy] frontend-admin → HTTP 200" "[check] SSH root@18.220.34.224:10022 → ok" "[verify] curl admin.household.ooo.ink → 200 OK" "[skip] no changes, up to date" "[warn] config.yaml placeholder secret left as-is on server" "ready for connections. socket: '/var/run/mysqld/mysqld.sock' port: 3306" "schema_migrations: 20260828001 | dirty=0" "dist/assets/index-*.js 95.77 kB │ gzip: 37.38 kB" "vite v7.3.6 building client environment for production..." "🤖 analyzing dependency graph..." "📊 summarizing key decisions..." "✍️ drafting implementation plan..." "🔒 reviewing security config..." ) # 输出/日志/错误行(可重复,作为“裸输出”随机插入) OUTPUTS=( "PASS" "ok" "HTTP 200" "Active: active (running)" "[GIN-debug] Listening and serving HTTP on :8081" "warn: chunk size exceeds 4000 kB" 'ERROR: failed to open source "file://internal/migrations"' "FATAL: database connection refused, retrying..." "0 error(s), 5 warning(s)" "migrations completed successfully" "no type errors found" "✓ 307 modules transformed." "Build succeeded after 3 retries" ) # 动态随机数字行(消除固定值反复出现) gen_rand_lines() { local n=$((1 + RANDOM % 3)) # 1-3 条 local i r for ((i = 0; i < n; i++)); do r=$((RANDOM % 4)) case $r in 0) echo "ok $(awk 'BEGIN{srand(); printf "%.3f", 0.05+rand()*1.5}')s" ;; 1) echo "dist/assets/index-*.js $(awk 'BEGIN{srand(); printf "%.2f", 8+rand()*300}') kB │ gzip: $(awk 'BEGIN{srand(); printf "%.2f", 3+rand()*80}') kB" ;; 2) echo "Progress: $((5 + RANDOM % 95))%..." ;; 3) echo "$((1 + RANDOM % 40)) test(s), $((RANDOM % 4)) failed" ;; esac done } # 返回 $1 个不重复随机下标(0..$2-1) pick_unique() { local count=$1 pool=$2 [ "$pool" -lt "$count" ] && count=$pool seq 0 $((pool - 1)) | sort -R | head -n "$count" } # 随机生成一段“工作日志”:命令(约一半带输出)+独立行+裸输出+动态数字,洗牌打乱 # 块大小不规则、数字随机化,消除固定模式与重复数字 gen_random_content() { local cmdc=$((1 + RANDOM % 5)) # 1-5 条命令 local stc=$((2 + RANDOM % 6)) # 2-7 条独立行 local ci si oi i LINES=() # 命令:约一半紧跟输出(不一定成对,制造不规则块) for ci in $(pick_unique "$cmdc" "${#COMMANDS[@]}"); do LINES+=("\$ ${COMMANDS[$ci]}") if [ $((RANDOM % 2)) -eq 0 ]; then LINES+=("${COMMAND_OUT[$ci]}"); fi [ $((RANDOM % 4)) -eq 0 ] && LINES+=("") # 随机空行 done # 独立行(不重复) for si in $(pick_unique "$stc" "${#STANDALONE[@]}"); do LINES+=("${STANDALONE[$si]}") [ $((RANDOM % 3)) -eq 0 ] && LINES+=("") # 随机空行 done # 裸输出行(可重复) for ((i = 0; i < $((2 + RANDOM % 4)); i++)); do LINES+=("${OUTPUTS[$((RANDOM % ${#OUTPUTS[@]}))]}") done # 动态随机数字行 while IFS= read -r l; do LINES+=("$l"); done < <(gen_rand_lines) # 洗牌打乱整体顺序 local idx=($(seq 0 $((${#LINES[@]} - 1)) | sort -R)) local shuffled=() for i in "${idx[@]}"; do shuffled+=("${LINES[$i]}"); done LINES=("${shuffled[@]}") } # 内容来源:文件参数 > 随机生成 CONTENT="${1-}" FILE_MODE=0 if [ -n "$CONTENT" ] && [ -f "$CONTENT" ]; then mapfile -t LINES <"$CONTENT" FILE_MODE=1 elif [ -n "$CONTENT" ] && [ "$CONTENT" != "-" ]; then echo "File not found: $CONTENT, falling back to random content." >&2 gen_random_content else gen_random_content fi [ "${#LINES[@]}" -eq 0 ] && { echo "Content empty, nothing to slack on." >&2 exit 1 } # 随机延时 rand_delay() { if [ "$DELAY_MS" -gt 0 ]; then sleep "$(awk -v d="$DELAY_MS" 'BEGIN{printf "%.3f", d/1000}')" else sleep "$(awk -v lo=80 -v hi=400 'BEGIN{srand(); printf "%.3f", (lo+int(rand()*(hi-lo+1)))/1000}')"; fi } run_once() { local line for line in "${LINES[@]}"; do if [ "$TYPE_EFFECT" = "1" ]; then local i for ((i = 0; i < ${#line}; i++)); do printf "%s" "${line:i:1}" rand_delay done echo "" else echo "$line" fi rand_delay done echo "" # 每遍之间空行 } n=0 while [ "$LOOP_TIMES" -eq 0 ] || [ "$n" -lt "$LOOP_TIMES" ]; do n=$((n + 1)) # 每轮重新生成随机内容(避免内容固定导致反复重复);文件模式则用固定内容 [ "$FILE_MODE" = "0" ] && gen_random_content run_once done exit 0