ディレクトリが常に同じではない場合に、ディレクトリ内の各ディレクトリ名から変数を作成するループを作成することは可能ですか?

ディレクトリが常に同じではない場合に、ディレクトリ内の各ディレクトリ名から変数を作成するループを作成することは可能ですか?

私は Synology DS 1019+ で実行するスクリプトを作成中です。このスクリプトは、特定のディレクトリ内のすべてのサブフォルダを取得し、別のディレクトリにサブフォルダを作成し、サブフォルダ内のすべての .mkv ファイルのハード リンクを他の場所に新しく作成したサブフォルダに作成します。ただし、2 番目の場所にサブフォルダが既に存在する場合は、ハード リンクのみを作成するようにしたいです。

ファイルの性質上、フォルダー構造とフォルダー内のファイルは、このスクリプトが使用されるインスタンスごとに異なります。このスクリプトをループさせて、各ループで場所 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 のフォルダー内のファイルがハードリンクされる代わりに、場所 B のメイン ディレクトリ内に "_2X68P~X" という名前の空のフォルダーが作成されます (たとえば、私のテストでは、"TEST 1" にハードリンクされた TEST.mkv を含む "featurette" フォルダーが作成されますが、"TEST 1" 内に空のゴミ データ フォルダーが作成されます)。

私はbasenameとdirnameの使用を試みたが、ディレクトリ内の各フォルダを循環させる方法をまだ見つけられていない。また、cd /the/directory/path/ "${PWD##*/}"

編集: この投稿から数時間経って、解決策を見つけました。上記のコードは、具体的でない部分が多すぎて論理的に正しくなく、何も起こりませんでした。結局、最初からやり直さなければなりませんでした。最終的にできたコードがこれです。このコードは、必要な機能を果たします。これを行う最もエレガントな方法ではないかもしれませんが、実行したテストに基づくと、十分に機能します。

#! /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を提供します。オプションはディレクトリとファイルを選択しますが、最後のオプションは でまだ選択されていないものをすべて無視します。rsynctarget--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何らかの方法で 2 つの変数とdirB(説明の「場所 A」と「2 番目の場所」)に値を割り当てていると仮定します。

内のすべてのファイルをループします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

関連情報