Truncate file name to 40 characters

Hello all.

I would like to make a script (or two shell scripts) that will do the following.

I need the maximum file name and directory name to be 38 characters long.
As well, if shortening the file name ends up making all of the files in that directory have the same name, then I would like the script to recognize this problem and then append numbers to the end of the file name. For example, the files shown below would have the same name if shortened to 38 characters.:

becomes

and

becomes

so they have the same name, hence I would like to add a suffix of two digit numbers, starting at 01. So the originals would become

As well, I need to replace any occurrence of " [<>=?:;"*+,|]" in both the directory and file name with an underscore "_".

So, the script would modify the following directory

to

[quote]
/home/music/The Best of the Rat Pack _ more/

AND it would change the following file names located in that directory

to

I would need this to work recursively on all of the directories below /home/music/.

I found this "ruby" script using google, but it does not help with appending numbers to file names that are the same once truncated. Perhaps someone knows how to modify it so it does what I want it do do:confused:. I hope this helps:

    #!/usr/bin/ruby

# usage xbox_prep.rb DIRECTORY_NAME

DirName = ARGV[0]
file_name = ""          # name of the file to be checked
old_full_path = ""      # name and path of the file to be checked
new_full_path = ""      # new name and path of the file (modified if necessary)
basename = ""           # basename of the file
extension = ""          # extension of the file to be checked


if DirName == nil
        puts "usage:"
        puts ""
        puts "xbox_prep.rb DIRECTORY_NAME"
        puts ""
else

Dir.foreach(DirName){
        |file_name|
        if file_name != "." and file_name !=".."
         old_full_path = DirName + "/" + file_name
         basename = File.basename(old_full_path, ".*")
         extension = File.extname(old_full_path)


         # Modify the basename if neccessary
         basename.slice!(38,128)                        # shorten basename to 38 chars
         basename.gsub!(/[<>=?:;"*+,|]/,'_')            # Remove invalid characters

         # rename the file
         new_full_path = DirName + "/" + basename + extension
         File.rename(old_full_path, new_full_path)
         puts basename + extension

        end
}

end
  

Many thanks in advance for the help with this.

Try this bash/ksh script that renames the files in the current directory.

rename_seq ()
{
  seq=1
  oldname="$1"
  newname="$2"
  ext="$3"
  while [ -e "$newname$(printf "%02d" $seq).$ext" ]; do
    (( seq ++ ))
  done
  mv "$oldname.$ext" "$newname$(printf "%02d" $seq).$ext"
}

ls | while read name; do
  ext="${name##*.}"
  name="${name%.*}"
  newname="${name//[<>=?:;\"*+,|]/_}"
  newname="${newname:0:38}"
  if [ -e "${newname}.$ext" ]; then
    rename_seq "$newname" "$newname" "$ext"
  fi
  if [ -e "${newname}"??".$ext" ]; then
    rename_seq "$name" "$newname" "$ext"
  else
    mv "$name.$ext" "$newname.$ext"
  fi
done

Hi and thanks for helping me out.

DO I need to add

#!/bin/bash

at the beginning of this script to work and also, does it work recuresively?

My situtation is such that I have directory structure

/home/music/ARTIST_NAME/ALBUM/

and there are about 1800 folders (artists) in the music folder.

Again, my gratitude for the help

Updates base on Scrutinizer's script.

#! /bin/bash
i
# rename function

rename_seq ()
{
  seq=1
  oldname="$1"
  newname="$2"
  ext="$3"
  subpath="$4"
  while [ -e "$newname$(printf "%02d" $seq).$ext" ]; do
    (( seq ++ ))
  done
  mv "$subpath/$oldname.$ext" "$subpath/$newname$(printf "%02d" $seq).$ext"
}

BASE=/home/music/ARTIST_NAME/ALBUM
cd $BASE

# Rename filename first

find . -type f -print | while read name; do
  name=${name##*/}
  subpath=${name%/*}
  ext="${name##*.}"
  name="${name%.*}"
  newname="${name//[<>=?:;\"*+,|]/_}"
  newname="${newname:0:38}"
  if [ -e "${newname}.$ext" ]; then
    rename_seq "$newname" "$newname" "$ext" "$subpath"
  fi
  if [ -e "${newname}"??".$ext" ]; then
    rename_seq "$name" "$newname" "$ext" "$subpath"
  else
    mv "$subpath/$name.$ext" "$subpath/$newname.$ext"
  fi
done

# Rename directories' name

find . type d -print |while read Dname; do
  newDname="${Dname//[<>=?:;\"*+,|]/_}"
  mv "Dname" "newDname"
done

Is there a way I can trouble shoot this without actually making anything happen?

And also, can I use ">& logfile.txt" to pipe the output from the script to a logfile that I can see what is happening?

Thanks again for everyone's help so far.

I am testing with just one directory in the /home/music/ directory.

It is as follows "/home/music/B-52's, The/Cosmic Thing/B-52's, The - Rock Lobster.mp3"

I tried running it and this is what I got:

mv: cannot stat `B-52\'s, The.B-52\'s, The': No such file or directory

Am I doing something wrong?

Perhaps it is the quotes in the file names. You could try:

newname="${name//[[:punct:]]/_}"

Instead of the collection of characters..

Thanks [COLOR=Black][COLOR=\#22229C]Scrutinizer.

I tried replacing it with

but I get the following:

mv: cannot stat `B-52\'s, The.B-52\'s, The': No such file or directory
mv: cannot stat `xboxmusicrenamer.sh': No such file or directory

thanks again:)

OK.

After doing some testing, I have found that the following script works, but on files only. Also, the script itself must be in the same directory as the files for it to work. I also changed the extension to "mp3" only as that is the only file type I want to rename.

#! /bin/bash

rename_seq ()
{
  seq=1
  oldname="$1"
  newname="$2"
  ext="$3"
  while [ -e "$newname$(printf "%02d" $seq).$ext" ]; do
    (( seq ++ ))
  done
  mv "$oldname.mp3" "$newname$(printf "%02d" $seq).mp3"
}

ls | while read name; do
  ext="${name##*.}"
  name="${name%.*}"
  newname="${name//[[:punct:]]/_}"
  newname="${newname:0:38}"
  if [ -e "${newname}.mp3" ]; then
    rename_seq "$newname" "$newname" "mp3"
  fi
  if [ -e "${newname}"??".$ext" ]; then
    rename_seq "$name" "$newname" "mp3"
  else
    mv "$name.mp3" "$newname.mp3"
  fi
done

Could someone please help me with doing this same process but recursively from the /home/music directory and also apply the renaming to the directories as well?

Maybe I didn't explain better before, but I have my music organized in folders by artist name and beneath that, by album name.

For example,

/home/music/Beatles, The/Abbey Road/Because.mp3
/home/B-52's, The/Cosmic Thing/B-52's, The - Rock Lobster.mp3

Hence the script should search through all of the directories and rename them to 38 characters and remove any instances of punctuation marks and hyphens.

Thanks again to Sychronizer and rdcwayx for their help so far.

do you see my reply in page 1? It had already included the process to rename directory.

Below code (also included) can be used to fix your another problem: the script itself must be in the same directory as the files for it to work.

BASE=/home/music/ARTIST_NAME/ALBUM
cd $BASE

Hi rdcwayx.

I did see your reply and I am grateful for your help, but it doesn't work.

This is my output from the terminal.

marco@marco-desktop:~/Music$ ./both.sh
./both.sh: line 2: i: command not found
./both.sh: line 19: cd: /home/marco/Music/ARTIST_NAME/ALBUM: No such file or directory
mv: cannot stat `just_files.sh/just_files.mp3': No such file or directory
mv: cannot stat `just_files.sh/just_files.mp3': No such file or directory
mv: cannot stat `B_52_s_ The _ Rock Lobster99999999999999999999999999999999.mp3/B_52_s_ The _ Rock Lobster99999999999999999999999999999999.mp3': No such file or directory
mv: cannot stat `B_52_s_ The _ Rock Lobster999999999999999999999999999999.mp3/B_52_s_ The _ Rock Lobster999999999999999999999999999999.mp3': No such file or directory
mv: cannot stat `Folder.jpg/Folder.mp3': No such file or directory
mv: accessing `both.sh/both.mp3': Not a directory
mv: accessing `both.sh~/both.mp3': Not a directory
mv: cannot stat `Dname': No such file or directory
mv: cannot stat `Dname': No such file or directory
mv: cannot stat `Dname': No such file or directory
marco@marco-desktop:~/Music$ 

As I mentioned in my last post, in /home/marco/music/ there are about 1800 folders each corresponding to a particular musical artist. Then below each artist is an album folder. And in each album folder are the .mp3 files that I want to rename. There is also a file called "folder.jpg" in each album folder that doesn't need renaming that is why I replaced the "$ext" with "mp3" in the script.
To give an example:

/home/marco/Music/B-52's, The/Cosmic Thing/B-52's, The - Rock Lobster.mp3
/home/marco/Music/Pink Floyd/Dark Side of the Moon/Pink Floyd - Money.mp3

I guess the problem is that it is not changing to the proper directory?

Also, when I run the script you suggested it does not rename any of the files, while the one in my last post will rename the files.

I am very new and don't understand too well the scripting language but I am trying so bear with me please:).