I will describe the problem quite verbose, as I have learned that only talking about a specific sub-problem I have identified leads to missed oppurtunities ... So I will put a tl;dr up front: There is a set of folders that need to be renamed according to a mapping in a CSV file.

The folder names follow the following pattern:


The digits in the middle are relevant and specify the new name the folder should have. So I could run the following sed command to extract the part of the foldername I am interested in.

sed 's/[[:alpha:]]*\([[:digit:]]*\)_[[:alnum:]]*/\1/'

So we might have a folder thats named deptA100257_2bfde391c6af30fde3fca94b07bc8e7c and can pull out the relevant ID 100257. I then need to rename the folder according to the following CSV:


The new name is on the left, the ID of the old name on the right. So the folder from the example above should be renamed to 63.

First obvious problem: Multiple Ids may map to a single name. I would solve this by creating all "new" folders up front and copy the folder contents instead.

And I could hack this up using Python or whatever, possibly even some bash loops. But something tells me that at the core, this operation (substitution according to a file) isn't exactly uncommon. So before re-inventing the wheel ...

I prefer solutions using standard *NIX shells and tools (especially bash or zsh) and no "external" languages like Perl, Ruby, Python ... But in the end I am more or less looking for a "smart" approach and if there is a nice Ruby one-liner that gets the job done, I am ok with that.


I would use find to get the folder names, parse them with sed, grep the corresponding id and copy stuff over:

$ find . -mindepth 1 -type d | while read dir; do 
   id=$(echo "$dir" | sed 's/\.\/[[:alpha:]]*\([[:digit:]]*\)_[[:alnum:]]*/\1/'); 
   new_name=$(grep -w "$id" names.csv | cut -d ';' -f 1); 
   mkdir -p "$new_name" && mv -rv "$dir"/* "$new_name"/ && rmdir "$dir"; 

The tricks are

  • use mkdir -p which will create the directory and exit silently if it exists.
  • use grep -w on the csv file to only get those lines that contain the entire ID bordered by non-word characters. That way you avoid matching both 1123 and 123 for the id 123.
  • That rmdir would fail as the directory is not empty, Maybe mv -v "$dir"/* "$new_name"/? Also need to be careful you don't require . files from the base directory when copying/moving with the * glob. – Matt Jan 4 '14 at 17:09
  • @mindthemonkey of course it would facepalm. Fixed. – terdon Jan 4 '14 at 21:16

Assuming your directories are all under current working directory, here is a starting point (so test it before running in prod):


for d in ./*;
  # only work with directory
  [[ ! -d "$d" ] && continue

  # extract id from directory
  id="$(echo "$d" | sed 's/[[:alpha:]]*\([[:digit:]]*\)_[[:alnum:]]*/\1/')"

  # fetch new name
  nid="$(awk -F';' '/'"$id"'/ {print $1}' "$csvFile")"

  # merge all matching dir into one
  mv "$d" "$nid"


Did you look at :

  • mmv: Mass Move and rename ;
  • zmv: a zsh module that allow people to do massive rename.
  • 2
    Nice but your gawk will match any lines containing the id, not only those that have the specific id. It will match both foo123 and 123bar for the id 123 for example. It will also create subdirectories rather than copying files for the second folder with the same target id. – terdon Jan 4 '14 at 15:17
  • your description did not expose the possibility of ambiguous id. I'm aware my script is not the solution, just a useful proposition :) – Édouard Lopez Jan 4 '14 at 15:31
  • 1
    It's quite clearly stated in the OP. It's both shown in the example and explicitly mentioned: "First obvious problem: Multiple Ids may map to a single name. I would solve this by creating all "new" folders up front and copy the folder contents instead." – terdon Jan 4 '14 at 15:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.