Как отсортировать файлы по каталогам и подкаталогам по имени?

Я новичок в 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

0
задан 13 June 2021 в 09:26

2 ответа

Я не совсем уверен, как это сделать только в терминале, чтобы его не было слишком трудно читать, но я думаю, что вы могли бы получить результат, который ищете, или по крайней мере, начните с чего-то вроде этих строк:

Изменить: обновлено информацией из комментария. Также поменяны местами вторичный и первичный, так как они были наоборот.

Edit2: понял, что, хотя вторичное имя больше не зависит от размещения, основное имя зависит от размещения вторичного.

#!/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 должны быть заполнены правильными путями. Кроме того, поля "(mpc | flf | dtd)" в grep можно заполнить выписку с другими вторичными лицами.

0
ответ дан 28 July 2021 в 11:29

В случаях, когда структура целевого каталога не существует, вы можете разрезать путь на части и напоминать их в желаемом порядке.

#!/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 оптимизирует использование mkdir а затем используйте, например, mmv для переименования.

#!/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
ответ дан 28 July 2021 в 11:29

Другие вопросы по тегам:

Похожие вопросы: