![递归重命名文件-最好使用一行代码](https://linux22.com/image/1093944/%E9%80%92%E5%BD%92%E9%87%8D%E5%91%BD%E5%90%8D%E6%96%87%E4%BB%B6-%E6%9C%80%E5%A5%BD%E4%BD%BF%E7%94%A8%E4%B8%80%E8%A1%8C%E4%BB%A3%E7%A0%81.png)
我找到了这个答案我如何...但它根本不起作用——出于我不知道的原因,它没有重命名任何文件
在我开始搜索之前,我认为这即使对于新手企鹅来说也应该是件容易的事,但对我来说似乎并非如此。
例如,我根本无法告诉ls
列出*.txt
所有子文件夹中的所有内容,这让我很惊讶(没有 grep 或类似的东西)。
然后我找到find
并find . -name name_1.txt
列出了文件,但是
for f in $(find . -name name_1.txt) ; do echo "$f" ; done
用空格作为分隔符来分割整个文件路径,因此无法将该输出传递给某些命令,例如mv
或rename
我想问一下上面的命令有什么问题,如果可能的话,一些漂亮的单行命令,以便我可以递归重命名name_1.txt
为name_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`