3

I am using a simple script to create some directories. Finding some specific files by name and then moving them into the directories that I have created. The code that I am using is below:


mkdir ./3DBGB_run   
mkdir ./run_optimization   
mkdir ./run_optimization/project_mesh   
mkdir ./run_optimization/CFD_optimized    
find . -name '*.template' -exec mv -i {} ./3DBGB_run \;                 
find . -name '3dbgbinput.*.dat' -exec mv -i {} ./3DBGB_run \;           
find . -name 'controlinputs.*.dat' -exec mv -i {} ./3DBGB_run \;            
find . -name '*.iec' -exec mv -i {} ./run_optimization/project_mesh \;           
find . -name '*.trb' -exec mv -i {} ./run_optimization/project_mesh \;  
find . -name '*.py' -exec mv -i {} ./run_optimization \;**

Code runs and moves the files to the desired directories but then it also display an error message for each file that "cannot move file because it is the same file"

4
  • @rye kayo how do I post a question with code written as you have suggested the edit?
    – Syed Moez
    Dec 26, 2014 at 20:02
  • I would.. Makes the question a bit easier to read
    – ryekayo
    Dec 26, 2014 at 20:02
  • @rye kayo yes you are right. how do I post the question like this. I dont know how to write code like you have suggested. Can you tell me so that I can post better next time.
    – Syed Moez
    Dec 26, 2014 at 20:04
  • The {} symbol will wrap your code in a block and highlight it in the grey background you see.
    – ryekayo
    Dec 26, 2014 at 20:05

2 Answers 2

3

You should avoid search in target directory. So you can add ! -path $TARGET_DIR as for example:

find . -name '*.template' ! -path "*3DBGB_run/*" -exec mv -it ./3DBGB_run {} \+
7
  • It still gives the same error. It moves the file and then for each file it says mv: ./3DBGB_run/controlinputs.12.dat.template' and ./3DBGB_run/controlinputs.12.dat.template' are the same file whereas I only have one such file and it is moved to the desired directory and then it displays the error.
    – Syed Moez
    Dec 26, 2014 at 20:16
  • @SyedMoez Add some changes. Try again.
    – Costas
    Dec 26, 2014 at 20:19
  • I am using this now {main_directory=$(pwd) mkdir ./3DBGB_run find . -name '*.template' ! -path $main_directory -exec mv -i {} ./3DBGB_run \;} still the same error
    – Syed Moez
    Dec 26, 2014 at 20:23
  • Command should be find "$main_directory" -name '*.template' ! -path "$main_directory/3DBGB_run*" -exec mv -i {} ./3DBGB_run \+
    – Costas
    Dec 26, 2014 at 20:59
  • This works. but with \; at the end if I use \+ then i get a missing argument to '-exec' error. so the find command was finding the same file in two directories the original one and once after moving it
    – Syed Moez
    Dec 26, 2014 at 21:52
2

find is finding your files twice: in the place where they started, and where you moved them to. That means it ends up running:

mv -i 3DBGB_run/x.template 3DBGB_run/x.template

and produces the error you see.

find sees files "live" as it goes - it doesn't build up a list in advance and then run the command for everything in the list. The order that it looks at files and directories is undefined (it's likely to come from the filesystem), so it will happen for every file that's examined before the directory you move it into.

Because find doesn't know what you're doing in the -exec, it can't compensate for it. You can do a couple of things about this:

  1. Exclude the directories from the search space: find . -name '*.template' -path "./3DBGB_run" -prune -o -exec mv -i {} ./3DBGB_run \;. The -path part matches the directory you're moving things into, and -prune then excludes that whole tree from recursion. -o causes the rest of the command (your original -exec) to run the rest of the time. The command never runs on files inside the directory. (This is an explicit example in the manual of GNU find)
  2. Build up the list in advance of the move. This may be better in some circumstances, but if your filenames have spaces or other IFS characters then it doesn't work out so well. If that doesn't apply, something like:

    files=$(find . -name '*.template')
    mv "${files[@]}" 3DBGB_run
    

    will also work.


When you're using find -exec, ending the command with + instead of ; will make find run the minimum number of commands, collecting multiple arguments into each execution, which is more efficient. Sometimes that doesn't work for a particular command, but it would be fine here. If this is a one-time command it doesn't really matter, but if you run it a lot then saving processes will save time.

2
  • I am using the second method. It works, Also if I use \+ i am getting an error.
    – Syed Moez
    Dec 26, 2014 at 21:34
  • There was a stray ! in the command - I took it out now. If you've solved your issue with the other method that's fine, though. Dec 26, 2014 at 22:19

You must log in to answer this question.

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