1

I inadvertently formatted a Time Machine backup external hard drive. I was able to recover many of the files, but not the names of those files.

All of the recovered files have generic names like "file01010101.doc", which is not helpful. In order to know which files are duplicates, I need to compare the recovered files the originals I have on my machine, and have them renamed accordingly. Then, any files that still have a generic name must be unique and not a duplicate.

Question: How do I do this automatically? Is there a program, bash script, or Automator action that can do duplicate file finding and renaming? There's almost 500,000 files, so doing this manually is not practical.

3

In this situation, renaming files is not the way to go!

As you stated in the OP, "There's almost 500,000 files, so doing this manually is not practical.", and as mention in my comment to the OP "I'd recommend checking out Gemini 2 which you can download a copy for free and run it to see what it finds. If you like the results you can consider purchasing it."... But I really didn't clarify why I mentioned an app that detects and deletes duplicates.

1. Make a new and current Time Machine backup of the e.g. Macintosh HD.
2. Use e.g., Gemini 2 to delete all duplicates from the recovered files.

What, delete all the duplicates!? ... Yes, with a current Time Machine backup of the e.g., Macintosh HD, why do you need to keep any duplicates!? You don't, as you'd already have properly named duplicates, and modified copies as applicable, of the files on the Macintosh HD on the Time Machine backup. Therefore, does it really make sense to waste time to rename any duplicates of the recovered files? I say No!

Now the files that remain in the recovered files are unique and you can decide from there how you want to proceed. You'll certainly have a much smaller number of files to decide whether or not you want to keep them, but it will not be an easy task to rename them to a meaningful name, as they are after all unique and do not have a meaningful name.

The files that do remain from the recovered files could be broken down into two groups, OS/Apps and User Data, the latter of which has more importance than the former. It should be relatively easy to create the two groups and get rid of the OS/Apps group as most of those files will be older than the current OS and of no real value. The User Data files, some may be files you've deleted from the Macintosh HD over time and the others may be modified copies of the deleted files and modified copies of the current files prior to the mishap. These are the ones you'll want to retain to search through as needed.

The most important thing in this situation is to have a current Time Machine backup of the e.g. Macintosh HD, and isolating unique User Data files within the recovered files, and is really the only point of sifting through the recovered files! Not messing around wasting time renaming files you already have on both the e.g. Macintosh HD and the Time Machine backup.


Note that I am a licensed user of the Gemini 2 app, but have no other affiliation with the developer MacPaw.

1

Here is a solution that I have tested several times and it seems to work. I'm sure someone with more experience can offer a solution which is much quicker than mine, but so far this is the best I can come up with.

I strongly suggest making a copy of your "recovered" files with generic file naming. Then I would run the following code on your copied files.

This AppleScript code works for me using the latest version of macOS Mojave.

Just paste this AppleScript code into Script Editor.app and you can run the code from there.

set genericFolder to (choose folder with prompt "Choose The Parent Folder Containing The Files To Be Renamed")
set sourceFolder to (choose folder with prompt "Choose The Parent Folder Containing The Files With Proper Names")

tell application "Finder"
    set genericFiles to files of entire contents of genericFolder as alias list
    set sourceFiles to files of entire contents of sourceFolder as alias list
end tell

repeat with genericFile in genericFiles
    repeat with sourceFile in sourceFiles
        try
            set isIdentical to (last word of (do shell script "diff -s " & quoted form of POSIX path of genericFile & " " & quoted form of POSIX path of sourceFile) is "identical") as boolean
            if isIdentical is true then
                tell application "System Events" to set name of genericFile to name of sourceFile
            end if
        end try
    end repeat
end repeat

This image is the folder and file structure before running the code. The source files are on the left image and the files to be renamed are on the right image. Take notice that the folder and file structures are different in both images.

enter image description here

This next image is the result after running the code

enter image description here

This solution was tested with only 38 files with generic names. On my system it took 1 minute and 33 seconds to process and rename the files accordingly. Without doing any actual math, if you are trying to process 500,000 files with this code, you could be looking at the better part of a full day for the process to complete. You may want to consider breaking the process down to processing a few folders at time, rather than the full mother load all at once.

However, if you are only looking to rename files with the name extension ".doc" , you can replace this code from above...

tell application "Finder"
    set genericFiles to files of entire contents of genericFolder as alias list
    set sourceFiles to files of entire contents of sourceFolder as alias list
end tell

With this code instead, which will make the process much much quicker.

tell application "Finder"
    set genericFiles to ((files of entire contents of genericFolder) whose name extension is "doc") as alias list
    set sourceFiles to ((files of entire contents of sourceFolder) whose name extension is "doc") as alias list
end tell

You can also have the code process only files with name extensions that you define, as in this following example.

set nameExtensions to {"doc", "pdf"}

tell application "Finder"
    set genericFiles to ((files of entire contents of genericFolder) whose name extension is in nameExtensions) as alias list
    set sourceFiles to ((files of entire contents of sourceFolder) whose name extension is in nameExtensions) as alias list
end tell
0

I would strongly recommend a total backup of all your data before proceeding. After that, create a new account and play-around from the new account.

"Advanced Bash-Scripting Guide" covers everything with numerous examples. http://www.tldp.org/guides.html It the fist manual listed. Bash is powerful but exacting.

Should be able to find what you need in the existing code. The code eliminates all duplicate files by moving only one copy of each unique file to a new directory. ( It's been 9 years since I worked on this code. It deletes things too. ) The existing code creates hashes of all the files in a folder. It compares the hashes to find duplicates. You should be able to substitute a rename at this point. It has code to create a unique name for some reason. The code contains extensive debugging code to create a log of it's doing. Turn on the log and follow what it is doing.

#!/bin/bash

# Purpose of this script:
#
# Accurately eliminate duplicate files within a given folder. Optionally, consolidate all files
# to a common folder.  Duplicate names within the consolidate folder will be made unique.
#
# Methodology:
# Find folders within a specified top folder which are not bundles. Find files
# within each found folder [and within subfolders ]. because each folder is 
# handled individually.)
# Find potential bundles and checksum their entire content as one item.
# Get MD5 checksums for each item and save an index of all checksums and
# filepaths. Sort the index by checksum.  Compare each
# item's checksum and if a duplicate is found, move the duplicate to the trash.
# Compare each item's name and if a duplicate is found, append incrementing #X 
# to the name prior to the last period (as in "Filename #2.jpg")
# Ignore iTunes and iPhoto folders 
#
# Optionally move files and potential bundles to the top-level folder
# Delete .DS_Store, .FBCIndex*, and .FBCSemaphoreFile files and subsequently 
# delete empty subfolders.  Optionally regroup map files into folders based on 
# the name of .frq file if found, or .shp file
#
# This script is a partial rewrite of the code from JulieJulieJulie's Consolidate17 script.  
# See:
#   http://discussions.apple.com/message.jspa?messageID=11577992#11577992
#
# additional discussion:
#   https://discussions.apple.com/thread/2434165?start=0&tstart=0
#   https://discussions.apple.com/thread/8276669
# 
#   Copyright 2018 rccharles
#
#   GNU General Public License 
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation,  version 3
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   For a copy of the GNU General Public License see 
#   <http://www.gnu.org/licenses/>.
#
copyRight="Copyright (c) 2010 & 2018 rccharles. GNU General Public License."
#
#


# debug info
export PS4='+(${BASH_SOURCE}:${LINENO}):'

## not in the tiger version of bash ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'


##########
### Functions (subroutines which can be called by name)

function helpHelpIsAllINeed () {
echo
echo "${savedCommandName##*/} [ options ] [ directory-to-compress ]"
echo
echo "options:"
echo "-h  Display quick help."
echo
echo "-m  Moving files is disabled." 
echo "-M  Move files to top level." 
echo
echo "-r  Regrouping map files is disabled." 
echo "-R  Regroup map files." 
echo
echo "-V  Display very detailed messages." 
echo
echo "example:"
echo "    ./${savedCommandName##*/} -mrV /Users/mac/cons/see"
echo
}

function Show_Time () {
let currentRunTime="$( date +%s ) - ${Seconds_since_the_epoch_start}"
let stepRunTime=currentRunTime-previousRunTime
echo "  Elapsed time in seconds since start of processing: ${currentRunTime}" \
     "   Time of this step: ${stepRunTime}"
echo
let previousRunTime=currentRunTime
}

function echoTrashInfo () {
    echo " -${trashFileName}"
    echo "${fileName} > ${trashFileName}" \
        >>"${saveFolder}/Consolidate_Trashed_List_${runDateTime}.txt"

    case "${fileType}" in
        f ) let trashFileCount+=1
            ;;
        d ) let trashDirectoryCount+=1
            ;;
        * ) Echo 
            Echo "Error --- Error in echoTrashInfo. fileName=${fileName};"
            Echo "Error --- fileType=${fileType};"
            Echo
            ;;
    esac    

}

declare     folder  \
            MainFolder  \
            MoveFiles="Question"    \
            RegroupMapFiles="Question"  \
            runDateTime=$(date '+%Y-%m-%d_%H.%M')   \
            Seconds_since_the_epoch_start   


declare -x  tab=$'\t'   \
            trashFolder \
            verbose="Yes"   \
            veryVerbose="Yes" \
            whereIsTrash


declare -i  count=0 \
            offsetMainFolder \
            currentRunTime \
            previousRunTime=0 \
            stepRunTime \
            trashDirectoryCount=0 \
            trashFileCount=0

declare -a  filePath    \
            fileName    \
            fileSum     \
            folders


savedCommandName="$0"
echo
echo "${savedCommandName} script revised $(GetFileInfo -m $0)"
echo
bigVersion="Lizard 4"

echo "=============================================================="
echo
echo "       ${bigVersion}"
echo "                    ${bigVersion}"
echo "                                 ${bigVersion}"
echo 
echo "=============================================================="
echo
echo "${copyRight}"
echo


# If the utility md5 is not present then just quit, it's needed for the checksums.
[ ! -x /sbin/md5 ] && exit 2

# Check for command-line options used when calling the script
if [ $# -gt 0 ] ; then
    while getopts "hmMrRV" Option ; do
        case "${Option}" in
        h ) helpHelpIsAllINeed
            echo "Bye for now."
            exit 7 
            ;;
        m ) echo "-m argument used on command line, moving files is disabled." 
            echo  
            MoveFiles="No" 
            ;;
        M ) echo "Moving files.  -M argument used on command line." 
            echo  
            MoveFiles="Yes" 
            ;;
        r ) echo "-r argument used on command line, regrouping map files is disabled." 
            echo
            RegroupMapFiles="No" 
            ;;
        R ) echo "Regrouping map files. -R argument used on command line." 
            echo
            RegroupMapFiles="Yes" 
            ;;
        V ) echo "Display very detailed messages. -V argument used on command line." 
            echo
            veryVerbose="Yes" 
            ;;
        * ) echo "Unknown argument among arguments $* on command line." 
            helpHelpIsAllINeed
            exit 6 
            ;;
        esac
    done
fi

# We're done with switches / options from the command line
shift $(($OPTIND - 1))

# Main folder can be declared on the command line or interactively
MainFolder="${1}"

# If the main folder doesn't exist, prompt once, then just quit if it's still not there.
if [ ! -d "${MainFolder}" ] ; then
    echo "Folder not specified. Type the path to the top-level folder or drag"
    echo "it into this Terminal window, then click back in this window and press return:"
    read MainFolder
    echo
fi

[ ! -d "${MainFolder}" ] \
    && echo "Folder not found. Was ${MainFolder}" \
    && exit 4

[ "${MainFolder}" = "/" ] \
    && echo "You must be crazy." \
    && exit 5

echo "Holding down Control-c on the keyboard will stop this script in an emergency."
echo

if [ "${MoveFiles}" = "Question" ] ; then
    echo "WARNING: allowing the script to move files could cause problems!"

    echo
    echo "Do you want to move all files and bundles to the top level at the end of the run?"
    read -n1 -p "Press 'n' to NOT move files and keep the folder structure intact; otherwise press any key. "
    if [ "${REPLY}" = "n" -o "${REPLY}" = "N" ] ; then
        MoveFiles="No"
    else
        MoveFiles="Yes"
    fi
    echo


fi

if [ "${RegroupMapFiles}" = "Question" ] ; then
    echo "Do you want to disable regrouping of map files into folders based on the .shp filename?"
    read -n1 -p "Press 'n' to NOT regroup map files; otherwise press any key. "
    if [ "${REPLY}" = "n" -o "${REPLY}" = "N" ] ; then
        RegroupMapFiles="No"
    else
        RegroupMapFiles="Yes"
    fi
    echo
fi

[ "${veryVerbose}" = "Yes" ] \
    && ulimit -a \
    && df \
    && echo

[ "${veryVerbose}" = "Yes" ] \
    && echo "MainFolder=${MainFolder};"

# get physical path 
if [ -d "$MainFolder" ]; then
    pushd $PWD
    cd "$MainFolder"
    MainFolder=$( /bin/pwd -P )
    popd
else
    # just to be sure.
    echo "You need to supply a directory name for ${MainFolder}"
    exit 8
fi  

let offsetMainFolder="${#MainFolder}"-1

# Ensure that the path is in a consistant format. i.e. no //
# drop trailing directory separator if needed
[ "${MainFolder:${offsetMainFolder}}" = "/" ] \
    && MainFolder="${MainFolder:0:${offsetMainFolder}}"

# Place all created files in one directory.
saveFolder="${MainFolder}/saved--Consolidated--Data"

# Figure out the trash folder name. Each user has his or her own trash folder.
# Each volume has a different trash folder. On the startup drive, 
# the trash folders are in the users home folder. On the other volumes, the 
# trash folder contains a folder with the user id for each user.
#
# This isn't perfect.  
if [ $( echo -n "${MainFolder:0:7}" | tr '[:upper:]' '[:lower:]' ) \
        = "/users/" ] ; then
    whereIsTrash="u"
    trashFolder="${HOME}/.Trash"
elif [  $( echo -n "${MainFolder:0:9}" | tr '[:upper:]' '[:lower:]' ) \
        = "/volumes/" ] ; then
    whereIsTrash="v"
    diskName="${MainFolder:9}"
    diskName="${diskName%%/*}"
    trashFolder="/Volumes/${diskName}/.Trashes"
    if [ ! -d ${trashFolder} ] ; then
        # Needs work.  Should be ok, since folder is created when formated.
        Echo "Creating trash folder. ${trashFolder};" 
        saveUmask=$( umask )
        mkdir ${trashFolder} 
        umask ${saveUmask}
    fi
    currentId=$( id -ru )
    trashFolder="${trashFolder}/${currentId}"
    if [ ! -d ${trashFolder} ] ; then
        Echo "Creating user's individual trash folder. ${trashFolder};"
        saveUmask=$( umask )
        umask 077
        mkdir ${trashFolder} 
        umask ${saveUmask} 
    fi
else
    echo "Not sure where main folder resides. defulat to ~/.Trash"
    whereIsTrash="u"
    trashFolder="${HOME}/.Trash"
fi


[ "${veryVerbose}" = "Yes" ] \
    && echo "MainFolder=${MainFolder};" \
    && echo "saveFolder=${saveFolder};" \
    && echo "trashFolder=${trashFolder};"



[ ! -d "${saveFolder}" ] \
    && mkdir "${saveFolder}"

#Housekeeping for Index files.

# If the index archive file does not exist, 
# create it so that it will be there for sorting and merging later
[ ! -e "${saveFolder}/Index_Archive.txt" ] \
    && touch "${saveFolder}/Index_Archive.txt"

# If the index file exists, archive it and be sure to delete the index.
if [ -e "${saveFolder}/Index.txt" ] ; then
    echo "----------------------------" >> "${saveFolder}/Index_Archive.txt" 
    cat "${saveFolder}/Index.txt" >> "${saveFolder}/Index_Archive.txt" 
    rm "${saveFolder}/Index.txt"
fi

touch "${saveFolder}/Index.txt"

# In case of a crash, clean up from previous run. 
[ -e "${saveFolder}/names.txt" ] \
    && rm "${saveFolder}/names.txt"

touch "${saveFolder}/names.txt"

# Ensure that the trashed list file will exist even if no files were trashed
[ ! -e "${saveFolder}/Consolidate_Trashed_List_${runDateTime}.txt" ] \
    && touch "${saveFolder}/Consolidate_Trashed_List_${runDateTime}.txt"

[ "${veryVerbose}" = "Yes" ] \
    && ls -l "${saveFolder}/Index.txt" \
    && ls -l "${saveFolder}/names.txt" \
    && ls -l "${saveFolder}/Consolidate_Trashed_List_${runDateTime}.txt" \
    && ls -ld "${trashFolder}" \
    && ls -ld "${trashFolder}/.." \
    && echo

echo "--> Deleting .DS_Store and .FBC files from subfolders."
find -d "${MainFolder}" -type f \( -name ".DS_Store" -o -name ".FBCIndex*" \
    -o -name ".FBCSemaphoreFile" \) -delete 


if [ "${veryVerbose}" = "Yes" ]  ; then
    echo "Gathering debug information.  May take a moment.  Counting files."
    fileCountBefore=$( find ${MainFolder} -type f \
        \! \(  -path "${saveFolder}" -o -path "${saveFolder}/*" \) \
        | wc -l )
    trashCountBefore=$( find ${trashFolder} -type f | wc -l )
fi

# Set the internal field separator to newline to preserve spaces in file paths
IFS=$'\n'

# Set the start time now that the user interaction is done
Seconds_since_the_epoch_start=$( date +%s )

##########
### Find items
echo "--> Finding folders and ignoring any folder whose name contains a period and it's content (potential packages)."


echo "--> then finding files & generating list of MD5 checksums for file content."


find "${MainFolder}" -type d \
    \! \( -name "*.*" -o -name "iPhoto Library" -o -name "iTunes" \) \
    \! \( -path "*/*.*/*" -o -path "*/iPhoto Library/*" -o -path "*/iTunes/*" \
          -o -path "${saveFolder}" -o -path "${saveFolder}/*" \) \
| (

while read folder
do

    [ "${veryVerbose}" = "Yes" ] \
    && echo "folder=${folder};"  

    # Perform a 'find' within each of the folders for files in that folder 
    # (and not in subdirectories) Skip hidden files.
    find "${folder}" -maxdepth 1 -type f \! -name ".*"  \
    | (

        while read theFilePath
        do
            # Get an MD5 checksum for each file's combined content of both
            # data and resource forks               
            fileCheckSum=$( cat "${theFilePath}" "${theFilePath}/rsrc" | md5 )
            echo " ${fileCheckSum}  ${theFilePath}" 
            echo "${fileCheckSum}${tab}f${tab}${theFilePath}" \
                >> "${saveFolder}/Index.txt"
        done
      )
done
)

Show_Time

echo "--> Finding and processing potential packages/bundles."
echo "--> Note; we look for a period in the base filename which" \
    "may not be acurate in all cases."
# Find folders within $MainFolder which are possible packages and bundles
find "${MainFolder}" -type d \
  \( -iname "*.*" -o -iname "iPhoto Library" -o -iname "iTunes" \) \
  \! \( -name ".*" -o -ipath "*/*.*/*" -o -ipath "*/iPhoto Library/*" \
        -o -ipath "*/iTunes/*" \) \
| ( 
    while read folder 
    do

        fileCheckSum=$( find "${folder}" -type f \! -name ".DS_Store" \
            -exec  cat '{}' '{}/rsrc' \; | md5 )

        echo "${fileCheckSum}  ${folder}" 
        echo "${fileCheckSum}${tab}d${tab}${folder}" >> "${saveFolder}/Index.txt"

    done
)   

######### ;;;;;;;;
echo
Show_Time

echo "--> Sorting list of files and potential bundles by checksum then"
echo "    Compare checksums."
sort -t "${tab}"  "${saveFolder}/Index.txt" | 
    (
        declare previousCheckSum=""

        declare -i trashCount=0

        # Process both files and application bundles.
        while read theData 
        do
            checkSum="${theData:0:32}"
            fileType="${theData:33:1}"
            fileName="${theData:35}"

            [ "${veryVerbose}" = "Yes" ] \
                && echo "${checkSum} ${fileName};"

            if [ "${checkSum}" = "${previousCheckSum}" ] ; then
                # Duplicate file. Move current file to trash.

                [ "${verbose}" = "Yes" ] \
                    && echo -n " ="

                # Make up trash name. 
                # Base name on path name so we can remember 
                # where file came from
                trashFileName="${fileName}"
                case "${whereIsTrash}" in
                u ) trashFileName="${trashFileName:7}"
                    trashFileName="${trashFileName#*/}" # chop user id
                    ;;
                v)  trashFileName="${trashFileName:9}"
                    ;;
                * ) echo "<><><><> Serious error. whereIsTrash=${whereIsTrash};"
                esac

                trashFileName=$(echo -n "${trashFileName}" | tr "/" "~" )
                trashFileName="${trashFolder}/${trashFileName}"

                # don't let a directory be copyied into another directory.
                # Happens with applications. 
                # Might as well avoid files too.
                [ ! -e "${trashFileName}" ] \
                    &&  mv -n "${fileName}" "${trashFileName}"

                if [ -e "${fileName}" ] ; then 
                    # Move didn't work.
                    myRandom=$RANDOM
                    trashFileName="${trashFileName}~$(date '+%Y-%m-%d_%H.%M')~${myRandom}"
                    mv -n "${fileName}" "${trashFileName}"

                    if [ -e "${fileName}" ] ; then
                        # Odd , second move didn't work.
                        echo
                        echo "big time error "
                        echo "<><> fileName=${fileName};" \
                            "myRandom=${myRandom}" \
                            "trashFileName=${trashFileName};"
                        echo
                    else
                        # Ok, moved file to trash
                        echoTrashInfo
                    fi
                else
                    # Ok, moved file to trash
                    echoTrashInfo
                fi 

            else
                # Output data for next step.
                # Mac OS X hfs+ defaults to case independent names, so
                # sort on lower case. 
                # ie A folder may not contain the names abc & Abc.
                lowerBaseName=$( echo -n "${fileName##*/}" | \
                    tr '[:upper:]' '[:lower:]' )
                echo "${lowerBaseName}${tab}${fileName}" \
                    >>"${saveFolder}/names.txt"
            fi
            previousCheckSum="${checkSum}"


        done

        outLine="Total trashed files: ${trashFileCount}"

        outLine="${outLine}  Total trashed applications/bundles: ${trashDirectoryCount}"
        echo  
        echo "${outLine}"
        echo
        {
            echo  
            echo "${outLine}"
            echo
        }>> "${saveFolder}/Consolidate_Trashed_List_${runDateTime}.txt"
    )


Show_Time



##########
### Compare names

echo "--> Sorting list of names."


# Sort (by basename) 
sort -t "${tab}"  "${saveFolder}/names.txt" |
(

    declare previousBaseName="" \
            baseName

    declare -i alterCount

    let alterCount=0

    while read theData 
    do
    echo "..${theData}"
        lowerBaseName="${theData%${tab}*}"  
        fileName="${theData#*${tab}}"
        baseName="${fileName##*/}"

        [ "${veryVerbose}" = "Yes" ] \
            && echo "${lowerBaseName}; ${baseName}; ${fileName};"

        if [ "${previousBaseName}" = "${lowerBaseName}" ] ; then

            [ "${verbose}" = "Yes" ] \
                && echo -n " ="

            # Rename files with duplicate names by appending #X prior to 
            # the filename extension (before the last period.)

            directoryName="${fileName%/*}"
            extension="${baseName##*.}" 

            # Was an extension found?
            if [ "${extension}" != "${baseName}" ] ; then
                # extension found, since a period was in the data
                extension=".${extension}"
                name="${baseName%.*}"
            else
                extension=""
                name="${baseName}"
            fi  

            while [ "1" = "1" ] ; do    # do forever... simulate do until

                let alterCount+=1
                actualAlteration="${alterCount}"

                if [ ${alterCount} -gt 9999 ] ; then
                    echo 
                    echo "================== odd: alterCount too big!!! "
                    echo "previousBaseName=${previousBaseName}; baseName=${baseName}; fileName=${fileName}; "
                    echo "================== odd: alterCount too big!!! "
                    echo
                    actualAlteration="${alterCount}${RANDOM}"
                    break
                fi

                # Manually implement do until. 
                # If file doesn't exist, break. Unused name found. 
                [ ! -e "${directoryName}/${name} #${actualAlteration}${extension}" ] \
                    && break

            done

            # rename
            newName="${directoryName}/${name} #${actualAlteration}${extension}"

            mv -n "${fileName}" "${newName}"
            if [ -e "${fileName}" ] ; then
                # Odd , rename didn't work.
                echo
                echo "another big time error "
                echo "<><><> fileName=${fileName};" \
                    "newName=${newName}" 
                echo
            else
                # all went well with rename
                echo " +${newName}" 
            fi


        else
            let alterCount=0    

        fi

        previousBaseName="${lowerBaseName}"

    done

)

Show_Time

##########
### Moving items to top-level
if [ "${MoveFiles}" = "Yes" ] ; then
    echo "--> Finding possible packages/bundles and moving them to the top-level."
    find "${MainFolder}" -mindepth 1 -type d \
    \( -iname "*.*" -o -iname "iPhoto Library" -o -iname "iTunes" \) \
    \! \( -name ".*" -o -ipath "*/*.*/*" -o -ipath "*/iPhoto Library/*" \
    -o -ipath "*/iTunes/*"  \)  \
        -exec mv -n '{}' "${MainFolder}" \; 

    echo "--> Finding files and moving them to the top-level."
    folders=( $(find "${MainFolder}" -mindepth 1 -type d \
    \! \( -name "*.*" -o -name "iPhoto Library" -o -name "iTunes" \) \
    \! \( -path "*/*.*/*" -o -path "*/iPhoto Library/*" -o -path "*/iTunes/*" \
    -o -path "${saveFolder}" -o -path "${saveFolder}/*"  \) ) )

    # Perform a 'find' within each of the folders for files in that folder 
    # (and not in subdirectories)
    for folder in ${folders[*]} ; do
    find "${folder}" -maxdepth 1 -type f \! -name ".*"  -exec mv -n '{}' "${MainFolder}" \;
    done
fi

echo "--> Deleting empty subfolders. (This only deletes folders which are completely empty.)"

find -d "${MainFolder}" -type d -empty -delete 


##########
### Regroup map files into their own folders
if [ "${RegroupMapFiles}" = "Yes" ] ; then
    echo "--> Finding map file groups in top-level and regrouping them to their own folders in the top-level."

    # deal with .frq first, .frq indicates group with differing filename end prior to .shp
    Maps=( $( find "${MainFolder}" -maxdepth 1 -iname "*.frq" ) )
    for Map in ${Maps[*]} ; do
        [ ! -e "${Map}" ] && continue
        [ "${Map}" = "" ] && continue
        fullfilename=$( basename "${Map}" )
        filename="${fullfilename%.*}"
        if [ ! -e "${saveFolder}/${filename}.map" ] ; then
            mkdir "${saveFolder}/${filename}.map"
            find "${MainFolder}" -maxdepth 1 -iname "${filename}*.*" -type f \
                -exec mv -n '{}' "${saveFolder}/${filename}.map" \;
        fi
    done

    Maps=( $( find "${MainFolder}" -maxdepth 1 -iname "*.shp" ) )
    for Map in ${Maps[*]} ; do
        [ ! -e "${Map}" ] && continue
        [ "${Map}" = "" ] && continue
        fullfilename=$( basename "${Map}" )
        filename="${fullfilename%.*}"
        if [ ! -e "${saveFolder}/${filename}.map" ] ; then
            mkdir "${saveFolder}/${filename}.map"
            find "${MainFolder}" -maxdepth 1 -iname "${filename}.*" -type f \
                -exec -n mv '{}' "${saveFolder}/${filename}.map" \;
        fi
    done
fi

Show_Time
echo

if [ "${veryVerbose}" = "Yes" ]  ; then
    echo "Gathering post run debug information.  May take a moment." \
        "Counting files."
    fileCountAfter=$( find ${MainFolder} -type f \
        \! \(  -path "${saveFolder}" -o -path "${saveFolder}/*" \) \
        | wc -l )
    trashCountAfter=$( find ${trashFolder} -type f | wc -l )
    let trashDiff=trashCountAfter-trashCountBefore
    let calculateFileCountAfter=fileCountAfter+trashDiff
    echo
    echo "Information on files and directories in folder/directory ${MainFolder}"
    echo "fileCountBefore=${fileCountBefore};" \
        "fileCountAfter=${fileCountAfter};" 
    echo
    echo "trashDiff=${trashDiff};     " \
        "trashCountBefore=${trashCountBefore};" \
        "trashCountAfter=${trashCountAfter};"
    echo
    echo "==========="  
    echo "calculateFileCountAfter=${calculateFileCountAfter};"
    echo
    if [ "${fileCountBefore}" -ne "${calculateFileCountAfter}" ] ;  then
        echo "- - - - - - - -"
        echo "- - - - - - - - Error: Some files have gone missing."
        echo "- - - - - - - -" \
            "fileCountBefore should be equal to calculateFileCountAfter"
        echo "- - - - - - - - Where files deleted from the trash?"
        echo "- - - - - - - -"
    fi

fi
echo "DONE."
echo "NOTE: Invisible files and files with unresolved name conflicts may be left within any remaining subfolders!"
echo
echo "${savedCommandName} script revised $(GetFileInfo -m $0)"
echo 
echo "Bye from ${bigVersion}"
echo


exit 0

Here is an example of the output:

https://pastebin.com/zVWRDA9E

additional references.

This script is a partial rewrite of the code from JulieJulieJulie's Consolidate17 script.
See:

http://discussions.apple.com/message.jspa?messageID=11577992#11577992

additional discussion:

https://discussions.apple.com/thread/2434165?start=0&tstart=0

https://discussions.apple.com/thread/8276669

You must log in to answer this question.

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