Bash

如何將文件移動到按日期分隔的子目錄中

  • December 23, 2021

我有一個大目錄,其中包含過去幾年到現在最後一次修改的文件。是否有一個簡單的命令或命令我可以在互動式 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實用程序(不要與renamefrom 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 statperldoc -f localtimestrftime()可以在 中找到有關的詳細資訊perldoc POSIX

順便說一句,rename可以在命令行或標準輸入中將文件名作為參數(如果您使用重命名-0選項,甚至可以使用 NUL 分隔的文件名,這在處理包含換行符和其他煩人字元的文件名時很有用)。見man rename

引用自:https://unix.stackexchange.com/questions/683425