Bash 腳本:有條件地刪除舊文件,同時保留最新副本

Bash 腳本:有條件地刪除舊文件,同時保留最新副本

注意:雖然 jeff-schaller 給了答案,但它取決於zsh;所以我想得到一個基於的答案Bash

我喜歡建立一個 Bash 腳本來有條件地從備份目錄中刪除舊檔案。

2 個不同的檔案備份有 2 個條件:

1、保留最新的副本Edge_Profile_*.tgz,刪除其餘的Edge_Profile_*.tgz 僅當年齡超過 5 天時

2, 保留最新的副本Firefox_Profile_*.tgz,並刪除其餘的Firefox_Profile_*.tgz他們多大並不重要

以下是我修改 AskUbuntu 答案的方法:https://askubuntu.com/a/933098/928088

腳本:

#!/bin/bash

LOG_FILE="/home/admn/Cleanup.log"
TEMP_LOG="/tmp/Temp_Cleanup.log"

mv $LOG_FILE $TEMP_LOG

{

cd /home/admn/Downloads/Test;

echo "Cleanup log:" `date`

find /home/admn/Downloads/Test/Edge_Profile_*.tgz -type f \( -mtime +5 -printf 'Y\t' -o -printf 'N\t' \) -printf '%A@\t%p\0' |
    sort -zk2,2 | head -zn -1 | while read -r -d '' flag _ file; do \
        case "$flag" in 
            'Y') echo rm "$file" 
               ;; 
            *) echo "skipping $file (too new)"
               ;; 
        esac;
done

echo

find /home/admn/Downloads/Test/Firefox_Profile_*.tgz -type f \( -printf 'Y\t' -o -printf 'N\t' \) -printf '%A@\t%p\0' |
    sort -zk2,2 | head -zn -1 | while read -r -d '' flag _ file; do \
        case "$flag" in 
            'Y') echo rm "$file" 
               ;; 
            *) echo "skipping $file (too new)"
               ;; 
        esac        
done

} &>> $LOG_FILE

cat $TEMP_LOG >>$LOG_FILE

exit;

在日誌檔案中輸出echo

/usr/local/scripts/cleanup.sh

rm /home/admn/Downloads/Test/Edge_Profile_Jul_06_2021_00-35.tgz
rm /home/admn/Downloads/Test/Edge_Profile_Jul_07_2021_00-35.tgz
....
skipping /home/admn/Downloads/Test/Edge_Profile_Jul_12_2021_00-35.tgz (too new)
skipping /home/admn/Downloads/Test/Edge_Profile_Jul_13_2021_00-35.tgz (too new)
....

rm /home/admn/Downloads/Test/Firefox_Profile_Jul_01_2021_00-35.tgz
rm /home/admn/Downloads/Test/Firefox_Profile_Jul_02_2021_00-35.tgz
....

實際運行腳本時在日誌檔案中輸出,不含echo

/home/admn/Downloads/cleanup.sh: line 24: skipping /home/admn/Downloads/Test/Edge_Profile_Jul_12_2021_00-35.tgz (too new): No such file or directory
/home/admn/Downloads/cleanup.sh: line 24: skipping /home/admn/Downloads/Test/Edge_Profile_Jul_13_2021_00-35.tgz (too new): No such file or directory
....

目錄中文件總數:20個文件

1、Edge_Profile_*.tgz:7月06日至7月17日:12個文件

2、Firefox_Profile_*.tgz:7月01日至7月8日:8個文件

問題:

(1) 我思考該腳本可以工作,但我不確定,因為我在不知道發生了什麼的情況下修改了大部分內容。

(2) 輸出到日誌檔:

我希望日誌檔案中的輸出與我得到的完全相同echo,除了檔案名稱(不包含完整路徑),例如:

rm Edge_Profile_Jul_11_2021_00-35.tgz

skipping Edge_Profile_Jul_12_2021_00-35.tgz (too new)

作業系統:Ubuntu MATE 21.04

多謝。

答案1

在允許您直接存取檔案的 shell 中,根據修改時間操作檔案要容易得多。 zsh 就是這樣一種 shell。只需sudo apt install zsh安裝即可。由於您的檔案似乎位於一個目錄中,因此該答案是非遞歸的。首先示範更簡單的情況:

  • 要保留 Firefox_Profile_*.tgz 的最新副本並刪除其餘部分,無論它們有多舊:

    echo would rm -v -- Firefox_Profile_*.tgz(.om[2,-1])
    

    echo would如果看起來正確,請刪除該部分。這使用了一個glob(通配符)限定符在括號內做三件事:

    • 僅選擇純檔案(不是目錄或套接字等).
    • 依修改時間對文件進行排序(排序),從最新到最舊,om
    • 選擇結果清單的一部分,從第二個元素開始到結尾-跳過第一個(最新)文件,[2,-1]

    如果沒有匹配的文件,zsh 將停止並抱怨“zsh:找不到匹配項”,並且不會執行rm.

  • 要保留 Edge_Profile_*.tgz 的最新副本並僅在其餘內容超過 5 天時刪除它們,首先我們獲取最新的副本:

    newest=(Edge_Profile_*.tgz(.om[1]))
    

    ……然後我們得到超過五天的:

    older=(Edge_Profile_*.tgz(.m+5))
    

    這裡的新部分是+5onm修飾符。這將選擇超過 5 天的文件。之後,我們確保最新的不在要刪除的清單中:

    remove=("${(@)older:|newest}")
    

    這裡的新部分是數組減法符號:|;它記錄在zsh手冊的參數擴充部分。它選擇不在“最新”中的“較舊”元素。最後,我們刪除該文件列表:

    echo would rm -v -- "${remove[@]}"
    

相關內容