Why GNU find -execdir command behave differently than BSD find?

kenorb

On my OSX, I've installed GNU find next to default BSD find via: brew install findutils.

As far as I understand, BSD find is following POSIX standards and GNU makes it optional (as per this post), which makes a lot of inconsistencies in expected output.

For example:

BSD find

$ find -L /etc -execdir echo {} ';' | head
etc
AFP.conf
afpovertcp.cfg
aliases
aliases.db
apache2
extra
httpd-autoindex.conf
httpd-dav.conf
httpd-default.conf

GNU find

$ gfind --version
find (GNU findutils) 4.4.2
$ POSIXLY_CORRECT=1 gfind -L /etc -execdir echo {} ';' | head
/etc
/etc/AFP.conf
/etc/afpovertcp.cfg
/etc/aliases
/etc/aliases.db
/etc/apache2
/etc/apache2/extra
/etc/apache2/extra/httpd-autoindex.conf
/etc/apache2/extra/httpd-dav.conf
/etc/apache2/extra/httpd-default.conf
gfind: `echo' terminated by signal 13
gfind: `echo' terminated by signal 13
... endless loop here

Note: I'm using -L above as my /etc is link to private/etc.

In GNU find manual I can see that I can specify POSIXLY_CORRECT to follow POSIX standard, however this doesn't work for above example.

Any other way of forcing the same output (e.g. POSIX standard) for GNU find for above example?

Apart of endlessly looping, why GNU prints relative filenames and BSD prints full paths instead?

Stéphane Chazelas

It's not an endless looping, it's just GNU find reporting that echo died of a SIGPIPE (because the other end of the pipe on stdout has been closed when head died).

-execdir is not specified by POSIX. And even for -exec, there's nothing in the POSIX spec that says that if the command is killed by a SIGPIPE, find should exit.

So, would POSIX specify -execdir, gfind would probably be more POSIX conformant than your BSD find (assuming your BSD find exits upon its child dying of a SIGPIPE as the wording of your question suggests, FreeBSD find doesn't in my tests and does run echo in a loop for every file (like for GNU find, not endless)).

You may say that for most common cases, find exiting upon a child dying of SIGPIPE would be preferable, but the -executed command could still die of a SIGPIPE for other reasons than the pipe on stdout being closed, so exiting find for that would be borderline acceptable.

With GNU find, you can tell find to quit if a command fails with:

find . ... \( -exec echo {} \; -o -quit \)

As to whether a find implementation is allowed or forbidden to report children dying of a signal on stderr, here (with the usage of -execdir) we're outside the scope of POSIX anyway, but if -exec was used in place of -execdir, it seems that would be a case where gfind is not conformant.

The spec for find says: "the standard error shall be used only for diagnostic messages" but also says there:

Default Behavior: When this section is listed as "The standard error shall be used only for diagnostic messages.", it means that, unless otherwise stated, the diagnostic messages shall be sent to the standard error only when the exit status indicates that an error occurred and the utility is used as described by this volume of POSIX.1-2008.

Which would indicate that since find doesn't return with a non-zero exit status in that case, it should not output that message on stderr.

Note that by that text, both GNU and FreeBSD find would be non-compliant in a case like:

$ find /dev/null -exec blah \;; echo "$?"
find: `blah': No such file or directory
0

where both report an error without settng the exit-status to non-zero. Which is why I raised the question on the austin-group (the guys behind POSIX) mailing list.

Note that if you change your command to:

(trap '' PIPE; find -L /etc -execdir echo {} \; | head)

echo will still be run for every file, will still fail, but this time, it will be echo reporting the error message.


Now about filename vs /etc/filename vs ./filename being displayed.

Again, -execdir being not a standard option, there's no text that says who's right and who's wrong. -execdir was introduced by BSD find and copied later by GNU find.

GNU find has done some intentional changes (improvements) over it. For instance, it prepends file names with ./ in the arguments passed to commands. That means that find . -execdir cmd {} \; doesn't have a problem with filenames starting with - for instance.

The fact that -L -execdir doesn't pass a filepath relative to the parent directory is actually a bug that affects version 4.3.0 to 4.5.8 of GNU find. It was fixed in 4.5.9, but that's on the development branch and there hasn't been a new stable release since (as of 2015-12-22, though one is imminent).

More info at the findutils mailing list.

If all you want is print the base name of every file in /etc portably, you can just do:

find -L /etc -exec basename {} \;

Or more efficiently:

find -L ///etc | awk -F / '/\/\// && NR>1 {print last}
                          {if (NF > 1) last = $NF
                           else last = last "\n" $NF}
                          END {if (NR) print last}'

which you can simplify to

find -L /etc | awk -F / '{print $NF}'

if you can guarantee file paths don't contain newline characters (IIRC, some versions of OS/X had such files in /etc though).

GNUly:

find -L /etc -printf '%f\n'

As to whether:

find -exec echo {} \;

in the link you're referring to, is POSIX or not.

No, as a command invocation, that is not POSIX. A script that would have that would be non-compliant.

POSIX find requires that at least one path be given, but leaves the behaviour unspecified if the first non-option argument of find starts with - or is a find predicate (like !, or (), so GNU find behaviour is compliant, so are implementations that report an error (or treat the first argument as a file path even if it represents a find predicate) or spray red paint at your face, there's no reason POSIXLY_CORRECT would affect the find behaviour there.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

find with -execdir

From Dev

How does find -execdir <command> + work?

From Dev

Why does jQuery behave differently than javascript?

From Dev

Why does PowerShell behave differently than cmd.exe given the same command?

From Dev

C++ Why does the iterators behave differently when used with the find function?

From Dev

GNU coreutils `sort` behave differently

From Dev

Why does "include" behave differently in the global context than it does in a class?

From Dev

Clojure - Why does into behave differently with a list than a vector?

From Dev

Why does width:auto behave differently than height:auto?

From Dev

Why does "include" behave differently in the global context than it does in a class?

From Dev

Why would Ctrl-C behave differently than kill -2

From Dev

Reason why a shell command behave differently depending on OS

From Dev

find command works differently in zsh and bash

From Dev

find command works differently in zsh and bash

From Dev

Why do I end up with 4 invocations instead of 3 when using this find -execdir {} + (plus)?

From Dev

Why does strerror_r behave differently when compiled with gnu90 and c90 standards?

From Dev

Why does sem (GNU parallel) behave differently with single quotes and double quotes?

From Dev

Why does sem (GNU parallel) behave differently with single quotes and double quotes?

From Dev

Using `find`, how can I get `rm` to print a fuller path name than it does when executed through `-execdir`?

From Dev

Why alias behave different than running bash command directly?

From Dev

Why locate is faster than find?

From Dev

Why do Ruby procs/blocks with splat arguments behave differently than methods and lambdas?

From Dev

Why do lodash's .isObject, .isPlainObject behave differently than "typeof x === 'object'"?

From Dev

Why does F# Interactive behave differently than compiler with regards to immutable value definition?

From Dev

Why does .foreach behave differently than for...of when executing a recursive callback?

From Dev

Why does less css behave differently when served over port 80 than other ports?

From Dev

Why does F# Interactive behave differently than compiler with regards to immutable value definition?

From Dev

Why does `curl <this machine's IP>` behave differently than `curl localhost`?

From Dev

Why whould xterm behave differently than x-terminal-emulator when it points to the same executable?

Related Related

  1. 1

    find with -execdir

  2. 2

    How does find -execdir <command> + work?

  3. 3

    Why does jQuery behave differently than javascript?

  4. 4

    Why does PowerShell behave differently than cmd.exe given the same command?

  5. 5

    C++ Why does the iterators behave differently when used with the find function?

  6. 6

    GNU coreutils `sort` behave differently

  7. 7

    Why does "include" behave differently in the global context than it does in a class?

  8. 8

    Clojure - Why does into behave differently with a list than a vector?

  9. 9

    Why does width:auto behave differently than height:auto?

  10. 10

    Why does "include" behave differently in the global context than it does in a class?

  11. 11

    Why would Ctrl-C behave differently than kill -2

  12. 12

    Reason why a shell command behave differently depending on OS

  13. 13

    find command works differently in zsh and bash

  14. 14

    find command works differently in zsh and bash

  15. 15

    Why do I end up with 4 invocations instead of 3 when using this find -execdir {} + (plus)?

  16. 16

    Why does strerror_r behave differently when compiled with gnu90 and c90 standards?

  17. 17

    Why does sem (GNU parallel) behave differently with single quotes and double quotes?

  18. 18

    Why does sem (GNU parallel) behave differently with single quotes and double quotes?

  19. 19

    Using `find`, how can I get `rm` to print a fuller path name than it does when executed through `-execdir`?

  20. 20

    Why alias behave different than running bash command directly?

  21. 21

    Why locate is faster than find?

  22. 22

    Why do Ruby procs/blocks with splat arguments behave differently than methods and lambdas?

  23. 23

    Why do lodash's .isObject, .isPlainObject behave differently than "typeof x === 'object'"?

  24. 24

    Why does F# Interactive behave differently than compiler with regards to immutable value definition?

  25. 25

    Why does .foreach behave differently than for...of when executing a recursive callback?

  26. 26

    Why does less css behave differently when served over port 80 than other ports?

  27. 27

    Why does F# Interactive behave differently than compiler with regards to immutable value definition?

  28. 28

    Why does `curl <this machine's IP>` behave differently than `curl localhost`?

  29. 29

    Why whould xterm behave differently than x-terminal-emulator when it points to the same executable?

HotTag

Archive