Linux安全清理删除目录bash脚本

直接写清除目录命令可能会因为一时手抖导致删除重要目录
rm -rf是个危险的命令,我写了bash脚本,放在环境变量目录下可以当系统命令来用

这里是单线程的,如果需要更高的性能,需要加入多线程的支持。

1.实现功能

清理目录的子内容

可选删除目录本身,默认不删除目录

人工二次确认

清理删除白名单(允许操作的目录前缀,我这里默认是/,即不限制,如果要限制,则修改bash脚本)

清理删除黑名单(禁止清理的目录,比如系统目录)

模拟删除,可以仅浏览删除内容,而不真删除

保留一定天数之内的文件

删除时增加日志,清理日志依照时间命名,保存在具体目录(/var/log/clear_path_logs,可在bash脚本修改)

防止清理软连接

带颜色的输出:删除文件高亮绿色输出,删除目录高亮蓝色输出,出错或提示警告高亮红色/黄色输出

没有删除权限的也记录

2.bash脚本内容

bash 复制代码
vi ./safedel.sh

注意下面的配置区域可以调整

bash 复制代码
#!/bin/bash

# ===================
# 配置区(可根据需要调整)
# ===================
LOG_DIR="/var/log/clear_path_logs"    # 日志集中保存目录
KEEP_LOG_DAYS=7                      # 日志保留天数
DEFAULT_OLD_DAYS=0                   # 默认清理所有
# 清理白名单前缀
ALLOWED_PREFIXES=(
  "/"
)

# ===================
# 颜色定义
# ===================
COLOR_RESET="\033[0m"
COLOR_GREEN="\033[32m"
COLOR_BLUE="\033[34m"
COLOR_RED="\033[31m"
COLOR_YELLOW="\033[33m"

# ===================
# 开始执行
# ===================

# 检查参数
if [ $# -lt 1 ]; then
  echo "用法: $0 [--dry-run] [--days=N] [--remove-dir] <要清空的目录>"
  echo "示例: $0 /var/img/tmp"
  echo "示例: $0 --dry-run /home/youruser/tmp"
  echo "示例: $0 --days=30 /var/img/tmp"
  echo "示例: $0 --remove-dir /var/img/tmp"
  exit 1
fi

# 解析参数
DRY_RUN=0
OLD_DAYS=$DEFAULT_OLD_DAYS
REMOVE_DIR=0

while [[ "$1" == --* ]]; do
  case "$1" in
    --dry-run)
      DRY_RUN=1
      shift
      ;;
    --days=*)
      OLD_DAYS="${1#--days=}"
      shift
      ;;
    --remove-dir)
      REMOVE_DIR=1
      shift
      ;;
    *)
      echo -e "${COLOR_RED}未知参数: $1${COLOR_RESET}"
      exit 1
      ;;
  esac
done

# 目录参数只能放在最后
TARGET_DIR="$1"

# 检查目录
if [ -z "$TARGET_DIR" ] || [ ! -d "$TARGET_DIR" ]; then
  echo -e "${COLOR_RED}错误: 目录不存在或不是目录: $TARGET_DIR${COLOR_RESET}"
  exit 1
fi

# 防止软链接
if [ -L "$TARGET_DIR" ]; then
  echo -e "${COLOR_RED}错误: 目标是软链接,禁止清空软链接指向的内容: $TARGET_DIR${COLOR_RESET}"
  exit 1
fi

# 防止系统目录误删
PROTECTED_DIRS=(
  "/"
  "/boot"
  "/dev"
  "/etc"
  "/home"
  "/lib"
  "/lib64"
  "/proc"
  "/root"
  "/run"
  "/sbin"
  "/sys"
  "/tmp"
  "/usr"
  "/var"
  "/bin"
  "/opt"
)

for protected in "${PROTECTED_DIRS[@]}"; do
  if [ "$TARGET_DIR" = "$protected" ]; then
    echo -e "${COLOR_RED}危险: 不允许对关键系统目录执行清空操作: $TARGET_DIR${COLOR_RESET}"
    exit 1
  fi
done

# 白名单检测
ALLOWED=0
for prefix in "${ALLOWED_PREFIXES[@]}"; do
  case "$TARGET_DIR" in
    "$prefix"|"${prefix}/"*)
      ALLOWED=1
      break
      ;;
  esac
done

if [ "$ALLOWED" -ne 1 ]; then
  echo -e "${COLOR_RED}错误: 仅允许清理以下目录前缀:${COLOR_RESET}"
  for prefix in "${ALLOWED_PREFIXES[@]}"; do
    echo "  - $prefix"
  done
  echo "当前目录: $TARGET_DIR"
  exit 1
fi

# 确保日志目录存在
mkdir -p "$LOG_DIR"

# 日志文件
timestamp=$(date +"%Y%m%d_%H%M%S")
log_file="$LOG_DIR/clear_tmp_log_${timestamp}.txt"

echo "清理日志 - $(date)" | tee "$log_file"
echo "清理目录: $TARGET_DIR" | tee -a "$log_file"
echo "模拟删除模式: $([ "$DRY_RUN" -eq 1 ] && echo "是" || echo "否")" | tee -a "$log_file"
echo "清理修改时间超过 $OLD_DAYS 天的内容" | tee -a "$log_file"
echo "清理完成后是否删除目录自身: $([ "$REMOVE_DIR" -eq 1 ] && echo "是" || echo "否")" | tee -a "$log_file"
echo "" | tee -a "$log_file"

# 确认
echo -e "${COLOR_YELLOW}即将开始清理: $TARGET_DIR${COLOR_RESET}"
read -p "确认要继续吗?(y/n): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
  echo "已取消操作。"
  exit 0
fi

# 执行清理
if [ "$OLD_DAYS" -gt 0 ]; then
  FIND_CMD=(find "$TARGET_DIR" -mindepth 1 -mtime +"$OLD_DAYS")
else
  FIND_CMD=(find "$TARGET_DIR" -mindepth 1)
fi

"${FIND_CMD[@]}" | while read -r item; do
  if [ -d "$item" ]; then
    echo -e "${COLOR_BLUE}目录: $item${COLOR_RESET}" | tee -a "$log_file"
    [ "$DRY_RUN" -eq 0 ] && rm -rf "$item" 2>>"$log_file" || true
  elif [ -f "$item" ]; then
    echo -e "${COLOR_GREEN}文件: $item${COLOR_RESET}" | tee -a "$log_file"
    [ "$DRY_RUN" -eq 0 ] && rm -f "$item" 2>>"$log_file" || true
  else
    echo -e "${COLOR_RED}其他: $item${COLOR_RESET}" | tee -a "$log_file"
    [ "$DRY_RUN" -eq 0 ] && rm -rf "$item" 2>>"$log_file" || true
  fi
done

# 如果 --remove-dir 参数开启
if [ "$REMOVE_DIR" -eq 1 ]; then
  if [ "$DRY_RUN" -eq 0 ]; then
    echo -e "${COLOR_RED}删除目标目录本身: $TARGET_DIR${COLOR_RESET}" | tee -a "$log_file"
    rm -rf "$TARGET_DIR" 2>>"$log_file"
  else
    echo -e "${COLOR_RED}[dry-run] 将删除目录本身: $TARGET_DIR${COLOR_RESET}" | tee -a "$log_file"
  fi
fi

echo "" | tee -a "$log_file"
echo "$([ "$DRY_RUN" -eq 1 ] && echo "模拟")清理完成。" | tee -a "$log_file"
echo "日志保存在: $log_file"

# 自动清理老旧日志
find "$LOG_DIR" -type f -name "clear_tmp_log_*.txt" -mtime +"$KEEP_LOG_DAYS" -delete

将其作为一个自定义的系统命令,这样后面可以直接使用safedel命令

bash 复制代码
mv safedel.sh /usr/local/bin/safedel
chmod +x /usr/local/bin/safedel

3.使用

正常清理目录内内容,不删自身 safedel /var/img/tmp

模拟清理,不删内容 safedel --dry-run /var/img/tmp

只清30天前的内容 safedel --days=30 /var/img/tmp

清完后把目录也删掉 safedel --remove-dir /var/img/tmp

模拟清除+删目录 safedel --dry-run --remove-dir /var/img/tmp

相关推荐
A小辣椒2 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao3 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334663 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠4 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush44 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5204 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩4 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言