найти не рекурсивный, когда файл вверху


8

Представьте себе исходное дерево. Везде есть xml-файлы.

Но поскольку в корне этого дерева находится XYZ.xml, он не найдет мои xml-файлы.

find -iname *.xml

возвращается

./XYZ.xml

вместо

./XYZ.xml
./a/b/c/bob.xml
./b/d/top.xml

1
От man find: Обратите внимание, что вы должны заключать в кавычки шаблоны как само собой разумеющееся, иначе оболочка будет расширять любые подстановочные знаки в них.
артданил

Ответы:


18
find -iname '*.xml'

В противном случае ваша оболочка расширяется *.xmlдо XYZ.xml, и фактически выполняемая команда

find -iname XYZ.xml

Причина, по которой он работает, если в текущем каталоге нет файлов XML, заключается в том, что оболочки обычно оставляют подстановочные знаки нерасширенными, если они не совпадают с чем-либо. В общем, в любое время вы хотите подстановочные быть расширен с помощью программы, отличной от оболочки (например , с помощью find, tar, scpи т.д.) , вы должны процитировать их так что оболочка не будет пытаться расширить их самостоятельно.


1
Thx, это так просто, но мне было интересно, как обойти это в течение нескольких месяцев. Я нашел это действительно странным и очень противоречивым поведением, но теперь я понимаю, так как это не находка, а ошибка Бэша.
Оливье Тупен,

2
Это не вина "bash" как таковая, а ваша отказ от цитирования подстановочных знаков, которые вы хотели передать в качестве аргументов. Это относится ко всем программам, которые принимают ввод оболочки. Оболочка расширяет их как глобусы, если они не указаны или не экранированы.
Калеб

1
Я думаю, что Оливье имел в виду это в том смысле, что это вопрос bash, а не о find.
пользователь неизвестен

6

Вы должны процитировать свой аргумент так:

find ./ -name '*.xml'

так что он передается для поиска вместо раскрытия оболочкой, а затем передается для поиска в качестве расширенной версии.


1
Итак, если *.xmlв текущем каталоге ничего не совпадает, он передается буквально, поэтому он работает в другом случае. Очень полезный ответ.
Эрик Уилсон

1

Подстановочные знаки раскрываются оболочкой, а не командой. findэто одна из немногих команд, которая выполняет сопоставление с подстановочными знаками, аналогичное оболочке, в свое время.

При запуске ls *.xmlсначала оболочка расширяется *.xmlдо списка подходящих файлов, например file1.xml file2.xml file3.xml, а затем оболочка вызывает lsполученный список аргументов file1.xml file2.xml file3.xml. Вот почему вы видите тот же список имен файлов echo *.xml, даже если echoничего не знаете о файлах и не заботитесь о том, являются ли его аргументы именами файлов.

Когда вы бежите find . -name "*.xml":

  1. Оболочка анализирует командную строку, чтобы распознать специальные символы и разбить ее на слова и выражения. Здесь есть только список слов find, ., -name, *.xmlгде *цитируются. Так *как цитируется, это обычный символ, что касается оболочки.
  2. Оболочка запускает команду findс указанным списком аргументов: ., -name, *.xml.
  3. findищет файлы, чье имя соответствует шаблону *.xmlв любом каталоге в текущем каталоге.

Когда вы запускаете find . -name *.xmlи нет подходящих файлов *.xml:

  1. Оболочка анализирует командную строку, чтобы распознать специальные символы и разбить ее на слова и выражения. Здесь есть только список слов find, ., -name, *.xmlгде *не котируется.
  2. Поскольку слово *.xmlсодержит подстановочный знак без кавычек, оболочка выполняет генерацию имени файла. Поскольку нет подходящих имен файлов, шаблон остается нерасширенным.
  3. Оболочка выполняет команду findс результирующим списком аргументов, что ., -name, *.xml.
  4. findищет файлы, чье имя соответствует шаблону *.xmlв любом каталоге в текущем каталоге.

Когда вы запускаете find . -name *.xmlи текущий каталог содержит file1.xml, file2.xmlи file3.xml:

  1. Оболочка анализирует командную строку, чтобы распознать специальные символы и разбить ее на слова и выражения. Здесь есть только список слов find, ., -name, *.xmlгде *не котируется.
  2. Поскольку слово *.xmlсодержит подстановочный знак без кавычек, оболочка выполняет генерацию имени файла: *.xmlзаменяется списком совпадающих имен файлов.
  3. Оболочка выполняет команду findс результирующим списком аргументов, который ., -name, file1.xml, file2.xml, file3.xml.
  4. findжалуется на синтаксическую ошибку при достижении file2.xml.

Когда вы запускаете find . -name *.xmlи текущий каталог содержит один соответствующий файл file.xml:

  1. Оболочка анализирует командную строку, чтобы распознать специальные символы и разбить ее на слова и выражения. Здесь есть только список слов find, ., -name, *.xmlгде *не котируется.
  2. Поскольку слово *.xmlсодержит подстановочный знак без кавычек, оболочка выполняет генерацию имени файла: *.xmlзаменяется списком совпадающих имен файлов.
  3. Оболочка выполняет команду findс результирующим списком аргументов, что ., -name, file.xml.
  4. findвидит совершенно правильную команду, но, вероятно, это не то, что вы намеревались: findвелено искать файлы, вызываемые file.xmlв любом каталоге, а не искать какие-либо подходящие файлы *.xml.

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

(То, что я описываю, это поведение по умолчанию большинства распространенных оболочек: sh, bash, dash, ksh, ... Некоторые оболочки могут быть настроены для отображения ошибки вместо запуска команды с нерасширенными подстановочными знаками или для расширения несоответствующих подстановочных знаков до пустых список. Ни один из них не поможет здесь.)



-2

Пожалуйста, попробуй:

find ./ -name *.xml

Я только что попробовал, тот же результат.
Эрик Уилсон

Я попробовал, и это работает. На GNU bash 4.2.8
bbaja42

3
Это не работает, когда глобус соответствует чему-либо в текущем каталоге. Это неправильный синтаксис! *Всегда должны быть заключены в кавычки или спасшийся передать его найти.
Калеб
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.