15

I use the following command to clear a directory, of files and directories over 30 days old, and move them to an archive directory which I can delete after a few weeks if nobody asks for their files back. The target directory has subdirectories by user name, so will the archive directory.

This is the command I use:

find /path/to/directory/username/ -mtime +30 -exec mv "{}" /path/to/archive/username/ \;

I suggested a modified version of this to answer a question on ask ubuntu, another user edited the code to change the end of line \; for + as it's faster(and more correct?). See here

However, using + in this way works if the -exec command is ls -lh but not in the actual command that I use. If I try it with + I get an error message:

find: missing argument to '-exec'

I don't understand why it's behaving this way, or what the correct command would be. Please don't just post a command correction, I'd like to understand rather than just follow a suggestion blindly.

Arronical
  • 19,893

2 Answers2

19

The user in that post may said that the + sign at the end of a -exec command is faster, but not why.

Lets assume the find command return the following files:

/path/to/file1
/path/to/file2
/path/to/file3

The normal -exec command (-exec command {} \;) runs once for each matching file. For example:

find ... -exec mv {} /target/ \;

Executes:

mv /path/to/file1 /target/
mv /path/to/file2 /target/
mv /path/to/file3 /target/

If you use the + sign (-exec command {} +) the command is build by adding multiple matched files at the end of the command. For example:

find ... -exec mv -t /target/ {} +

Executes:

mv -t /target/ /path/to/file1 /path/to/file2 /path/to/file3

To use the + flag correctly the argument to process must be at the end of the command, not in the middle. That's why find trows missing argument to '-exec' in your example; it misses the closing {}.

chaos
  • 27,506
  • 12
  • 74
  • 77
  • I've always wondered why find -exec requires the {} to be the last arg, when used with +. Anyone know why that design decision was made, instead of letting constructs like the OP's command line work? – Peter Cordes Jul 09 '15 at 03:05
11

The user explained their edit....

'+' exec's terminator is faster than '\;' see https://askubuntu.com/questions/558817/what-is-the-difference-between-using-and-in-exec-command; and creating a backup file from original file is good idea

...using this link. I think basically instead of using multiple commands, it sends all the filenames to one command instance, to speed things up. Here is a example from here:

Using -exec with a semicolon (find . -exec ls '{}' \;), will execute

ls file1
ls file2
ls file3

But if you use a plus sign instead (find . -exec ls '{}' \+), all filenames will be passed as arguments to a single command:

ls file1 file2 file3

There are other forms available using ; and + as well (from here:)

Therefore the following example syntax is allowed for find command:

find . -exec echo {} \;
find . -exec echo {} ';'
find . -exec echo {} ";"
find . -exec echo {} \+
find . -exec echo {} +

HOWEVER, I'm not sure this will work with the move command anyway, as it's syntax is mv [OPTION]... SOURCE DEST, unless the -t option or similar is used. However it should work with ls with no extra options etc as they can understand when multiple filenames are given. The + may also need to be escaped (i.e. \+)

Wilf
  • 30,194
  • 17
  • 108
  • 164
  • Both great answers, but I've got to give it to chaos for being a tiny bit quicker, and explaining the mv -t, both +1s though! – Arronical Jul 08 '15 at 14:05