【问题标题】:bash script to remove directories based on modified file datebash脚本根据修改的文件日期删除目录
【发布时间】:2021-03-19 14:15:41
【问题描述】:

我希望创建一个 bash 脚本,它递归地遍历目录,并从树的最末端开始按日期检查文件。如果最新文件超过 90 天,请上一个目录并检查相同的内容。如果没有超过 90 天的文件,请删除根目录。

例子

/ftpdir/Site1/folder1/folder2

如果文件夹 2 没有较新的文件,但文件夹 1 有,则删除文件夹 1,但保留 Site1

我已经在AutoIT 中写了这个,但现在需要它作为 bash 脚本,我有点迷路了。

谢谢

编辑:我以为我很清楚,但让我澄清一些事情:

  1. 我不希望通过 FTP 协议执行此操作 - 这将作为每日 cron 作业运行
  2. 我的 FTP 站点被用作垃圾场。人们创建文件夹和子文件夹,这反过来又会填满空间。大部分东西都被废弃了。
  3. @Jonathan Leffler 了解我在这里想要做什么。再次对造成的混乱表示歉意。
  4. 我可以发布我的原始 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的子文件夹。

标签: linux bash scripting


【解决方案1】:
#! /bin/bash

# Usage: "ThisProgram /path/to/root/of/files"
# If "/path/to/root/of/files" is not specified, use the current directory instead.

# First, get a list of all subdirs, in depth-first order
find "${1:-.}" -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"

done

【讨论】:

  • 我会在星期二回到办公室时试试这个。
  • 这似乎可行,但我该如何解决空白问题?
  • 我已将脚本更新为对空格友好。请注意,该脚本现在需要 bash。
  • 谢谢,@Rob。我已经发布了对你的脚本的更新,它对我来说非常适合。
  • 反复使用find 在我看来像是严重的矫枉过正,而通往wc 的管道让我不寒而栗。你真正需要的可能是case $i/*/. in "$i/*/.") no subdirectories;; 来检查直接子目录的存在(取决于nullglob 的设置),第二个find 至少应该有一个-depth 0。反模式[ $(whatever | wc -l) -gt 0 ] 通常写得更优雅whatever | grep -q .,甚至只是简单的旧whatever &gt;/dev/null。另请参阅 UUOC 页面上的讨论 partmaps.org/era/unix/award.html#wc
【解决方案2】:

仅删除旧文件,您编写问题的方式听起来相当复杂。

如果您只想删除超过 90 天的文件:

find $DIR -type f -mtime +90d | xargs rm -f

如果您想删除整个目录(如果该目录中的所有文件都是 90 天):

if test $(find $DIR -type f -mtime -90d | wc -l) -eq 0; then
  rm -rf $DIR
fi

如果您想要不同的东西,请澄清您的问题:-)

【讨论】:

  • 这样做的问题是,即使目录中有较年轻的文件,它也会删除超过 90 天的文件,这并不是问题所要求的(如果我理解正确的话;我可能会感到困惑,因为它没有写得那么清楚)。
【解决方案3】:

在这里找到你想要的答案:here find /ftpdir/Site1/ -type f -mtime +90 -delete find /ftpdir/Site1/ -type d -empty -mtime +90 -delete

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-30
    • 2013-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多