On Sun, Dec 20, 2015 at 7:54 PM, Stephane Chazelas <stephane.chaze...@gmail.com> wrote: > 2015-12-20 18:30:36 +0000, James Youngman: >> On Fri, Dec 18, 2015 at 11:43 PM, Stephane Chazelas >> <stephane.chaze...@gmail.com> wrote: >> >> > At that Q&A, we also discuss the behaviour of GNU find when both >> > -L and -execdir are used for which I think at least the >> > documentation could benefit from some clarification.
For those just joining us, that Q&A is http://unix.stackexchange.com/questions/250191/why-gnu-find-execdir-command-behave-differently-than-bsd-find/250194 >> Could you be more specific? > [...] > > Hi James > > Well what I wrote at the link was quite explicit. But to expand > a bit: > > -execdir cmd {} is a feature introduced by BSDs and there, is > explicitely documented to run cmd from within dirname(file) and > where {} is expanded basename(file). > > In the GNU find documentation, it's less clearly stated, but it > mostly says the same thing. > > What -execdir does is more described in the -exec section: > > -- Action: -exec command ; > This insecure variant of the '-execdir' action is specified by > POSIX. The main difference is that the command is executed in the > directory from which 'find' was invoked, meaning that '{}' is > expanded to a relative path starting with the name of one of the > starting directories, rather than just the basename of the matched > file. > > > It says with -execdir, {} is the basename of the file which > (without -L) is not completely true as it's "./" concatenated > with the basename of the file. > > With -L (and it's not documented except in a comment in the > code, again see http://unix.stackexchange.com/a/250194), cmd is > not run from dirname(file), and {} is not "./" basename(file), Right; that comment is http://git.savannah.gnu.org/cgit/findutils.git/tree/find/exec.c?id=v4.5.14#n86 :- /* Record the WD. If we're using -L or fts chooses to do so for any other reason, state.cwd_dir_fd may in fact not be the directory containing the target file. When this happens, rel_path will contain directory components (since it is the path from state.cwd_dir_fd to the target file). We deal with this by extracting any directory part and using that to adjust what goes into execp->wd_for_exec. */ Not stated there is the fact that -L is implemented in ftsfind by turning on the FTS_LOGICAL flag of fts. The gnulib fts implementation forces FTS_CWDFD off for this case: /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ if (ISSET(FTS_LOGICAL)) { SET(FTS_NOCHDIR); CLR(FTS_CWDFD); } The {} in -execdir always expands to the relative path to the file we're considering. I don't want to document that this is dependent on the setting of -L since that's a bug (see below). > it's mostly the same as -exec. > > /tmp/test$ mkdir -p 1/2/3 > /tmp/test$ find . -exec pwd \; -exec echo {} \; > /tmp/test > . > /tmp/test > ./1 > /tmp/test > ./1/2 > /tmp/test > ./1/2/3 > /tmp/test$ find . -execdir pwd \; -execdir echo {} \; > /tmp/test > ./. > /tmp/test > ./1 > /tmp/test/1 > ./2 > /tmp/test/1/2 > ./3 > /tmp/test$ find -L . -execdir pwd \; -execdir echo {} \; > /tmp/test > ./. > /tmp/test > ././1 > /tmp/test > ././1/2 > /tmp/test > ././1/2/3 > > > > Ideally, I'd say it would be better if GNU find behaviour was > the same as BSD's (where above you'd get the same output with > and without -L. I agree. > > If not (as I agree it won't make much difference from a security > point of view as we're following links anyway), IMO the behaviour > should be documented (along with the fact that it diverges from > the original BSD implementation). Trying your example with recent find code ($PWD here is the root of a freshly built findutils tree), though, I don't get the same result. It looks to me as if the the behaviour you're describing is a previously reported and fixed bug (https://savannah.gnu.org/bugs/?27563). That bug was fixed in version 4.5.9 (and apparently affects the current stable release): $ for binary in `pwd`/installed-64/bin/find-* ; do ( mkdir -p tmp/1/2/3 && cd tmp && printf "%-8s %s\n" "$(echo ${binary} | sed -e 's_^.*/find-__')" "$(${binary} -L . -mindepth 3 \( -execdir pwd \; , -execdir ls -d {} \; \) | tr '\n' ' ')" && rm -rf tmp); done | sort -V 4.2.21 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.22 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.23 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.24 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.25 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.26 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.27 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.28 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.29 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.30 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.31 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.32 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.2.33 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.3.0 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.1 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.2 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.3 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.4 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.5 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.6 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.7 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.9 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.10 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.11 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.12 /home/james/source/GNU/findutils/tmp ././1/2/3 4.3.13 /home/james/source/GNU/findutils/tmp ././1/2/3 4.4.0 /home/james/source/GNU/findutils/tmp ././1/2/3 4.4.1 /home/james/source/GNU/findutils/tmp ././1/2/3 4.4.2 /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.0 /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.1 /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.2 /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.3 /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.4 /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.5 /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.6b /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.6 /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.7 /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.8 /home/james/source/GNU/findutils/tmp ././1/2/3 4.5.9 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.5.10 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.5.11 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.5.12 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.5.13 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.5.14 /home/james/source/GNU/findutils/tmp/1/2 ./3 4.5.15 /home/james/source/GNU/findutils/tmp/1/2 ./3 Relevant bugfix: http://git.savannah.gnu.org/cgit/findutils.git/commit/?id=e1d0a991e96ee164d74579efc027b09336e50c79 Tests: http://git.savannah.gnu.org/cgit/findutils.git/commit/?id=a1f54022d1913a92ccb728211127d5c238397eb6 Thanks, James.