날짜별로 구분된 하위 디렉터리로 파일을 이동하는 방법

날짜별로 구분된 하위 디렉터리로 파일을 이동하는 방법

지난 몇 년 동안 마지막으로 수정된 파일이 포함된 큰 디렉터리가 있습니다. 하위 디렉터리를 생성하는 대화형 bash 셸에 한 번 입력할 수 있는 간단한 명령이 있습니까? 각각 4자리 연도로 이름이 지정되고 그 안에 있는 정보를 신뢰할 수 없을 때 해당 파일을 다음 위치로 이동하십시오. 파일의 나이와 관련된 파일 이름이 있는 각 하위 디렉터리를 확인하고 마지막으로 내가 실행하는 모든 것이 제대로 작동하고 파일이나 데이터가 손실되지 않았는지 확인하시겠습니까?

예를 들어, 다음과 같은 완전히 잘못된 예가 있습니다.

$ 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

답변1

for루프를 사용하여 디렉토리를 생성하여 date각 파일의 수정 연도를 얻을 수 있습니다(여기서는 GNU date또는 해당 옵션이 호환된다고 가정). -r그러면 각 파일이 해당 디렉터리로 이동됩니다.

for file in *; do
    [ ! -L "$file" ] &&
      dir_name=$(date -r "$file" +%Y) &&
      mkdir -p "$dir_name" &&
      mv -- "$file" "$dir_name"
done

답변2

사용진주 renamerename유틸리티(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명령줄이나 표준 입력에서 파일 이름을 인수로 전달할 수 있습니다(이름 바꾸기 옵션을 사용하는 경우 NUL로 구분된 파일 이름을 사용할 수도 있습니다. -0이는 개행 및 기타 성가신 문자가 포함된 파일 이름을 처리할 때 유용합니다). . 바라보다 man rename.

답변3

find여기에서 유용할 수 있습니다. printfGNU-가 필요합니다 find.

  1. 필요한 디렉토리 생성

    find -maxdepth 1 -mindepth 1 -type f -printf '%TY\n' | sort -u | xargs mkdir

  2. 그에 따라 파일을 이동하십시오.

    find -maxdepth 1 -mindepth 1 -type f -printf '%f\0%TY/%f\0' | xargs -0 -l2 mv --

2단계에서 NUL로 구분된 이름을 사용하면 이 방법이 공백, 개행 등을 포함하는 파일 이름에 매우 강력해집니다.

디렉터리를 포함하는 경우(텍스트에는 파일이라고 표시되어 있지만 예제에는 디렉터리가 포함되어 있음) 2단계에서 연도 이름이 지정된 디렉터리를 제외해야 합니다.

find -maxdepth 1 -mindepth 1 ! -name '[12][0129][0-9][0-9]' -printf '%f\0%TY/%f\0' | xargs -0 -l2 mv

...1000보다 오래되었거나 2999보다 이후의 파일이 없다고 가정합니다.


카탈로그의 연령도 업데이트하고 싶으신가요? 그런 다음 다음을 실행하십시오.

for dir in [12][0129][0-9][0-9] ; do
   touch -d ${dir}-01-01 $dir
done

이렇게 하면 디렉터리의 나이가 해당 연도의 1월 1일로 설정되고 향후 날짜 기반 검색이 단순화됩니다.

관련 정보