在Unix中重命名多个文件
目录中有多个文件以fgh开头,例如:
fghfilea fghfileb fghfilec
我想重命名所有的开始于前缀jkl。 有没有一个单一的命令来做到这一点,而不是单独重命名每个文件?
有几种方法,但使用rename
可能是最简单的。
使用一个版本的rename
:
rename 's/^fgh/jkl/' fgh*
使用另一个版本的rename
(与Judy2K的答案相同):
rename fgh jkl fgh*
你应该检查你的平台的手册页,看看上面哪个适用。
这是如何sed
和mv
可以一起使用做重命名:
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*
使用find
, xargs
和sed
:
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中复制文件时总是遇到的一个问题。
#!/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,它发现从fghfilea
到jklfilea
的映射,然后将其应用于所有过滤的文件。
其他单线解决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;
在文件列表上运行sed
expression式的通用脚本(将sed
解决scheme与rename
解决scheme组合在一起):
#!/bin/sh e=$1 shift for f in $*; do fNew=$(echo "$f" | sed "$e") mv "$f" "$fNew"; done
通过传递脚本sed
expression式,然后任何文件列表来调用,就像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