如何找出仅扩展名不同的文件

5
假设我有多个随机的`.txt`文件,并且在同一个目录下,我有几乎相同名称的文件,如`filename.sql`和`filename.txt`。如何找到这些`.sql`及其对应的`.txt`文件,而不选择任何其他`.txt`文件?(意图是将它们移动到单独的文件夹中。这里保证了相关`.sql`和`.txt`文件之间存在1:1的关系,因此我不担心移动最初提到的任何随机`.txt`文件之一。)
2个回答

3
非常简单:
$ mv `ls *.sql|sed s/.sql$/.txt/g` dir

为了看到并理解它是如何工作的,即shell在执行mv之前如何扩展行,请以echo开头:
$ ls
a.sql b.sql a.txt b.txt c.txt
$ echo mv `ls *.sql|sed s/.sql/.txt/g` dir
mv a.txt b.txt dir

如果文件名中含有空格(通常在Unix中不是一个好主意,但有时会发生)或目录中有数百个文件,则需要更加“强大”的方法:

$ for f in *.sql; do mv "$(echo $f|sed s/.sql$/txt/)" dir; done

.sql文件与相应的.txt文件一起移动:

$ for f in *.sql; do mv "$f" "$(echo $f|sed s/.sql$/txt/)" dir; done

2
选择当前目录中的所有 .sql 文件,将它们名称中的 .sql 替换为 .txt 并将文件移动到 dir 目录。 - piokuc
1
为了更加健壮(即仅在文件名末尾将.sql替换为.txt),请使用s/.sql$/.txt/。由于来自ls的每个文件名都将位于其自己的行上,因此替换末尾的g是不必要的。 - Lorkenpeist
2
@verbsintransit sed 不会修改文件名,它只会修改 ls 提供的输出。因此,当 ls 打印 foo.sql 时,sed 会使其打印 foo.txt,以便 mv 可以移动正确的文件。 - Lorkenpeist
1
不,你没有理解。在该行前加上 echo 命令,观察 shell 如何展开它。 - piokuc
1
好的。我感觉很聪明。我的意思是,用一个命令来完成这件事在教学上会很好,但在我目前的情况下并不是必要的。 - verbsintransit
显示剩余7条评论

2

piokuc的答案非常好,但如果你遇到参数列表太长的错误 (如果你一次移动很多文件时会发生),这个方法也可以解决问题:

ls *.sql | sed s/.sql/.txt/g | xargs -I% mv % /path/to/new/directory

解释:

  1. 列出所有以.sql扩展名结尾的文件名。
  2. 在文件名列表中用.txt替换.sql(这不会重命名文件,只是对管道输入进行操作)。
  3. xargs

    • xargs是一个运行其他程序的程序。我们将通过它来运行mv(移动文件)命令。
    • -I选项告诉xargs为每个由sed传递的单个文件名运行mv命令。
    • %是指实际对象/文件名被传递给xargs,因此在每次迭代中,这将是一个替换后的文件名之一。
    • 请注意,有2个%:一个附加在-I旁边,它告诉xargs使用和号字符作为文件名的标记。第二次出现在mv中,其中实际(并且现在已更改)的文件名被替换为令牌。

    基本上,xargs的意思是,“对于输入的每个文件名,运行mv NEW_FILE_NAME.txt /path/to/new/directory。”


+1 是的,我也在考虑添加这样的注释。同样地,可以像这样做:for f in *.sql; do mv echo $f|sed s/.sql$/txt/ dir; done - piokuc
无法在评论中正确显示格式,将复制到我的回答中 - piokuc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接