如何根据文件名中的模式将文件移动到特定目录?

时间:2017-12-01 02:56:10

标签: linux bash centos

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

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

详细说明一下:

  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. 如果目录和/或子目录不存在,我需要创建它们。

  6. 示例:

    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)。

3 个答案:

答案 0 :(得分:1)

这里的sed命令并没有做你想要实现的目标:

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

正则表达式[0-9].*的含义是"数字后跟任何"。 s/// sed命令执行替换。 结果是从第一个数字开始有效地删除输入中的所有内容。 所以对于" 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

这些是glob模式。 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

答案 1 :(得分:0)

我已回答了部分问题!

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 ####),照片子目录,并将文件移动到位:

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

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

全部谢谢!

答案 2 :(得分:0)

怎么样:

#!/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

希望这有帮助。