使用mv重命名多个文件以更改扩展名


27

我想重命名文件以更改其扩展名,以期有效地完成

mv *.txt *.tsv

但是当这样做时,我得到:

* .tsv不是目录

我觉得Google的前10个热门节目mv应该像这样工作有点奇怪。


您应该说明如何精确重命名这些文件。
Totor

1
好吧,我的文件扩展名为* .gappedPeak,并希望将其重命名为* .bed。它们都在同一个目录中,这应该非常简单,但是我需要一个完整的for循环才能成功
Sander Van der Zeeuw 2015年

我认为您在Google上找到的内容适用于MSDOS。
tiktak

@devnull的替代解决方案确实很有帮助
lucasvw

Answers:


22

发出命令时:

mv *.txt *.tsv

如果有任何匹配的文件(包括目录),那么外壳程序(假设bash)将扩展通配符。文件列表将传递到该程序,在此处。如果未找到匹配项,则将传递未扩展的版本。mv

再说一次:shell扩展了模式,而不是程序。


大量示例也许是最好的方法,所以我们开始:

范例1:

$ ls
file1.txt file2.txt

$ mv *.txt *.tsv

现在,在线上发生的事情mv外壳扩展*.txt到匹配的文件。由于没有*.tsv没有更改的文件。

使用两个特殊参数mv调用该命令:

  • argc:参数数量,包括程序。
  • argv:一组参数,包括程序作为第一个条目。

在上面的示例中将是:

 argc = 4
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = file2.txt
 argv[3] = *.tsv

mv看的程序检查,如果最后一个参数*.tsv,是一个目录。并非如此,该程序无法继续运行,因为它并非旨在连接文件。(通常将所有文件移动到一个。)也不要一味创建目录。

结果,它中止并报告错误:

mv: target ‘*.tsv’ is not a directory

范例2:

现在,如果您改为说:

$ mv *1.txt *.tsv

使用以下mv命令执行命令:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = *.tsv

现在,再次mv检查是否*.tsv存在。由于没有将文件file1.txt移动到*.tsv。也就是说:文件将*.tsv使用星号和全部重命名为。

$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’

$ ls
file2.txt *.tsv

范例3:

如果您改为说:

$ mkdir *.tsv
$ mv *.txt *.tsv

使用以下mv命令执行命令:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[1] = file2.txt
 argv[2] = *.tsv

由于*.tsv现在是目录,因此文件最终被移动到该目录。


现在:使用诸如some_command *.tsv实际意图保留通配符之类的命令时,应始终引用通配符。通过引用可以防止通配符在应该存在任何匹配项时被扩展。例如说mkdir "*.tsv"

范例4:

如果您这样做,则可以进一步查看该扩展:

$ ls
file1.txt file2.txt

$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists

范例5:

现在:该mv命令可以并且确实可以处理多个文件。但是,如果有两个以上,则最后一个必须是目标目录。(可选地-t TARGET_DIR,至少对于GNU mv,您可以使用该选项。)

这样就可以了:

$ ls -F
b1.tsv  b2.tsv  f1.txt  f2.txt  f3.txt  foo/

$ mv *.txt *.tsv foo

这里mv将被称为:

 argc = 7
 argv[0] = mv
 argv[1] = b1.tsv
 argv[2] = b2.tsv
 argv[3] = f1.txt
 argv[4] = f2.txt
 argv[5] = f3.txt
 argv[6] = foo

所有文件都存放在目录中foo


至于你的链接。您提供了一个(在评论中),mv根本没有提到,但是rename。如果您有更多链接,则可以共享。以及您声称要表达的手册页。


30

我知道这不能解决您的问题,但是如果您正在寻找另一种方法来命名文件,而不是使用替代方法循环,​​为什么不使用find?我已经多次使用此命令将大型目录中的文件扩展名替换为其中的数十万个文件。这可以在任何POSIX兼容系统上工作:

find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;

命令分解:

  1. ' .'=>搜索路径从当前目录开始,并以'标记。'

  2. -name=>设置查找匹配名称(在这种情况下,所有以结尾的文件 .gappedPeak

  3. -exec =>在每次比赛中执行以下命令

  4. sh -c =>'exec'为每个匹配创建一个独立的shell环境

  5. mv "$1" "${1%.gappedPeak}.bed"=> mv第一个变量(用$ 1表示)是当前文件名,变为新名称。在这里,我进行子字符串匹配并删除;因此,再次使用第一个var,$ 1,并使用从字符串中%删除.gappedPeak。该.bed在刚刚结束串接剩余的变量,它现在只是,与,创建新的文件名。test#.bedtest#.bed

  6. 下划线是$ 0的占位符

  7. {}是由每个(替换*.gappedPeak由所发现的)的文件名find的命令,并变为$ 1sh命令。

  8. \;标记-exec命令的结尾。您也可以使用';'";"

例:

[user@before]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.gappedPeak

[user@after]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.bed

您能否通过命令描述每个部分的功能?
user1717828 2015年

对此感到抱歉,我更新了我的帖子。希望能有所帮助。
devnull

1
很好,谢谢!有了bash指南和您的解释,我就能掌握一切。
user1717828 2015年

没问题。很高兴能帮到您。
devnull

奇迹般有效。这是file.abc-> blub.xyz在多个子目录中的另一个简化示例:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
Mahn 2016年

9

mv *.txt *.tsv不起作用;mv一次只能重命名一个文件。您可能误解了说明,或者它们是错误的。

mmvrename可以一次重命名多个文件。但是rename周围有两个版本,它们的名称不同。这里应该有很多问题。


1
cyberciti.biz/tips/…google上的第一个热门是说mv也应该工作,这就是为什么我觉得它很奇怪
Sander Van der Zeeuw 2015年

3
@SanderVanderZeeuw我不知道你在那里读了什么。这些示例使用rename,而不是mv
Hauke Laging

1
抱歉,我粘贴了错误的HTML。这是一个udemy.com/blog/rename-a-file-in-linux
Sander Van der Zeeuw

3
@SanderVanderZeeuw令人尴尬。这些人提供课程吗?不幸的是,我看不到有联系的可能性。您可以轻松地检查这是否有效。但是mv *.txt *.tsv mv(通常)看不到*.txt*.tsv只能看到shell扩展的文件名。这些通配符扩展为的文件数将是“随机”的。唯一可行的方法是,存在一个文件名*.txt,该文件名应重命名为(字面意义)*.tsv(不得引用该bash选项,nullglob不得设置)。
Hauke Laging 2015年

1
或更糟。如果一个人有一个名为如文件foo.txt一个名为baz.tsvmv *.txt *.tsv将覆盖现有.tsv文件...
Runium

4

例如,如果在运行命令时目录中有asd.txtqwe.txt文件mv *.txt *.tsv,它将尝试将这两个文件移动到名为的目录中*.tsv。因为没有这样的目录,所以会给出错误。


谢谢,这部分澄清了。仍然令我感到奇怪的是,我看到如此多的手册页,其中声称mv应该可以在多个页面上运行。
Sander Van der Zeeuw 2015年

2

rename(1)

rename是perl的制造商Larry Wall的perl脚本。它需要一个Perl正则表达式并使用文件名进行操作。

rename 's/\.txt$/.tsv/' *.txt

安装

Debian / Ubuntu

如果您需要rename在Debian / Ubuntu 上安装,可以执行

sudo apt install rename

0

要考虑的另一种选择是使用:

cp -p *.txt *.tsv
rm -f *.txt
  • 第一行将所有*.txt文件复制到,*.tsv同时使用-p标志保留其属性。
  • 第二行删除所有带有模式的文件 *.txt
  • 此方法需要您有足够的磁盘空间来临时保存源文件和目标文件
  • 此方法比mv仅更改/ directory / filename而不实际移动文件的速度慢,除非它们位于不同的分区上。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.