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?


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.

  • 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. – Jonathan Y. Jul 10 '13 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)? – Jonathan Y. Mar 23 '15 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 '15 at 16:33
  • @muru thank you. Revision history can be a great tool for learning, but much of that depends on detailed summaries. – Jonathan Y. Mar 23 '15 at 16:35

Put the list file file.list, with the new names in sequential order, with extension, as file.list in the folder with files to be renamed e.g.

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

Change directory to the working directory.

change extension in the code, all the files with that extension will be renamed in sequential order as per the list.

An undo_rename.sh file will be created in home folder to undo if needed.

rm ~/undo_rename.sh; count=1; for name in *.ext; do echo "mv" '"'`awk "NR==$count{print;exit}" file.list`'"' '"'$name'"' >> ~/undo_rename.sh; chmod +x ~/undo_rename.sh; mv "$name" "`awk "NR==$count{print;exit}" file.list`"; ((count+=1)); done
  • 1
    Do not parse ls. – muru Mar 23 '15 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 '15 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 '15 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 '15 at 12:59
  • Changed as suggested. – Vijay Mar 28 '15 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.