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 = CSV.read '/Users/sebastianzeki/Desktop/tbb.csv'
headers = csv_data.shift.map {|i| i.to_s }
string_data = csv_data.map {|row| row.map {|cell| cell.to_s } }
array_of_hashes = string_data.map {|row| Hash[*headers.zip(row).flatten] }


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 = CSV.open('/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|
File.rename(old_name,new_name)
end
end

Answer Source

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

csv_lines = CSV.open(input_file_name,
                     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)
end

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