Bash 脚本优化文件重命名

4

我是一个完全的新手,但我想出了以下脚本来完成以下操作:

我有一个名为“unrar”的文件夹,在其中有未知文件夹名称的子文件夹,里面包含rar文件。 现在我进入unknownsubfolder,找到rar文件并在unknownsubfolder中解压它。 之后,我找到新文件并将其重命名为unknownsubfoldername。现在我抓取该文件并将其移动到./unrar。

#!/bin/bash

cd /home/user/unrar/

for dir in /home/user/unrar/*; 
    do (cd "$dir" && find -name "*.rar" -execdir unrar e -r '{}' \;); done

echo "$(tput setaf 2)-> unrar done!$(tput sgr0)" 

for dir in /home/user/unrar/*; 
do (cd "$dir" && find -name "*.mkv" -exec mv '{}' "${PWD##*\/}.mkv" \;);     done
for dir in /home/user/unrar/*; 
do (cd "$dir" && find -name "*.mp4" -exec mv '{}' "${PWD##*\/}.mp4" \;);     done
 for dir in /home/user/unrar/*; 
do (cd "$dir" && find -name "*.avi" -exec mv '{}' "${PWD##*\/}.avi" \;); done

cd /home/user/unrar
find -name "*.mkv" -exec mv '{}' /home/user/unrar \;
find -name "*.mp4" -exec mv '{}' /home/user/unrar \;
find -name "*.avi" -exec mv '{}' /home/user/unrar \;

大多数情况下,这个方法可以很好地运作,但在某些情况下可能会出现问题。

我想要在目录中查找*.rar文件并解压缩它。新文件(.mkv|.avi|.mp4)应该被重命名为DIR(.mkv|.avi|.mp4),并移动到./unrar目录下。

这是我的文件结构。

./unrar/
    - unknownsubfolder/
        -file.rar
        -file.r00
        -....
    - unknownsubfolder1/
        - s01/
            - file.rar
            - file.r00
            - ....
        - s02/
            - file.rar
            - file.r00
            - ....
        - ....

如果是情况1,解压"/unknownsubfolder/file.rar"并获取"x.mkv"。该文件从"x.mkv"重命名为"unknwonsubfolder.mkv",然后移动到"./unrar/unknownsubfolder.mkv"(*.avi + *.mp4同理)==完美。
如果是情况2,在我的脚本中,将解压未知子文件夹/s01/file.rar,但不会将其重命名为s01.mkv,而是改为unknwonsubfolder1.mkv。(如果还有s02、s03、s04等),我总是会在./unrar中得到一个unknownsubfolder.mkv文件)==输出错误。
因此,我想问三个问题:
1. 如何获取正确的DIRname以便重命名文件?或者如何输入未知子目录/s01....?
2. 是否有一种方法可以从查找结果中排除某个单词?有时候"unknownsubfolder"中包含另一个文件夹+文件,称为"sample(.mkv|.avi|.mp4)"。我想要排除它,以防止原始文件被样例文件覆盖。这种情况有时会发生。
3. 我相信我可以组合一些代码,使它变得更短。有人能解释一下吗?我如何将mkv、avi和mp4组合成一行。
谢谢,祝好,wombat
(编辑:为了更好的理解)

我理解正确的话,在出现问题的情况下,您有30个子文件夹在unknownsubfolder中,而不是一个rar文件。根据您的措辞,人们可能会认为只有一个名为subfolder1-30的文件夹。那些子文件夹里面是否仍然只包含一个单独的rar文件? - user4918296
正确,unknownsubfolder 包含多达 30 个子文件夹,每个子文件夹都包含一个压缩的 rar 视频文件。 - wombat
1个回答

2
更新:
我调整了解决方案以适用于“unrar”。由于之前我没有安装“unrar”,所以我使用“gunzip”构建了解决方案,然后简单地将其替换为“unrar”。这种方法的问题是,默认情况下,“unrar”会提取到当前的工作目录。另一个区别是,提取的文件名可以与存档的名称完全不同——这不仅仅是不同的扩展名。原始档案在提取后也不会被删除。
以下是专门为“unrar”定制的解决方案,考虑了上述行为:
#!/bin/bash

path="$1"
omit="$2"

while read f;do
        unrar e -r "${f}" "${f%/*}" > /dev/null
done < <(find "${path}" -type d -name "${omit}" -prune -o -type f -print)

while read f;do
        new="${f%/*}"
        new="${new##*/}"
        mv "${f}" "${path}/${new}"
done < <(find "${path}" -type d -name "${omit}" -prune -o -type f -a \! -name '*.rar' -print )

您可以将脚本保存为rename-script(不要忘记使其可执行),然后像这样调用它。
./rename-script /path/to/unrar omitfolder

请注意,在脚本中没有使用 cd 命令。您至少需要提供 unrar 文件夹的位置作为第一个参数,否则将会出错。在 OP 的情况下,这将是 /home/user/unraromitfolder 不是路径,它只是您想要省略的文件夹的名称。因此,在 OP 的情况下,这将是 sample
./rename-script /home/user/unrar sample

根据评论中OP的要求,您可以阅读关于bash read-builtinprocess substitution的内容,以了解while循环如何工作以及如何将find返回的文件名分配给变量f

非常感谢您的回答。目前我还不太理解,但我会尝试弄清楚每个部分的作用,并提供更好的反馈。谢谢。 - wombat
当我运行该脚本时,出现语法错误在“done <<”处,意外的单词。我几乎可以理解该脚本中每一行的作用,但不确定“read f”和"${f}"是什么意思。我猜想它是我想要解压缩的文件,但是f如何知道它是要解压缩的文件呢?你能解释一下吗? - wombat
@wombat 我更新了解决方案,使其与 unrar 兼容。我之前使用的是 gunzip,现在只需将其替换为 unrar 即可。然而,你的错误是由于没有正确调用脚本造成的。你必须至少提供 unrar 文件夹的位置作为第一个参数。如果你的 unrar 文件夹始终位于相同位置,并且省略文件夹始终具有相同的名称,则可以通过修改 path="/home/user/unrar"omit=sample 将它们硬编码到脚本中。然后你就可以不带参数调用它了。 - user4918296
感谢您的时间和工作。我编辑了我的起始帖子,也许现在更容易理解了。使用您的脚本,我被问了很多次是否要覆盖文件。看起来它只是剪切了“rar”扩展名并将文件移动到./unrar目录下。没有解压缩rar文件。 - wombat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接