#!/usr/bin/env bash # clean_outputs.sh — 清理编译输出与日志垃圾文件 # # 用法: # clean_outputs.sh [选项] # # 选项: # --logs 清理 output/logs/ 下的运行日志(保留 last_run.txt / last_failed.txt) # --analyze 清理 output/analyze/ 下的单用例分析结果 # --build 清理 build_lab*/ 构建目录 # --test-result 清理 test/test_result/ 下的测试产物 # --all 清理以上全部 # --dry-run 只打印将要删除的内容,不实际删除 # --yes 跳过确认提示,直接删除(配合 --logs / --all 等使用) # # 不带任何选项时交互式选择。 set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' DO_LOGS=false DO_ANALYZE=false DO_BUILD=false DO_TEST_RESULT=false DRY_RUN=false AUTO_YES=false if [[ $# -eq 0 ]]; then # 交互模式 printf '%bclean_outputs.sh — interactive mode%b\n' "$CYAN" "$NC" printf 'Select what to clean (space-separated numbers, e.g. "1 3"):\n' printf ' 1) output/logs/ — run logs\n' printf ' 2) output/analyze/ — single-case analysis results\n' printf ' 3) build_lab*/ — CMake build directories\n' printf ' 4) test/test_result/ — test artifacts\n' printf ' 0) cancel\n' read -r -p 'choice: ' choices for c in $choices; do case "$c" in 1) DO_LOGS=true ;; 2) DO_ANALYZE=true ;; 3) DO_BUILD=true ;; 4) DO_TEST_RESULT=true ;; 0) printf 'cancelled.\n'; exit 0 ;; *) printf '%bunknown option: %s (ignored)%b\n' "$YELLOW" "$c" "$NC" ;; esac done fi while [[ $# -gt 0 ]]; do case "$1" in --logs) DO_LOGS=true ;; --analyze) DO_ANALYZE=true ;; --build) DO_BUILD=true ;; --test-result) DO_TEST_RESULT=true ;; --all) DO_LOGS=true; DO_ANALYZE=true; DO_BUILD=true; DO_TEST_RESULT=true ;; --dry-run) DRY_RUN=true ;; --yes|-y) AUTO_YES=true ;; *) printf '%bunknown option: %s%b\n' "$YELLOW" "$1" "$NC" >&2 ;; esac shift done if [[ "$DO_LOGS" == false && "$DO_ANALYZE" == false && \ "$DO_BUILD" == false && "$DO_TEST_RESULT" == false ]]; then printf 'nothing selected. use --help or run without arguments for interactive mode.\n' >&2 exit 0 fi # ---------- 收集要删除的路径 ---------- declare -a TARGETS=() if [[ "$DO_LOGS" == true ]]; then LOG_ROOT="$REPO_ROOT/output/logs" if [[ -d "$LOG_ROOT" ]]; then # 删除所有子目录(即每次的 run dir),保留 last_run.txt / last_failed.txt while IFS= read -r -d '' d; do TARGETS+=("$d") done < <(find "$LOG_ROOT" -mindepth 2 -maxdepth 2 -type d -print0 2>/dev/null) fi fi if [[ "$DO_ANALYZE" == true ]]; then ANALYZE_ROOT="$REPO_ROOT/output/analyze" if [[ -d "$ANALYZE_ROOT" ]]; then while IFS= read -r -d '' d; do TARGETS+=("$d") done < <(find "$ANALYZE_ROOT" -mindepth 1 -maxdepth 1 -print0 2>/dev/null) fi fi if [[ "$DO_BUILD" == true ]]; then while IFS= read -r -d '' d; do TARGETS+=("$d") done < <(find "$REPO_ROOT" -maxdepth 1 -type d -name 'build_lab*' -print0 2>/dev/null) fi if [[ "$DO_TEST_RESULT" == true ]]; then TR_ROOT="$REPO_ROOT/test/test_result" if [[ -d "$TR_ROOT" ]]; then TARGETS+=("$TR_ROOT") fi fi if [[ ${#TARGETS[@]} -eq 0 ]]; then printf '%bNothing to clean — target directories are already empty or do not exist.%b\n' "$GREEN" "$NC" exit 0 fi # ---------- 打印列表 ---------- printf '\n%bThe following will be %s:%b\n' "$YELLOW" \ "$([[ "$DRY_RUN" == true ]] && echo "listed (dry-run)" || echo "DELETED")" "$NC" TOTAL_SIZE=0 for t in "${TARGETS[@]}"; do SIZE=$(du -sh "$t" 2>/dev/null | cut -f1 || echo "?") printf ' [%s] %s\n' "$SIZE" "$t" done printf '\n' if [[ "$DRY_RUN" == true ]]; then printf '%bDry-run mode: nothing deleted.%b\n' "$CYAN" "$NC" exit 0 fi # ---------- 确认 ---------- if [[ "$AUTO_YES" == false ]]; then read -r -p "Proceed with deletion? [y/N] " confirm case "$confirm" in [yY][eE][sS]|[yY]) ;; *) printf 'cancelled.\n' exit 0 ;; esac fi # ---------- 删除 ---------- DELETED=0 ERRORS=0 for t in "${TARGETS[@]}"; do if rm -rf "$t" 2>/dev/null; then printf '%b deleted: %s%b\n' "$GREEN" "$t" "$NC" DELETED=$((DELETED + 1)) else printf '%b ERROR deleting: %s%b\n' "$RED" "$t" "$NC" ERRORS=$((ERRORS + 1)) fi done printf '\n' if [[ $ERRORS -eq 0 ]]; then printf '%bDone. %d item(s) deleted.%b\n' "$GREEN" "$DELETED" "$NC" else printf '%bDone. %d deleted, %d errors.%b\n' "$YELLOW" "$DELETED" "$ERRORS" "$NC" exit 1 fi