根据文件名将文件移动到正确的日期目录

时间:2018-06-23 11:47:28

标签: bash mv

我的某些文件位于错误的目录中,我正在尝试将其移至正确的位置。

示例:

目录20180622将仅包含名称中具有20180622的文件名

如果20180622目录包含名称中具有20180623的文件,则它是放错位置的文件,应转到相应的正确目录,即20180623 目录结构是固定的(幸运的是)

date1/a/b/someprefix.date1.somesuffix #no problem
date1/a/b/someprefix.date2.somesuffix # problem
date2/c/d/someprefix.date2.somesuffix # no problem
date2/e/f/someprefix.date3.somesuffix # problem

date1/a/b/someprefix.date1.somesuffix
date2/a/b/someprefix.date2.somesuffix # problem fixed
date2/c/d/someprefix.date2.somesuffix
date3/e/f/someprefix.date3.somesuffix #problem fixed

使用find . -type f可以获得所有文件的列表,但没有获得如何mv正确的位置的文件。 someprefix可以是任何东西(它也可能包含点,因此cut并不是从文件名中提取日期的好方法)$f =~ (.*)(201[5-8][0-9][0-9][0-9][0-9][0-9])(.*)是我试图从文件名中提取日期的

2 个答案:

答案 0 :(得分:1)

应该很容易处理,只需要一个循环和一个if。

for path in $(find . -type f); do
    dirdate=$(echo $path | cut -d '/' -f 2)
    filedate=$(basename $path | cut -d '.' -f 2)

    if [[ $dirdate != $filedate ]]; then
        mv $path $(dirname $path | sed "s/$dirdate/$filedate/g")
    fi
done

这里的想法非常简单:它循环遍历文件以获取整个文件路径(./date1/a/b/prefix.date.suffix),并检查date1是否等于date。如果没有,它将文件移到由date1代替date的相同路径。

编辑评论

如果您要处理文件名的多个分隔符,则只需更改filedate=行,如:

filedate=$(basename $path | awk -F'[._\-]' '{print $2}' 2> /dev/null)

有点棘手,但可以说是Bash。

2> /dev/null用于使awk的警告保持沉默。

答案 1 :(得分:1)

不幸的是,使用bash正则表达式匹配时,您无法提取所有子匹配,因此我只能依靠grep来查找所有日期。

find . -type f -print0 |
  while IFS= read -d "" -r filename; do
    mapfile -t dates < <(echo "$filename" | grep -Eo '\<201[5-8][0-9]{4}\>')
    if [[ ${#dates[@]} -eq 2 ]] && [[ ${dates[0]} != ${dates[1]} ]]; then
      destdir=$(dirname "$filename" | sed "s/${dates[0]}/${dates[1]}/")
      mkdir -p "$destdir"
      mv -v "$filename" "$destdir"
    fi
  done

测试:

$ tree
.
├── 20180621
│   └── a
│       └── b
│           ├── a.20180621.txt
│           └── foo.20180701.bar
└── 20180701
    └── c
        └── d
            └── ok.20180701

6 directories, 3 files

我们只有一个文件应移动

$ find . -type f -print0 |
   while IFS= read -d "" -r filename; do
     mapfile -t dates < <(echo "$filename" | grep -Eo '\<201[5-8][0-9]{4}\>')
     if [[ ${#dates[@]} -eq 2 ]] && [[ ${dates[0]} != ${dates[1]} ]]; then
       destdir=$(dirname "$filename" | sed "s/${dates[0]}/${dates[1]}/")
       mkdir -p "$destdir"
       mv -v "$filename" "$destdir"
     fi
   done
'./20180621/a/b/foo.20180701.bar' -> './20180701/a/b/foo.20180701.bar'

和结果

$ tree
.
├── 20180621
│   └── a
│       └── b
│           └── a.20180621.txt
└── 20180701
    ├── a
    │   └── b
    │       └── foo.20180701.bar
    └── c
        └── d
            └── ok.20180701

8 directories, 3 files

无需依赖grep,这是对Arount答案的一个调整:

find 20+([0-9])/ -type f -print0 |
    while IFS= read -d "" -r filename; do
        dirdate=${filename%%/*}
        if [[ "$(basename "$filename")" =~ 20[0-9]{6} ]]; then
            filedate=${BASH_REMATCH[0]}
            if [[ $dirdate != $filedate ]]; then
                dest=${filename/$dirdate/$filedate}
                echo mkdir -p "$(dirname "$dest")"
                echo mv -v "$filename" "$dest"
            fi
        fi
    done