在OS X终端中批量重命名文件的正则表达式

40

我想找一个用正则表达式批量重命名文件的方法,比如:

s/123/onetwothree/g

我记得我可以使用awk和sed与正则表达式一起使用,但是无法弄清如何将它们连在一起以获得所需的输出。


我只是想感谢ccpizza,因为他的Python正则表达式脚本对我非常有用。我本来想点赞的,但我是个新手,所以做不了什么...甚至不能评论。 我在我的MacBook Pro上使用他的Python脚本来重命名一堆带有捕获组的文件,这样我就不会丢失任何重要信息,并且我能够将文件名转换成更可接受的格式。 我刚开始学习Python,但我喜欢正则表达式,这个脚本对我非常有用! - NutSoft
5个回答

119
你可以安装基于Perl的rename实用程序:
brew install rename

然后直接像这样使用:

rename 's/123/onetwothree/g' *

如果您想在不重命名任何文件的情况下测试正则表达式,请添加 -n 开关。


31

通过在sed管道中构造重命名命令并将其输入到shell中,可以有效地执行重命名操作。

ls |
sed -n 's/\(.*\)\(123\)\(.*\)/mv "\1\2\3" "\1onetwothree\2"/p' |
sh

1
onetwothree后面应该是\3而不是\2。 - George
2
唯一能够递归工作的命令(使用查找命令)是 $ find . -iname test* | sed -E 's/\.\/(test)(.*)(\.jpg)/mv \1\2\3 \1\214\3/' | sh - Binarian

12

Namechanger非常好用。它支持使用正则表达式搜索和替换:考虑到我正在使用以下正则表达式进行超级复杂的重命名: \.sync-conflict-.*\. 这真是救命稻草。

正则表达式捕获组(Diomidis回答)可以通过CLI方式进入变量,我认为它们被称为$1和$2,所以rename -nv 's/^(\d{2})\.(\d{2}).*/s$1e$2.mp4/' *.mp4 变成了可能。注意$1和$2吗?那些来自于我的例子中捕获组一 (\d{2}) 和捕获组二 (\d{2})

输入图片说明


1
是的..问题确实提到了终端...尽管如此仍然很有用! https://mrrsoftware.com/namechanger/ - ptim
".sync-conflict-.*"这就是我要说的。也许使用ls xargs和mv命令可以做类似的事情。这个应用程序是那些使整个操作系统值得运行的程序之一。真正的美丽程序。" - Tomachi
Namechanger是一个改变游戏规则的工具!非常感谢您的指引。它可以在M2 Mac上的MacOS 12.6下运行,但需要重新编译。我会尝试联系作者。 - Adam Wildavsky

8

我提供友好的递归正则表达式文件重命名器, 默认情况下仅模拟替换操作并显示结果文件名。

当您满意干预测试结果时,请使用-w实际写入更改,使用-s抑制不匹配文件的显示; 使用-h--help显示使用说明。

最简单的用法:

# replace all occurences of 'foo' with 'bar'
# "foo-foo.txt" >> "bar-bar.txt"
ren.py . 'foo' 'bar' -s

# only replace 'foo' at the beginning of the filename
# "foo-foo.txt" >> "bar-foo.txt"
ren.py . '^foo' 'bar' -s

支持匹配组(例如\1\2等):

# rename "spam.txt" to "spam-spam-spam.py"
ren.py . '(.+)\.txt' '\1-\1-\1.py' -s 

# rename "12-lovely-spam.txt" to "lovely-spam-12.txt"
# (assuming two digits at the beginning and a 3 character extension 
ren.py . '^(\d{2})-(.+)\.(.{3})' '\2-\1.\3' -s

注意:在测试结果并想要实际写入更改时,不要忘记添加-w

适用于Python 2.x和Python 3.x。

#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import print_function
import argparse
import os
import fnmatch
import sys
import shutil
import re


def rename_files(args):

    pattern_old = re.compile(args.search_for)

    for path, dirs, files in os.walk(os.path.abspath(args.root_folder)):

        for filename in fnmatch.filter(files, "*.*"):

            if pattern_old.findall(filename):
                new_name = pattern_old.sub(args.replace_with, filename)

                filepath_old = os.path.join(path, filename)
                filepath_new = os.path.join(path, new_name)

                if not new_name:
                    print('Replacement regex {} returns empty value! Skipping'.format(args.replace_with))
                    continue

                print(new_name)

                if args.write_changes:
                    shutil.move(filepath_old, filepath_new)
            else:
                if not args.suppress_non_matching:
                    print('Name [{}] does not match search regex [{}]'.format(filename, args.search_for))


if __name__ == '__main__':

    parser = argparse.ArgumentParser(description='Recursive file name renaming with regex support')

    parser.add_argument('root_folder',
                        help='Top folder for the replacement operation',
                        nargs='?',
                        action='store',
                        default='.')
    parser.add_argument('search_for',
                        help='string to search for',
                        action='store')
    parser.add_argument('replace_with',
                        help='string to replace with',
                        action='store')
    parser.add_argument('-w', '--write-changes',
                        action='store_true',
                        help='Write changes to files (otherwise just simulate the operation)',
                        default=False)
    parser.add_argument('-s', '--suppress-non-matching',
                        action='store_true',
                        help='Hide files that do not match',
                        default=False)

    args = parser.parse_args(sys.argv[1:])

    print(args)
    rename_files(args)

感谢@ccpizza。在Windows 10上,使用Python 3非常好用。 - Bill

6
files = "*"
for f in $files; do
     newname=`echo "$f" | sed 's/123/onetwothree/g'`
     mv "$f" "$newname"
done

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