1

I have a task to copy all files from multiple directories with special names to a target directory.

So I build this directory to test my command. The test directory tree looks like:

.
├── dir1
│   └── file1
└── test

My intended command to mv all files from dir1 to test is:

find . -type d -name "*dir*" -exec mv {}/* test \;

Then I got:

mv: rename ./dir1/* to test/*: No such file or directory

I guess this is because in that extra -exec expression, the command didn't treat the * as a wildcard.

So I did:

find . -type d -name "*dir*" -exec mv {}/file1 test \;

Which successfully moved file1 to test.

But the point is, I need to now the expression for all files so that I can accomplish this file transfer work.

How should I express that in the find -exec command group?

3 Answers 3

2

mv "$dir_path"/* ... will not only move files but everything in "$dir_path". At least everything whose name does not start with a dot (hidden files). In bash you can change this with the option dotglob. But if the * expands nicely (matches everything but not too much for a command line) then you can use a shell for indirection:

find . -type d -name "*dir*" -exec bash -c 'mv "$0"/* /path/to/test' {} \;
3
  • 1
    what does the end \; mean? Can them be omitted? I'm been have this doubt for a long time.
    – Zen
    Jan 16, 2015 at 9:13
  • The ; is the end of the -exec block (other tests / commands may follow). But as it is also a shell control operator it must be quoted for becoming part of the command line. You could use ';' or ";". Jan 16, 2015 at 9:22
  • 1
    Don't interpolate {} inside a shell script. That can't work unless you know that the file names are restricted to a “tame” set of characters. When you use {} inside a shell snippet, the file name is interpreted as a piece of shell syntax instead of being correctly treated as a string. Pass the file name as an argument instead. Cc @Zen Jan 16, 2015 at 22:45
2

Try:

$ find -type d -name '*dir*' -exec sh -c '
  for d do
    for f in "$d"/*; do
      [ -f "$f" ] && mv -- "$f" /path/to/test
    done
  done
' sh {} +
4
  • Have you tried that? I guess -exec doesn't allow arguments between {} and +. You need mv -t /path/to/test -- {} +. Jan 16, 2015 at 4:54
  • @HaukeLaging: Oh, my bad, It had another error that only one instance of {} is allowed. I changed my solution.
    – cuonglm
    Jan 16, 2015 at 5:54
  • This is too complicate.
    – Zen
    Jan 16, 2015 at 9:22
  • @Zen: Yes, the extra work to copy files only.
    – cuonglm
    Jan 16, 2015 at 9:25
0

You might try this as well . Considering the test directory is in the same directory with other directories ,

find . -mindepth 2  ! -name test -exec cp {} test \;

This will copy all individual files to the directory test , escaping the dir1 , dir2 etc. Note that this will omit subdirectories itself and copies contents of them. you can also test this by using ls command.

find . -mindepth 2  ! -name test -ls 

You must log in to answer this question.

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