Answers:
可移植的方式(可在任何POSIX兼容系统上使用):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
在bash4中,可以使用globstar获取递归glob(**):
shopt -s globstar
for file in /the/path/**/*.abc; do
mv "$file" "${file%.abc}.edefg"
done
rename
Ubuntu中的(perl)命令可以使用perl正则表达式语法重命名文件,您可以将其与globstar或组合使用find
:
# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)
# Best to process the files in chunks to avoid exceeding the maximum argument
# length. 100 at a time is probably good enough.
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done
# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +
${1%.abc}...
sh -c
将第一个参数分配给$ 0,并将所有其余参数分配给position参数。因此,_
是一个伪参数,而'{}'是的第一个位置参数sh -c
。
如果所有文件都在同一文件夹中,这将执行所需的任务
rename 's/.abc$/.edefg/' *.abc
要递归重命名文件,请使用以下命令:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abc
在现代版本的Bash中。
s
刚开始的时候一样,在那里我还可以使用其他选项。谢谢 !
递归重命名的一个问题是,无论您使用什么方法查找文件,它都会将整个路径传递给rename
,而不仅仅是文件名。这使得很难在嵌套文件夹中执行复杂的重命名。
我使用find
的-execdir
动作来解决此问题。如果使用-execdir
代替-exec
,则从包含匹配文件的子目录中运行指定的命令。因此,它不会传递整个路径rename
,而只会传递./filename
。这使得编写正则表达式变得容易得多。
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;
详细:
-type f
表示仅查找文件,不查找目录-name '*.abc'
表示仅匹配以.abc结尾的文件名'{}'
是占位符,用于标记将在其中-execdir
插入找到的路径的位置。必须使用单引号将其引起来,以便使用空格和外壳字符处理文件名。-type
和之后的反斜杠-name
是bash行连续字符。我使用它们使该示例更具可读性,但是如果将命令全部放在一行上,则不需要它们。-execdir
需要反斜杠。它是用来转义分号的地方,分号将终止运行的命令-execdir
。好玩!正则表达式的解释:
s/
正则表达式的开始\.\/
匹配-execdir传入的前导./。使用\来使。逸出。和/元字符(请注意:这部分取决于您的的版本find
。请参阅用户@apollo的评论)(.+)
匹配文件名。括号捕获了该匹配项以供以后使用\.abc
转义,匹配abc$
将匹配项锚定在字符串的末尾
/
标记正则表达式“匹配”部分的结尾,以及“替换”部分的开头
version1_
将此文本添加到每个文件名
$1
引用现有的文件名,因为我们用括号捕获了它。如果在“匹配”部分使用多组括号,则可以在此处使用$ 2,$ 3等引用它们。.abc
新文件名将以.abc结尾。无需在“替换”部分中转义点元字符/
正则表达式的结尾之前
tree --charset=ascii
|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
`-- nested_file.abc
后
tree --charset=ascii
|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
`-- version1_nested_file.abc
提示:rename
-n选项非常有用。它会进行试运行,并向您显示它将更改的名称,但不会进行任何更改。
--execdir
并没有领先,./
因此\.\/
可以省略正则表达式中的部分。可能是因为我在OSX上不是ubuntu
# Rename all *.txt to *.text
for f in *.txt; do
mv -- "$f" "${f%.txt}.text"
done
另请参阅有关为什么不应该分析的条目ls
。
编辑:如果必须使用基本名称,则语法为:
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files
这就是我所做的,并且按照我想要的方式工作。我使用了mv
命令。我有多个.3gp
文件,我想将它们全部重命名为.mp4
这是一个简短的清单:
for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done
它只需扫描当前目录,拾取所有.3gp文件,然后使用mv重命名为 ren-name_of_file.mp4
file.3gp
为file.3gp.mp4
,这可能不是大多数人想要的。
.3gp
或.mp4
用于说明目的这里只是。
basename "$i" .mp4
删除以前的扩展名而不是“ ren- $ i.mp4”。
重命名文件和目录 find -execdir | rename
如果您不只是使用后缀来重命名文件和目录,那么这是一个很好的模式:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find . -depth -execdir rename 's/findme/replaceme/' '{}' \;
与相比,真棒-execdir
选项cd
在执行rename
命令之前会对目录执行a 操作-exec
。
-depth
确保重命名首先在孩子上进行,然后在父母上进行,以防止丢失父目录的潜在问题。
-execdir
是必需的,因为重命名在非基本名称的输入路径中不能很好地发挥作用,例如,以下操作失败:
rename 's/findme/replaceme/g' acc/acc
在PATH
需要的黑客,因为-execdir
有一个很讨厌的缺点:find
极其固执己见,拒绝做任何事情-execdir
,如果您有任何相对路径在您的PATH
环境变量,例如./node_modules/.bin
,与失败:
find:相对路径'./node_modules/.bin'包含在PATH环境变量中,与find的-execdir操作结合使用时,它是不安全的。请从$ PATH中删除该条目
另请参阅:为什么对PATH中的目录使用'-execdir'操作不安全?
-execdir
是POSIX的GNU查找扩展。rename
基于Perl,来自rename
软件包。在Ubuntu 18.10中测试。
重命名提前解决方法
如果您的输入路径不是来自find
,或者您已经受够了相对路径的烦恼,我们可以使用一些Perl预行来安全地重命名目录,如下所示:
git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'
我还没有找到一个方便的模拟为-execdir
具有xargs
:https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686
的sort -r
要求,以确保文件有其各自的目录后,由于较长的路径都较短的具有相同前缀之后。