【问题标题】:Bash -- Renaming FilesBash -- 重命名文件
【发布时间】:2013-11-14 19:01:26
【问题描述】:

我想编写一个脚本,通过几个不同的规则重命名大量文件。我需要从某些字符串中删除特定字符串,然后通过正则表达式重命名其他字符串(其中一些将是我之前从中删除字符串的字符串),然后根据文件名中的数字重命名其他字符串。

一般来说,假设我有多个目录(数百个),它们通常看起来像这样:

1234-pic_STUFF&TOREMOVE_2000.tiff
1234-pic_STUFF&TOREMOVE_4000.tiff
1234-MORESTUFFTOREMOVE-012.jpg
1234-MORESTUFFTOREMOVE-037.jpg
1234-STUFF&TOREMOVE.pptx.pdf        (don't ask about this one)
1234-ET.jpg
1234-DF.jpg

对于一个看起来像:

1234_smallNum.tiff
1234_bigNum.tiff
1234_smallNum.jpg
1234_bigNum.jpg
1234_CaseReport.pdf
1234_ET.jpg
1234_DF.jpg

我已经有使用 perl 脚本通过正则表达式重命名的 shell 脚本(我从 SO 中得到了它,但我无法再次找到它来引用它)。它们就像 remove_stuff_to_remove.sh 和 rename_case_reports.sh,我可以 cd 到每个目录并通过调用它们来单独执行它们而无需输入。

但是,我不知道如何根据数字转换文件名(2000 和 012 转换为 smallNum;4000 和 037 转换为 bigNum;请注意这些数字差异很大,因此我不能使用范围或正则表达式;我必须将这些数字相互比较。)

而且我不知道如何自动化整个过程,以便我可以从所有这些目录的根目录中调用一个脚本,它会为我完成所有这些事情。我非常了解正则表达式,但我在使用 find 命令或一般的 shell 脚本时做得不太好。

另外,我说的是 Bash,但实际上,如果这可以在 Java、C、Python、Ruby 或 Lisp 中更好地完成,我对这些语言的了解要好得多,我只想在获得这些文件之前解决这个问题甩给我(在接下来的一个月左右)......

【问题讨论】:

  • 顺便说一句,Perl 或 Bash 似乎是完成此类任务最相关的选择。
  • 我开始明白了。您确定在一个目录中不能有两个以上同名、相同扩展名但编号不同的文件吗?
  • 是的,我确定。这是医疗数据,每个最多有 2 次“扫描”(但可能只有一次,在这种情况下,它被认为很小)。
  • 您能否提供一些真实的示例数据?或者您是否建议 1234_bigNum.tiff 是您最终可能得到的实际文字文件名?
  • 我想要一个算法解决方案,它不依赖于我的确切数据。我花了很多时间研究类似的问题,除非您遇到与 OP 完全相同的问题,否则答案基本上是无用的。我想真正了解可用于做这类事情的工具,以便我可以将答案推广到其他应用程序。就像我说的,我了解正则表达式,我什至有能够识别我的确切数据的正则表达式,我只是不知道如何将它们应用于这个重命名问题。

标签: regex linux bash shell


【解决方案1】:

真的 - 不要用 bash 折磨自己,只需使用您最喜欢的脚本语言。下面将让您了解如何在 Ruby 中处理此问题。写的仓促,请不要笑:

#!/usr/bin/env ruby

require 'find'

def move(path, old_name, new_suffix)
    number = old_name.sub(/^(\d+).*/,'\1')
    File.rename(path+'/'+old_name, path+'/'+number+'_'+new_suffix)
end

where_to_look = ARGV[0] || '.'
Find.find(where_to_look) do |dir|
    path = where_to_look+'/'+dir
    next if !File.directory?(path)
    entries = Dir.entries(path).select{|x| File.file?(path+'/'+x) }
    next if entries.size != 7

    %w(tiff jpg).each do |ext|
        imgs = entries.select{|x| x =~ /\d+\.#{ext}$/ }
        next if imgs.size != 2
        imgs.sort{|a,b| ai = $1.to_i if a =~ /(\d+)\.#{ext}$/ ; bi = $1.to_i if b =~ /(\d+)\.#{ext}$/ ; ai <=> bi }
        move(path, imgs.first, 'smallNum.'+ext)
        move(path, imgs.last, 'bigNum.'+ext)
    end
    report = entries.detect{|x| x =~ /\.pptx\.pdf$/ }
    move(path, report, 'CaseReport.pdf') if !report.nil?
    %w(ET DF).each do |code|
        file = entries.detect{|x| x =~ /^\d+-#{code}\.jpg$/ }
        move(path, file, code+'.jpg') if !file.nil?
    end
end

【讨论】:

  • 哇,这只是说明我最近有多累......我完全忘记了 Ruby 中所有漂亮的文件方法......我陷入了使用 bash 的想法并遇到了墙。我责怪我的教授,他们这学期不让我用 C 以外的任何东西。 :P
【解决方案2】:

Bash 的字符串替换:

$ match="foo"
$ repl="bar"
$ value="___foo___"
$ echo "${value/$match/$repl}"
___bar___

http://tldp.org/LDP/abs/html/string-manipulation.html

您可以将此模式应用于您的每个转换。

$ for file in $(find . -name "*-pic_STUFF\&TOREMOVE_2000.tiff"); do
    mv "$file" "${file/-pic_STUFF\&TOREMOVE_2000.tiff/_smallNum.tiff}"; done

【讨论】:

  • 感谢Bash字符串替换的例子;我以前从未见过有人这样做(为此+1)。但这并不能解决比较两个数字的问题(2000 和 4000 只是示例,也可以是 3750 和 4100)。
猜你喜欢
  • 2016-08-01
  • 2020-02-18
  • 2016-01-25
  • 2012-12-31
  • 2012-09-02
  • 2015-12-11
  • 1970-01-01
  • 2019-09-02
  • 1970-01-01
相关资源
最近更新 更多