在Unix中重命名多个文件

目录中有多个文件以fgh开头,例如:

fghfilea fghfileb fghfilec 

我想重命名所有的开始于前缀jkl。 有没有一个单一的命令来做到这一点,而不是单独重命名每个文件?

有几种方法,但使用rename可能是最简单的。

使用一个版本的rename

 rename 's/^fgh/jkl/' fgh* 

使用另一个版本的rename (与Judy2K的答案相同):

 rename fgh jkl fgh* 

你应该检查你的平台的手册页,看看上面哪个适用。

这是如何sedmv可以一起使用做重命名:

 for f in fgh*; do mv "$f" $(echo "$f" | sed 's/^fgh/jkl/g'); done 

根据下面的注释,如果文件名中有空格,则引号可能需要包围返回名称的子函数以将文件移动到:

 for f in fgh*; do mv "$f" "$(echo $f | sed 's/^fgh/jkl/g')"; done 

重命名可能不在每个系统中。 所以如果你没有它,在bash shell中使用shell这个例子

 for f in fgh*; do mv "$f" "${f/fgh/xxx}";done 

使用mmv :

 mmv "fgh*" "jkl#1" 

有很多方法可以做到这一点(不是所有的方法都可以在所有的unixy系统上运行):

  • ls | cut -c4- | xargs -I§ mv fgh§ jkl§

    §可以被你方便的任何东西取代。 你可以用find -exec来做到这一点,但是在很多系统上的performance会有微妙的差异,所以我通常会避免这种情况

  • for f in fgh*; do mv "$f" "${f/fgh/jkl}";done

    粗俗但有效的,因为他们说

  • rename 's/^fgh/jkl/' fgh*

    真的很漂亮,但重命名不存在于BSD,这是最常见的Unix系统afaik。

  • rename fgh jkl fgh*

  • ls | perl -ne 'chomp; next unless -e; $o = $_; s/fgh/jkl/; next if -e; rename $o, $_';

    如果你坚持使用Perl,但是你的系统没有重命名,你可以使用这个怪物。

其中的一些有点复杂,列表还远远没有完成,但是你会在这里find几乎所有的Unix系统。

 rename fgh jkl fgh* 

使用findxargssed

 find . -name "fgh*" -type f -print0 | xargs -0 -I {} sh -c 'mv "{}" "$(dirname "{}")/`echo $(basename "{}") | sed 's/^fgh/jkl/g'`"' 

它比@ nik的解决scheme更复杂,但它允许recursion地重命名文件。 例如,结构,

 . ├── fghdir │  ├── fdhfilea │  └── fghfilea ├── fghfile\ e ├── fghfilea ├── fghfileb ├── fghfilec └── other ├── fghfile\ e ├── fghfilea ├── fghfileb └── fghfilec 

会变成这个,

 . ├── fghdir │  ├── fdhfilea │  └── jklfilea ├── jklfile\ e ├── jklfilea ├── jklfileb ├── jklfilec └── other ├── jklfile\ e ├── jklfilea ├── jklfileb └── jklfilec 

使xargs工作的关键是从xargs调用shell 。

要安装Perl 重命名脚本:

 sudo cpan install File::Rename 

Stephan202的回答中提到了两个重命名 。 基于Debian的发行版有Perl重命名 。 Redhat / rpm发行版有C重命名 。
OS X没有默认安装(至less在10.8),Windows / Cygwin也没有。

在Solaris上,您可以尝试:

 for file in `find ./ -name "*TextForRename*"`; do mv -f "$file" "${file/TextForRename/NewText}" done 

我会build议使用我自己的脚本,它解决了这个问题。 它还可以select更改文件名的编码,并将组合变音符号转换为预合成字符,这是我从我的Mac中复制文件时总是遇到的一个问题。

https://github.com/kugland/rename.pl/blob/master/rename.pl

 #!/bin/sh #replace all files ended witn .f77 to .f90 in a directory for filename in *.f77 do #echo $filename #b= echo $filename | cut -d. -f1 #echo $b mv ${filename} ${filename%.f77}.f90 #print $? done 

我的重命名群发文件的版本:

 for i in `ls`; do (echo mv $i $i) ; done > result.txt cat result.txt | sed -e "s#from_pattern#to_pattern#g” > result1.sh sh result1.sh 

这里有一种使用命令行Groovy的方法:

 groovy -e 'new File(".").eachFileMatch(~/fgh.*/) {it.renameTo(it.name.replaceFirst("fgh", "jkl"))}' 

使用重命名 (Windows,Mac和Linux友好):

 $ renamer --regex --find "^fgh" --replace "jkl" * 

使用StringSolver工具(窗口和Linux bash)的例子处理:

 filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea 

它首先计算一个基于示例的filter ,其中input是文件名和输出(ok和notok,任意string)。 如果filter有选项–auto或者在这个命令后被单独调用,它会创build一个文件夹ok和一个文件夹notok并分别向它们推送文件。

然后使用filter, mv命令是一个半自动移动 ,通过修饰符–auto 自动移动 。 使用以前的filter感谢 – filter,它发现从fghfileajklfilea的映射,然后将其应用于所有过滤的文件。


其他单线解决scheme

其他同样的方法(每一行是相同的),所以你可以select你最喜欢的方式做它。

 filter fghfilea ok fghreport ok notfghfile notok; mv --filter fghfilea jklfilea; mv filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter fghfilea "mv fghfilea jklfilea" # Even better, automatically infers the file name filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter "mv fghfilea jklfilea" 

多步骤的解决scheme

要仔细查看命令是否运行良好,可以键入以下内容:

 filter fghfilea ok filter fghfileb ok filter fghfileb notok 

当你确信filter是好的时候,执行第一步:

 mv fghfilea jklfilea 

如果你想testing,并使用以前的filter,请input:

 mv --test --filter 

如果转换不是你想要的(例如,即使是mv --explain你看到的东西是错误的),你可以键入mv --clear重新开始移动文件,或者添加更多的例子mv input1 input2其中input1和input2是其他的例子

当你有信心时,只需input

 mv --filter 

瞧! 所有的重命名都是使用filter完成的。

免责声明:我是这项作品的合着者,为学术目的。 可能很快就会出现一个bash的function。

(在我的Mac上)更容易在Ruby中执行此操作。 这里有两个例子:

 # for your fgh example. renames all files from "fgh..." to "jkl..." files = Dir['fgh*'] files.each do |f| f2 = f.gsub('fgh', 'jkl') system("mv #{f} #{f2}") end # renames all files in directory from "021roman.rb" to "021_roman.rb" files = Dir['*rb'].select {|f| f =~ /^[0-9]{3}[a-zA-Z]+/} files.each do |f| f1 = f.clone f2 = f.insert(3, '_') system("mv #{f1} #{f2}") end 

这对我使用正则expression式:

我想要这样的文件重命名:

 file0001.txt -> 1.txt ofile0002.txt -> 2.txt f_i_l_e0003.txt -> 3.txt 

usig [az | _] + 0 *([0-9] +。 )regexp其中([0-9] +。 )是在重命名命令上使用的组子string

 ls -1 | awk 'match($0, /[az|\_]+0*([0-9]+.*)/, arr) { print arr[0] " " arr[1] }'|xargs -l mv 

生产:

 mv file0001.txt 1.txt mv ofile0002.txt 2.txt mv f_i_l_e0003.txt 3.txt 

另一个例子:

 file001abc.txt -> abc1.txt ofile0002abcd.txt -> abcd2.txt ls -1 | awk 'match($0, /[az|\_]+0*([0-9]+.*)([az]+)/, arr) { print arr[0] " " arr[2] arr[1] }'|xargs -l mv 

生产:

  mv file001abc.txt abc1.txt mv ofile0002abcd.txt abcd2.txt 

警告,小心点。

我写了这个脚本来search所有.mkv文件recursion重命名find的文件为.avi。 你可以定制它到你的需求。 我已经添加了一些其他的东西,比如从文件path中获取文件目录,扩展名,文件名等等,只是在将来需要引用某些东西。

 find . -type f -name "*.mkv" | while read fp; do fd=$(dirname "${fp}"); fn=$(basename "${fp}"); ext="${fn##*.}"; f="${fn%.*}"; new_fp="${fd}/${f}.avi" mv -v "$fp" "$new_fp" done; 

在文件列表上运行sedexpression式的通用脚本(将sed解决scheme与rename解决scheme组合在一起):

 #!/bin/sh e=$1 shift for f in $*; do fNew=$(echo "$f" | sed "$e") mv "$f" "$fNew"; done 

通过传递脚本sedexpression式,然后任何文件列表来调用,就像rename的版本:

 script.sh 's/^fgh/jkl/' fgh* 

你也可以使用下面的脚本。 在terminal上运行非常容易

/ /一次重命名多个文件

 for file in FILE_NAME* do mv -i "${file}" "${file/FILE_NAME/RENAMED_FILE_NAME}" done 

例:-

 for file in hello* do mv -i "${file}" "${file/hello/JAISHREE}" done