Почему find печатает начальный символ «./», если пути не указаны?

13

Почему findраспечатка ведет ./к результатам, если пути не указаны?

$ find
./file1
./file2
./file3

В чем причина не распечатывать это?

$ find
file1
file2
file3
Н.Р.
источник

Ответы:

16

Причина , почему вы видите это происходит потому , что разработчик GNU выбрал обеспечить «разумное» поведение для , когда ни один путь не дается. Напротив, POSIX не утверждает, что параметр является необязательным:find find

findУтилита должна рекурсивно спускаться по иерархии каталогов из каждого файла , указанного путем , оценивая логическое выражение , состоящее из первичных , описанных в разделе операндов для каждого найденного файла. Каждый операнд пути должен оцениваться без изменений, как он был предоставлен, включая все завершающие <slash>символы; все имена путей для других файлов, встречающихся в иерархии, должны состоять из конкатенации операнда текущего пути, a, <slash>если операнд текущего пути не заканчивается одним, и имени файла относительно операнда пути. Относительная часть не должна содержать ни точечных, ни точечных компонентов, ни конечныхсимволы и только отдельные <slash>символы между компонентами имени пути.

Вы можете увидеть разницу в резюме для каждого. GNU имеет (как это принято) дополнительные пункты в квадратных скобках:

find [-H] [-L] [-P] [-D debugopts] [-Olevel] [starting-point...]
       [expression]

в то время как POSIX не указывает, что это может быть необязательным:

find [-H|-L] path... [operand_expression...]

В программе GNU это делается в ftsfind.c:

  если (пусто)
    {
      / *
       * Мы используем временную переменную здесь, потому что некоторые действия изменяют
       * путь временно. Следовательно, если мы используем строковую константу,
       * мы получаем coredump. Лучший пример этого, если мы скажем
       * "find -printf% H" (обратите внимание, не "find. -printf% H").
       * /
      char defaultpath [2] = ".";
      return find (путь по умолчанию);
    }

и литерал "."используется для простоты. Таким образом, вы увидите тот же результат с

find

и

find .

потому что (и POSIX согласен), данный путь будет использоваться для префикса результатов (см. выше для объединения ).

Немного поработав, можно было определить, когда эта функция была впервые добавлена; он присутствовал при первоначальном создании "findutils" в 1996 году (см. 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);
+}

Из списка изменений для поиска 3.8, это было, по-видимому

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 "."
Томас Дики
источник
11

Обычно выполняется пост-обработка файлов, и в этом случае может быть огромное преимущество, начиная с имени файла ./. В частности, если имя файла начинается с -, следующая команда может интерпретировать это имя файла как параметр. ./избегает этого

В качестве примера рассмотрим каталог с этими файлами:

$ ls
--link  --no-clobber

Теперь представьте, как будет работать эта команда, если имена файлов были указаны без ./переднего:

$ find -type f -exec cp -t ../ {} +

Мы можем проиллюстрировать проблему findсамим собой. Давайте запустим его в том же каталоге, что и выше. Следующие работы:

$ find ./*
./--link
./--no-clobber

Следующие ошибки:

$ find *
find: unknown predicate `--link'
Try 'find --help' for more information.
John1024
источник
1
Это имеет смысл. Но тогда возникает вопрос, почему он не стоит перед «.» когда ты бежишь find *.
Н.Р.
@nr Хорошо. Я ожидаю, что это ведет себя таким образом для некоторой исторической совместимости. Я добавил к ответу пример того, почему это нежелательное поведение.
John1024
3
Некоторые версии file требуют, чтобы пользователь указал путь (например, BSD, найденный в OS X). Так что вам обычно нужно явно сказать что-то вроде find . -type f .... Оттуда для некоторых версий find (например, для GNU find) это не большой шаг - просто установить значение по умолчанию .и оставить все остальное как есть.
ilkkachu
1
Причина find *не отображается .потому, что *перечисляет все файлы и папки, но исключает .. Делайте echo *в каталоге, который содержит только один или два файла, и вы увидите, что .нет в списке. Таким образом, find *оперирует каждый файл расширением. Это так же, как если бы вы сказали find Desktop/из домашнего каталога. Вы увидите результат какDesktop/foo_bar.txt
Сергей Колодяжный
1
@ John1024: Я считаю, что Мригеш и Томас Дики правильно ответили на вопрос. В этом ответе говорится, почему так удобно findвести себя так. Есть ли у вас какая-либо авторитетная справочная информация для поддержки подразумеваемой претензии, которая findбыла разработана для такого поведения по этой причине?
G-Man говорит: «Восстановите Монику»
4

findПотребности команды пути (ы) для поиска. Если мы не указываем ничего, он использует текущий каталог ( .) в качестве отправной точки. Точно так же, если вы передаете путь, например /tmp, он считает это своей отправной точкой. И поэтому результаты.

Если текущий каталог:

        $ find
or
        $ find .

output:
        ./file1
        ./file2
        ./file3

Если /tmpкаталог:

        $ find /tmp

output:
        /tmp/file4
        /tmp/file5

Если abcкаталог под текущим каталогом:

        $ find abc

output:
        abc/file6
        abc/file7

Если несколько каталогов в текущем каталоге:

        $ find fu bar

output:
        fu/file10
        fu/file11
        bar/file8
        bar/file9
Мригеш Приядарши
источник
Да, я согласен, что findнужен путь для поиска чего-либо и что по умолчанию это текущий каталог. Вопрос в том, почему он печатает ведущий, ./когда file.txtточно так же, как ./file.txt.
Н.Р.
1
это не то, что найти добавляет "." в самом начале он добавляет все, что вы указываете в качестве пути, будь то "/ tmp", "abc" или ".". Он вернет все значения соответственно.
Мригеш Приядарши
-2

Если вы не укажете путь, findкоманда примет его ${PWD}как путь и распечатает его на выходе. Пользователь, не указывающий путь, не меняет способ findработы. И поиск всегда работает с путями по умолчанию.

MelBurslan
источник
1
Понимаю. Но если выполнить ее под /tmp, то $PWDэто /tmpне ./.
Н.Р.
если вы хотите увидеть предыдущее /tmp, запустите команду. find /tmpЕсли вы не укажете путь, он всегда будет текущим каталогом, то есть./
MelBurslan
1
Дело не в том, что я хочу видеть предшествующее /tmp. Дело в том, что этого не может быть $PWD.
Н.Р.
Мои извинения ${PWD}были неправильными
словами
2
Нет, это не предполагает $ PWD. Сравните выходные данные find ., find $PWDи find(без пути, если ваша находка поддерживает это).
ilkkachu