如何从命令行将特定目录的文件名中的所有“x”转换为“y”?

如何从命令行将特定目录的文件名中的所有“x”转换为“y”?

作为一名在服务器命令行上工作的程序员,我一直习惯用下划线“ _”而不是空格“ ”来命名文件 - 因为在命令行中你必须转义空格 - 但这在命令行之外是不必要的,而且很快就会过时。我想在切换到空格时保持一切统一。

在“终端”中,我想知道如何将 Mac OS X 上特定目录的文件名中的所有“x”转换为“y”?请注意,“x”表示任何内容,“y”只是一个空格。

我想以递归方式执行此操作,处理所有子目录,而不是一次只处理一个文件夹。

答案1

在“终端”中,我想知道如何将 Mac OS X 上特定目录的文件名中的所有“x”转换为“y”?请注意,“x”表示任何内容,“y”只是一个空格。

我想以递归方式执行此操作,处理所有子目录,而不是一次只处理一个文件夹。

调整一些基本sed@meatspace 所指的概念在他的评论中(位于这一页)并添加find我想出了这个脚本:

find . -type d -path '*/\.*' -prune -o -not -name '.*' -type f |\
  while read FULL_ITEM_PATH
  do
    FILE_DIRNAME=$(dirname "${FULL_ITEM_PATH}");
    FILE_BASENAME=$(basename "${FULL_ITEM_PATH}");
    mv "${FILE_DIRNAME}"/"${FILE_BASENAME}" "${FILE_DIRNAME}"/"$(echo $FILE_BASENAME | sed -e 's/_/ /g')";
  done

这将用于find查找当前目录中的所有文件(包括子目录/文件),然后搜索文件名中的下划线(_)并根据需要将其更改为空格()。脚本会忽略“点文件”/“不可见文件”(如.DS_Storevia)-prune -o -not -name '.*',然后核心逻辑仅对实际文件名起作用(而不是目录名),方法是将文件基名与目录名分开。

我在我的 Mac OS X 10.9.5(Mavericks)机器上创建了一个测试目录树,其中的文件_名称中包含下划线(),其中一些嵌套在子目录中,如下所示:

./foo_bar
./foo_bar_two
./foo_bar_two_three
./foo_bar_two_three_bleagh.txt
./nested/foo_bar
./nested/foo_bar_two
./nested/foo_bar_two_three
./nested/foo_bar_two_three_bleagh.txt
./nested_foo/foo_bar
./nested_foo/foo_bar_two
./nested_foo/foo_bar_two_three
./nested_foo/foo_bar_two_three_bleagh.txt

然后我运行该脚本,它们都自动更改为使用空格(),如下所示:

./foo bar
./foo bar two
./foo bar two three
./foo bar two three bleagh.txt
./nested/foo bar
./nested/foo bar two
./nested/foo bar two three
./nested/foo bar two three bleagh.txt
./nested_foo/foo bar
./nested_foo/foo bar two
./nested_foo/foo bar two three
./nested_foo/foo bar two three bleagh.txt

当脚本运行时,如果您想进行一个简单的“试运行”来查看脚本将对哪些文件执行操作,请将命令替换mvecho如下形式:

find . -type d -path '*/\.*' -prune -o -not -name '.*' -type f |\
  while read FULL_ITEM_PATH
  do
    FILE_DIRNAME=$(dirname "${FULL_ITEM_PATH}");
    FILE_BASENAME=$(basename "${FULL_ITEM_PATH}");
    echo "${FILE_DIRNAME}"/"${FILE_BASENAME}" "${FILE_DIRNAME}"/"$(echo $FILE_BASENAME | sed -e 's/_/ /g')";
  done

使用调试的好处echo是,您还可以准确地看到脚本核心中发生的事情。因此,尽管我已经编写了此脚本以满足此问题中指定的确切需求,但如果出现新的需求/想法,请随意尝试它以使其适应。

答案2

当在相关目录中时:

for f in in *; do echo mv "$f" "${f/_*_/ }"; done

这将列出要进行的更改 -echo当您希望它真正执行重命名时,请删除。像所有 *nix 一样,有无数种方法可以做到这一点,但上面的内容非常清楚。如果您经常执行此任务,请考虑将其保存bin为脚本。

答案3

这行代码怎么样?(我希望粘贴这里的命令不会弄乱空格)

for f in `find . -type f -name '*_*'` ; do echo mv "$f" "${f//_/ }"; done        

我试了一下,似乎有效。(准备就绪后,您需要删除该回声)

不执行任何目录重命名。我想这就是你想要的?递归似乎工作正常。还可以正确处理多个下划线。

答案4

我可能会使用 Perl 来做这件事。

#!/usr/bin/perl

use strict;
use warnings;

use File::Find;

sub rename_files {
   #skip directories
   return if -d $File::Find::name;

   my $newname = $File::Find::name;
   #turn underscores into space. 
      $newname =~ s/_/ /g; 
   rename $File::Find::name, $newname;
}

find ( \&rename_files, 'path_to_change' ); 

相关内容