Can you recommend me a script or app?

I have a samba share that was previously hosted by and accessed by Windows operating systems. As a result the filenames of all the files are not very command-line/linux friendly. I need to get a script or app that can go through the samba share recursively and change all file names to lowercase and replace spaces in the names with a “.”, “_” or something. Anyone have any suggestions?

Please backup your files before attempting.

Try this


##Set IFS to help with files with spaces
IFS=$'
'

##Get files
for FILE in $(find /some/dir -type f)
do
     ##Replace .'s with _'s
     NEWFILE=`echo ${FILE} | sed s/"\."/"_"/g`
     ##Set everything to lowercase
     NEWFILE=`echo ${NEWFILE} | tr [A-Z] [a-z]`
     ##Rename file
     mv ${FILE} ${NEWFILE}
done

unset IFS

Good luck,
Hiatt

Thanks. There are several hundred GB in the share so it will take a good while to back up and I wont start it this evening…ill let you know how well it worked as soon as I do get it all done, maybe within a couple of days if I can get to it before the weekend.

On 2011-04-06 03:36, jthiatt08 wrote:
>
> Please backup your files before attempting.

You can also run first time with echo, and change to mv when satisfied.


Cheers / Saludos,

Carlos E. R.
(from 11.2 x86_64 “Emerald” at Telcontar)

Sorry, I found a problem with the original script, here is a revision.
This will replace spaces with “_”


##Set IFS to help with files with spaces
IFS=$'
'

##Get files
for FILE in $(find /some/dir -type f)
do
     ##Replace .'s with _'s
     NEWFILE=`echo ${FILE} | sed s/" "/"_"/g`
     ##Set everything to lowercase
     NEWFILE=`echo ${NEWFILE} | tr [A-Z] [a-z]`
     ##Rename file
     mv ${FILE} ${NEWFILE}
done

unset IFS

robin_listas makes a good point, you can replace mv with echo to see what the file renaming will look like.

Good luck,
Hiatt

That was a great Idea, thx for suggesting it.

The script worked like a charm, will installing the Russian lang support on my PC make it work on the Russian characters also? Or will I need different code for that?

  
Snip from the file I piped the echo to: 

./mnt/vol-1/Media.Misc/Video.music/AVSEQ17.DAT ./mnt/vol-1/media.misc/video.music/avseq17.dat
./mnt/vol-1/Media.Misc/Video.music/Сливки- Буду любить.MPG ./mnt/vol-1/media.misc/video.music/Сливки-.Буду.любить.mpg
./mnt/vol-1/Media.Misc/Video.music/АКАДЕМИЯ-Я ОБИДИЛАСЬ.DAT ./mnt/vol-1/media.misc/video.music/АКАДЕМИЯ-Я.ОБИДИЛАСЬ.dat
./mnt/vol-1/Media.Misc/Video.music/глюкоза.DAT ./mnt/vol-1/media.misc/video.music/глюкоза.dat

I found that and fixed it before I tested it. It has worked like a charm on the echo test run, except for non standard characters. ::slight_smile:

Ok, I made a few modifications so the script requests input and then executes. The only issue I am finding so far is that it works with an echo test but not a real run. The problem is that it only runs against files and not folders, but the case changing changes the entire path string so when it attempts to write the new file with a modified name it cannot find the path since the case in the folder names no longer match. Any ideas how to fix that? Also, im rather new at this so any suggestions on cleaning up the code itself will be appreciated.


#! /bin/bash


# *********************This is the original code submitted to me by jthiatt08 here:
# **http://forums.opensuse.org/english/get-technical-help-here/applications/457475-can-you-recommend-me-script-app.html
# 
# ##Set IFS to help with files with spaces
# IFS=$'
'
# 
# ##Get files
# for FILE in $(find /some/dir -type f)
# do
#      ##Replace .'s with _'s
#      NEWFILE=`echo ${FILE} | sed s/"\."/"_"/g`
#      ##Set everything to lowercase
#      NEWFILE=`echo ${NEWFILE} | tr [A-Z] [a-z]`
#      ##Rename file
#      mv ${FILE} ${NEWFILE}
# done
# 
# unset IFS


##Set IFS to help with files with spaces
IFS=$'
'

RUNSCRIPT="no"


until  "$RUNSCRIPT" == "yes" ] ; do  ## loop through the questions until clear signal to execute is given

clear  ##Helps when rerunning the script for debugging

      echo "This script will recursivly change one ascii character to another and/or change the case of the characters."
      echo "Case change is performed first so the character modification will supercede it."

      ## Get the path to the root folder for your operation and verify it is valid and accessable.
      echo -n "Please enter the path to the folder you wish to run in. (Default is ./):"
      read RTPATH
      if  "$RTPATH" == "" ] ; then  #Test for a blank entry and assign it the value of ./
	    RTPATH='./'
      else
	    while  ! -d $RTPATH ] ; do  #The while loop tests the path until it is given one that is accessable.
		  echo
		  echo "\"$RTPATH\" is not recognized as a valid path, or it is not accessable."
		  echo -n "Please enter the path to the folder you wish to run in.:"
		  read RTPATH
	    done
      fi

      ## Determine if the user wants to change the case of the file and folder names
      echo
      echo "Do you wish to change the case of file and folder names?"
      echo -n "(U for uppercase, l for Lowercase or Enter for no change):"
      read CASE
      if  "$CASE" == "U" ] ; then
	    CASEMESSAGE="All file and folder names will be changed to uppercase."
      elif  "$CASE" == "l" ] ; then
	    CASEMESSAGE="All file and folder names will be changed to lowercase."
      else
	    CASEMESSAGE="No change will be made to the case of file and folder names."
      fi

      ## Determine if the user wants to perform a find and replace during the operation and if so get the required information.
      echo
      echo "Do you wish to perform a find and replace?"
      echo -n '(Press "Enter" to skip find and replace or enter the string or character you want replaced.):'
      read STRORIG
      if  "$STRORIG" == "" ] ; then
	    FANDP="no"
	    FANDPMESSAGE="You have chosen not to perform a find and replace operation."
      else
	    echo -n "What character or string would you like to replace it with?:"
	    read STRREP
	    FANDP="y"
	    FANDPMESSAGE="You have chosen to replace \"$STRORIG\" with \"$STRREP\" in every file and folder name."
      fi

	## Determine if the user wants to do a test run first and identify the file name and path to pipe the data to.
      echo
      echo -n "Do you want to do a test run to see what changes will be made? (n or [y]):"
      read TESTRUN
      if  "$TESTRUN" == "n" ] ; then
	    break ;
      else TESTRUN="y"
	   FCFILE="$HOME/fileconvert.txt"
      fi
	    

      echo
      echo "The path you are going to work on is: $RTPATH"
      echo
      echo $CASEMESSAGE
      echo 
      echo $FANDPMESSAGE
      echo 
      echo -n "Is this correct? (Type \"yes\" to accept, Ctrl+c to quit, any other input will assume \"no\" and repeat the questions):"
      read RUNSCRIPT
done


 ##Get files
 for FILE in $(find $RTPATH -type f)
 do
      ##Perform find and replace if needed
      if  "$FANDP" == "y" ] ; then
	NEWFILE=`echo ${FILE} | sed s/"$STRORIG"/"$STRREP"/g`
      fi

      ##Change case if l or U was selected
      if  "$CASE" == "l" ] ; then
	NEWFILE=`echo ${NEWFILE} | tr [A-Z] [a-z]`
      elif  "$CASE" == "U" ] ; then
	NEWFILE=`echo ${NEWFILE} | tr [a-z] [A-Z]`
      fi
      ##Rename file  or print potential changes to a text document.
      if  "$TESTRUN" == "n" ] ; then
	   mv ${FILE} ${NEWFILE}
      else echo ${FILE} ${NEWFILE} >> $FCFILE
      fi
 done
 
 unset IFS


On 2011-04-15 06:36, Avanesov79 wrote:
>
> Ok, I made a few modifications so the script requests input and then
> executes. The only issue I am finding so far is that it works with an
> echo test but not a real run. The problem is that it only runs against
> files and not folders, but the case changing changes the entire path
> string so when it attempts to write the new file with a modified name it
> cannot find the path since the case in the folder names no longer match.

man basename


Cheers / Saludos,

Carlos E. R.
(from 11.2 x86_64 “Emerald” at Telcontar)

I like the changes, well played sir. :slight_smile:

Hiatt

Thanks ::slight_smile:

I have the earlier problems fixed. I had to use the suggested “basename” as well as “dirname” to separate the path from the file/folder name and only perform the operations on the name, then rejoin them for the move. Apparently “find” also does its complete search in the beginning so to avoid looking for a folder in a path name that changed I had to remove the “-type f” from find so it would organize the list by directory structure and pipe it to “sort -r” so it would execute on the deepest files/folders first to avoid invalid path errors.

Also added an if statement so if the new and old files matched it would skip them instead of issuing an error (or trying to copy a folder into itself).

If anyone would like to run a few tests on this for problems I havent found it would be great. ::slight_smile:


#! /bin/bash

## Filenameconvert.bash
## Avanesov79 Opensuse forums
## This script will allow you to recursively change the case of file and directory names, and/or perform a find and replace.
## Making a test run to see the potential changes to a file is also an option.

# *********************This is the original code submitted to me by jthiatt08 here:
# **http://forums.opensuse.org/english/get-technical-help-here/applications/457475-can-you-recommend-me-script-app.html
# 
# ##Set IFS to help with files with spaces
# IFS=$'
'
# 
# ##Get files
# for FILE in $(find /some/dir -type f)
# do
#      ##Replace .'s with _'s
#      NEWFILE=`echo ${FILE} | sed s/"\."/"_"/g`
#      ##Set everything to lowercase
#      NEWFILE=`echo ${NEWFILE} | tr [A-Z] [a-z]`
#      ##Rename file
#      mv ${FILE} ${NEWFILE}
# done
# 
# unset IFS
#***************************************************************************************************************************


##Set IFS to help with files with spaces
IFS=$'
'

RUNSCRIPT="no"  ## Set Variable so until loop will continue until changed.

until  "$RUNSCRIPT" == "yes" ] ; do  ## loop through the questions until clear signal to execute is given

clear  ##Helps when rerunning the script for debugging

## Set variables to safe defaults in case of possible leftovers from previous loop.##
	RTPATH="$HOME/foo/bar"
	CASE=""
	FANDP="no"
	STRORIG=""
	STRREP=""
	TESTRUN="y"

	echo "This script will recursively change the case of file and folder names and/or perform a find and replace."
	echo "Case change is performed first so the find and replace will supersede it."
	echo
	echo "***"
	## Get the path to the root folder for your operation and verify it is valid and accessable.
	echo -n "Please enter the path to the folder you wish to run in. (Default is ./):"
	read RTPATH
	if  "$RTPATH" == "" ] ; then  #Test for a blank entry and assign it the value of ./
		RTPATH='./'
	else
		while  ! -d $RTPATH ] ; do  #The while loop tests the path until it is given one that is accessable.
			echo
			echo "\"$RTPATH\" is not recognized as a valid path, or it is not accessible."
			echo 'Try removing any variables such as "$HOME", "./" or "~/" if present and enter the full path.'
			echo -n "Please enter the path to the folder you wish to run in.:"
			read RTPATH
		done
	fi

	echo "***"

	## Determine if the user wants to change the case of the file and folder names
	echo
	echo "Do you wish to change the case of file and folder names?"
	echo -n "(U for uppercase, l for Lowercase or Enter for no change):"
	read CASE
	if  "$CASE" == "U" ] ; then
		CASEMESSAGE="All file and folder names will be changed to uppercase."
	elif  "$CASE" == "l" ] ; then
		CASEMESSAGE="All file and folder names will be changed to lowercase."
	else
		CASEMESSAGE="No change will be made to the case of file and folder names."
	fi

	echo "***"

	## Determine if the user wants to perform a find and replace during the operation and if so get the required information.
	echo
	echo "Do you wish to perform a find and replace?"
	echo -n '(Press "Enter" to skip find and replace or enter the string or character you want replaced.):'
	read STRORIG
	if  "$STRORIG" == "" ] ; then
		FANDP="no"
		FANDPMESSAGE="You have chosen not to perform a find and replace operation."
	else
		echo -n "What character or string would you like to replace it with?:"
		read STRREP
		FANDP="y"
		FANDPMESSAGE="You have chosen to replace \"$STRORIG\" with \"$STRREP\" in every file and folder name."
	fi

	echo "***"

	## Determine if the user wants to do a test run first and identify the file name and path to pipe the data to.
	echo
	echo -n "Do you want to do a test run to see what changes will be made? (n or [y]):"
	read TESTRUN
	if  "$TESTRUN" == "n" ] ; then
		TESTMESSAGE="You have chosen not to perform a test run, files will be modified."
	else TESTRUN="y"
		FCFILE="$HOME/filenameconvert.txt"
		TESTMESSAGE="You have chosen to perform a test run, no files will be modified at this time. Output will be piped to $FCFILE."
	fi

	echo "***"

	## Repeat choices for user to verify and confirm execution.
	echo "*********************************************************************************************************************"
	echo
	echo "The path you are going to work on is: $RTPATH"
	echo
	echo $CASEMESSAGE
	echo 
	echo $FANDPMESSAGE
	echo 
	echo $TESTMESSAGE
	echo
	echo -n 'Is this correct? (Type "yes" to accept, Ctrl+c to quit, any other input will assume "no" and repeat the questions):'
	read RUNSCRIPT
	echo "*********************************************************************************************************************"
done

echo "***************************************************************"
echo "***** Executing your requested modifications, please wait.*****"
echo "***************************************************************"

##Get files
for FILE in $( find $RTPATH | sort -r ) ; do
	NEWFILE=`basename $FILE` ## Get the name of the file or directory
	PATHNAME=`dirname $FILE`  ## Get the path to the file or directory

	##Change case if l or U was selected
	if  "$CASE" == "l" ] ; then
		NEWFILE=`echo ${NEWFILE} | tr [A-Z] [a-z]`
	elif  "$CASE" == "U" ] ; then
		NEWFILE=`echo ${NEWFILE} | tr [a-z] [A-Z]`
	fi

	##Perform find and replace if needed
	if  "$FANDP" == "y" ] ; then
		NEWFILE=`echo ${NEWFILE} | sed s/"$STRORIG"/"$STRREP"/g`
	fi

	NEWFILE="$PATHNAME/$NEWFILE"  ## Recreate the full path to the modified file or directory

	##Rename file or print potential changes to a text document.
	if  "$TESTRUN" == "n" ] ; then
		if  "${FILE}" != "${NEWFILE}" ] ; then  ## Only make a change if the original and new files do not match
			mv ${FILE} ${NEWFILE}
		fi
	else echo ${FILE} ${NEWFILE} >> $FCFILE
	fi
done

unset IFS