【问题标题】:Is there a grep or shell script that uses a regex to change filenames?是否有使用正则表达式更改文件名的 grep 或 shell 脚本?
【发布时间】:2009-10-31 09:09:25
【问题描述】:

如何递归地将xxx-xxx_[a-zA-Z]+_\d+_(\d+)\.jpg 更改为$1.jpg?

【问题讨论】:

    标签: regex linux bash shell


    【解决方案1】:
    #!/bin/bash
    
    find . | while read OLD; do
        NEW="`sed -E 's/(.*\/)?xxx-xxx_[a-zA-Z]+_[0-9]+_([0-9]+)\.jpg/\1\2.jpg/' <<< "$OLD"`"
        [ "$OLD" != "$NEW" ] && mv "$OLD" "$NEW"
    done
    

    对此的一些说明:

    • 将find 的输出连接到while read 循环是一次读取find 输出的一种简洁方式。这很好,因为它会在 find 找到它们时处理文件,而不必先建立整个文件列表,如果你在反引号中使用 `find` 就会发生这种情况。

    • 如果您有大量不相关的文件,那么您可以按照 soulmerge 的回答将 -regex 选项添加到 find,但如果没有,则不需要。

    • 我修改了您的正则表达式以允许在前面使用目录名称。他们将在\1 中被捕获,您要查找的号码将是\2。

    • sed &lt;&lt;&lt; "$OLD" 和echo "$OLD" | sed 是一样的,只是更花哨一点……

    • [ "$OLD" != "$NEW" ] &amp;&amp; mv 和if [ "$OLD" != "$NEW" ]; then mv; fi 是一样的,只是更高级一点……

    编辑:为了兼容性,将\d 更改为[0-9]。我在我的 Mac 上测试了它,它可以工作。以下是我设置的测试目录中发生的情况:

    mv ./1/xxx-xxx_ERR_19_02.jpg ./1/02.jpg
    mv ./2/xxx-xxx_BLAH_266_14.jpg ./2/14.jpg
    mv ./xxx-xxx_ERR_19_01.jpg ./01.jpg
    

    【讨论】:

    • find 是递归的,所以应该这样!
    • 使用 find 的 -name 和 -type f 选项来搜索文件名。
    • 你确定它有效吗,我刚刚得到了一个帮助信息,用于快速向下滚动屏幕?
    • 使用这种技术处理带有空格或换行符的文件名很棘手(最好的情况是棘手的;最坏的情况是不可能的)。
    【解决方案2】:

    在SuperUser.com 上查看此问题的各种答案。它正在处理相同的问题(使用正则表达式重命名文件)。 [我花了很长时间才在 StackOverflow 上找到它——因为它不在 SO 上,而是在 SU 上! :( ]

    【讨论】:

      【解决方案3】:

      我正在为您提供可以处理任何文件名的更详细的版本(即使是那些在带有空格污染名称的文件夹中的文件):

      # file rename.sh
      old="$1"
      new="$(dirname "$1")/$(echo "$(basename "$1")"|sed 's/^xxx-xxx_[a-zA-Z]+_[0-9]+_//')"
      mv "$old" "$new"
      
      # execute this in the shell:
      find . -regex "xxx-xxx_[a-zA-Z]+_[0-9]+_[0-9]+\.jpg$" -exec ./rename.sh "{}" ";"
      

      【讨论】:

      • 它匹配一个文件名,例如:xxx-xxx_ERR_19_01.jpg 并返回 01 What do I do with that code?
      • 我认为它不能满足我的需要:我有 1/xxx-xxx_ERR_19_01.jpg 2/xxx-xxx_ERR_19_01.jpg 3/xxx-xxx_ERR_19_01.jpg
      • ...已修复,需要一个帮助文件,但现在可以处理任何事情。
      • 嗯.. 没用 :( 该命令很快就完成了。也许 find 需要一个参数才能递归?
      • find 默认情况下是递归的。如果您希望它不存在,则必须指定选项。
      【解决方案4】:

      如果你有rename(或prename)命令(它是一个 Perl 脚本,有时 Perl 附带):

      find -type d -name dir -exec rename 's/xxx-xxx_[a-zA-Z]+_\d+_(\d+)\.jpg/$1.jpg/' {}/xxx-xxx_[a-zA-Z]*[0-9].jpg \;
      

      【讨论】:

      • 重命名 's/ 是为了什么?我不明白's'是什么意思?
      • s/.../.../ 是 Perl(和 sed)的替代命令。它在第一个和第二个斜杠之间搜索正则表达式,并将其替换为第二个和第三个斜杠之间的正则表达式。 $1 是对括号中正则表达式部分的反向引用(sed 使用 \1)。
      • 答案在两个方面存在缺陷:(1) 替换字符串应该是 '$1.jpg' 而不是 '$1',以及 (2) 重命名或前缀脚本未作为标准分发Perl(无论如何,不​​是在所有平台上)。尽管如此,“重命名”Perl 脚本是一个有价值的工具 - 请参阅 superuser.com/questions/63421
      【解决方案5】:
      find /path -type f -name "???-???_[a-zA-Z]*_[0-9]*_*.???" | while read FILE
      do
        f=${FILE%%.???}  
        number=${f##*_}
        extension=${FILE##*.}
        path=${FILE%/*}
        echo "mv '$FILE' '$path/$number.$extension"
      done
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-29
        • 2022-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多