【问题标题】:How do I move files to specific directories based on a pattern in the filename?如何根据文件名中的模式将文件移动到特定目录?
【发布时间】:2017-12-01 02:56:10
【问题描述】:

如果其中任何一个不是特别清楚,请告诉我,我会尽力澄清。

我基本上需要将一组具有各种扩展名和与文件名相似的模式的文件分类到与扩展名的模式和类型匹配的目录和子目录中。

稍微详细一点:

  1. 所有文件,无论扩展名如何,都以模式“zz####”开头,其中#### 是从 1 到 900 的数字; "zz1.zip 到 zz950.zip、zz1.mov 到 zz950.mov、zz1.mp4 到 zz950.mp4"

  2. 某些文件包含附加字符; “zz360_hello_world.zip”

  3. 有些文件包含空格; “zz370_hello world.zip”

  4. 我需要按照特定格式对这些文件进行排序并移动到目录和子目录中:“/home/hello/zz1/zip, /home/hello/zz1/vid”

  5. 如果目录和/或子目录不存在,我需要创建它们。

例子:

zz400_testing.zip       ----> /home/hello/zz400/zip
zz400 testing video.mov ----> /home/hello/zz400/vid

zz500.zip                       ----> /home/hello/zz500/zip
zz500_testing another video.mp4 ----> /home/hello/zz500/vid

我在这里找到了一些关于更简单用例的答案,但无法满足我的特定需求。

任何帮助都将不胜感激。

谢谢!

编辑:添加我一直在搞乱的代码

for f in *.zip; do
    set=`echo "$f"|sed 's/[0-9].*//'`
    dir="/home/demo/$set/photos"
    mkdir -p "$dir"
    mv "$f" "$dir"
done

我想我只是想不通如何匹配正则表达式。我已经做到了这一点:

[demo@alpha grep]$ echo zz433.zip|sed 's/[0-9].*//'
zz

脚本将运行 mkdir,甚至将 zip 文件移动到适当的位置。我只是无法创建正确的顶级目录(zz433)。

【问题讨论】:

  • 你的代码在哪里?你试过什么? mkdir 创建目录,ls 使用通配符选择文件,或者find 也可以这样做,mv 移动文件,如果您需要循环文件,请使用while,而不是for,因为for 不会正确处理空格。试试看,如果您在此处发布问题,我们将帮助您继续前进。
  • @Nic3500 抱歉,我已经用相关信息编辑了我的帖子。我是新手>_

标签: linux bash centos


【解决方案1】:

这里的sed 命令并没有达到你想要达到的效果:

set=`echo "$f"|sed 's/[0-9].*//'`

正则表达式[0-9].*的含义是“一个数字后跟任何东西”。 seds/// 命令执行替换。 结果是从第一个数字开始有效地从输入中删除所有内容。 所以对于“zz360_hello_world.zip”它会删除从“3”开始的所有内容, 只留下“zz”。

还要注意,为了匹配文件,*.zip 模式与您的描述不匹配。您正在寻找以“zz”开头和从 1 到 900 的数字的文件。如果您不介意包含大于 900 的数字,那么您可以像这样编写循环表达式:

for f in zz[0-9][^0-9]* zz[0-9][0-9][^0-9]* zz[0-9][0-9][0-9][^0-9]*; do

或者更简洁的同一件事:

for f in zz{[0-9],[0-9][0-9],[0-9][0-9][0-9]}[^0-9]*; do

这些是全局模式。 zz[0-9][^0-9]* 的意思是“以 'zz' 开头,然后是一个数字,然后是一个非数字,然后是任何东西”。 在上面的示例中,我使用三种模式来涵盖“zz”后跟 1、2 或 3 位数字,然后是非数字的情况。 第二个例子是第一个更紧凑的形式, 这个想法是a{b,c}d 扩展为abdacd

接下来,要获得适当的前缀,您可以使用带有case 语句的模式匹配并提取子字符串。 这些模式的语法与前面 for 语句示例中的 glob 语法相同。

case "$f" in
    zz[0-9][0-9][0-9]*) prefix=${f:0:5} ;;
    zz[0-9][0-9]*) prefix=${f:0:4} ;;
    zz[0-9]*) prefix=${f:0:3} ;;
esac

您似乎还想按文件类型创建分组。您可以通过切断名称的开头直到带有ext=${f##*.} 的点来获得文件扩展名,然后使用前面示例中的case 语句将扩展名映射到所需的目录名称。

综合以上内容:

for f in zz{[0-9],[0-9][0-9],[0-9][0-9][0-9]}[^0-9]*; do
    case "$f" in
        zz[0-9][0-9][0-9]*) prefix=${f:0:5} ;;
        zz[0-9][0-9]*) prefix=${f:0:4} ;;
        zz[0-9]*) prefix=${f:0:3} ;;
    esac

    ext=${f##*.}
    case "$ext" in
        mov|mp4) group=vid ;;
        *) group=$ext ;;
    esac

    dir="/home/demo/$prefix/$group"
    mkdir -p "$dir"
    mv "$f" "$dir"
done

【讨论】:

    【解决方案2】:

    我已经回答了我自己的部分问题!

    for f in *.zip; do
        set=`echo "$f"|grep -o -P 'zz[0-9]+.{0,0}'`
        dir="/home/demo/$set/photos"
        mkdir -p "$dir"
        mv "$f" "$dir"
    done
    

    基本上,以下脚本会抓取如下文件:

    zz232.zip
    zz233test.zip
    zz234 test.zip
    

    然后它会创建顶级目录(zz####)、photos 子目录,并将文件移动到位:

    /home/demo/zz232/photos/zz232.zip
    /home/demo/zz233/photos/zz233test.zip
    /home/demo/zz234/photos/zz234 test.zip
    

    继续扩展脚本以获得更多功能。

    谢谢大家!

    【讨论】:

    • 你看到我的回答了吗?它不仅解决了问题中损坏的sed 和正则表达式,而且比这个答案更有效。
    • @janos 我做到了,我很感激!不过说实话,我在这里完全是个菜鸟,你的回答并没有完全超出我的想象。
    • 我在回答中添加了更多解释。如果您需要更多信息,请告诉我。
    【解决方案3】:

    怎么样:

    #!/bin/bash
    
    IFS=$'\n'
    
    for file in *; do
        if [[ $file =~ ^(zz[0-9]+).*\.(zip|mov|mp4)$ ]]; then
            ext=${BASH_REMATCH[2]}
            if [ $ext = "mov" -o $ext = "mp4" ]; then
                ext="vid"
            fi
            dir="/home/hello/${BASH_REMATCH[1]}/$ext"
            mkdir -p $dir
            mv "$file" $dir
        fi
    done
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-06
      • 2021-07-12
      • 1970-01-01
      • 2019-01-02
      • 2016-03-21
      相关资源
      最近更新 更多