【问题标题】:How to find all files in subdirectories that match pattern and replace pattern如何在匹配模式和替换模式的子目录中查找所有文件
【发布时间】:2020-10-09 12:31:32
【问题描述】:

我正在尝试将我的一些视频文件移动到新的子目录中,同时也在我的 Unraid 系统上重命名它们。这些文件都遵循类似的命名约定:

featurette name-featurette.mkv

我想将这些文件从它们的当前目录移动到一个子目录并像这样重命名它们:

featurettes/featurette name.mkv 

我可以使用 find 和 execdir 创建目录并重新定位文件:

find . -type f -name *-featurette.mkv -maxdepth 2 -execdir mkdir ./featurettes/ \;
find . -type f -name *-featurette.mkv -maxdepth 2 -execdir mv {} ./featurettes/ \;

我正在为重命名作品而苦苦挣扎。我已经尝试了重命名命令,但无法让它在 featurettes 目录中工作,更不用说从上面的两个目录中执行命令了。我在 featurettes 目录中尝试了以下命令:

rename \-featurette.mkv .mkv *

但是我得到了错误:

invalid option -- 'f'

我认为通过转义破折号可以避免该问题,但它似乎不起作用。非常感谢有关如何从与其匹配的子目录中的所有文件中删除此模式的任何建议。

【问题讨论】:

  • 使用引号等重命名 "-featurette.mkv" ".mkv" *
  • 另外,对于 find 命令中的所有文件,您不必像以前那样多次调用 mkdirmute。只需一次,mkdir -p your/name,然后移动并重命名。

标签: linux bash


【解决方案1】:

man rename 你可以看到这个命令获取选项和 3 个位置参数:

概要 重命名 [options] 表达式替换文件...

因此,在您的情况下,第一个参数被解释为一个选项。您可以使用以下语法:

rename -- '-featurette' '' *-featurette.mkv

重命名文件。 -- 表示任何选项都结束了,后面的只是位置参数。


总之,用一个mv 进程复制文件并重命名它们:

mkdir -p target/dir
find . -maxdepth 2 -type f -name "*-featurette.mkv" -exec mv -t target/dir {} +
cd target/dir && rename -- '-featurette' '' *-featurette.mkv

如果要重命名位于不同子目录中的许多文件,可以使用以下语法:

find . -name "*-featurette.mkv" -print0 | xargs -r0 rename -- '-featurette' ''  

【讨论】:

    【解决方案2】:
    find . \
      -maxdepth 2 \
      -type f \
      -name '*-featurette.mkv' \
      -execdir sh -c '
    echo mkdir -p ./featurettes/
    echo mv -- "$@" ./featurettes/
    ' _ {} \+
    

    我修复或改进的实现问题:

    • -maxdepth 2 必须在 -type f 之前
    • -name '*-featurette.mkv' 必须引用模式以防止 shell 扩展它。
    • -execdir 最好与内联 shell 一起使用,因此它还可以处理来自同一目录的多个参数

    还请记住,在使用 -execdir 运行命令时,findcd 到该目录。这意味着mv -- "$@" ./featurettes/' 会将文件移动到./featurettes/' 目录相对-execdir 刚刚cd

    在移动时也会重命名文件的版本:

    (没有echodry-run 保护,所以只有如果你确定它可以达到你想要的效果)

    #!/usr/bin/env sh
    
    find . \
      -maxdepth 2 \
      -depth \
      -name '*-featurette.mkv' \
      -type f \
      -execdir sh -c '
    mkdir -p featurettes
    for arg
    do
      basename=${arg##*/}
      mv -- "$basename" "./featurettes/${basename%-featurette.mkv}.mkv"
    done
    ' _ {} +
    

    【讨论】:

    • hmm,这似乎不起作用。它似乎只是为每个 featurette 文件回显 mkdir 命令和 mv 命令。
    • @kwatz 很明显,我放置了echo 是为了保护您免受发烧友复制粘贴的潜在损害。您的评论只是证实他们有很好的理由。
    • 抱歉,对于那些没有太多 bash 经验的人来说,这不是很明显。
    • 这比我原来的解决方案更优雅地移动文件,但不能解决删除文件名的 -featurette 部分的问题
    • @kwatz,就是这样。只是出于礼貌,因为代码可能会产生意想不到的副作用。这也提醒您不要运行您在此处找到的代码,除非您了解它的作用。审核可能会删除故意恶意代码,但诚实的人为错误和不完全了解环境或将如何使用,意味着您应该始终了解代码,然后再使用它。
    【解决方案3】:

    可以使用Bash的shell参数扩展功能来获取文件名的部分,例如:

    $> filename=name-featurette.mkv
    $> echo ${filename%-*} #To print first part before '-'
    name
    $> echo ${filename##*.} #To get the extension
    mkv
    $> echo ${filename#*-} #To print the part after '-' with extension
    featurette.mkv
    

    有了这个并稍微修改你的 find 命令,你应该能够移动+重命名你的文件:

    find . -type f -name '*-featurette.mkv' -maxdepth 2 -execdir sh -c 'f="{}"; mv -- "$f" ./featurettes/"${f%-*}.mkv"' \;
    

    其实你应该可以将 find 命令合二为一来创建目录、移动和重命名文件。

    find . -type f -name '*-featurette.mkv' -maxdepth 2 -execdir sh -c 'f="{}"; mkdir ./featurettes; mv -- "$f" ./featurettes/"${f%-*}.mkv"' \;
    

    【讨论】:

    • mkdir -p 因为它会在第一次创建后抛出警告
    猜你喜欢
    • 1970-01-01
    • 2018-02-11
    • 2016-01-19
    • 2023-03-17
    • 1970-01-01
    • 2014-02-04
    • 1970-01-01
    • 2012-05-18
    • 1970-01-01
    相关资源
    最近更新 更多