情况描述
有一台Windows Server服务器,开启FTP用来存储Java应用dump文件,需要定时清理,考虑有两种清理方案:
方案一:
在Linux通过挂载Windows共享目录,cifs 文件系统,通过Shell 脚本 + 定时任务清理(这个用find + crond 就可以,不赘述)
mount -t cifs -o username=win-username,password=win-pasword,uid=linux-username,gid=linux-group //win-ip/path /mount_dir_path
方案二:
在Windows写bat脚本,通过计划任务程序加载定时任务执行清理
需求描述
需求一:需要清理7天前的dump
需求二:需要清理同一个系统的dump,保留一个(目前没验证保留的是否最新文件)
脚本内容
需求一
一、dos 测试
win + r ,输入cmd
或者
鼠标右键桌面左下角win标识,选择运行,输入cmd
注意:
1、不要用Windows PowerShell dir显示内容不一样,而且计划任务程序默认加载的也是cmd ,bat的默认执行程序也是cmd
2、注意目录路径
# 打印查询结果,验证文件是否是目标文件
> forfiles /P "E:\test" /M *.hprof /D -7 /C "cmd /c echo @file"
> forfiles /? # 查看帮助文档
/P 地址
/M 模糊匹配
/D -7 代表7天前
/C 后面跟命令
"cmd /c del/F/s/q @file" 删除文件
"cmd /c echo @file" 打印文件
> forfiles /P "E:\test" /M *.hprof /D -7 /C "cmd /c del/F/s/q @file"
二、脚本内容
新建一个文件,后缀修改为bat,右键,选择编辑
如果看不到后缀,打开文件浏览器,最上面菜单查看,找到文件扩展名,勾选
输入上面测试过的内容(注意路径):
@echo off
forfiles /P "E:\test" /M *.hprof /D -7 /C "cmd /c del/F/s/q @file"
双击,测试和验证清理效果
三、添加任务计划程序
Win+R,调出运行窗口,输入compmgmt.msc 进入计算机管理
或
鼠标右键桌面左下角Win图标,选择计算机管理
系统工具 》 任务计划程序 》任务计划程序库 》 右边窗口操作底下的基本任务 》 按照指引填写 注意选择脚本,保存即可
测试运行,找到自己的任务,鼠标右键,运行,验证脚本执行情况
历史记录可以查看历史运行情况,如果看不到,操作窗口,点击启用所有任务历史记录即可
需求二
步骤基本一致,这里就直接贴脚本和注意事项了
@echo off
setlocal enabledelayedexpansion
rem 定义磁盘路径
set "disk=E:\"
rem 进入工作目录
cd /d E:\test
rem 获取磁盘信息
for /f "tokens=3" %%a in ('dir %disk% ^| find "可用字节"') do set "freeSpace=%%a"
rem 将字节数转换为GB
set /a freeSpaceGB=%freeSpace%/1073741824
rem 设置阈值
set "thresholdGB=250"
echo ############ >> "E:\cleanscritps\%date:~0,4%-%date:~5,2%-%date:~8,2%.txt"
echo %date% %time% >> "E:\cleanscritps\%date:~0,4%-%date:~5,2%-%date:~8,2%.txt"
echo free disk: %freeSpaceGB% GB >> "E:\cleanscritps\%date:~0,4%-%date:~5,2%-%date:~8,2%.txt"
rem 判断剩余容量是否小于阈值
if %freeSpaceGB% lss %thresholdGB% (
echo 需要清理文件,剩余容量为 %freeSpaceGB% GB
rem 在这里可以添加清理文件的操作
rem 获取当前目录文件的文件名
for /F "delims=" %%F in ('dir /b /a:-d *.hprof') do (
rem 依据下划线分割获取第一段文件名的文本
for /f "tokens=1 delims=_" %%A in ("%%~nxF") do (
rem 清理相同前缀的文件,保留一份
if not defined prefix[%%A] (
set prefix[%%A]=1
) else (
echo "%%F"
echo delete file "%%F" >> "E:\cleanscritps\%date:~0,4%-%date:~5,2%-%date:~8,2%.txt"
del /q "%%F"
)
)
)
) else (
echo 不需要清理文件,剩余容量为 %freeSpaceGB% GB >> "E:\cleanscritps\%date:~0,4%-%date:~5,2%-%date:~8,2%.txt"
)
endlocal
rem pause
注意事项:
1、注意如果你的脚本和目标文件不在C盘,切换磁盘需要添加 /d 参数,否则不生效,找不到文件,脚本会执行,但是无法达到预期
cd /d E:\test
2、set “disk=E:” 这个是设置参数,并不是将工作目录设置到E盘
3、>> 这个重定向和Linux一样,是追加的意思
4、date 的格式化输出
echo %date:~0,4%-%date:~5,2%-%date:~8,2%_%time:~0,2%
2023-12-21_21
echo %date:~0,4%-%date:~5,2%-%date:~8,2%
2023-12-21
5、注意 bat 和 cmd 对于对象的取值
% 用于cmd dos 窗口
%% 用于批处理(bat)
%date% 取变量值
bat 脚本中如下脚本可以执行:
for /f "tokens=3" %%a in ('dir D: ^| find "可用字节"') do set "freeSpace=%%a"
dos 窗口执行报错
此时不应有 %%a。
dos 窗口测试需要如下方式:
for /f "tokens=3" %a in ('dir D: ^| find "可用字节"') do set "freeSpace=%a"
6、对于循环结构里面的解释
# 遍历符合条件的文件,并定义变量F 比如 E:/test/xxx.hprof
for /r %%F in (*.hprof) do
# 取文件名全称,然后通过下划线分隔,打印第一段给到变量A
for /f "tokens=1 delims=_" %%A in ("%%~nxF") do
%%~nxF 仅将 %F 扩展到一个文件名和扩展名,比如 xxx.hprof
"tokens=1 delims=_" %%A 是指 '_' 分隔,第一段 赋值给 A
/f 指会打开文件
# 定义一个类似字典的数据结构
prefix[%%A]
具体见:
for /?
7、注意计划任务是调用的 C:\Windows\System32\cmd.exe
8、bat 脚本的三种运行方式
1)双击
2)拖动到cmd命令窗口执行 或者 输入bat脚本全路径执行
3)任务计划程序添加任务执行程序
9、上述脚本不会针对文件的创建时间清理,可能会出现将新文件清理的情况,所以如下补充对时间排序
# 打印当前目录下 txt 结尾文件,按时间排序
dir /b /o:-d *.txt
dir: 列出目录中的文件和子目录
/b: 使用空格式(只列出文件名,不显示其他信息,如文件大小、修改日期等)
/o:-d: 按修改日期排序,-d 表示降序(从新到旧)
-n 按名称(字母顺序)
-s 按大小
-e 按扩展名(字母顺序)
-d 按日期(默认为修改日期)
/a:-d 参数确保 dir 命令不会列出目录,只列出文件
如下命令有两个问题(%F 用于dos,%%F 用于bat脚本):
一、for /r 是递归搜索,而 for 是非递归搜索,仅在当前目录中查找
二、按照平日逻辑,dir 的命令已经完成排序,按理说for 循环就应该直接打印的
但是实际上,如下命令在bat脚本中会先在括号内排序,然后for 会将结果再按字母排序,就会出现不在预期内的结果
# dir 排序后 for 会再排序,也就是不会按照日期排序,会按照文件名排序打印
for /r %F in (dir /b /a:-d *.hprof) do echo %F
# 如下的方式才能按照日期排序并打印
for /F "delims=" %F in ('dir /b /a:-d *.hprof') do echo %F
区别在于 用for /F 代替 for ,以及去除 /r 这个递归参数