如何从命令行递归更改多个文件的扩展名?

我有很多扩展名为.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'