Why is it that find
prints out a leading ./
to results if no paths are given?
$ find
./file1
./file2
./file3
What is the reason for not printing out this?
$ find
file1
file2
file3
The reason why you see this is because the developer of GNU find
chose to provide a "reasonable" behavior for find
when no path is given. In contrast, POSIX doesn't state that the parameter is optional:
The
find
utility shall recursively descend the directory hierarchy from each file specified by path, evaluating a Boolean expression composed of the primaries described in the OPERANDS section for each file encountered. Each path operand shall be evaluated unaltered as it was provided, including all trailing<slash>
characters; all pathnames for other files encountered in the hierarchy shall consist of the concatenation of the current path operand, a<slash>
if the current path operand did not end in one, and the filename relative to the path operand. The relative portion shall contain no dot or dot-dot components, no trailing characters, and only single<slash>
characters between pathname components.
You can see the difference in the synopsis for each. GNU has (as is the convention) optional items in square brackets:
find [-H] [-L] [-P] [-D debugopts] [-Olevel] [starting-point...]
[expression]
while POSIX doesn't indicate that it can be optional:
find [-H|-L] path... [operand_expression...]
In the GNU program, that's done in ftsfind.c
:
if (empty) { /* * We use a temporary variable here because some actions modify * the path temporarily. Hence if we use a string constant, * we get a coredump. The best example of this is if we say * "find -printf %H" (note, not "find . -printf %H"). */ char defaultpath[2] = "."; return find (defaultpath); }
and a literal "."
is used for simplicity. So you'll see the same result with
find
and
find .
because (and POSIX agrees) the given path will be used to prefix the results (see above for concatenation).
With a little work, one could determine when the feature was first added; it was present in the initial creation of "findutils" in 1996 (see find.c
):
+ /* If no paths are given, default to ".". */
+ for (i = 1; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
+ process_top_path (argv[i]);
+ if (i == 1)
+ process_top_path (".");
+
+ exit (exit_status);
+}
From the changelog for find 3.8, this was apparently
Sat Dec 15 19:01:12 1990 David J. MacKenzie (djm at egypt)
* find.c (main), util.c (usage): Make directory args optional,
defaulting to "."
Usually, one does post-processing of the files and, in that case, there can be a huge advantage to starting the filename with ./
. In particular, if a file name starts with -
, a subsequent command could interpret that filename an option. ./
avoids that.
As an example, consider a directory with these files:
$ ls
--link --no-clobber
Now, imagine how this command would work if the file names were provided without the ./
in front:
$ find -type f -exec cp -t ../ {} +
We can illustrate the problem with find
itself. Let's run it in the same directory as above. The following works:
$ find ./*
./--link
./--no-clobber
The following fails:
$ find *
find: unknown predicate `--link'
Try 'find --help' for more information.
The find
command needs path(s) to search.
If we don't specify any,
it uses the current directory (.
) as its starting point.
Similarly, if you pass the path, e.g., /tmp
,
it considers that as its starting point.
And therefore the results.
If current directory:
$ find
or
$ find .
output:
./file1
./file2
./file3
If /tmp
directory:
$ find /tmp
output:
/tmp/file4
/tmp/file5
If abc
directory under the current directory:
$ find abc
output:
abc/file6
abc/file7
If multiple directories under the current directory:
$ find fu bar
output:
fu/file10
fu/file11
bar/file8
bar/file9
find
needs a path to search anything and that it defaults to the current directory. The question is why it prints out the leading ./
when file.txt
is just the same as ./file.txt
.
– n.r.
Aug 05 '16 at 17:32
If you do not specify a path, find
command assumes the ${PWD}
as the path and prints it out on its output. User not specifying the path doesn't change the way find
works. And find always works with paths by default.
/tmp
, run the command find /tmp
If you do not specify a path it will always be current directory, which is ./
– MelBurslan
Aug 05 '16 at 17:06
find .
, find $PWD
and find
(without a path, if your find supports it).
– ilkkachu
Aug 05 '16 at 17:24
find *
. – n.r. Aug 05 '16 at 17:10file
demand the user to give a path (like the BSD find on OS X). So you usually need to explicitly say something likefind . -type f ...
. From there, it's not a big step for some versions of find (like GNU find) to just default to.
and leave everything else as is. – ilkkachu Aug 05 '16 at 17:23find *
not showing the.
is because*
lists all files and folders, but excludes.
. Doecho *
in a directory that contains only one or two files, and you will see that.
is not listed. Thus,find *
operates on each file expanded. It's the same as if you saidfind Desktop/
from home directory. You will see output asDesktop/foo_bar.txt
– Sergiy Kolodyazhnyy Aug 06 '16 at 05:28find foo
doesn't prepend./
- it prependsfoo/
– user253751 Aug 06 '16 at 08:52-files
from getting interpreted as flags tofind
itself. – n.r. Aug 06 '16 at 13:32find *
print. .. file1 file2 file3
?”; it’s “Why doesn’tfind *
print./file1 ./file2 ./file3
?”. immibis (and Mrigesh and Thomas Dickey) have answered that question. – G-Man Says 'Reinstate Monica' Aug 06 '16 at 21:16find
behaves the way it does. Do you have any authoritative reference information to support the implied claim thatfind
was designed to behave in this way for this reason? – G-Man Says 'Reinstate Monica' Aug 06 '16 at 21:19find
but with the*
. Do the thing withecho *
and you'll see – Sergiy Kolodyazhnyy Aug 06 '16 at 21:20find *
will print onlyfile1 file2 file3
. It will not print. .. file1 file2 file3
– Sergiy Kolodyazhnyy Aug 06 '16 at 21:30