【发布时间】:2021-03-19 14:15:41
【问题描述】:
我希望创建一个 bash 脚本,它递归地遍历目录,并从树的最末端开始按日期检查文件。如果最新文件超过 90 天,请上一个目录并检查相同的内容。如果没有超过 90 天的文件,请删除根目录。
例子:
/ftpdir/Site1/folder1/folder2
如果文件夹 2 没有较新的文件,但文件夹 1 有,则删除文件夹 1,但保留 Site1
我已经在AutoIT 中写了这个,但现在需要它作为 bash 脚本,我有点迷路了。
谢谢
编辑:我以为我很清楚,但让我澄清一些事情:
- 我不希望通过 FTP 协议执行此操作 - 这将作为每日 cron 作业运行
- 我的 FTP 站点被用作垃圾场。人们创建文件夹和子文件夹,这反过来又会填满空间。大部分东西都被废弃了。
- @Jonathan Leffler 了解我在这里想要做什么。再次对造成的混乱表示歉意。
- 我可以发布我的原始 AutoIT 脚本来展示我想要完成的工作。
EDIT 2 - 原始 AutoIT 脚本
#include <array.au3>
#include <Date.au3>
#include <File.au3>
#include <GuiConstants.au3>
#include <GuiButton.au3>
#Include <GuiListBox.au3>
#include <EditConstants.au3>
#include <ListBoxConstants.au3>
#include <WindowsConstants.au3>
#Include <GuiListBox.au3>
#Include <GuiMonthCal.au3>
Global $FolderName = "\\ph-svr-web1\ftpsites"
Global $rootFolder
Global $now = _Date_Time_SystemTimeToDateStr(_Date_Time_GetSystemTime(), 1)
Global $badSubs = 0, $olderThan = 90
Global $dirsToDeleteListBox, $topIndex, $TotalFoldersFound = 0
Global $ScanFoldersButton, $RemoveFoldersButton, $TotalFoldersFoundLabel, $TotalFoldersFoundNumber
Global $Calendar, $OlderThanNumberDays
Main()
Func Main()
$MainWindow = GuiCreate("Remove Older Files From FTP Site", 900)
GUISetFont(12)
$dirsToDeleteListBox = GUICtrlCreateList("", 40, 35, 550, 300, BitOr($WS_BORDER, $WS_VSCROLL, $LBS_NOTIFY, $LBS_DISABLENOSCROLL, $WS_HSCROLL, $LBS_EXTENDEDSEL))
$ScanFoldersButton = GuiCtrlCreateButton("Scan FTP Site", 40, 330)
$RemoveFoldersButton = GUICtrlCreateButton("Delete Selected Folders", 180, 330)
_GUiCtrlButton_Enable($RemoveFoldersButton, False)
$TotalFoldersFoundLabel = GUICtrlCreateLabel("Total Folders Found = ", 400, 335)
$TotalFoldersFoundNumber = GUICtrlCreateLabel($TotalFoldersFound, 560, 335, 100)
$Calendar = GUICtrlCreateMonthCal($MainWindow, 620, 35, 250, 220);, $MCS_NOTODAY)
$OlderThanDateLabel = GUICtrlCreateLabel("Searching for files dated prior to:", 630, 270)
GUISetFont(12, 600)
$OlderThanDateValue = GUICtrlCreateLabel(SetCalendarDate($olderThan), 650, 300)
$OlderThanNumberDays = GUICtrlCreateLabel("(" & $olderThan & " days)", 750, 300, 100)
GUISetFont(12, 400)
GUISetState()
GUICtrlSetResizing ($MainWindow, 513 )
While 1
$GUIAction = GuiGetMsg()
Switch $GUIAction
Case $GUI_EVENT_CLOSE
ExitLoop ; closes the GUI
Case $ScanFoldersButton
_GUICtrlButton_Enable($ScanFoldersButton, False)
_GUiCtrlButton_Enable($RemoveFoldersButton, False)
_GUICtrlListBox_ResetContent($dirsToDeleteListBox)
$TotalFoldersFound = 0
ScanFolder($FolderName)
_GUICtrlButton_Enable($ScanFoldersButton, True)
if $TotalFoldersFound > 0 then
_GUiCtrlButton_Enable($RemoveFoldersButton, True)
_GUICtrlListBox_SetTopIndex($dirsToDeleteListBox, 0)
endif
Case $RemoveFoldersButton
_GUICtrlButton_Enable($ScanFoldersButton, False)
_GUiCtrlButton_Enable($RemoveFoldersButton, False)
RemoveFolders()
_GUICtrlButton_Enable($ScanFoldersButton, True)
_GUiCtrlButton_Enable($RemoveFoldersButton, True)
Case $Calendar
GUICtrlSetData($OlderThanDateValue, SetCalendarDate(_DateDiff('D', GUICtrlRead($Calendar), $now)))
endswitch
wend
EndFunc
Func SetCalendarDate($Days)
$newDate = _DateAdd('D', -($Days), $now)
GUICtrlSetData($Calendar, $newDate)
$olderThan = $Days
GUICtrlSetData($OlderThanNumberDays, "(" & $olderThan & " days)")
Return $newDate
EndFunc
Func RemoveFolders()
$Dirs = _GUICtrlListBox_GetSelItemsText($dirsToDeleteListBox)
Switch $Dirs[0]
Case 0
MsgBox(276,"No folders selected","Please select folders to delete")
Case Else
ProgressOn("Deleting FTP Folders...", "Removing")
$totalDirs = UBound($Dirs) - 1
for $iI = 1 to $totalDirs
DirRemove($Dirs[$iI], 1)
ProgressSet((100 / $totalDirs), $Dirs[$iI])
$removeFromList = _GUICtrlListBox_FindString($dirsToDeleteListBox, $Dirs[$iI])
if $removeFromList > 0 then
_GUICtrlListBox_BeginUpdate($dirsToDeleteListBox)
_GUICtrlListBox_DeleteString($dirsToDeleteListBox, $removeFromList)
_GUICtrlListBox_EndUpdate($dirsToDeleteListBox)
$TotalFoldersFound -= 1
GUICtrlSetData($TotalFoldersFoundNumber, $TotalFoldersFound)
endif
next
ProgressOff()
MsgBox(64, "Folders Deleted", "The selected folders have been deleted")
EndSwitch
EndFunc
Func ScanFolder($SourceFolder)
Local $Search
Local $File
Local $FileAttributes
Local $FullFilePath
Local $FileDate
$Search = FileFindFirstFile($SourceFolder & "\*.*")
While 1
If $Search = -1 Then
ExitLoop
EndIf
$File = FileFindNextFile($Search)
If @error Then ExitLoop
$FullFilePath = $SourceFolder & ("\" & $File)
$FileAttributes = FileGetAttrib($FullFilePath)
$FileDate = _ArrayToString(FileGetTime($FullFilePath), "/", 0, 2)
$validRoot = ExtractRoot($FullFilePath)
If StringInStr($FileAttributes,"D") Then
if $validRoot >= 6 then
select
case _DateDiff('D', $FileDate, $now) <= $olderThan
$badSubs += 1
continuecase
case StringCompare($rootFolder, $FullFilePath) = 0
if $badSubs = 0 then
_GUICtrlListBox_BeginUpdate($dirsToDeleteListBox)
$topIndex = _GUICtrlListBox_AddString($dirsToDeleteListBox, $rootFolder)
_GUICtrlListBox_SetTopIndex($dirsToDeleteListBox, $topIndex)
_GUICtrlListBox_EndUpdate($dirsToDeleteListBox)
$TotalFoldersFound += 1
else
$removeFromList = _GUICtrlListBox_FindString($dirsToDeleteListBox, $rootFolder)
if $removeFromList >= 0 then
_GUICtrlListBox_BeginUpdate($dirsToDeleteListBox)
_GUICtrlListBox_DeleteString($dirsToDeleteListBox, $removeFromList)
_GUICtrlListBox_SetTopIndex($dirsToDeleteListBox, $topIndex)
_GUICtrlListBox_EndUpdate($dirsToDeleteListBox)
$TotalFoldersFound -= 1
endif
$badSubs = 0
endif
endselect
GUICtrlSetData($TotalFoldersFoundNumber, $TotalFoldersFound)
endif
ScanFolder($FullFilePath)
EndIf
Wend
FileClose($Search)
EndFunc
Func ExtractRoot($FileName)
$dirArray = StringSplit($FileName, "\")
if $dirArray[0] >= 6 then
$rootFolder = _ArrayToString($dirArray, "\", 1, 6)
endif
return $dirArray[0]
EndFunc
编辑 3:
感谢 Rob,我已根据自己的需要修改了他的脚本,如下所示:
#! /bin/bash
if [ -z "$1" ];
then
echo "You must enter a path after the script name"
exit
fi
# Usage: "ThisProgram /path/to/root/of/files"
dirs=( $(find "${1}" -maxdepth 1 -type d -print | sed 's:^./::'))
echo "$1"
for dir in "${dirs[@]}"; do
if [ $dir != $1 ]; then
echo "$dir"
# First, get a list of all subdirs, in depth-first order
find "${dir:-.}" -depth -type d -print0 |
while read -r -d '' i
do
# For each subdir, test to see if it matches two conditions. If either
# condition fails, this subdir is not a candidate for deletion.
# echo "Trying $i"
# First: is it at the lowest level, i.e. does it have any surviving children?
[ "$(find "$i" -type d -print | wc -l)" -gt 1 ] && continue
# echo "$i has no subdirs"
# Second: does it have any recent files?
[ "$(find "$i" -type f -mtime -90 | wc -l)" -gt 0 ] && continue
# echo "$i has no new files"
# If we got here, then this candidate has no subdirs and no recent files. Nuke it.
# echo rm -rf "$i"
echo "$i"
# rm -rf "$i"
done
fi
【问题讨论】:
-
什么?这没有多大意义。如果一个目录的最新文件超过 90 天,并且它的父目录也没有超过 90 天的文件,则删除一个目录:S 为什么?明确你想做什么。如果 folder1 有两个子目录会发生什么?删除目录的条件是什么?
-
将其视为一个目录,其中包含有关某些“事件”的已保存电子邮件,每封电子邮件只有一个文件。如果最近的消息超过 90 天,则事件已经结束,并且可以删除整个目录。如果任何消息的历史少于 90 天,请保留目录中的所有文件;该事件仍然足够“活跃”,我们需要所有信息。该示例使用 FTP。它的描述仍然令人困惑。
-
对原始问题的修改
-
对不起,我还是不明白你的要求。 “检查同一件事”和“删除根目录”是什么意思?
-
@Rob - 检查是否有超过 90 天的文件。至于删除根目录,不是(在这种情况下)ftpdir,而是所述ftpdir的子文件夹。