【问题标题】:Bulk renaming of files based on lookup基于查找的文件批量重命名
【发布时间】:2011-05-07 15:19:25
【问题描述】:

我有一个充满图像文件的文件夹,例如

  • 1500000704_full.jpg
  • 1500000705_full.jpg
  • 1500000711_full.jpg
  • 1500000712_full.jpg
  • 1500000714_full.jpg
  • 1500000744_full.jpg
  • 1500000745_full.jpg
  • 1500000802_full.jpg
  • 1500000803_full.jpg

我需要根据文本文件的查找来重命名文件,该文本文件包含以下条目:

  • SH103239 1500000704
  • SH103240 1500000705
  • SH103241 1500000711
  • SH103242 1500000712
  • SH103243 1500000714
  • SH103244 1500000744
  • SH103245 1500000745
  • SH103252 1500000802
  • SH103253 1500000803
  • SH103254 1500000804

所以,我想重命名图像文件,

  • SH103239_full.jpg
  • SH103240_full.jpg
  • SH103241_full.jpg
  • SH103242_full.jpg
  • SH103243_full.jpg
  • SH103244_full.jpg
  • SH103245_full.jpg
  • SH103252_full.jpg
  • SH103253_full.jpg
  • SH103254_full.jpg

我怎样才能最轻松地完成这项工作?任何人都可以为我写一个可以为我执行此操作的快速命令或脚本吗?我有很多这些图像文件,手动更改是不可行的。

我在 ubuntu 上,但如果需要,我可以根据工具切换到 Windows。理想情况下,我希望将它放在 bash 脚本中,以便我可以学习更多或简单的 perl 或 python。

谢谢

编辑:不得不更改文件名

【问题讨论】:

  • 查找文件中的条目数量是否与图像文件的数量相同?
  • 图片多于文件条目数
  • 那么迭代条目比迭代文件更有效。

标签: python perl bash


【解决方案1】:
import os,re,sys

mapping = <Insert your mapping here> #Dictionary Key value entries (Lookup)

for k,v in mapping:
    for f in os.listdir("."):
        if re.match('1500',f): #Executes code on specific files
            os.rename(f,f.replace(k,v))

【讨论】:

    【解决方案2】:

    我修改了 Wesley 的准则以适应我的具体情况。我有一个映射文件“sort.txt”,它由不同的 .pdf 文件和数字组成,以根据网站 DOM 操作的输出指示我希望它们的顺序。我想将所有这些单独的 pdf 文件合并到一个 pdf 文件中,但我想保留它们在网站上的顺序。所以我想在导航菜单中根据它们的树位置附加数字。

    1054 spellchecking.pdf
    1055 using-macros-in-the-editor.pdf
    1056 binding-macros-with-keyboard-shortcuts.pdf
    1057 editing-macros.pdf
    1058 etc........
    

    这是我想出的代码:

    import os, sys
    
    # A dict with keys being the old filenames and values being the new filenames
    mapping = {}
    
    # Read through the mapping file line-by-line and populate 'mapping'
    with open('sort.txt') as mapping_file:
        for line in mapping_file:
    
            # Split the line along whitespace
            # Note: this fails if your filenames have whitespace
            new_name, old_name = line.split()
            mapping[old_name] = new_name
    
    
    # List the files in the current directory
    for filename in os.listdir('.'):
        root, extension = os.path.splitext(filename)
    
        #rename, put number first to allow for sorting by name and 
        #then append original filename +e extension
        if filename in mapping:
            print "yay" #to make coding fun
            os.rename(filename, mapping[filename] + filename + extension)
    

    我没有像 _full 这样的后缀,所以我不需要那个代码。除了相同的代码之外,我从来没有真正接触过python,所以这对我来说是一次很好的学习经历。

    【讨论】:

      【解决方案3】:

      这是一个有趣的小技巧:

      paste -d " " lookupfile.txt lookupfile.txt | cut -d " " -f 2,3 | sed "s/\([ ]\|$\)/_full.jpg /g;s/^/mv /" | sh
      

      【讨论】:

        【解决方案4】:

        这是一个用于重命名的简单 Python 2 脚本。

        #!/usr/bin/env python
        
        import os
        
        # A dict with keys being the old filenames and values being the new filenames
        mapping = {}
        
        # Read through the mapping file line-by-line and populate 'mapping'
        with open('mapping.txt') as mapping_file:
            for line in mapping_file:
                # Split the line along whitespace
                # Note: this fails if your filenames have whitespace
                new_name, old_name = line.split()
                mapping[old_name] = new_name
        
        suffix = '_full'
        
        # List the files in the current directory
        for filename in os.listdir('.'):
            root, extension = os.path.splitext(filename)
            if not root.endswith(suffix):
                # File doesn't end with this suffix; ignore it
                continue
            # Strip off the number of characters that make up suffix
            stripped_root = root[:-len(suffix)]
            if stripped_root in mapping:
                os.rename(filename, ''.join(mapping[stripped_root] + suffix + extension))
        

        脚本的各个部分都是硬编码的,实际上不应该这样。其中包括映射文件的名称 (mapping.txt) 和文件名后缀 (_full)。这些大概可以作为参数传入并使用sys.argv 进行解释。

        【讨论】:

        • 嗨,你能告诉我一些关于我应该如何运行这个脚本的细节吗?当我运行它时,什么也没有发生。我的 mapping.txt 文件与上面的原始帖子相同。任何提示都会很棒。
        • 对不起,没关系。我正在运行另一个脚本。这很好用。谢谢。
        • 不,又好又简单perl -lane 'rename("$F[1].jpg", "$F[0].jpg")' mapping.txt。嘘!
        • 嘿韦斯利,谢谢你的剧本。你能帮我调整一下脚本吗,因为图像文件名最后有“_full”。脚本运行假设我的映射文件具有相同的文件名....我已经编辑了主要帖子以说明我的意思....抱歉我不清楚。
        • 这应该可以满足您的要求。试一试。
        【解决方案5】:

        这在 Bash 中非常简单,假设每个文件的查找文件中都有一个条目,并且每个文件都有一个查找条目。

        #!/bin/bash
        while read -r to from
        do
            if [ -e "${from}_full.jpg" ]
            then
                mv "${from}_full.jpg" "${to}_full.jpg"
            fi
        done < lookupfile.txt
        

        如果查找文件的条目数多于文件数,则此方法可能效率低下。如果相反,那么迭代文件的方法可能效率低下。但是,如果数字接近,那么这可能是最好的方法,因为它实际上不需要进行任何查找。

        如果您更喜欢纯 Bash 的查找版本:

        #!/bin/bash
        while read -r to from
        do
            lookup[from]=$to
        done < lookupfile.txt
        
        for file in *.jpg
        do
            base=${file%*_full.jpg}
            mv "$file" "${lookup[base]}_full.jpg"
        done
        

        【讨论】:

          【解决方案6】:

          Wesley 使用生成器的重写:

          import os, os.path
          
          with open('mapping.txt') as mapping_file:
              mapping = dict(line.strip().split() for line in mapping_file)
          
          rootextiter = ((filename, os.path.splitext(filename)) for filename in os.listdir('.'))
          mappediter = (
              (filename, os.path.join(mapping[root], extension))
              for filename, root, extension in rootextiter
              if root in mapping
          )
          for oldname, newname in mappediter:
              os.rename(oldname, newname)
          

          【讨论】:

          • 讨厌。也许我做 python 的时间还不够长(四五年!),但这对我来说完全不可读。
          • @Graeme Perrow:阅读有关发电机的 David Beazley,改变了我的生活。 dabeaz.com/generators
          【解决方案7】:
          #!/bin/bash
          
          for FILE in *.jpg; do
              OLD=${FILE%.*}  # Strip off extension.
              NEW=$(awk -v "OLD=$OLD" '$2==OLD {print $1}' map.txt)
              mv "$OLD.jpg" "$NEW.jpg"
          done
          

          【讨论】:

            【解决方案8】:

            这将解决您的问题:

            #!/usr/bin/perl
            while (<DATA>) {
                my($new, $old) = split;
                rename("$old.jpg", "$new.jpg")
                    || die "can't rename "$old.jpg", "$new.jpg": $!";
            }
            __END__
            SH103239 1500000704
            SH103240 1500000705
            SH103241 1500000711
            SH103242 1500000712
            SH103243 1500000714
            SH103244 1500000744
            SH103245 1500000745
            SH103252 1500000802
            SH103253 1500000803
            SH103254 1500000804
            

            DATA 切换到ARGV 以读取特定输入文件中的行。

            通常对于批量重命名操作,我使用类似这样的东西:

            #!/usr/bin/perl
            # rename script by Larry Wall
            #
            # eg:
            #      rename 's/\.orig$//'  *.orig
            #      rename 'y/A-Z/a-z/ unless /^Make/'  *
            #      rename '$_ .= ".bad"'  *.f
            #      rename 'print "$_: "; s/foo/bar/ if <STDIN> =~ /^y/i'  *
            #      find /tmp -name '*~' -print | rename 's/^(.+)~$/.#$1/'
            
            ($op = shift) || die "Usage: rename expr [files]\n";
            
            chomp(@ARGV = <STDIN>) unless @ARGV;
            
            for (@ARGV) {
                $was = $_;
                eval $op;
                die if $@;  # means eval `failed'
                rename($was,$_) unless $was eq $_;
            }
            

            我有一个功能更全的版本,但这应该足够了。

            【讨论】:

            • 能否提供您所拥有的功能更全的版本供我们使用。这也可能对其他用户有用......你的脚本还能做什么。像 mkdir 等。谢谢。
            【解决方案9】:

            读入文本文件,用当前文件名创建一个哈希,如files['1500000704'] = 'SH103239'等等。然后遍历当前目录中的文件,从哈希中获取新的文件名,然后重命名。

            【讨论】:

            • 用字符串下标数组?
            • 查看@Wesley 的答案,了解与我尚未编写的代码类似的代码。
            猜你喜欢
            • 2012-07-23
            • 2017-09-19
            • 1970-01-01
            • 2013-01-17
            • 2013-12-19
            • 2017-04-20
            • 2012-09-02
            • 1970-01-01
            相关资源
            最近更新 更多