按类型查找文件并根据其父目录重命名它们

时间:2015-07-22 03:06:51

标签: shell unix find mv

因此,我尽可能地通过互联网尽力寻找能够帮助我解决我目前遇到的问题的事情。

例如,我有一个包含许多目录的文件,在这些目录中包含文件和图像。

我的目标是将这些文件重命名为基于其父文件夹,例如:

/主要/次要/文件

因为我的所有文件都已经命名,我希望能够将我的图像重命名为secondary0001.jpg secondary0002.jpg等等。

我一直在寻找并尝试使用各种方法来创建工作脚本。

目前我觉得这可能是我迄今为止的最大努力。

find $2 -type f -iname IMG_[0-9][0-9][0-9][0-9].jpg -exec mv -n {}$dirname {}.jpg\; 

$ 2包含我整个文件夹的文件夹,因此$ 2等同于Alpha / Primary / Secondary / file

非常感谢任何帮助,谢谢。

1 个答案:

答案 0 :(得分:0)

假设您的图片文件名不包含空格,而且您的文件夹名称不包含空格(因此,不需要极端的滑稽动作来处理极其笨拙的文件名),那么你可以考虑:

find "$directory" -type f -iname 'IMG_[0-9][0-9][0-9][0-9].jpg' -print |
while read file
do
    base=$(basename "$file")
    dir=$(dirname "$file")
    bdir=$(basename "$dir")
    suffix=$(echo "$base" | sed 's/^[Ii][Mm][Gg]_//')
    mv "$file" "$dir/$bdir$suffix"
done

我没有说有效率的事情。由于您没有使用Bash或Ksh对此进行标记,因此我没有假设他们的任何设施进行变量编辑。除了使用$(…)代替反向标记`…`-iname选项到find之外,这基本上适用于从Bourne shell派生的任何shell。过去20年左右。

如果您决定在目录或文件名中需要空格等,则需要查看代码。它可能最安全(因为它使用"$file"等变量引用的双引号,但是如果文件名或目录名可以包含换行符,则需要非常担心。

  

使用您的方法我现在已经找到了重命名这些文件的方法。但是,当我根据他们的目录重命名它们时,我会在每个文件上进行写操作并丢失许多文件。有没有办法避免这种情况,例如在文件名末尾添加数字?

  1. 通过在echo前放置一个mv进行测试,这样您就知道会发生什么,而不会实际发生。
  2. 我认为您必须修改代码或者与合理推断的情况略有不同。下面是一个示例,其中包含一个全新的垃圾目录层次结构中的一组空文件。每个目录的输入名称是唯一的;每个目录的输出名称是唯一的;除非已经存在使用目录中存在的修订命名方案的文件,否则脚本无法生成冲突并丢失数据。即使您将文件向上移动一级,名称也应该是唯一的,因为子目录首先是唯一的。
  3. 示例运行:

    $ mkdir junk
    $ cd junk
    $ for dir in primary secondary tertiary
    > do (mkdir $dir; cd $dir; touch $(seq -f 'IMG_%04.0f.jpg' 1 10))
    > done
    $ ls
    primary   secondary tertiary
    $ ls *
    primary:
    IMG_0001.jpg IMG_0002.jpg IMG_0003.jpg IMG_0004.jpg IMG_0005.jpg IMG_0006.jpg IMG_0007.jpg IMG_0008.jpg IMG_0009.jpg IMG_0010.jpg
    
    secondary:
    IMG_0001.jpg IMG_0002.jpg IMG_0003.jpg IMG_0004.jpg IMG_0005.jpg IMG_0006.jpg IMG_0007.jpg IMG_0008.jpg IMG_0009.jpg IMG_0010.jpg
    
    tertiary:
    IMG_0001.jpg IMG_0002.jpg IMG_0003.jpg IMG_0004.jpg IMG_0005.jpg IMG_0006.jpg IMG_0007.jpg IMG_0008.jpg IMG_0009.jpg IMG_0010.jpg
    $ directory=.
    $ find "$directory" -type f -iname 'IMG_[0-9][0-9][0-9][0-9].jpg' -print |
    > while read file
    > do
    >     base=$(basename "$file")
    >     dir=$(dirname "$file")
    >     bdir=$(basename "$dir")
    >     suffix=$(echo "$base" | sed 's/^[Ii][Mm][Gg]_//')
    >     mv "$file" "$dir/$bdir$suffix"
    > done
    $ ls
    primary   secondary tertiary
    $ ls *
    primary:
    primary0001.jpg primary0003.jpg primary0005.jpg primary0007.jpg primary0009.jpg
    primary0002.jpg primary0004.jpg primary0006.jpg primary0008.jpg primary0010.jpg
    
    secondary:
    secondary0001.jpg secondary0003.jpg secondary0005.jpg secondary0007.jpg secondary0009.jpg
    secondary0002.jpg secondary0004.jpg secondary0006.jpg secondary0008.jpg secondary0010.jpg
    
    tertiary:
    tertiary0001.jpg tertiary0003.jpg tertiary0005.jpg tertiary0007.jpg tertiary0009.jpg
    tertiary0002.jpg tertiary0004.jpg tertiary0006.jpg tertiary0008.jpg tertiary0010.jpg
    $
    

    当我在每个目录中创建1000个文件并计时移动时,重命名3000个文件需要46秒(在Mac OS X 10.10.4上使用硬盘和无SSD运行)。这比我预期的要长一点。

    如下所示修改脚本会将每个目录1000个文件的运行时间更改为8秒(从46开始),速度提高约5个。这值得改进,但仍然感觉脚本不是运行速度与现代Linux一样快 - 但这可能是古代机器,硬盘,HTFS文件系统和Mac OS X开销的组合(窗口的标题栏会在脚本运行时更改当前运行的命令名称,例如)。

    directory='.'
    time find "$directory" -type f -iname 'IMG_[0-9][0-9][0-9][0-9].jpg' -print |
    while read file
    do
        #base=$(basename "$file")
        base=${file##*/}
        #dir=$(dirname "$file")
        dir=${file%/*}
        #bdir=$(basename "$dir")
        bdir=${dir#*/}
        #suffix=$(echo "$base" | sed 's/^[Ii][Mm][Gg]_//')
        suffix=${base/[Ii][Mm][Gg]_/}
        mv "$file" "$dir/$bdir$suffix"
    done
    

    为了进一步改进,我将转到Perl并让它将重命名操作作为系统调用而不是调用单独的程序。这样可以减少更多的进程开销(在修订后的脚本中仍然有3000个mv命令,而Perl或等效的只有一个进程用于整个移动)。

    请注意,参数替换有效,因为名称被约束为表现良好(每个名称中至少有一个斜杠;根目录未命名等)。由basenamedirname命令处理的边缘情况不由参数替换处理。对推广要谨慎。