Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I have a project with many files, located in several sub-directories. Dropbox somehow replaced the latest versions of some of those files with an old version and renamed the latest ones by adding " (Johns in Konflikt stehende Kopie 2013-03-17).txt" to tmen.

Now, I need to rename all files that have that addition " (Johns in Konflikt stehende Kopie 2013-03-17)" to the original filename, removing the old "authoritative" version (as Dropbox saw them).

Is there a shell script or something to run in terminal for a certain directory, which would do this recursively on a target directory?

For example: "filename (Johns in Konflikt stehende Kopie 2013-03-17)" should be renamed to "filename" and in case there was already a file called filename, remove that first.

share|improve this question

2 Answers 2

This worked for me:

while read -r i;
do
        old_file=${i%%(*}
        rm $old_file
        mv "$i" "$old_file"
done <<< "$(find | grep "2013-03-17)$")"

Before:

./files/filename2 (Johns in Konflikt stehende Kopie 2013-03-17)
./files/filename2
./files/filename (Johns in Konflikt stehende Kopie 2013-03-17)
./files/filename
./files/subfolder/filename (Johns in Konflikt stehende Kopie 2013-03-17)
./files/subfolder/filename

After:

./files/filename 
./files/filename2 
./files/subfolder/filename 

Do a backup of your files just in case.

Explanation:

while read -r i; <<< "$(find | grep "2013-03-17)$")" reads all lines from the output of that command, which returns path/filename for all files ending in 2013-03-17) -- you might need to add the extension of the file or get only the filename.

old_file=${i%%(*} sets old_file as everything in the string outputed by the find command, that is, filename (Johns in Konflikt stehende Kopie 2013-03-17) and all others, as everythig before (, that is, filename.

rm $old_file removes the old files, that is, everything named filename and filename2

mv "$i" "$old_file" renames filename (Johns in Konflikt stehende Kopie 2013-03-17) to filename

share|improve this answer

Based on Alex's answer I wrote a script that lets you interactively go through the list of conflicted files and decide if you want to use the copy flagged as conflicted by Dropbox to replace the plain copy.

#!/bin/bash

counter=0
resolved=0
diffprompt=true 
mvprompt=true
mvall=false 
while read -r i
do
    if [ ! -f "$i" ]; then
        break;
    fi
    echo 
    echo "Found conflicted file:"
    echo "    $i"
    old_file=`echo "$i" | sed 's/ (.*)//g'`
    echo "    $old_file"
    if [ "$diffprompt" = true ]; then
        echo
        while true; do
            prompt1="Show diff between the two files [y/n]?"
            prompt2="press q to quit, r to stop diff prompts"
            read -p "...$prompt1 ($prompt2)" yn </dev/tty
            case $yn in
                [Yy]* ) diffuse "$i" "$old_file"; break;;
                [Nn]* ) break;;
                [Qq]* ) exit;;
                [Rr]* ) diffprompt=false; break;;
                * ) echo "Please answer yes or no.";;
            esac
        done
    fi

    if [ "$mvall" = true ]; then
        mv "$i" "$old_file"
    elif [ "$mvprompt" = true ]; then
        echo
        while true; do
            prompt3="Keep the conflicted version and"
            prompt4="overwrite the plain version [y/n]?"
            prompt5="press q to quit, r to stop mv prompts,"
            prompt6="a to move all files without prompting again"
            read -p "...$prompt3 $prompt4 ($prompt5 $prompt6)" yn </dev/tty
            case $yn in
                [Yy]* ) mv "$i" "$old_file"; resolved=$((resolved+1)); break;;
                [Aa]* ) mv "$i" "$old_file"; mvall=true; break;;
                [Nn]* ) break;;
                [Qq]* ) exit;;
                [Rr]* ) mvprompt=false; break;;
                * ) echo "Please answer yes or no.";;
            esac
        done
    fi
    counter=$((counter+1))
done <<< "$(find . -name '*(pmd-laptop*2014-08-06)*')"

# please note that my conflict device is called 'pmd-laptop'
# and that the date of the conflict is '2014-08-06'
# replace those in the find string according to your case

echo 
echo "Total number of conflicts = $counter"
echo "Conflicts resolved = $resolved"
share|improve this answer
    
Interesting. (1) If any of the original filenames contain parentheses preceded by a space (e.g., foo (bar)), your script will mangle them (although it is an improvement over Alex’s). (2) If the user types a to automatically move all remaining files, those subsequent moves are not counted towards the “Conflicts resolved” ($resolved). (3) I believe, especially for such a long loop body, that find … | while read … is more understandable than while read … <<< $(find …). Also, if the find output is very large, the $(find …) construct might fail. –  Scott Aug 7 at 20:08

Your Answer

 
discard

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.