【问题标题】:Add prefix to all images (recursive)为所有图像添加前缀(递归)
【发布时间】:2011-09-02 15:58:11
【问题描述】:

我有一个包含 5000 多张图片的文件夹,所有图片都带有 JPG 扩展名。

我想要做的是递归地为所有图像添加“thumb_”前缀。

我发现了一个类似的问题:Rename Files and Directories (Add Prefix) 但我只想将前缀添加到具有 JPG 扩展名的文件中。

【问题讨论】:

标签: linux bash command-line-interface


【解决方案1】:

可能的解决方案之一:

find . -name '*.jpg' -printf "'%p' '%h/thumb_%f'\n" | xargs -n2  echo mv

原理:找到所有需要的文件,并为标准 mv 命令准备参数。

注意事项:

  • mv 的参数被 ' 包围,以允许文件名中包含空格。
  • 缺点是:这不适用于包含 ' 撇号本身的文件名,就像许多 mp3 文件一样。如果您需要移动更奇怪的文件名,请检查以下内容。
  • 上述命令用于空运行(仅显示带参数的 mv 命令)。对于实际工作,请删除伪装成 mvecho

任何文件名重命名。在外壳中,您需要一个分隔符。问题是,文件名(存储在 shell 变量中)通常可以包含分隔符本身,所以:

mv $file $newfile         #will fail, if the filename contains space, TAB or newline
mv "$file" "$newfile"     #will fail, if the any of the filenames contains "

正确的解决方案是:

  • 准备一个适当转义的文件名
  • 使用易于理解任何文件名的脚本语言

bash 中准备正确的转义是可能的,它的内部 printf%q 格式化指令 = print quoted。但是这个解决方案又长又无聊。

恕我直言,最简单的方法是使用 perl 和零填充 print0,如下所示。

find . -name \*.jpg -print0 | perl -MFile::Basename -0nle 'rename $_, dirname($_)."/thumb_".basename($_)'

以上使用 perl 的能力来混淆文件名并最终重命名文件。

【讨论】:

    【解决方案2】:

    当心带有空格的文件名(for ... in ... 表达式会跳过这些),并注意find . ... 的结果将始终以./ 开头(因此尝试给你像thumb_./file.JPG 这样的名称这不太正确)。

    因此,在所有情况下都可以做到这一点并非易事。我发现可以正常工作的表达式(带有空格、子目录等等)是:

    find . -iname \*.JPG -exec bash -c 'mv "$1" "`echo $1 | sed \"s/\(.*\)\//\1\/thumb/\"`"' -- '{}' \;
    

    即使这样也可能与某些名称(带引号)相冲突......

    【讨论】:

      【解决方案3】:

      您可以使用相同的答案,只需使用*.jpg,而不仅仅是*

      【讨论】:

        【解决方案4】:

        在 OS X 10.8.5 中,find 没有 -printf 选项。包含 rename 的端口似乎依赖于一个需要数小时才能安装的 WebkitGTK 开发包。

        这一行递归文件重命名脚本对我有用:

        find . -iname "*.jpg"  -print | while read name; do cur_dir=$(dirname "$name"); cur_file=$(basename "$name"); mv "$name" "$cur_dir/thumb_$cur_file"; done
        

        我实际上是用“admin_”前缀重命名 CakePHP 视图文件,以便将它们全部移动到管理部分。

        【讨论】:

        • 您可以随时安装findutils macport - 包含 gnu-find(命令:gfind)和-printf
        • 只是注意到我的每一行都有一个文件未找到错误,但它按承诺工作
        【解决方案5】:

        for file in *.JPG; do mv $file thumb_$file; done

        如果是当前目录下的多个目录级别:

        for file in $(find . -name '*.JPG'); do mv $file $(dirname $file)/thumb_$(basename $file); done


        证明:
        jcomeau@intrepid:/tmp$ mkdir test test/a test/a/b test/a/b/c
        jcomeau@intrepid:/tmp$ touch test/a/A.JPG test/a/b/B.JPG test/a/b/c/C.JPG
        jcomeau@intrepid:/tmp$ cd test
        jcomeau@intrepid:/tmp/test$ for file in $(find . -name '*.JPG'); do mv $file $(dirname $file)/thumb_$(basename $file); done
        jcomeau@intrepid:/tmp/test$ find .
        .
        ./a
        ./a/b
        ./a/b/thumb_B.JPG
        ./a/b/c
        ./a/b/c/thumb_C.JPG
        ./a/thumb_A.JPG
        jcomeau@intrepid:/tmp/test$
        

        【讨论】:

        • 如参考文献中所述。问题的答案,您需要考虑带空格的文件名。
        • @MadisonFord 如果您的文件具有 .jpg 而不是 .JPG 的扩展名,这将无法在正常的 linux 环境中运行。 Bash 通常区分大小写。 shopt -s nocaseglob 将关闭区分大小写。
        • @MadisonFord,文件名中的空格对您来说是个问题吗?你粘贴了哪个命令?
        【解决方案6】:

        为此使用rename

        rename 's/(\w{1})\.JPG$/thumb_$1\.JPG/' `find . -type f -name *.JPG`
        

        【讨论】:

          【解决方案7】:

          仅适用于当前文件夹中的jpg 文件

          for f in `ls *.jpg` ; do mv "$f" "PRE_$f" ; done
          

          【讨论】:

          • 我需要在所有文件夹中执行此操作(递归)我有 300 多个文件夹和 5000 多个图像。
          • 错了。几乎从不解析ls 的输出。尝试使用文件touch "a b c.jpg" 而不是for f in *.jpg 好多了。
          • 使用@jcomeau_ictx 的答案,移动文件时只需输入""
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-02-04
          • 2014-07-26
          • 2018-08-09
          • 2020-10-03
          • 2013-04-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多