¿Es posible hacer un bucle que cree una variable a partir de cada nombre de directorio dentro de un directorio cuando los directorios no son siempre los mismos?

¿Es posible hacer un bucle que cree una variable a partir de cada nombre de directorio dentro de un directorio cuando los directorios no son siempre los mismos?

Estoy trabajando en un script para ejecutar en mi Synology DS 1019+ que toma todas las subcarpetas dentro de un directorio determinado, crea las subcarpetas en otro directorio y luego crea enlaces físicos de todos los archivos .mkv dentro de las subcarpetas en las subcarpetas recién creadas en la otra ubicación. Sin embargo, si la subcarpeta ya existe en la segunda ubicación, entonces quiero que simplemente cree el enlace físico.

Debido a la naturaleza de mis archivos, la estructura de carpetas y los archivos dentro de dichas carpetas serán diferentes para cada instancia en la que se utilizará este script. ¿Hay alguna manera de hacer que este script se repita para que cada bucle tome la siguiente carpeta dentro de la Ubicación A y realice el mkdir de cada subcarpeta y tarea de enlace físico (a los archivos dentro de dicha subcarpeta)?

Esto es lo que tengo actualmente:

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

No tengo ninguna habilidad con los bucles, especialmente los bucles anidados, por lo que no estoy seguro de por dónde empezar a solucionar este problema. Actualmente, en lugar de replicar las carpetas en la ubicación A (si aún no existen) en la Ubicación B, y los archivos dentro de las carpetas en la Ubicación A están vinculados, obtengo una carpeta vacía con un nombre de "_2X68P~X" dentro del Los directorios principales de la ubicación B (por ejemplo, en mi prueba, en lugar de que "TEST 1" obtenga una carpeta "featurette" con un TEST.mkv vinculado dentro de ella, solo obtengo esa carpeta de datos basura dentro de "TEST 1" que está vacía.

Intenté usar el nombre base y el nombre del directorio, pero todavía tengo que encontrar una manera de hacer que se repita para que recorra cada carpeta dentro de un directorio. También he intentado utilizarcd /the/directory/path/ "${PWD##*/}"

EDITAR: En el transcurso de las horas posteriores a la publicación de esto, encontré una solución. El código que tenía arriba simplemente no era lógicamente sólido, debido a que había demasiadas áreas que no eran específicas, lo que significaba que no sucedería nada. Terminé teniendo que reiniciar desde cero. Aquí está el código con el que terminé, y este código hace el trabajo que necesito. Puede que no sea el método más elegante para hacer esto, pero funciona bastante bien según las pruebas que he realizado.

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

Respuesta1

Usando rsyncy asumiendo que desea vincular todos .mkvlos archivos dentro o debajo del sourcedirectorio al targetdirectorio, incluida la creación de todos los directorios (incluso si no tienen .mkvarchivos).

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

La opción --archive( ) conserva los metadatos del archivo y también activa la copia recursiva de directorios. La opción proporciona un directorio desde el cual se pueden vincular archivos existentes a . Las opciones seleccionan directorios y archivos, mientras que la opción final ignora todo lo que no esté seleccionado con .-arsync--link-destrsynctarget--include.mkv--exclude--include

Para eliminar directorios vacíos que puedan generarse en target, puedes usar findasí:

find target -type d -empty -delete

...asumiendo con tus findimplementos la -emptyprueba y la -deleteacción.

Ejemplo:

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

El rsynccomando anterior se ejecuta y targetse convierte...

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

Solo muestro que los archivos están vinculados (mismo número de inodo, el recuento de enlaces es 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

Eliminar directorios vacíos:

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

Respuesta2

Asumiré que de alguna manera asignas valores a las dos variables dirAy dirB("Ubicación A" y "segunda ubicación" en tu descripción).

Realiza un bucle en todos los archivos en dirA.

Cada vez que el archivo dirAes un directorio, crea otro directorio con el mismo nombre en dirB. El --parentmodificador evita mkdirque se produzca un error si el nuevo directorio ya existe, lo que elimina la necesidad de comprobar la existencia del nuevo directorio.

El interno ifverifica que haya archivos .mkv y, de lo contrario, omite el directorio.

Este script funciona para un único nivel de directorio: si tiene directorios dentro de directorios, no se examinarán.

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

información relacionada