Home > Software design >  How do batch copy and rename files with same names under different folders to a separate folder with
How do batch copy and rename files with same names under different folders to a separate folder with

Time:11-17

Say I have folders named user/john/john1, john2 and john3 and I have one file called dog.txt inside each of them. I want to create a separate folder called johns_dogs and copy all the dog.txt from each folder into this new folder, but with the files renamed as john1_dog.txt, john2_dog.txt, john3_dog.txt.

How would I go about this? I assume I can use a for loop for this, and I have been playing around with it..i just can't seem to get it right; specifically isolating the folder names to apply to the file name using the linux terminal. Using GUI is not an option. Thank you :)

for fname in user/john/*/dog.txt;
do
  new_name=basename $(PWD)
  cp user/john/*/dog.txt > $new_name.txt;
done

This is what I've tried to do...but it doesn't work, and i don't know why?

CodePudding user response:

One option would be to use bash string substitution via parameter expansion to build the desired output path for each file:

for f in ./user/john/*/dog.txt ; do 
    new="${f//\//_}"
    new="${new/._user_john_/./johns_dogs/}"
    cp "$f" "$new"
done

or as one-liner:

for f in ./user/john/*/dog.txt ; do new="${f//\//_}" ; new="${new/._user_john_/./johns_dogs/}" ; cp "$f" "$new"; done

After running above command contents of .johns_dogs directory:

find ./johns_dogs/*
./johns_dogs/john1_dog.txt
./johns_dogs/john2_dog.txt
./johns_dogs/john3_dog.txt
./johns_dogs/john4_dog.txt
./johns_dogs/john5_dog.txt

String replacement details:

new="${f//\//_}"  # replace all '/' with '_' in original path to create new path
new="${new/._user_john_/./johns_dogs/}" # replace '._user_john_' with './johns_dogs' to complete new path

CodePudding user response:

Instead of some utterly incomprehensible, works-by-voodoo-magic, write-test-debug-then-throw-away script, my approach in similar cases is as follows:

  • Use the ls command to create a "long" listing of your files. (One full filename per line.)
  • Pipe it into a text file.
  • Open the text file in an editor which supports column editing.
  • Copy the column of filenames to the clipboard.
  • While keeping the copied column in the clipboard:
    • Edit the column of filenames, so as to turn them into the destination filenames. (Use column-mode and/or search-and-replace for this.)
  • Paste the column of original filenames from the clipboard into the text file, right before the column of altered filenames.
  • Prepend cp at the start of each line.
  • Save the text file as a shell script. (Prepend #!bash, do the necessary chmod)
  • Run the shell script.

It might seem like a lot of work, but actually you can do it very quickly (as long as you do not have to manually modify each line) and the great benefit of it is that you can just examine it with your eyes and have a fairly high degree of confidence that once run, it will do the right thing, whereas the script might destroy your filesystem and you will only know after the fact.

I mean, please do not get me wrong, I am a Software Engineer, I write code for a living, I solve problems by writing code, but there are some cases where it is just not worth writing code.

  • Related