当目录并不总是相同时,是否可以创建一个循环,从目录中的每个目录名称创建一个变量?

当目录并不总是相同时,是否可以创建一个循环,从目录中的每个目录名称创建一个变量?

我正在编写一个在 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 中的文件夹内的文件硬链接,而是在位置 B 的主目录(例如,在我的测试中,不是“TEST 1”获取其中包含硬链接 TEST.mkv 的“featurette”文件夹,而是在“TEST 1”中获取空的垃圾数据文件夹。

我尝试使用基名和目录名,但我还没有找到一种方法让它循环,以便它循环遍历目录中的每个文件夹。我也尝试过使用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选项提供了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

相关内容