2

I want to rename all files in a directory. The new names don't follow any pattern, so I can't use rename. Is there any efficient way to do this, so I won't have to use mv foo.txt bar.txt for every single file?

5
  • If the new names do not follow any pattern the only thing you can do is list the directory contents to a file and then edit the file to suit.
    – suspectus
    May 9, 2013 at 16:25
  • You could write your own BASH script to ask for a new name for each file
    – Wolfizen
    May 9, 2013 at 16:30
  • 5
    By sheer luck I discovered imv (from renameutils) which allows you to interactively rename a file. But that will only accept one file, so you need a loop: for file in *; do imv "$file"; done.
    – Bobby
    May 9, 2013 at 16:33
  • Thanks Bobby, that's exactly what I've been looking for. Could you post it as an answer, please, so I can upvote you properly?
    – n.st
    May 9, 2013 at 16:37
  • 1
    Pinging @Bobby (n.st, you need to explicitly @-mention users in order for them to receive a notification.)
    – slhck
    May 9, 2013 at 20:48

3 Answers 3

3

When thinking about writing this as a script I checked if possible names are already taken, and turns out my guess "interactive move" is already written and ready to use. For most systems it should be available in the renameutils-package, which contains various tools which are very helpful:

  • qmv/qcp: Quick Move/Copy, writes all filenames to a text file which then can be edited.
  • imv/icp: Interactive Move/Copy, asks for the new name of the files.

The problem with imv/icp in this case is, that those only accept one argument:

imv FILENAME

Multiple arguments will yield an error. So you'll basically have to wrap it up in a short for loop:

for file in *; do imv "$file"; done

That is of course hard to type, so we should wrap this into a ready to use function which we can place in our .bashrc file.

# Mass Interactive Move
function mimv {
    for file in "$*"; do
        imv "$file"
    done
}

Fortunately, imv shows the name of the file which is currently process, so we don't need any echo statement in there so that we know what is going on.

4

You can use this command:

for i in *; do
   read -p "$i -> " newname
   if [[ ! -z "$newname" ]]; then
      mv -v -- "$i" "$newname"
   fi
done

It will prompt you for a new name for every file and also for every directory (for i in *) in the current directory. The new name gets read into $newname. If you hit Enter without typing in a new name, nothing is done (-z $newname checks, if $newnameis empty (zero); ! is logical not), otherwise mv is used to rename the file.


If you want to change the file name only a little bit, it's more efficient if you can edit it, starting with the old file name, as suggested by @grawity:

for i in *; do
   read -p "$i -> " -e -i "$i" newname
   if [[ ! -z "$newname" ]]; then
      mv -v -- "$i" "$newname"
   fi
done

I tested it with filenames containing spaces and braces, however please use it on your own risk (and make a backup of the original files before).

8
  • 2
    Heh, you were faster. And you did test with spaces in the names, which I forgot.
    – Hennes
    May 9, 2013 at 16:49
  • 2
    If you use read -p "$i -> " -e -i "$i" newname, it'll let you edit the old name directly. May 9, 2013 at 16:55
  • @Hennes: I was trained by a comment by slhck (superuser.com/questions/593396/…) earlier that day ;)
    – mpy
    May 9, 2013 at 16:55
  • @grawity: Thanks, that's a neat trick -- I incorporated it into my answer.
    – mpy
    May 9, 2013 at 17:04
  • @mpy: except you didn't, -e -i "$i" is the key part :D May 9, 2013 at 17:13
-1
#!/usr/bin/env bash

for files in $( echo * );
do
     echo -n Rename $files  to which name? ;
     read new_name ;
     mv "$files" "$new_name";
done
3
  • 2
    for files in $(echo *) is very redundant – it could be replaced with for files in *, which even works properly with spaces in names. May 9, 2013 at 16:58
  • Aye. i used it in an earlier version. One which asked for a pattern of files so you could just use ./q testfile to rename all files matching testfile*. I cut those parts out before posting. (It was not as nice as mpy's answer is atm, but I do like to add small things such as if [ -z $1 ] ; then echo Usage: $0 files to rename exit fi
    – Hennes
    May 9, 2013 at 17:07
  • if [ -z "$1" ] May 9, 2013 at 17:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .