How do I move all the files with the same name scattered through the file system into one folder?

I can think of two possible solutions:

  1. If you have installed mv from GNU coreutils (which probably is the case), then the following command...

    find / -name "HAHA" -type f -exec mv --backup=numbered "{}" /home \;
    

    ...will move all files called HAHA to /home. The --backup=numbered option of mv ensures that every time the mv command executes, it will check if there already exists a file named HAHA in the target directory -- and if it does, then it first renames it to HAHA.~n~ (where n is an increasing number) before moving the new file to the /home. In the end, you will end up with files named like HAHA, HAHA.~1~, HAHA.~2~ etc. in /home.

  2. This shell script should do the trick, but it is not resistant against paths containing newlines:

    IFS="
    "      # if you are using bash, you can just use IFS=$'\n' here
    i=1
    for file in $(find / -name "HAHA" -type f); do
      mv "${file}" "/home/HAHA${i}"
      i=$((${i} + 1))
    done
    

    This iterates over all the HAHA files and moves each one to /home/HAHAn, where n again is an increasing number, starting with 1.


I found a simple solution with a small script. The script is called cpf (or whatever name you give it) and is as follows:

#!/bin/bash

dir=xyz       # Directory where you want the files
num=1

for file in "$@"
do
    base=`basename -- "$file"`
    mv -- "$file" "$dir/$base.$num"
    num=$(($num+1))
done

You execute the command as follows:

find . -name HAHA -print0 | xargs -0x cpf

I would use while loop:

i=1
find / -name 'HAHA' -print0 | while read -d '' -r file; do mv "$file" "/home/${file##.*/}$((i++))"; done

Important here is print0 option of find which (together with -d '' option of read) treats properly files with white spaces in their names. If you need to do such operation only once then first line which sets i=1 is not needed since bash (and most of other shells) will simply created this variable automatically.