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


2

我一直在命名文件,作为程序员在服务器命令行上工作的习惯,下划线“ _”而不是空格“ ” - 因为从命令行你必须转义空格 - 但这在命令行之外是不必要的很快就变老了。我想在切换到空间的同时保持一切均匀。

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

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


1
y是一个空间吗?可能想澄清一下。否则,您将获得以文件名中的空格打破的答案,如此经常。
slhck 2015年

Answers:


2

从“终端”,我想知道如何在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查找您所在的当前目录中的所有文件(包括子目录/文件),然后在文件名(_)中搜索下划线并根据需要将它们更改为spaces()。该脚本忽略“点文件”/“不可见文件”,如.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

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

./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调试的好处是你还可以确切地看到脚本核心中发生了什么。因此,虽然我编写了这个脚本以满足此问题中指定的确切需求,但如果它们出现,请随意尝试使其适应新的需求/想法。


1
对我来说,这会返回所有内容的错误:mv: rename ./Springhill/WPCS_Head_Start_Pre-School/WPCS_Head_Start_Pre-School_Office_Systems/.DS_Store to ./Springhill/WPCS Head Start Pre-School/WPCS Head Start Pre-School Office Systems/.DS Store: No such file or directory
Viziionary 2015年

@MediaWebDev您只提到名称中使用“_”的文件,而不是目录。所以我已经升级了简单的脚本,使其更加健壮。它现在将目录路径与文件名分开,sed仅对文件名运行逻辑,然后用于mv移动/重命名文件而不对目录执行操作。我还添加了逻辑来忽略不可见的文件.DS_Store; 基本上任何.以名称开头的文件。
JakeGould 2015年

哦,好的,抱歉缺乏清晰度。谢谢,很酷!
Viziionary 2015年

我建议添加-depthfind以便在更改其中的文件之前不要更改更高级别的目录(文件夹)名称。
roaima 2015年

@roaima问题和此脚本仅用于处理文件名,而不是目录。所以这不是一个真正的问题。目录永远不会受此脚本的影响。
JakeGould 2015年

0

在相关目录中时:

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

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


2
显示的替换表达式将删除下划线之间的任何子字符串,因此foo_bar_baz.txt将重命名foo baz.txt为例如。考虑${f//_/ }用空格替换所有下划线而不修改文件名。
zackse 2015年

1
我的意思是它改变目录中的所有文件名,就像在子目录中的文件一样。目录中的每个文件名及其内容都是递归的。
Viziionary 2015年

0

对于批处理/复杂重命名任务,请使用rename命令

例如, 在当前文件夹中的所有.txt文件 中用_替换空格

rename 's/ /_'  *.txt

以递归方式重命名所有文件

find /path/to/target -type f -exec rename 's/ /_/' '{}' \;

0

我可能会用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' ); 

-1

这个班轮怎么样?(我希望在这里粘贴我的命令不会搞砸空间)

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

我尝试时似乎工作。(准备好后你需要删除那个回声)

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


-2

有多个shell:

david_koontz @ Macbook:更多〜/ bin / rename

#!/bin/csh -f

if  ( $1 != "" && $2 != ""  ) then

    foreach file ( `ls *$1*` )
    setenv target  `echo $file | sed s/"$1"/"$2"/`
        if ( -f $file ) then
            echo renaming $file to $target
            mv $file $target
        endif
    end
else
    echo "usage: $0 src_pattern_match  dest_pattern_substitution"
    exit -1
endif
exit 0

对于递归重命名:

#!/bin/csh -f

    if  ( $1 != "" && $2 != ""  ) then

        # limit the depth search with -maxdepth:

        foreach file ( `find . -maxdepth 8 -iname \*$1\* -type f -exec echo \{\} \;`)
            setenv filehead $file:h
            setenv filetail $file:t
            setenv targettail `echo $filetail | sed s/"$1"/"$2"/`
            echo renaming $file $filehead/$targettail
            mv $file $filehead/$targettail
        end
    else
        "usage: $0 src_pattern_match  dest_pattern_substitution"
        exit -1;
    endif

exit 0;

对于recursive_rename,您可以使用可选的$ 3来传递最大深度或消除-maxdepth 8,这提供了递归深度限制。

您可以添加一个可以添加的选项,-imv可以使用和可选参数来启用交互式重命名。

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.