Можно ли создать цикл, который создаст переменную из каждого имени каталога внутри каталога, если каталоги не всегда одинаковы?

Можно ли создать цикл, который создаст переменную из каждого имени каталога внутри каталога, если каталоги не всегда одинаковы?

Я работаю над скриптом для запуска на моем Synology DS 1019+, который берет все подпапки в определенном каталоге, создает подпапки в другом каталоге, затем создает жесткие ссылки всех файлов .mkv в подпапках в недавно созданных подпапках в другом местоположении. Однако, если подпапка уже существует во втором местоположении, то я хочу, чтобы он просто создал жесткую ссылку.

Из-за характера моих файлов структура папок и файлы в указанных папках будут разными для каждого случая, для которого будет использоваться этот скрипт. Есть ли способ сделать этот скрипт цикличным, чтобы каждый цикл брал следующую папку в расположении A и выполнял mkdir каждой подпапки и задачу жесткой ссылки (к файлам в указанной подпапке)?

Вот что у меня есть на данный момент:

#! /bin/bash

echo "Enter Movie Collection:"
read MOVIE_DIR
echo "Enter Bonus Feature Disc: "
read BONUS_DIR

cd "/volume1/Plex/Movies/$MOVIE_DIR/"

for dir in */.; do

    if [[ ! -e "$dir"/*/ ]]; then
        mkdir "$dir"/*/
    fi

    if [[ ! -d "$dir"/*/ ]]; then
        ln /volume1/Plex/"Bonus Feature Discs"/$BONUS_DIR/*/*.mkv -t ./"$dir"/*/.
    fi
done

Я совсем не разбираюсь в циклах, особенно вложенных, поэтому не знаю, с чего начать устранение неполадок. В настоящее время вместо того, чтобы реплицировать папки в расположении A (если они еще не существуют) в расположении B, а файлы в папках в расположении A были жестко связаны, я получаю пустую папку с именем "_2X68P~X" в основных каталогах расположения B (например, в моем тесте вместо того, чтобы "TEST 1" получал папку "featurette" с жестко связанным TEST.mkv внутри нее, я просто получаю эту папку с мусорными данными в "TEST 1", которая пуста.

Я пытался использовать basename, а также dirname, но я еще не нашел способа сделать так, чтобы он циклически проходил по каждой папке в каталоге. Я также пытался использоватьcd /the/directory/path/ "${PWD##*/}"

EDIT: В течение нескольких часов после публикации этого я нашел решение. Код, который я привел выше, просто не был логически обоснованным из-за слишком большого количества неконкретных областей, что означало, что ничего не произойдет. В итоге мне пришлось перезапустить его с нуля. Вот код, который у меня получился, и этот код действительно выполняет ту работу, которая мне нужна. Это может быть не самый элегантный метод для этого, но он работает достаточно хорошо, судя по проведенным мной тестам.

#! /bin/bash

#Ask the user to input the directories of both the bonus disc's files and where the movies are located that the bonus disc's contents will be needed.
echo "Enter the name of the Movie Collection and press [ENTER]: "
read MOVIE_DIR
echo "Enter the name of the Bonus Feature Disc and press [ENTER]: "
read BONUS_DIR


#This goes to the location of the bonus disc specified by the end user. I believe this part is necessary for creating the text document below, but it might not be.
cd "/volume1/Plex/Bonus Feature Discs/$BONUS_DIR/" || return

#This creates a text document that has each directory within the specified Bonus Disc directory as a separate line  
    ls -d -- */ >> /volume1/Plex/"Bonus Feature Discs"/output.txt
    echo ls  -d -- */


#This goes to the movie directory specified by the end user. This cd is definitely required
cd "/volume1/Plex/Movies/$MOVIE_DIR/" || return


#the for loop loops through every movie that resides in the movie collection folder
 for dir in *; do

    #this while loop reads the text document and will use each line from the document as a variable.
    while IFS=' ' read -r line; do
        name="$line"

        #A directory with the name of the line of the text document will be created in each movies directory only if it doesn't already exist
        mkdir -p "$dir/$name"

        #this will create the hard links to every single video that resides in the folders within the bonus features disc into the corresponding folders for each movie
        if [[ ! -e "/volume1/Plex/Movies/$MOVIE_DIR/$name" ]]; then 
            ln "/volume1/Plex/Bonus Feature Discs/$BONUS_DIR/$name"*.mkv -t ./"$dir/$name"
        fi

    done < "/volume1/Plex/Bonus Feature Discs/output.txt"
 done

echo "Linking Completed"
echo $dir

#finally, once all the work is complete, the script will delete the text document that is no longer needed
rm "/volume1/Plex/Bonus Feature Discs/output.txt"

решение1

Используя rsync, и предполагая, что вы хотите жестко связать все .mkvфайлы в каталоге или под ним sourceс targetкаталогом, включая создание всех каталогов (даже если они пусты .mkv).

rsync --archive --link-dest="$PWD/source" \
    --include='*/' \
    --include='*.mkv' \
    --exclude='*' \
    source/ target

Параметр --archive( -a) rsyncсохраняет метаданные файла, а также запускает рекурсивное копирование каталогов. Параметр --link-destзадает rsyncкаталог, из которого существующие файлы могут быть жестко связаны с target. --includeПараметрами выбираются каталоги и .mkvфайлы, а последний --excludeпараметр игнорирует все, что еще не выбрано с помощью --include.

Чтобы удалить пустые каталоги, которые могут быть созданы в target, вы можете использовать findследующее:

find target -type d -empty -delete

... предполагая, что вы findреализуете -emptyтест и -deleteдействие.

Пример:

source
|-- dir1
|   |-- file1.mkv
|   |-- file1.txt
|   |-- file2.mkv
|   `-- file2.txt
|-- dir2
|   |-- file1.mkv
|   |-- file1.txt
|   |-- file2.mkv
|   `-- file2.txt
|-- dir3
|   |-- file1.mkv
|   |-- file1.txt
|   |-- file2.mkv
|   `-- file2.txt
`-- dir4
    `-- file1.doc

Приведенная выше команда rsyncвыполняется и targetстановится...

target
|-- dir1
|   |-- file1.mkv
|   `-- file2.mkv
|-- dir2
|   |-- file1.mkv
|   `-- file2.mkv
|-- dir3
|   |-- file1.mkv
|   `-- file2.mkv
`-- dir4

Просто показываем, что файлы жестко связаны (одинаковый номер inode, количество ссылок равно 2):

$ ls -l -i source/dir1/file1.mkv target/dir1/file1.mkv
3118217 -rw-r--r--  2 kk  kk  0 Apr 10 17:03 source/dir1/file1.mkv
3118217 -rw-r--r--  2 kk  kk  0 Apr 10 17:03 target/dir1/file1.mkv

Удаление пустых каталогов:

$ find target -type d -empty -delete
$ tree target
target
|-- dir1
|   |-- file1.mkv
|   `-- file2.mkv
|-- dir2
|   |-- file1.mkv
|   `-- file2.mkv
`-- dir3
    |-- file1.mkv
    `-- file2.mkv

решение2

Я предполагаю, что вы каким-то образом присваиваете значения двум переменным dirAи dirB(«Местоположение A» и «второе местоположении» в вашем описании).

Вы проходите цикл по всем файлам в формате dirA.

Каждый раз, когда файл в dirAявляется каталогом, вы создаете другой каталог с тем же именем в dirB. --parentПереключатель предотвращает mkdirвыдачу ошибки, если новый каталог уже существует, устраняя необходимость проверки существования нового каталога.

Внутренняя часть ifпроверяет наличие файлов .mkv и пропускает каталог, если их нет.

Этот скрипт работает для одного уровня каталогов: если у вас есть каталоги внутри каталогов, они не будут просматриваться.

    #! /bin/bash

    dirA=...
    dirB=...

    cd "$dirA"

    for dir in *; do
      if [ -d "$dir" ]; then
         names=$(find "$dir" -maxdepth 1 -name '*.mkv')
         if [ "$names" ]; then
           mkdir --parent "$dirB/$dir"
           ln "$dir"/*.mkv "$dirB/$dir"
         fi
      fi
    done

Связанный контент