如何从命令行递归更改多个文件的扩展名?
我有很多扩展名为.abc
文件,并希望将它们更改为.edefg
如何从命令行执行此操作?
我有一个包含许多子文件夹的根文件夹,因此解决方案应该递归工作。
便携式方式(适用于任何符合POSIX标准的系统):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
在bash4中,您可以使用globstar来获取递归globs(**):
shopt -s globstar for file in /the/path/**/*.abc; do mv "$file" "${file%.abc}.edefg" done
Ubuntu中的(perl) rename
命令可以使用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/' {} +
另见http://mywiki.wooledge.org/BashFAQ/030
如果所有文件都在同一文件夹中,这将执行所需的任务
rename 's/.abc$/.edefg/' *.abc
要递归重命名文件,请使用以下命令:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
递归重命名的一个问题是,无论使用何种方法来定位文件,它都会传递整个路径进行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结尾的文件名 -
-type
和-name
之后的反斜杠是bash行继续符。 我用它们来使这个例子更具可读性,但在实践中并不需要它们。 - 但是,
-execdir
行末尾的反斜杠是必需的。 它是esacpe分号,它终止由-execdir
运行的命令。 有趣!
正则表达式的解释:
-
s/
正则表达式的开头 -
\.\/
匹配前导./那个-execdir传入。使用\来逃避。 和/元字符 -
(.+)
匹配文件名。 括号捕获匹配以供以后使用 -
\.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
‘s -n选项很有用。 它会干运行并显示它将改变的名称,但不会进行任何更改。
另一种便携方式:
find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
# Rename all *.txt to *.text for f in *.txt; do mv -- "$f" "${f%.txt}.text" done
另请参阅有关为何不解析ls
的条目。
编辑:如果你必须使用basename,你的语法将是:
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
这是一个简短的oneliner:
for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done
只需扫描当前目录,获取所有.3gp文件,然后将(使用mv)重命名为ren-name_of_file.mp4
我找到了一种实现这一目标的简单方法。 要将许多文件的扩展名从jpg更改为pdf,请使用:
for file in /path/to; do mv $file $(basename -s jpg $file)pdf ; done
我将使用同名 包中的 mmv命令 :
mmv ';*.abc' '#1#2.edefg'
的;
匹配零或更多*/
并且对应于替换中的#1
。 *
对应于#2
。 非递归版本将是
mmv '*.abc' '#1.edefg'