10

Suppose I have a folder with some 20 files (say, photos I took on a trip), and I want to rename them in one go, only there isn't any specific Perl expression I want to use (for example, if I'd like to add additional text to each name that's not part of the individual files' meta-data, such as descriptions and/or comments).

And suppose I can more easily generate a text file with what I want each file's name to be (or, if preferable, a 'before-and-after' sort of list).

Is there any way to apply the changes implied in that text list to the folder in question?

2 Answers 2

11

This looks like a job for xargs.

If your file is formatted like this:

old_file1 new_file1
old_file2 new_file2

then you can do xargs -a your_file -n 2 mv.

4
  • Super, you learn something new every day. xargs handle's spaces and special characters just fine, too, as long as I remember to protect them properly. Jul 10, 2013 at 22:41
  • @muru can you explain your motivation for rolling back revisions of this answer (in particular, why is piping cat inferior to input redirection)? Mar 23, 2015 at 16:31
  • @JonathanY. there's no advantage to it if you're just reading from a single file, and spawns an additional process, and creates a subshell with no gain.
    – muru
    Mar 23, 2015 at 16:33
  • @muru thank you. Revision history can be a great tool for learning, but much of that depends on detailed summaries. Mar 23, 2015 at 16:35
4

1. Open the terminal and change directory to the working directory (where the files to be renamed are located).

2. File names with numbers can alter the sequence therefor zero pad the numbers in file names by running the following code after changing .ext to your extension e.g. .txt .pdf etc.

rename 's/\d+/sprintf("%04d",$&)/e' *.ext

3. Put the list file, with the new names in sequential order, with extension, as file.list in the home folder. eg.

newname file x.jpg
newname file y.jpg
newname file z.jpg

4. Run the code below in terminal after changing .ext in the code to your extension e.g. .txt .pdf etc.

rm ~/undo.sh; for old in *.ext; do read new;  mv -v "${old}" "${new}"; echo "mv" '"'$new'"' '"'$old'"' >> ~/undo.sh; chmod +x ~/undo.sh; done < ~/file.list

5. An undo.sh file will be created in home folder to undo the renames if needed.

6. If you don't need the undo file the following code is enough.

for old in *.ext; do read new; mv -v "${old}" "${new}"; done < ~/file.list
6
  • 1
    Do not parse ls.
    – muru
    Mar 23, 2015 at 16:10
  • You can use simpler and safer code: count=1; for name in *.ext; do mv "$name" "$(awk -v file="$name" '$1 == file {print $2}')"; ((count+=1)); done. There's no need to use ls for this when *.ext is handled by the shell anyway.
    – muru
    Mar 26, 2015 at 11:01
  • This does not work. I have a duel boot with Ubuntu 14.04 and Windows 8.1. Most of my files and folders have spaces in names. I am not a professional but I think replacing the spaces does the trick. I am using and this code works perfectly well for all the photos videos etc except for your example of new line and may be other similar expressions.
    – Vijay
    Mar 26, 2015 at 12:56
  • Ah, yes because awk splits on spaces. Aside from that awk bit however, you'd be much better off using my loop overall, which does handle spaces very well, dual boot or no dual boot.
    – muru
    Mar 26, 2015 at 12:59
  • Changed as suggested.
    – Vijay
    Mar 28, 2015 at 17:18

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.