递归重命名文件-最好使用一行代码

递归重命名文件-最好使用一行代码

我找到了这个答案我如何...但它根本不起作用——出于我不知道的原因,它没有重命名任何文件

在我开始搜索之前,我认为这即使对于新手企鹅来说也应该是件容易的事,但对我来说似乎并非如此。

例如,我根本无法告诉ls列出*.txt所有子文件夹中的所有内容,这让我很惊讶(没有 grep 或类似的东西)。
然后我找到findfind . -name name_1.txt列出了文件,但是

for f in $(find . -name name_1.txt) ; do echo "$f" ; done

用空格作为分隔符来分割整个文件路径,因此无法将该输出传递给某些命令,例如mvrename

我想问一下上面的命令有什么问题,如果可能的话,一些漂亮的单行命令,以便我可以递归重命名name_1.txtname_2.txt

答案1

find . -name '*.txt' -print0 | xargs -0 -n1 bash -c 'mv "$0" "${0/oldname/newname}"'

显然,该重命名模式只是一个简单的示例,但请注意,它将编辑整个路径,而不仅仅是文件名。

答案2

mmv 命令将通过一个相当简单的调用完成此操作:

mmv“;name_1.txt”“#1name_2.txt”

“;”通配符在替换文件名中重复使用,因为“#1”也匹配子目录。

如果您需要更复杂的示例,您应该查看手册页。

答案3

正如@ams 指出的那样,许多递归替换解决方案要求您使用整个路径,而不仅仅是文件名。

我使用find-execdir操作来解决这个问题。如果使用-execdir而不是-exec,则指定的命令将从包含匹配文件的子目录中运行。因此,rename它不会将整个路径传递给 ,而是只传递./filename。这使得编写替换命令变得容易得多。

find /the/path -type f \
               -name '*_one.txt' \
               -execdir rename 's/\.\/(.+)_one\.txt$/$1_two.txt/' {} \;

详细地:

  • -type f表示仅查找文件,而不查找目录
  • -name '*_one.txt'意味着只匹配以 _one.txt 结尾的文件名
  • 在这个答案中,我使用rename命令而不是 mv。rename 使用 Perl 正则表达式来重命名每个文件。
  • -type和后面的反斜杠-name是 bash 的行继续符。我使用它们来使此示例更具可读性,但实际上并不需要它们。
  • 但是,行尾的反斜杠-execdir是必需的。它用于省略分号,从而终止 运行的命令-execdir。真有趣!

正则表达式的解释:

  • s/正则表达式的开始
  • \.\/匹配 -execdir 传入的前导 ./。使用 \ 转义 . 和 / 元字符
  • (.+)匹配文件名的开头。括号捕获匹配项以供以后使用
  • _one\.txt匹配“_one.txt”,转义点元字符
  • $将匹配项锚定在字符串的末尾
  • /标记正则表达式“匹配”部分的结束以及“替换”部分的开始
  • $1引用现有文件名,因为我们用括号将其捕获。如果您在“匹配”部分中使用多组括号,则可以在此处使用 $2、$3 等引用它们。
  • _two.txt新文件名将以“_two.txt”结尾。此处“替换”部分无需转义点元字符
  • /正则表达式的结束

tree --charset=ascii

|-- a_one.txt
|-- b_one.txt
|-- Not_this.txt
`-- dir1
    `-- c_one.txt

tree --charset=ascii

|-- a_two.txt
|-- b_two.txt
|-- Not_this.txt
`-- dir1
    `-- c_two.txt

提示:rename-n 选项很有用。它会进行试运行并向您显示将更改哪些名称,但不会进行任何更改。

答案4

您可以探索众多可用的选择:

`$ apt-cache search rename | grep -i rename` 

相关内容