and some quick checks, these commands list files or dirs in ".", and none
in subdirs of ".". (Pls let me know if and why this is not a good idiom to use.)
--
The purpose of this post is to understand why the above
find works. I think prune is like 'next' in awk or perl.
I do not understand what "-name ." is doing.
Theory:
A file may not be named "."; find therefore sees -name "."
as referring to the dirname of the pathname being examined;
so "-name ." will be true for files in ".", but not for subdirs.
Can anyone come up w/better explanation? My theory does not explain
why "find . \( -name . -o -prune \) -type d -print" works.
>and some quick checks, these commands list files or dirs in ".", and none
>in subdirs of ".". (Pls let me know if and why this is not a good idiom
>to use.)
It's a little bit tricky, but I don't see anything wrong with it. If you just
want subdirectories of the current directory, expanding the glob "*/" is
probably better. If you have GNU find, -maxdepth 1 is easier to read.
>The purpose of this post is to understand why the above
>find works. I think prune is like 'next' in awk or perl.
>I do not understand what "-name ." is doing.
Since you started with "find .", the first file to be tested is "." which
matches the "-name ." predicate. That's on the left side of the -o operator,
which sort-circuits, so the -prune operator is not applied.
The "-name ." predicate will be false for everything else, regardless of
whether it's a file or directory, so the -prune will apply.
When the file being tested is not a directory, -prune is a no-op returning
true. When the file being tested *is* a directory, -prune disables recursion
into that directory, and returns true.
So except for the initial test of the top of the hierarchy, "-name ." is
false and "-prune" is true and recursion is disabled for all directories.
FALSE OR TRUE = TRUE so the parenthesized expression is true, and processing
continues with the -type. (There's an implicit AND between predicates that
don't have a -o between them.)
>> and some quick checks, these commands list files or dirs in ".", and none
>> in subdirs of ".". (Pls let me know if and why this is not a good idiom
>> to use.)
> […]
>> The purpose of this post is to understand why the above
>> find works. I think prune is like 'next' in awk or perl.
>> I do not understand what "-name ." is doing.
> Since you started with "find .", the first file to be tested is "." which
> matches the "-name ." predicate. That's on the left side of the -o
> operator, which sort-circuits, so the -prune operator is not applied.
No. Each directory on a Unixoid system contains a hidden file named `.' which points to itself. (And a hidden file named `..' pointing to its parent directory.)
The first `.' in the find(1) command line, indeed all positional arguments before the first option is/are considered to be the directory path(s) from where to start the search; in this case the current directory. It is equivalent to `./'. (That positional argument is optional in GNU find and defaults to the current directory.)
As always, find(1) searches recursively from that directory but because of `-name .' only considers the contents of the directory named so, IOW that current directory. Then …
> The "-name ." predicate will be false for everything else, regardless of
> whether it's a file or directory, so the -prune will apply.
> When the file being tested is not a directory, -prune is a no-op returning
> true. When the file being tested *is* a directory, -prune disables
> recursion into that directory, and returns true.
Essentially true, but ISTM that it would have been better to just refer to the man page (here: of GNU find):
| -prune True; if the file is a directory, do not descend into it. If | depth is given, false; no effect. Because -delete implies -depth,
| you cannot usefully use -prune and -delete together.
| […]
| expr1 -o expr2
| Or; expr2 is not evaluated if expr1 is true.
-- PointedEars
Twitter: @PointedEars2
Please do not Cc: me. / Bitte keine Kopien per E-Mail.
>>> and some quick checks, these commands list files or dirs in ".", and none
>>> in subdirs of ".". (Pls let me know if and why this is not a good idiom
>>> to use.)
>> […]
>>> The purpose of this post is to understand why the above
>>> find works. I think prune is like 'next' in awk or perl.
>>> I do not understand what "-name ." is doing.
>> Since you started with "find .", the first file to be tested is "." which
>> matches the "-name ." predicate. That's on the left side of the -o
>> operator, which sort-circuits, so the -prune operator is not applied.
> No. Each directory on a Unixoid system contains a hidden file named `.' > which points to itself. (And a hidden file named `..' pointing to its parent > directory.)
> The first `.' in the find(1) command line, indeed all positional arguments > before the first option is/are considered to be the directory path(s) from > where to start the search; in this case the current directory.
I assume the \(-name . -o prune \) is considered "before the first option", so
find further refines only it's list of dirs to decend into
from \(-name . -o prune \); ie it's not considering filenames until
"-type" above.
--snip
> As always, find(1) searches recursively from that directory but because of > `-name .' only considers the contents of the directory named so, IOW that > current directory.
--snip
related example that might be useful to others:
/tmp $ touch a b c
/tmp $ mkdir foo
/tmp $ cd foo
/tmp/foo $ touch e f g
/tmp/foo $ cd ..
/tmp $ mkdir bar
/tmp $ touch bar/{h,i,j}
/tmp $ find . \( -name . -o -name foo -o -prune \) -print
.
./a
./b
./bar
./c
./foo
./foo/e
./foo/f
./foo/g
> Thomas 'PointedEars' Lahn <PointedE...@web.de> writes:
>> Alan Curry wrote:
>>> Am Nym <xtdk...@gmail.com> wrote:
>>>> From web searching:
>>>> find . \( -name . -o -prune \) -type f -print
>>>> find . \( -name . -o -prune \) -type d -print
>> […]
>> The first `.' in the find(1) command line, indeed all positional
>> arguments before the first option is/are considered to be the directory
>> path(s) from where to start the search; in this case the current
>> directory.
> I assume the \(-name . -o prune \) is considered "before the first
> option", so find further refines only it's list of dirs to decend into
> from \(-name . -o prune \); ie it's not considering filenames until
> "-type" above.
No, find(1) is a very special command (one of those that do not fully comply with the POSIX Utility Syntax Guidelines as specified in IEEE 1003.1, section 12.2). There are options as you know them from other commands ("options"), and there are predicates that are also options ("predicates") but are treated like positional arguments.
While options may be in any order (except that a warning is issued if they precede a positional argument or a predicate), positional arguments and predicates are processed in-order (to allow for short-circuit evaluation with -o[r], and post-processing like -exec, -printf, -print, and -ls).
Predicates can be grouped with `( … )' to change precedence; you need to quote or escape find's `(' and `)' because they are part of subshell syntax in the shell. Therefore, `\(-name . -o prune \)' does not work, but
`\( -name . -o prune \)' does.
So in this case, there are *no* (real) options. There is the first positional argument: `.'. The rest of the positional arguments are predicates.
> --snip
>> As always, find(1) searches recursively from that directory but because
>> of `-name .' only considers the contents of the directory named so, IOW
>> that current directory.
> --snip
> related example that might be useful to others:
> /tmp $ touch a b c
> /tmp $ mkdir foo
> /tmp $ cd foo
> /tmp/foo $ touch e f g
> /tmp/foo $ cd ..
> /tmp $ mkdir bar
> /tmp $ touch bar/{h,i,j}
> /tmp $ find . \( -name . -o -name foo -o -prune \) -print
> .
> ./a
> ./b
> ./bar
> ./c
> ./foo
> ./foo/e
> ./foo/f
> ./foo/g
ACK.
-- PointedEars
Twitter: @PointedEars2
Please do not Cc: me. / Bitte keine Kopien per E-Mail.
>>> and some quick checks, these commands list files or dirs in ".", and none
>>> in subdirs of ".". (Pls let me know if and why this is not a good idiom
>>> to use.)
>> […]
>>> The purpose of this post is to understand why the above
>>> find works. I think prune is like 'next' in awk or perl.
>>> I do not understand what "-name ." is doing.
>> Since you started with "find .", the first file to be tested is "." which
>> matches the "-name ." predicate. That's on the left side of the -o
>> operator, which sort-circuits, so the -prune operator is not applied.
>No. Each directory on a Unixoid system contains a hidden file named `.' >which points to itself. (And a hidden file named `..' pointing to its parent >directory.)
If you hadn't started with "No", I wouldn't think you were contradicting me.
Where's the conflict between what you wrote and what I wrote? I see no errors
in either (except the misspelled "short-circuit") and have no idea why you
chose to inject this idiot-level lecture on "." and ".."
>The first `.' in the find(1) command line, indeed all positional arguments >before the first option is/are considered to be the directory path(s) from >where to start the search; in this case the current directory. It is >equivalent to `./'. (That positional argument is optional in GNU find and >defaults to the current directory.)
This also doesn't conflict with what I said. Do you object to my description
of this as the "first file to be tested"? I stand by that. The paths given to
find as search start points *are* tested against the predicates, as you can
see here:
The file named "." (which is a directory, I should't really waste time
pointing that out because everyone obviously already knows it) is tested by
the -name predicate, which decides whether it will pass through to the -prune
and -print predicates.
Thomas 'PointedEars' Lahn wrote:
> […] find(1) is a very special command (one of those that do not fully
> comply with the POSIX Utility Syntax Guidelines as specified in IEEE
> 1003.1, section 12.2). There are options as you know them from other
> commands ("options"), and there are predicates that are also options
> ("predicates") but are treated like positional arguments.
> While options may be in any order (except that a warning is issued if they
> precede a positional argument or a predicate), […]
^^^^^^^^^^^^^^
I meant to say "or _are preceded by_ a predicate"; but I had mistaken GNU's -maxdepth for a real option when it is in fact a special predicate:
| $ find . \( -name . -o -prune \) -print -maxdepth 1
| find: warning: you have specified the -maxdepth option after a non-option
| argument (, but options are not positional (-maxdepth affects tests
| specified before it as well as those specified after it). Please specify
| options before other arguments.
| | .
On 2012-11-03, Am Nym <xtdk...@gmail.com> wrote:
<conversation snipped>
> I assume the \(-name . -o prune \) is considered "before the first
> option", so find further refines only it's list of dirs to decend into
> from \(-name . -o prune \); ie it's not considering filenames until
> "-type" above.
(that's for GNU find, but they all have the path and the expression).
-type is not an option, it's a test, as is -name. -prune is an action.
If there were any options in the expression, they would be "processed
when the command line is parsed, while the tests don't do anything
until files are examined". (This is not about the command-line options
like -L, your find may not have any.)
Find starts with the given path(s), "." in your examples, then applies
the expression to each object it finds. If it is considering a directory
that is not subject to -prune, it recursively processes the directory
contents. There is no list, it looks at one item at a time and applies
the expression to it.
So what you see is:
start with .
-name . is true, the -o part is not processed
-type f is false, do not do anything else to .
but . is a directory so look at its contents
look at a file in .
-name . is false, so look at the -o part
-prune is a true no-op for a file, so just keep going
-type f is true
according to the implicit -print at the end, print the file name
look at a directory in .
-name . is false, so look at the -o part
-prune is true, remember that it applies to this directory
-type f is false, do not do anything else to the directory
but it is a directory
do not look at its contents because -prune applies
Alan Curry wrote:
> Thomas 'PointedEars' Lahn <use...@PointedEars.de> wrote:
>> Alan Curry wrote:
>>> Am Nym <xtdk...@gmail.com> wrote:
>>>> From web searching:
>>>> and some quick checks, these commands list files or dirs in ".", and
>>>> none
>>>> in subdirs of ".". (Pls let me know if and why this is not a good
>>>> idiom to use.)
>>> […]
>>>> The purpose of this post is to understand why the above
>>>> find works. I think prune is like 'next' in awk or perl.
>>>> I do not understand what "-name ." is doing.
>>> Since you started with "find .", the first file to be tested is "."
>>> which matches the "-name ." predicate. That's on the left side of the -o
>>> operator, which sort-circuits, so the -prune operator is not applied.
>> No. Each directory on a Unixoid system contains a hidden file named `.'
>> which points to itself. (And a hidden file named `..' pointing to its
>> parent directory.)
> If you hadn't started with "No", I wouldn't think you were contradicting
> me. Where's the conflict between what you wrote and what I wrote? I see no
> errors in either (except the misspelled "short-circuit") and have no idea
> why you chose to inject this idiot-level lecture on "." and ".."
The reason that `.' is found (and need _not_ be found *first* as you claimed) is _not_ (as you claimed) that the first positional argument is `.', but that `-name .' descends into the directory named `.' *in* `.' (`./.', which is of course equivalent to `.').
>> The first `.' in the find(1) command line, indeed all positional
>> arguments before the first option is/are considered to be the directory
>> path(s) from where to start the search; in this case the current
>> directory. It is equivalent to `./'. (That positional argument is
>> optional in GNU find and defaults to the current directory.)
> This also doesn't conflict with what I said. Do you object to my
> description of this as the "first file to be tested"? I stand by that. The
> paths given to find as search start points *are* tested against the
> predicates,
Evidentially, for the -name predicate they are not (for that would be superfluous if the paths were only `.', and error-prone if they were not).
Only the files that the directories specified by the paths *contain* are tested with -name, of course. One of those files is `.' first-level in each path.
However, the paths are tested when using the -path predicate, for example, which can be found (according to GNU find's manpage) both in GNU find and
on the OP's HP-UX.
Eric wrote:
> On 2012-11-03, Am Nym <xtdk...@gmail.com> wrote:
> <conversation snipped>
>> I assume the \(-name . -o prune \) is considered "before the first
>> option", so find further refines only it's list of dirs to decend into
>> from \(-name . -o prune \); ie it's not considering filenames until
>> "-type" above.
> (that's for GNU find, but they all have the path and the expression).
> -type is not an option, it's a test, as is -name. -prune is an action.
Yes, that is one way to look at it. However, the more useful umbrella term here is "predicate"; the manpage does describe those arguments as options (unfortunately), but they are part of an expression based on predicate logic after all.
For example, -type f as a "test" is true if and only if the file found is a regular file. -prune as an "action" actually is a tautological predicate (always true) with special meaning. -exec as an "action" is either true or false depending on what the command run by -exec has as exit status; with
`-exec COMMAND \; -print' nothing will be printed if COMMAND is not successful because `false AND x' is always `false'. And so on.
-- PointedEars
Twitter: @PointedEars2
Please do not Cc: me. / Bitte keine Kopien per E-Mail.
In article <4595675.4ZulOvX...@PointedEars.de>,
Thomas 'PointedEars' Lahn <use...@PointedEars.de> wrote:
>Alan Curry wrote:
>> Thomas 'PointedEars' Lahn <use...@PointedEars.de> wrote:
>> If you hadn't started with "No", I wouldn't think you were contradicting
>> me. Where's the conflict between what you wrote and what I wrote? I see no
>> errors in either (except the misspelled "short-circuit") and have no idea
>> why you chose to inject this idiot-level lecture on "." and ".."
>The reason that `.' is found (and need _not_ be found *first* as you >claimed) is _not_ (as you claimed) that the first positional argument is >`.', but that `-name .' descends into the directory named `.' *in* `.' >(`./.', which is of course equivalent to `.').
Well now at least I can see the difference between what you wrote and what I
wrote. Luckily for me your assertion is wrong.
>> This also doesn't conflict with what I said. Do you object to my
>> description of this as the "first file to be tested"? I stand by that. The
>> paths given to find as search start points *are* tested against the
>> predicates,
>Evidentially, for the -name predicate they are not (for that would be >superfluous if the paths were only `.', and error-prone if they were not).
>Only the files that the directories specified by the paths *contain* are >tested with -name, of course. One of those files is `.' first-level in each >path.
You've stated a testable hypothesis. This is good. In your theory of
operation, find will always find something to match "-name ." under the
starting directory. In my theory of operation, "-name ." will only match if
"." is actually given as an argument.
The test shows that my theory was correct. When "." appears among the
arguments to find, the string "." is matched against the -name pattern. When
something else is given as an argument, that something is matched against the
-name pattern.
The arguments given to find to start the search (here, a * which expands to the
3 arguments foo bar baz) are tested against the -name predicate and the ones
that match are passed through to -print. One of them is a directory, the
other one isn't. The -name predicate doesn't care about the difference
because it just matches the filename string against the pattern.
In conclusion: "find . -name ." does indeed match the . because it begins the
search by testing the first name in the path-list (in this case ".") against
the predicates.
Eric <e...@deptj.eu> writes:
> On 2012-11-03, Am Nym <xtdk...@gmail.com> wrote:
> <conversation snipped>
>> I assume the \(-name . -o prune \) is considered "before the first
>> option", so find further refines only it's list of dirs to decend into
>> from \(-name . -o prune \); ie it's not considering filenames until
>> "-type" above.
Glad to be corrected on above.
--snip
> -type is not an option, it's a test, as is -name. -prune is an action.
> If there were any options in the expression, they would be "processed
> when the command line is parsed, while the tests don't do anything
> until files are examined".
Thanks, good to know.. think this is the relevant GNU textinfo node:
> (This is not about the command-line options
> like -L, your find may not have any.)
> Find starts with the given path(s), "." in your examples, then applies
> the expression to each object it finds. If it is considering a directory
> that is not subject to -prune, it recursively processes the directory
> contents. There is no list, it looks at one item at a time and applies
> the expression to it.
> So what you see is:
> start with .
> -name . is true, the -o part is not processed
> -type f is false, do not do anything else to .
> but . is a directory so look at its contents
> look at a file in .
> -name . is false, so look at the -o part
> -prune is a true no-op for a file, so just keep going
Thomas 'PointedEars' Lahn <PointedE...@web.de> writes:
> No, find(1) is a very special command (one of those that do not fully comply > with the POSIX Utility Syntax Guidelines as specified in IEEE 1003.1, > section 12.2).
> There are options as you know them from other commands > ("options"), and there are predicates that are also options ("predicates") > but are treated like positional arguments.
> While options may be in any order (except that a warning is issued if they > precede a positional argument or a predicate), positional arguments and > predicates are processed in-order (to allow for short-circuit evaluation > with -o[r], and post-processing like -exec, -printf, -print, and -ls).
> Predicates can be grouped with `( … )' to change precedence; you need to > quote or escape find's `(' and `)' because they are part of subshell syntax > in the shell. Therefore, `\(-name . -o prune \)' does not work, but
> `\( -name . -o prune \)' does.
> So in this case, there are *no* (real) options. There is the first > positional argument: `.'. The rest of the positional arguments are > predicates.
> RTFineM.
will do, in Linux, this will show a relevant section:
pac...@kosh.dhis.org (Alan Curry) writes:
> In article <4595675.4ZulOvX...@PointedEars.de>,
> Thomas 'PointedEars' Lahn <use...@PointedEars.de> wrote:
>>Alan Curry wrote:
>>> Thomas 'PointedEars' Lahn <use...@PointedEars.de> wrote:
>>> If you hadn't started with "No", I wouldn't think you were contradicting
>>> me. Where's the conflict between what you wrote and what I wrote? I see no
>>> errors in either (except the misspelled "short-circuit") and have no idea
>>> why you chose to inject this idiot-level lecture on "." and ".."
>>The reason that `.' is found (and need _not_ be found *first* as you >>claimed) is _not_ (as you claimed) that the first positional argument is >>`.', but that `-name .' descends into the directory named `.' *in* `.' >>(`./.', which is of course equivalent to `.').
> Well now at least I can see the difference between what you wrote and what I
> wrote. Luckily for me your assertion is wrong.
>>> This also doesn't conflict with what I said. Do you object to my
>>> description of this as the "first file to be tested"? I stand by that. The
>>> paths given to find as search start points *are* tested against the
>>> predicates,
>>Evidentially, for the -name predicate they are not (for that would be >>superfluous if the paths were only `.', and error-prone if they were not).
>>Only the files that the directories specified by the paths *contain* are >>tested with -name, of course. One of those files is `.' first-level in each >>path.
> You've stated a testable hypothesis. This is good. In your theory of
> operation, find will always find something to match "-name ." under the
> starting directory. In my theory of operation, "-name ." will only match if
> "." is actually given as an argument.
> The test shows that my theory was correct. When "." appears among the
> arguments to find, the string "." is matched against the -name pattern. When
> something else is given as an argument, that something is matched against the
> -name pattern.
> The arguments given to find to start the search (here, a * which expands to the
> 3 arguments foo bar baz) are tested against the -name predicate and the ones
> that match are passed through to -print. One of them is a directory, the
> other one isn't. The -name predicate doesn't care about the difference
> because it just matches the filename string against the pattern.
> In conclusion: "find . -name ." does indeed match the . because it begins the
> search by testing the first name in the path-list (in this case ".") against
> the predicates.
Nice/enjoyed this thread - admittedly do not follow all of it.
So ..
find . -name . -o -prune -type f -print
is a simplier way to list only files in CWD:
$ mkdir bar; touch baz
$ touch bar/{a,b,c}
$ touch a s d f
$ find . -name . -prune -print
.
$ find . -name . -o -prune -type f -print
./s
./d
./baz
./a
./f