Sebastian Zeki Sebastian Zeki - 4 years ago 112
Ruby Question

How to find and replace a list of filenames from a list

I have a CSV file made of two columns.

One column is the old filename, and the other is the new filename.

I want to replace the actual filenames in a folder with the new file names.

I have looked extensively but can't find out how to do this.

My input file is this:

New Old
Dys.FSA_BB_NEW_0204_Sp_5_HBG_fq.gz.res Cyto_Dys2.0
Dys.FSC_Sp_BB_LC_0028_R1_30_HBG_fq.gz.res Cyto_Dys2.0
Dys_BB_NEW_0177_Sp_FSD.5_HBG_fq.gz.res Cyto_Dys2.0
Dys_FSE.BB_AM_0104_Sp_5_HBG_fq.gz.res Cyto_Dys2.0
Dys_FSF.AM_0068_Sp_5_HBG_fq.gz.res Cyto_Dys2.0
Dys_FSG.BB_LC_261_Sp_15_HBG_fq.gz.res Cyto_Dys2.0
Dys_FSH.BB_LC_0047_Sp_10_HBG_fq.gz.res Cyto_Dys2.0
Dys_FastSeqB_BB_LC_0028_Sp_15_HBG_fq.gz.res Cyto_Dys2.0
Dys_FSA_OC_AH_255_E_B1_Biopsy_30_LBG_fq.gz.res AneupDysplasticBEFS
Dys_FSC_OC_UC_025_E_B1_Biopsy_25_LBG_fq.gz.res AneupDysplasticBEFS
Dys_FSD_BB_POR_0028_Biopsy_30_HBG_fq.gz.res AneupDysplasticBEFS
Dys_FSH_BB_NEW_0097_Biopsy_70_HBG_fq.gz.res AneupDysplasticBEFS
Dys_FSI_BB_AM_0003_Biopsy_60_LBG_fq.gz.res AneupDysplasticBEFS

I imagine I have to create an array of hashes first from the csv using something like this:

require 'csv'
csv_data = '/Users/sebastianzeki/Desktop/tbb.csv'
headers = {|i| i.to_s }
string_data = {|row| {|cell| cell.to_s } }
array_of_hashes = {|row| Hash[*] }

This gives me:

[{"New"=>"Dys.FSA_BB_NEW_0204_Sp_5_HBG_fq.gz.res", "Old"=>"Cgd"}, {"New"=>"Dys.FSC_Sp_BB_LC_0028_R1_30_HBG_fq.gz.res", "Old"=>"C4444"}, {"New"=>"Dys_BB_NEW_0177_Sp_FSD.5_HBG_fq.gz.res", "Old"=>"g43tret"}, {"New"=>"Dys_FSE.BB_AM_0104_Sp_5_HBG_fq.gz.res", "Old"=>"dgffgd.0"}, {"New"=>"Dys_FSF.AM_0068_Sp_5_HBG_fq.gz.res", "Old"=>"Cygfdg"}, {"New"=>"Dys_FSG.BB_LC_261_Sp_15_HBG_fq.gz.res", "Old"=>"tttetwt"}, {"New"=>"Dys_FSH.BB_LC_0047_Sp_10_HBG_fq.gz.res", "Old"=>"Cyto_Dyggg"}, {"New"=>"Dys_FastSeqB_BB_LC_0028_Sp_15_HBG_fq.gz.res", "Old"=>"Cygfdys2.0"}, {"New"=>"Dys_FSA_OC_AH_255_E_B1_Biopsy_30_LBG_fq.gz.res", "Old"=>"AngfdgFS"}, {"New"=>"Dys_FSC_OC_UC_025_E_B1_Biopsy_25_LBG_fq.gz.res", "Old"=>"AndEFS43"}, {"New"=>"Dys_FSD_BB_POR_0028_Biopsy_30_HBG_fq.gz.res", "Old"=>"A234lasticBEFS"}, {"New"=>"Dys_FSH_BB_NEW_0097_Biopsy_70_HBG_fq.gz.res", "Old"=>"Aneup4344FS"}, {"New"=>"Dys_FSI_BB_AM_0003_Biopsy_60_LBG_fq.gz.res", "Old"=>"AgdfgsticBEFS"}]

So how do I now convert the actual filename in a folder to the new one (in the same folder)?

edited using @tuo's answer

csv_lines ='/Users/sebastianzeki/Desktop/tbb.csv',
headers: true,
col_sep: "\b")

filenames = Dir.glob("/Users/sebastianzeki/myfolder/*")

csv_lines.each do |row|
old_name = row['Old']
new_name = row['New']
filenames.each do |filename|

Answer Source

You might want to load the CSV into CSV::Rows like this:

csv_lines =,
                     headers: true,
                     col_sep: "\b")

This will give you all the csv rows with headers, you can iterate those lines like this:

path = '/your/dir/path/'

csv_lines.each do |row|
  old_name = row['Old']
  new_name = row['New']

  #TODO: find the file with the old name and update it to the new one 

  #EDIT: it can be done like this:
  File.rename(path + old_name, path + new_name)

I guess you already know how to do the rename job. :)

Edit: I added renaming into my code. No need to scan the folder in each loop. You just need to find one file and rename it at a time.

PS. You can add exception handler in the loop in case there is any missing file in your input file.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download