如何按名称将文件分类到目录和子目录中?

如何按名称将文件分类到目录和子目录中?

我是 ubuntu 和编程世界的新手,我真的不知道该怎么做!

我有一个文件夹,其中有很多文件,名称如下:

000_S_001_mpc_asd.json
000_S_001_mpc_asd.nii
000_S_001_mpc_asd_aa.nii
011_S_001_mpc_asd.json
011_S_001_mpc_asd.nii
011_S_001_mpc_asd_aa.nii
000_S_002_mpc_asd.json
000_S_002_mpc_asd.nii
000_S_002_mpc_asd_aa.nii
000_S_001_dtd_rty.bval
000_S_001_dtd_rty.bvec
000_S_001_dtd_rty.nii
000_S_001_dtd_rty.json
011_S_001_dtd_rty.bval
011_S_001_dtd_rty.bvec
011_S_001_dtd_rty.nii
011_S_001_dtd_rty.json
000_S_002_dtd_rty.bval
000_S_002_dtd_rty.bvec
000_S_002_dtd_rty.nii
000_S_002_dtd_rty.json
011_S_001_flf_lkj.json
011_S_001_flf_lkj.nii
011_S_001_flf_lkj_aa.nii
000_S_001_flf_lkj.json
000_S_001_flf_lkj.nii
000_S_001_flf_lkj_aa.nii
000_S_002_flf_lkj.nii
000_S_002_flf_lkj_aa.nii

假设 xxx_S_xxx 是主要名称,而文件名称的其余部分提供次要信息(我们称之为次要名称)。

我想在辅助名称中找到一个特定的名称,并以此名称创建一个文件夹(例如 mpc、dtd 或 flf),然后创建以每个文件的主要名称命名的子文件夹,并将相应的文件放入这些文件夹中。也许一张图片可以更好地解释我想说的话。

例如,上面我给出的名称的输出将如下所示:

期望输出

可以从终端执行此操作吗?我将非常感激您的帮助。

我的操作系统是 Ubuntu 20.04 LTS

答案1

如果目标目录结构不存在,你可以砍掉小路分成几部分并按照所需的顺序排列。

#!/bin/bash

while IFS=_ read -r a b c d e; do
    mkdir -p target/$d/${a##*/}_${b}_${c}; mv -t $_ ${a}_${b}_${c}_${d}_$e
done < <(printf %s\\n files/*)

或者正则表达式,其中数组BASH_REMATCH记录匹配到的部件。第一个数组成员包含与整个正则表达式匹配的部分。括号中的子表达式匹配的子字符串将分配给以下成员。

#!/bin/bash

for i in files/*; do
    if [[ $i =~ ^files/([0-9]+_S_[0-9]+)_(mpc|dtd|flf) ]]; then
        mkdir -p target/${BASH_REMATCH[2]}/${BASH_REMATCH[1]}; mv -t $_ $i
    fi
done

您还可以将该过程分为两个步骤,首先创建目录结构,然后awk结合xargs优化使用,例如重命名。mkdirmmv

#!/bin/bash

builtin cd files

printf %s\\0 * | \
awk -F _ ' \
    BEGIN{ RS = ORS = "\0" } { printf("../target/%s/%s_%s_%s\0", $4, $1, $2, $3) } \
' | xargs -0 mkdir -p

# Remember we have change our working directory.
mmv -m '*_S_*_*_*' '../target/#3/#1_S_#2/#1_S_#2_#3_#4'

答案2

我不太清楚如何纯粹在终端上做到这一点而不会变得太难阅读,但我认为你可以得到你想要的结果,或者至少可以开始这样做:

编辑:更新了评论中的信息。还交换了次要和主要,因为它们是倒置的。

编辑2:意识到虽然次要名称不再依赖于位置,但主要名称依赖于次要的位置。

#!/bin/bash

input_directory="/path/to/your/data"
output_directory="/path/to/your/output"

cd "$input_directory"
for file in *; do

    if [ ! -f "$file" ]; then
        continue;
    fi

    # place your secondary names inside "(mpc|flf|dtd)" seperated by '|'
    secondary=$(echo "$file" | grep -o -E "(mpc|flf|dtd)");
    princple=$(echo "$file" | grep -o -E "([0-9]+_S_[0-9]+)");
    
    # skip over and alert that a secondary match was not found for a file
    if [ "$secondary" == "" ]; then
        echo "No secondary match found!! Skipping $file";
        continue;
    fi

    destination="${output_directory}/$secondary/$princple"

    # create the directories if they don't exist
    if [ ! -d "$destination" ]; then
        mkdir -p "$destination";
    fi

    # uncomment to move the files to the new directories if the test output
    # from echo is correct
    #mv "$file" "$destination"

    # test to print result of moving the files
    from=$(readlink -f "$file")
    echo "$from -> $destination/$file"
done

grep -o -E "(mpc|flf|dtd)"在文件名中搜索二级名称关键字之一,例如 (mpc、dtd 或 flf),然后将该词保存到二级变量中。

grep -o -E "([0-9]+_S_[0-9]+)相同的想法,通过寻找 xxx_S_xxx 模式。

它可以按如下方式运行:bash script.sh

input_directory和变量output_directory需要填写正确的路径。此外,grep 语句中的字段“(mpc|flf|dtd)”可以填写其他辅助路径。

相关内容