Ist es möglich, eine Schleife zu erstellen, die aus jedem Verzeichnisnamen innerhalb eines Verzeichnisses eine Variable erstellt, wenn die Verzeichnisse nicht immer gleich sind?

Ist es möglich, eine Schleife zu erstellen, die aus jedem Verzeichnisnamen innerhalb eines Verzeichnisses eine Variable erstellt, wenn die Verzeichnisse nicht immer gleich sind?

Ich arbeite an einem Skript, das auf meiner Synology DS 1019+ ausgeführt werden kann. Es nimmt alle Unterordner in einem bestimmten Verzeichnis, erstellt die Unterordner in einem anderen Verzeichnis und erstellt dann Hardlinks aller .mkv-Dateien in den Unterordnern in den neu erstellten Unterordnern am anderen Speicherort. Wenn der Unterordner jedoch bereits am zweiten Speicherort vorhanden ist, soll nur der Hardlink erstellt werden.

Aufgrund der Art meiner Dateien sind die Ordnerstruktur und die Dateien in diesen Ordnern bei jeder Instanz, für die dieses Skript verwendet wird, unterschiedlich. Gibt es eine Möglichkeit, dieses Skript in einer Schleife laufen zu lassen, sodass jede Schleife den nächsten Ordner an Standort A nimmt und die mkdir- und Hardlink-Aufgabe jedes Unterordners (zu den Dateien in diesem Unterordner) ausführt?

Folgendes habe ich derzeit:

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

Ich bin überhaupt nicht bewandert, wenn es um Schleifen geht, insbesondere verschachtelte Schleifen, daher bin ich mir nicht sicher, wo ich mit der Fehlerbehebung beginnen soll. Derzeit werden die Ordner an Ort A nicht an Ort B repliziert (sofern sie nicht bereits vorhanden sind) und die Dateien in den Ordnern an Ort A nicht fest verknüpft, sondern ich erhalte einen leeren Ordner mit dem Namen „_2X68P~X“ in den Hauptverzeichnissen von Ort B (z. B. erhalte ich in meinem Test nicht einen Ordner „featurette“ mit einer fest verknüpften Datei TEST.mkv, sondern nur diesen leeren Mülldatenordner in „TEST 1“.

Ich habe versucht, sowohl basename als auch dirname zu verwenden, aber ich habe noch keine Möglichkeit gefunden, es in einer Schleife laufen zu lassen, sodass es alle Ordner innerhalb eines Verzeichnisses durchläuft. Ich habe auch versucht,cd /the/directory/path/ "${PWD##*/}"

EDIT: Im Laufe der Stunden, nachdem ich das gepostet hatte, habe ich eine Lösung gefunden. Der Code, den ich oben hatte, war einfach nicht logisch, da zu viele Bereiche nicht spezifisch waren, was bedeutete, dass nichts passieren würde. Ich musste schließlich von vorne beginnen. Hier ist der Code, den ich am Ende hatte, und dieser Code erledigt die Arbeit, die ich brauche. Es ist vielleicht nicht die eleganteste Methode, dies zu tun, aber basierend auf den Tests, die ich durchgeführt habe, funktioniert es gut genug.

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

Antwort1

Verwenden Sie und gehen Sie davon aus, dass Sie alle Dateien im oder unter dem Verzeichnis rsyncfest mit dem Verzeichnis verknüpfen möchten , einschließlich der Erstellung aller Verzeichnisse (auch wenn diese keine Dateien enthalten)..mkvsourcetarget.mkv

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

Die Option --archive( -a) sorgt dafür, rsyncdass die Dateimetadaten erhalten bleiben und löst außerdem rekursives Kopieren von Verzeichnissen aus. Die --link-destOption gibt rsyncein Verzeichnis an, von dem aus vorhandene Dateien fest in verknüpft werden können target. Die --includeOptionen wählen Verzeichnisse und .mkvDateien aus, während die letzte --excludeOption alles ignoriert, was nicht bereits mit ausgewählt wurde --include.

Um leere Verzeichnisse zu löschen, die möglicherweise in generiert wurden target, können Sie findFolgendes verwenden:

find target -type d -empty -delete

... vorausgesetzt, Sie findimplementieren den -emptyTest und die -deleteAktion.

Beispiel:

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

Der rsyncobige Befehl wird ausgeführt und targetwird zu ...

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

Zeigt lediglich, dass die Dateien fest verknüpft sind (dieselbe Inode-Nummer, Link-Anzahl ist 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

Löschen leerer Verzeichnisse:

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

Antwort2

Ich gehe davon aus, dass Sie den beiden Variablen dirAund dirB(„Standort A“ und „zweiter Standort“ in Ihrer Beschreibung) irgendwie Werte zuweisen.

Sie führen eine Schleife durch alle Dateien in dirA.

Jedes Mal, wenn die Datei in dirAein Verzeichnis ist, erstellen Sie ein weiteres Verzeichnis mit demselben Namen auf dirB. Der --parentSchalter verhindert, mkdirdass ein Fehler ausgegeben wird, wenn das neue Verzeichnis bereits vorhanden ist, sodass nicht mehr geprüft werden muss, ob das neue Verzeichnis vorhanden ist.

Das Innere ifprüft, ob MKV-Dateien vorhanden sind, und überspringt das Verzeichnis, wenn dies nicht der Fall ist.

Dieses Skript funktioniert auf einer einzelnen Verzeichnisebene: Wenn Sie Verzeichnisse innerhalb von Verzeichnissen haben, werden diese nicht berücksichtigt.

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

verwandte Informationen