作为一名在服务器命令行上工作的程序员,我一直习惯用下划线“ _
”而不是空格“ ”来命名文件 - 因为在命令行中你必须转义空格 - 但这在命令行之外是不必要的,而且很快就会过时。我想在切换到空格时保持一切统一。
在“终端”中,我想知道如何将 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_Store
via)-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
当脚本运行时,如果您想进行一个简单的“试运行”来查看脚本将对哪些文件执行操作,请将命令替换mv
为echo
如下形式:
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' );