Find -Exec Cmd {} + VS | Xargs

find -exec cmd {} + vs | xargs

Speed difference will be insignificant.

But you have to make sure that:

  1. Your script will not assume that no
    file will have space, tab, etc in
    file name; the first version is
    safe, the second is not.

  2. Your script will not treat a file starting with "-" as an option.

So your code should look like this:

find . -exec cmd -option1 -option2 -- {} +

or

find . -print0 | xargs -0 cmd -option1 -option2 --

The first version is shorter and easier to write as you can ignore 1, but
the second version is more portable and safe, as "-exec cmd {} +" is a relatively new option in GNU findutils (since 2005, lots of running systems will not have it yet) and it was buggy recently. Also lots of people do not know this "-exec cmd {} +", as you can see from other answers.

Which is faster, 'find -exec' or 'find | xargs -0'?

I expect the xargs version to be slightly faster as you aren't spawning a process for each filename. But, I would be surprised if there was actually much difference in practice. If you're worried about the long list xargs sends to each invocation of rm, you can use -l with xargs to limit the number of tokens it will use. However, xargs knows the longest cmdline length and won't go beyond that.

Using semicolon (;) vs plus (+) with exec in find

This might be best illustrated with an example. Let's say that find turns up these files:

file1
file2
file3

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 '{}' \+), as many filenames as possible are passed as arguments to a single command:

ls file1 file2 file3

The number of filenames is only limited by the system's maximum command line length. If the command exceeds this length, the command will be called multiple times.

Solution for find -exec if single and double quotes already in use

In a double quoted string you can use backslashes to escape other double quotes, e.g.

find ... "rm \"\$(...)\""

If that is too convoluted use variables:

cmd='$(...)'
find ... "rm $cmd"

However, I think your find -exec has more problems than that.

  • Using {} inside the command string "cd '{}' ..." is risky. If there is a ' inside the file name things will break and might execcute unexpected commands.
  • $() will be expanded by bash before find even runs. So ls -t *.pdf | tail -2 will only be executed once in the top directory . instead of once for each found directory. rm will (try to) delete the same file for each found directory.
  • rm "$(ls -t *.pdf | tail -2)" will not work if ls lists more than one file. Because of the quotes both files would be listed in one argument. Therefore, rm would try to delete one file with the name first.pdf\nsecond.pdf.

I'd suggest

cmd='cd "$1" && ls -t *.pdf | tail -n2 | sed "s/./\\\\&/g" | xargs rm'
find . -type d -name bak -exec bash -c "$cmd" -- {} \;

find -exec - suppress errors only for find, but not for executed command

Using -exec option in find command is integration of xargs command into find command.

You can alwayes separate find from -exec by piping find output into xargs command.

For example:

 find / -type f -name "*.yaml" -print0 2>/dev/null | xargs  ls -l

Execute bash function from find command

You could manually loop over find's results.

while IFS= read -rd $'\0' file; do
remodup "$file"
done < <(find "$dir" -name "*.mod" -type f -print0)

-print0 and -d $'\0' use NUL as the delimiter, allowing for newlines in the file names. IFS= ensures spaces as the beginning of file names aren't stripped. -r disables backslash escapes. The sum total of all of these options is to allow as many special characters as possible in file names without mangling.

How do I use a pipe in the exec parameter for a find command?

Try this

find /path/to/jpgs -type f -exec sh -c 'jhead -v {} | grep 123' \; -print

Alternatively you could try to embed your exec statement inside a sh script and then do:

find -exec some_script {} \;


Related Topics



Leave a reply



Submit