5

I have a file system tree and on different locations within it are files with the same name. I tried the following command on the command line:

find / -name "HAHA" -exec mv {} /home \;

It only worked for one file, for the others I received an error message for having the same name.

Can I change the command in a way that for each file name a number will be attached to distinguish them?

enter image description here

  • If you don't need to keep the original name, you can always offload the action to a script that does something like mv "$0" /home/$(uuidgen) to give each file a new, unique name. Would such a solution be acceptable? – a CVn Feb 14 '15 at 14:45
  • sorry, I do not understand $0 and $(uuidgen) – Abdul Al Hazred Feb 14 '15 at 15:12
  • I tried to create a function to be given to find but it did not accept it. Creating a script worked but that did not allow the number to be incremented. I am interested in the solution myself now. – unxnut Feb 14 '15 at 15:26
4

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
  • 9
    Using xargs -x is highly recommended here. Otherwise, xargs might silently decide it would like to start several sequencial cpf processes, each of which would have their own counter and start overwriting the haha's already moved. – Henning Makholm Feb 14 '15 at 18:16
  • 1
    Or just remove xargs entirely and pipe the filenames to cpf (and modify cpf to read them from standard input) – immibis Feb 14 '15 at 21:59
9

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.

3

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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