Bash - 如何根据名称中的日期重新组织文件?

thi*_*oso 3 shell scripting bash shell-script

我正在处理数千个文件,其名称包含从 2001-01-01 到 2020-12-31 的连续日期。

此类文件的示例如下所示:

gpm_original_20010101.nc
gpm_cressman_20010101_cor_method-add_fac-0.5_pass-1_radius-500km.nc
gpm_cressman_20010101_cor_method-add_fac-0.5_pass-2_radius-250km.nc
gpm_cressman_20010101_cor_method-add_fac-0.5_pass-3_radius-150km.nc
gpm_cressman_20010101_cor_method-add_fac-0.5_pass-4_radius-75km.nc
gpm_cressman_20010101_cor_method-add_fac-0.5_pass-5_radius-30km.nc
.
.
.
gpm_original_20010131.nc
gpm_cressman_20010131_cor_method-add_fac-0.5_pass-1_radius-500km.nc
gpm_cressman_20010131_cor_method-add_fac-0.5_pass-2_radius-250km.nc
gpm_cressman_20010131_cor_method-add_fac-0.5_pass-3_radius-150km.nc
gpm_cressman_20010131_cor_method-add_fac-0.5_pass-4_radius-75km.nc
gpm_cressman_20010131_cor_method-add_fac-0.5_pass-5_radius-30km.nc
Run Code Online (Sandbox Code Playgroud)

依此类推,直到2020-12-31。我需要做的是根据年份和月份将这些文件重新组织到新文件夹中。

目录树需要遵循year子目录的逻辑months,如下所示:

2001
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12

2002
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
Run Code Online (Sandbox Code Playgroud)

等等。并且应该根据文件名中的等效日期将文件移动到这些目录。例如:200101xx名称中包含的所有文件都应移动到该2001/01文件夹中。

使用 bash 实现这一目标的最直接方法是什么?

sch*_*ity 6

如果我理解正确,这是我的建议:

for i in *.nc; do 
  [[ "$i" =~ _([0-9]{8})[_.] ]] && d="${BASH_REMATCH[1]}"
  mkdir -p "${d:0:4}/${d:4:2}"
  mv "$i" "${d:0:4}/${d:4:2}"
done
Run Code Online (Sandbox Code Playgroud)


Fel*_*xJN 5

循环几年和几个月:

#!/bin/bash

for year in {2001..2020} ; do
  mkdir $year
  for month in {01..12} ; do
    mkdir $year/$month
    mv gpm_cressman_${year}${month}* $year/$month
  done
done
Run Code Online (Sandbox Code Playgroud)

如果您每年和每月有太多长名称的文件(您声称为“数千”),则bash可能会达到其限制(“参数列表太长”)。无论是临时增加的ulimit或使用xargs

#!/bin/bash

for year in {2001..2020} ; do
  mkdir $year
  for month in {01..12} ; do
    mkdir $year/$month
    find -maxdepth 1 -type f -name "gpm_cressman_${year}${month}*" |
      xargs -I '{}' mv '{}' $year/$month
  done
done
Run Code Online (Sandbox Code Playgroud)