【问题标题】:Move files to correct date directories based on filename根据文件名将文件移动到正确的日期目录
【发布时间】:2018-06-23 11:47:28
【问题描述】:

我的一些文件位于不正确的目录中,我正在尝试将它们移动到正确的位置。

示例:

目录 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])(.*) 是我试图从文件名中提取日期的内容

【问题讨论】:

  • someprefixsomesuffix 总是一样吗?
  • 不幸的是没有 :( ,它可以是任何文本,我只能保证日期将始终被包含,但是 somesuffix 总是以 .gz 结尾。如果有的话,我可以为所有一组 someprefix 运行多个命令一个解决方案
  • 鉴于 Python 是您用户名的一部分,我建议使用它而不是 Bash 来解决这个问题。实施起来会更容易。
  • 你可以在这里学习如何操作 bash 参数:gnu.org/software/bash/manual/html_node/…

标签: bash mv


【解决方案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

【讨论】:

    【解决方案2】:

    它应该很容易处理,你只需要一个循环和一个 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 的同一路径。

    为 cmets 编辑

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

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

    这有点棘手,但假设它是 Bash。

    2&gt; /dev/null 是让awk 的警告静音。

    【讨论】:

    • 是的,几乎可以工作,但前缀和后缀可以有dot .-_作为分隔符,所以从文件名中删除日期现在对我来说是个问题。我需要一个正则表达式,它给我filenamedate=$(echo $path | cut -d '/' -f 5) 现在说我得到 sometext_date-sometext 或 dometext-date-sometext 或 sometext.date.sometext 等。所以一个可以提取模式 201[5-8][0-9][ 的正则表达式上面的 0-9][0-9][0-9] 是理想的。日期始终采用 YYYYMMDD 格式,由两端的东西分隔 [anything]YYYYMMDD[anything]
    • $f =~ (.*)(201[5-8][0-9][0-9][0-9][0-9][0-9])(.*) 之类的东西不确定,只是添加到这里作为我的尝试
    猜你喜欢
    • 2014-06-06
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 2016-03-21
    • 2023-04-10
    • 2018-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多