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

相关推荐
遇见火星1 小时前
Linux 下使用tcpdump进行网络分析原
linux·网络·tcpdump
荒--2 小时前
Linux中安装mysql8,转载及注意事项
linux·运维·adb
yangmf20402 小时前
如何防止 ES 被 Linux OOM Killer 杀掉
大数据·linux·elasticsearch·搜索引擎·全文检索
I_Scholar3 小时前
mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz的下载安装和使用
linux·mysql
imhikaru3 小时前
Linux Shell 重定向与管道符号(>, >>, |)的实现机制
linux·服务器·网络
张三和李四的家4 小时前
ubuntu的libc 库被我 sudo apt-get --reinstall install libc6搞没了
linux·ubuntu
whoarethenext4 小时前
linux的时间轮
linux·运维·linq·时间轮
黑不溜秋的4 小时前
驱动开发系列54 - Linux Graphics QXL显卡驱动代码分析(一)设备初始化
linux·服务器·qemu·qxl·虚拟显卡
独行soc4 小时前
2025年渗透测试面试题总结-拷打题库35(题目+回答)
linux·运维·服务器·python·网络安全·面试·职场和发展