Bash
如何將文件移動到按日期分隔的子目錄中
我有一個大目錄,其中包含過去幾年到現在最後一次修改的文件。是否有一個簡單的命令或命令我可以在互動式 bash shell 中鍵入一次,它可以創建子目錄,每個子目錄的名稱是四位數的年份,當我不能依賴任何資訊時將相應的文件移動到每個子目錄中關於文件年齡的文件名,最後驗證我執行的所有內容都正常工作並且我沒有失去任何文件或數據?
例如給出這個完全假的例子:
$ cd ~/Documents $ ls -lhrt ... -rw-r--r-- 4 user user 4.0K Jun 29 2017 oldfile.txt -rw-r--r-- 4 user user 4.0K May 15 2018 2018file.md -rw-r--r-- 4 user user 4.0K Apr 14 2019 04.dat -rw-r--r-- 4 user user 4.0K Jul 21 2019 somepage.html drw-r--r-- 4 user user 4.0K Jul 21 2019 somepage_files -rw-r--r-- 4 user user 4.0K Mar 13 2020 march.dat -rw-r--r-- 4 user user 4.0K Feb 12 18:03 file02.dat -rw-r--r-- 4 user user 4.0K Oct 11 18:03 OctReport.txt
完成後,我想得到以下結果:
$ cd ~/Documents $ find . . ./2017 ./2017/oldfile.txt ./2018 ./2018/2018file.md ./2019 ./2019/04.dat ./2019/somepage.html ./2019/somepage_files ./2019/somepage_files/... ./2020 ./2020/march.dat ./2021 ./2021/file02.dat ./2021/OctReport.txt
您可以使用
for
循環date
來獲取每個文件的修改年份(這裡假設 GNUdate
或與其選項兼容-r
)來創建目錄。然後每個文件將被移動到它們各自的目錄中。for file in *; do [ ! -L "$file" ] && dir_name=$(date -r "$file" +%Y) && mkdir -p "$dir_name" && mv -- "$file" "$dir_name" done
使用perl
rename
實用程序(不要與rename
from util-linux 或任何其他工具混淆rename
):$ rename -n -e 'BEGIN {use POSIX}; next unless -f $_; my $Y = strftime "%Y", localtime((stat $_)[9]); mkdir $Y unless -d $Y; s=^=$Y/=' * rename(04.dat, 2019/04.dat) rename(2018file.md, 2018/2018file.md) rename(file02.dat, 2021/file02.dat) rename(march.dat, 2020/march.dat) rename(OctReport.txt, 2021/OctReport.txt) rename(oldfile.txt, 2017/oldfile.txt) rename(somepage_files, 2019/somepage_files) rename(somepage.html, 2019/somepage.html)
該
-n
選項使其成為空執行。-v
當您確定它會執行您想要的操作時,將其刪除(或替換為詳細輸出)。例如$ find . -type f -ls 864326 9 drwxr-xr-x 2 cas cas 10 Dec 22 18:08 . 863863 1 -rw-r--r-- 1 cas cas 0 Oct 11 18:03 ./OctReport.txt 863999 1 -rw-r--r-- 1 cas cas 0 Jul 21 2019 ./somepage_files 864123 1 -rw-r--r-- 1 cas cas 0 Mar 13 2020 ./march.dat 863997 1 -rw-r--r-- 1 cas cas 0 May 15 2018 ./2018file.md 864122 1 -rw-r--r-- 1 cas cas 0 Apr 14 2019 ./04.dat 863862 1 -rw-r--r-- 1 cas cas 0 Feb 12 2021 ./file02.dat 863998 1 -rw-r--r-- 1 cas cas 0 Jul 21 2019 ./somepage.html 863996 1 -rw-r--r-- 1 cas cas 0 Jun 29 2017 ./oldfile.txt $ rename -v -e 'BEGIN {use POSIX}; next unless -f $_; my $Y = strftime "%Y", localtime((stat $_)[9]); mkdir $Y unless -d $Y; s=^=$Y/=' * 04.dat renamed as 2019/04.dat 2018file.md renamed as 2018/2018file.md file02.dat renamed as 2021/file02.dat march.dat renamed as 2020/march.dat OctReport.txt renamed as 2021/OctReport.txt oldfile.txt renamed as 2017/oldfile.txt somepage_files renamed as 2019/somepage_files somepage.html renamed as 2019/somepage.html $ find . -type f -ls 863996 1 -rw-r--r-- 1 cas cas 0 Jun 29 2017 ./2017/oldfile.txt 863862 1 -rw-r--r-- 1 cas cas 0 Feb 12 2021 ./2021/file02.dat 863863 1 -rw-r--r-- 1 cas cas 0 Oct 11 18:03 ./2021/OctReport.txt 863999 1 -rw-r--r-- 1 cas cas 0 Jul 21 2019 ./2019/somepage_files 864122 1 -rw-r--r-- 1 cas cas 0 Apr 14 2019 ./2019/04.dat 863998 1 -rw-r--r-- 1 cas cas 0 Jul 21 2019 ./2019/somepage.html 864123 1 -rw-r--r-- 1 cas cas 0 Mar 13 2020 ./2020/march.dat 863997 1 -rw-r--r-- 1 cas cas 0 May 15 2018 ./2018/2018file.md
有關這些 perl 函式的詳細資訊,請參見
perldoc -f stat
和perldoc -f localtime
。strftime()
可以在 中找到有關的詳細資訊perldoc POSIX
。順便說一句,
rename
可以在命令行或標準輸入中將文件名作為參數(如果您使用重命名-0
選項,甚至可以使用 NUL 分隔的文件名,這在處理包含換行符和其他煩人字元的文件名時很有用)。見man rename
。