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?
Best Answer
It's not an endless looping, it's just GNU
find
reporting thatecho
died of a SIGPIPE (because the other end of the pipe on stdout has been closed whenhead
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 BSDfind
(assuming your BSD find exits upon its child dying of a SIGPIPE as the wording of your question suggests, FreeBSDfind
doesn't in my tests and does runecho
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-exec
uted command could still die of a SIGPIPE for other reasons than the pipe on stdout being closed, so exitingfind
for that would be borderline acceptable.With GNU
find
, you can tellfind
to quit if a command fails with: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: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: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:
echo
will still be run for every file, will still fail, but this time, it will beecho
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 BSDfind
and copied later by GNUfind
.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 thatfind . -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 GNUfind
. 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:Or more efficiently:
which you can simplify to
if you can guarantee file paths don't contain newline characters (IIRC, some versions of OS/X had such files in /etc though).
GNUly:
As to whether:
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 offind
starts with-
or is afind
predicate (like!
, or(
), so GNUfind
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 reasonPOSIXLY_CORRECT
would affect thefind
behaviour there.