用regex重命名linux中的文件

时间:2015-02-21 13:06:38

标签: regex linux bash sed rename

这实际上不是一个问题,我自己解决了这个问题。但是我想在这里发布我的解决方案,以便在同样的情况下节省其他人的时间和精力。

所以我遇到了必须重命名(+3000)匹配特定模式的情况。在我的例子中,文件是来自syncthing的自动备份,因此文件将重命名为:

foo.bar -> foo~20150221-1330.bar

3 个答案:

答案 0 :(得分:3)

通过论坛和手册页进行了大量搜索后,我创建了以下单行程序,用linux中的find,sedxargsmv命令恢复原始文件名:

find . -type f  | sed -e 'p;s/\(.*\)~20[0-9]\{6\}-[0-9]\{6\}\(.*\)/\1\2/' | xargs -n2 -d'\n' mv

如果您愿意,可以使用自己的模式替换sed - 部分。顺便说一下,这个命令可以处理空格(感谢-d'\n'中的xargs标志),但不是新行。 我希望你们中的一些人觉得这个命令很有用。

好的,我将提供有关每个命令的更多信息:

  • find:提供当前目录中的所有常规文件(不是目录)
  • sedp将打印stdin中的每一行,s/regex/regex/将打印相同的行,但会替换。所以你得到每个文件后跟固定文件名:

    ./foo/bar~20150221-172703.txt
    ./foo/bar.txt`
    
  • xargs-n2将占用两行并将其作为参数发送至mv,-d' \ n'将解决文件夹名称中的空格问题(分隔符设置为换行符而不是空格)

答案 1 :(得分:0)

您的答案很好,但是如果您还想要解决也包含换行符的文件名,如果您不想使用sed,并且您想要确保只有的文件与此模式匹配的基本名称会被考虑在内(您的方法失败,例如,使用dir~20150221-172703/file,并且您的方法会使mvfile和{{1}抱怨很多当文件名与你的模式不匹配时,它是同一个文件)你需要稍微不同地进行。


一种可能性,如果您的file支持find选项(GNU -print0会这样做):让find吐出所有文件名,并使用find循环,其中Bash(不是while)将执行替换。像这样:

sed

您还可以确保find . -type f -print0 | while IFS= read -r -d '' file; do dirname=${file%/*} basename=${file##*/} # Perform the substitution only on basename # Since you like regex, you can use them if [[ $basename =~ ^(.*)~20[0-9]{6}-[0-9]{6}(.*)$ ]]; then new_basename=${BASH_REMATCH[1]}${BASH_REMATCH[2]} echo mv "$dirname/$basename" "$dirname/$new_basename" fi done 仅使用find过滤器(不是POSIX,但GNU -regex支持)来吐出匹配文件:

find

不确定这完全回答了你的问题,但至少它解决了你的方法存在的缺陷。

如果没有GNU的好东西,那么拥有健壮和干净的东西就更难了......

答案 2 :(得分:0)

您可以使用rnm

rnm -rs '/(.*)~20[0-9]{6}-[0-9]{6}(.*)/\1\2/' -fo -dp -1 *
  1. -fo:仅文件模式
  2. -dp:目录深度(-1表示无限深度,即所有子目录)。
  3. 您可以完全使用自己的正则表达式模式,在这种情况下,您必须将正则表达式模式更改为基本模式(BRE):

    rnm --regex basic -rs '/\(.*\)~20[0-9]\{6\}-[0-9]\{6\}\(.*\)/\1\2/' -fo -dp -1 *
    

    注意:

    1. 只有无效字符是空字符和路径分隔符(/)。
    2. 默认正则表达式模式是javascript。