1

I'm working with a tree of folders and files with the structure

  • \ Stories \ 00 \ 0 \ 00000 \ temp.xxx
  • \ Stories \ 00 \ 0 \ 00001 \ temp.xxx
  • ...
  • \ History \ 10 \ 5 \ 10552 \ temp.xxx
  • \ History \ 10 \ 5 \ 10553 \ temp.xxx
  • ...
  • \ History \ 45 \ 9 \ 45998 \ temp.xxx
  • \ History \ 45 \ 9 \ 45999 \ temp.xxx

What I need is to rename the files so that temp.xxx is changed into a sequenced file name as shown below:

  • \ Stories \ 00 \ 0 \ 00000 \ 00000.xxx
  • \ Stories \ 00 \ 0 \ 00001 \ 00001.xxx
  • ...
  • \ History \ 10 \ 5 \ 10552 \ 10552.xxx
  • \ History \ 10 \ 5 \ 10553 \ 10553.xxx
  • ...
  • \ History \ 45 \ 9 \ 45998 \ 45998.xxx
  • \ History \ 45 \ 9 \ 45999 \ 45999.xxx
2
0

If your structure is uniform and you have the depth of 3 inside your History folder, perhaps the intuitive way would be having nested for loops and then use the mv to rename.

The following code assumes that you have one file in each folder in layer3 and your /History does not contain anything other than directories.

for layer1 in /History/*; do
    for layer2 in /History/$layer1/*; do
        for layer3 in /History/$layer1/$layer2/*; do
           for files in /History/$layer1/$layer2/$layer3/*; do
                mv files $layer3.xxx
            done
        done
    done
done

perhaps these two links are also helpful:

http://www.cyberciti.biz/faq/bash-for-loop/

https://stackoverflow.com/questions/539583/how-do-i-recursively-list-all-directories-at-a-location-breadth-first

1
  • You may want to quote your variables. – slhck Dec 17 '14 at 16:25
0

You can do it with a command like this:

find . -name "temp*" | sed -E 's|(.*)\/(.*)\/temp(.[a-z]{3})|mv & \1\/\2\/\2\3|g' | source /dev/stdin

Step by step explanation.

This is your sample input:

$ find . -name "temp*"
./History/10/5/10552/temp.xxx
./History/10/5/10553/temp.xxx
./Stories/00/0/00000/temp.xxx
./Stories/00/0/00001/temp.xxx

I tweak the output to suit the required output.

$ find . -name "temp*" | sed -E 's|(.*)\/(.*)\/temp(.[a-z]{3})|\1\/\2\/\2\3|g'
./History/10/5/10552/10552.xxx
./History/10/5/10553/10553.xxx
./Stories/00/0/00000/00000.xxx
./Stories/00/0/00001/00001.xxx

So, we transform every temp* into a mv command with required output names. The command looks like this:

$ find . -name "temp*" | sed -E 's|(.*)\/(.*)\/temp(.[a-z]{3})|mv & \1\/\2\/\2\3|g'
mv ./History/10/5/10552/temp.xxx ./History/10/5/10552/10552.xxx
mv ./History/10/5/10553/temp.xxx ./History/10/5/10553/10553.xxx
mv ./Stories/00/0/00000/temp.xxx ./Stories/00/0/00000/00000.xxx
mv ./Stories/00/0/00001/temp.xxx ./Stories/00/0/00001/00001.xxx

To execute every command from the previous output, we must add | source /dev/stdin at the end of the command.

The results will be the following:

$ find . -name "*.xxx"
./History/10/5/10552/10552.xxx
./History/10/5/10553/10553.xxx
./Stories/00/0/00000/00000.xxx
./Stories/00/0/00001/00001.xxx

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.