Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I haven't had much success in finding a Linux version of namemangler, which I need to rename 1000 of files so they are readable on Windows.

Does anyone know of a Linux program that can do this?

If not, then a script might work as I only need to rename all files in a folder to, say, the first 16 characters. I suspect that the script route might be worth going down but not sure where to start.

share|improve this question

migrated from stackoverflow.com Feb 29 '12 at 13:30

This question came from our site for professional and enthusiast programmers.

2  
You probably could write quickly a Python or Perl or Ocaml or Ruby script doing that. –  Basile Starynkevitch Feb 29 '12 at 12:48
    
Why can't you just use a vfat filesystem, which allows long file names? –  wnoise Mar 1 '12 at 6:28
2  
Out of curiosity, how long are does names and what do they contain that they are not recognised by Windows? –  Bobby Mar 1 '12 at 19:34
add comment

6 Answers 6

On Debian, Ubuntu and derivatives, if you enter man rename at a command prompt, you'll get the manual page for a rename utility that allows arbitrary Perl-like regular expression commands to be used in the renaming.

For example, this will shorten (by truncating) all files in the current directory to a length of five:

rename 's/^(.{5}).*/$1/' *

It works by capturing the first five characters then using that in the substitution, removing the rest.

Another example is to shorten filenames (sans extension) to five characters wile preserving the extension:

rename 's/^(.{5}).*(\..*)$/$1$2/' *

It captures two groups, the first being the first five character, the second being the extension. This would turn myCarefullyCraftedDocument.pdf into myCar.pdf.

Warning: Use this carefully, preferably on a copy of your directory, or by taking backups first. You have been warned!! At a bare minimum, use rename -n first, which will show you what would be done without actually doing it.

share|improve this answer
1  
will this get rid of the prefix as in PDF? and what would happen to files with the same name once shorten? –  Grimlockz Feb 29 '12 at 13:01
    
That particular example will, yes. You can write a regex to leave the extension alone. I'll update the answer. It also protects against overwriting files that already exist, so later renames will fail. –  paxdiablo Feb 29 '12 at 13:04
    
thanks for your help on this - I'm very thankful. I do have one slight issue if some of the pdfs will be renamed to 5 lets say what would happen to the PDF's it tries to rename with the same name? Is they a way we can just add a unique number onto all the ones with this is? see below ename -n 's/^(.{5}).*(\..*)$/$1$2/' * Annexes 123114345234525.pdf renamed as Annex.pdf Annexes 123114432452352.pdf renamed as Annex.pdf –  Grimlockz Feb 29 '12 at 13:14
    
@Grimlockz, I don't think you can put that sort of intelligence into the rename regex itself. What you may need to do is write a script to wrap rename with that sort of intelligence, and that's better asked as a separate question so you'll get more people responding than just I. –  paxdiablo Feb 29 '12 at 13:19
    
@Grimlockz This is why you don't want to do everything in a regex. You'll be happier and better off writing a script that uses regexes. –  Spencer Rathbun Feb 29 '12 at 13:26
add comment

You can move conflicted files to other directory:

for i in *
do
    j=${i:0:16}

    if [ -e "$j" ]
    then
        mv "$i" /path/to/rename/later
    else
        mv "$i" "$j"
    fi
done
share|improve this answer
add comment

You can write a script to shorten file names and remove characters that Windows doesn't like in a few lines of bash. Warning, untested code, typed directly into my browser.

shopt -s dotglob extglob
for x in *; do
  y=${x//+([!-!#$%&'().0-9@A-Z^_`a-z{}~])/_}  # change all problematic characters to _
  if [[ $y = .* ]]; then y=_${y#.}; fi        # change dot files to begin with _
  y=${y:0:16}                                 # truncate names
  y=${y,,}                                    # convert to lowercase
  if [[ -e $y || $y =~ ^(aux|clock\$|com[0-9]|con|lpt[0-9]|nul|prn)(\.*)?$ ]]; then
    # The file exists or is a DOS/Windows reserved name.
    # Change foo.bar to foo~1.bar, foo~2.bar, ... (I ignore the length restriction here)
    i=1
    if [[ $y =~ \. ]]; then
      prefix=${y%%.*}; suffix=.${y#*.}
    else
      prefix=$y; suffix=
    fi
    y=${prefix}~$i$suffix
    while [[ -e $y ]]; do
      ((++i))
      y=${prefix}~$i$suffix
    done
  fi
  mv -- "$x" "$y"
done

If you need to recurse into subdirectories, call a shell script from find -depth -exec …. Or use zsh instead of bash; in zsh, **/*(od) expands to all the files under the current directory, recursively, with more deeply nested files first.

share|improve this answer
add comment

Shell/python/perl scripting for this kind of thing is just fine, but it seems like a gui app would be best for you, so I would recommend pyRenamer, which can do exactly what you want, among many other things (simple common operations via presets [getting rid of spaces, truncating filename from one point to another], simple search/replace, complicated regex, previewer, etc).

Your distribution might even have it in their software repository (Fedora does).

share|improve this answer
add comment

Some systems do not have the rename command, so as an alternative to paxdiablo's answer, here is how to do the same thing with mv.

for f in *.pdf; do 
    tmp=`echo $f | sed -r 's//^(.{5}).*(\..*)$/$1$2/'`
    mv -b ./"$f" ./"$tmp"
done

The -b flag on move creates a backup of files that would be deleted or overwritten. By changing the glob pattern in the for loop you can adjust what files it runs on, using * by itself to run on all files.

share|improve this answer
1  
No need to use echo and a pipe (could be very expensive if you have a lot of files), use a heredoc or herestring instead. –  Chris Down Feb 29 '12 at 13:48
1  
@ChrisDown see here. According to the wiki article, the piped processes are forked, but it says nothing about running them in their own shells. –  Spencer Rathbun Feb 29 '12 at 14:49
1  
For example, notice the difference between eval 'echo $BASH_SUBSHELL' and eval 'echo $BASH_SUBSHELL' | cat. –  Chris Down Feb 29 '12 at 15:36
2  
I just did a quick test, timeing a loop using echo $i | sed and another using sed ... <<<$i, and the herestring took about 2/3 the time of the echo. –  Kevin Feb 29 '12 at 19:39
1  
@SpencerRathbun Yes. << starts a here<i>doc</i>, which is multi-line and requires delimiters. <<< creates a here<i>string</i>, which just takes one variable/string. Try it out, var=abc // cat<<<$var // cat <<$var. –  Kevin Feb 29 '12 at 19:53
show 9 more comments

If you need to experiment with renaming files and happen to have KDE libraries installed on your system (or don't mind adding them), check out krename.

It allows you to do quite a few simple renaming tasks directly with its tools and also allows regular expressions for more complicated situations.

It shows you a preview of the renamed files as you build the renaming conditions. It also allows you to rename the same files again which is helpful if you want to do something complicated where doing it in stages would reduce the complexity of each stage to something you can figure out quickly.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.