如何在 Linux 中批量重命名与某个模式匹配的所有文件?

如何在 Linux 中批量重命名与某个模式匹配的所有文件?

我有包含以下内容的文件夹许多 .mkv我想重命名而无需手动执行此操作的文件。

模式是这样的:

...
[XVC]_Control_-_10_-_Doctors_[SCB055Y].mkv
[XVC]_Control_-_11_-_Engineers_[50OPZ00].mkv
...

我希望结果是:

...
Control-10-Doctors.mkv
Control-11-Engineers.mkv
...

我尝试过使用并通过和find进行管道传输,但我似乎无法让它工作。sedtr

这是我到目前为止所尝试过的:

find . -iname "*.mkv" -exec sed -e 's/\[[^][]*\]//g' {} \;
find . -type f "*mkv" | sed 's/\[[^][]*\]//g' | tr -d '_'
find . "*.mkv" -type f -print0 | xargs -0 sed -i '' -e 's/\[[^][]*\]//g' | tr -d '_'
find . -iname "*.mkv" -exec rename 's/\[[^][]*\]//g' .mkv '{}' \;
find . -iname "*.mkv" -exec rename -n 's/\[[^][]*\]//g' {} ";"

还有其他几个,但似乎都不起作用。我觉得令人费解的是下面的命令有效:

(input)
echo '[XVC]_Control_-_10_-_Doctors_[SCB055Y].mkv' | sed 's/\[[^][]*\]//g' | tr -d '_'`

(output)
Control-10-Doctors.mkv

编辑:

$ file $(which rename)
/usr/bin/rename: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d7b5a08ee8556c59dbdda26e998e20d4762c2bbc, for GNU/Linux 3.2.0, stripped
rename -n 's/\[.+?\]//g; s/_//g' *mkv
rename: not enough arguments
Try 'rename --help' for more information.

答案1

这将与 perl-rename 一起使用(称为renameprenameperl-rename取决于您的发行版):

$ rename -n 's/\[.*?\]|_//gs' ./*.mkv
[XVC]_Control_-_10_-_Doctors_[SCB055Y].mkv -> Control-10-Doctors.mkv
[XVC]_Control_-_11_-_Engineers_[50OPZ00].mkv -> Control-11-Engineers.mkv

如果这为您提供了所需的输出,请再次运行它,而无需-n实际重命名文件。

或者,写一个小循环:

find . -iname "*.mkv" -print0 |
    while IFS= read -rd '' file; do
        newName=$(printf -- '%s\n' "$file" | perl -pe 's/\[.*?\]|_//gs')
        echo mv -- "$file" "$newName"
    done

如果看起来正确,请删除echo并再次运行它以实际重命名文件。


由于各种原因,您的命令不起作用。

  1. find . -iname "*.mkv" -exec sed -e 's/\[[^][]*\]//g' {} \;

    这个命令是sed在文件本身上运行命令,因此它只会更改文件的内容,而不更改名称。甚至不是这样,因为您没有使用-i这意味着它只是将更改的内容打印到标准输出。

  2. find . -type f "*mkv" | sed 's/\[[^][]*\]//g' | tr -d '_'

    在这里,find正在打印文件名,但这些文件名只是作为文本(流)传递到sed其中,修改其输入,但不会更改文件名。它与 相同echo foo | sed 's/f/b/'foo如果碰巧存在该文件,则不会重命名该文件。

  3. find . "*.mkv" -type f -print0 | xargs -0 sed -i '' -e 's/\[[^][]*\]//g' | tr -d '_'

    在这里,sed再次对文件运行,因此它基本上与上面相同,只是如果文件的任何内容匹配,它实际上会修改文件。由于这些是二进制文件,您不太可能但并非不可能实际修改它们。

  4. find . -iname "*.mkv" -exec rename 's/\[[^][]*\]//g' .mkv '{}' \;

    这个实际上能够重命名文件,但由于您将字符串.mkv作为命令的第一个参数传递rename,所以它尝试重命名一个名为.mkv.由于您可能没有这样的文件,因此它什么也不做。第二个参数'{}'被忽略。这会起作用:

    find . -iname "*.mkv" -exec rename 's/\[[^][]*\]//g' {} \;
    

    但它会将文件重命名为_Control_-_10_-_Doctors_.mkvand_Control_-_11_-_Engineers_.mkv因为你没有处理_该文件中的 。

  5. find . -iname "*.mkv" -exec rename -n 's/\[[^][]*\]//g' {} ";"

    这个应该有用吧!它只是没有进行正确的重命名,正如上面 4 中所述。

相关内容