find -print0 не работает в конвейере с xargs -0, когда используются условия -or

Вопрос или проблема

Я пытаюсь “grep” контент из списка файлов в текущем каталоге, соответствующих расширениям asp, html и htm.

Я также использую cygwin с:

  • bash: 4.4.12(3)-release,
  • findutils (find и xargs): 4.6.0-1

Для этого я создал функцию bash:

function grepinpages() {
  find ./ -type f -iname "*.asp" -or -iname "*.html" -or -iname "*.htm" -print0 | \
    xargs -0 -n200 egrep "${@}" --
}

Так что я мог:

grepinpages -il "default\.asp"

И получить все файлы, содержащие без учета регистра “default.asp”.

Проблема в том, что я получаю совпадения только из нескольких файлов. На самом деле, если я изменю функцию на:

function grepinpages() {
  find ./ -type f -iname "*.asp" -or -iname "*.html" -or -iname "*.htm" -print0 | \
    xargs -0 -n200 echo egrep "${@}" --
}

Я получаю что-то вроде

egrep -il default\.asp -- file1.htm file2.htm dir1/file1.htm

Затем, если я упростю это еще больше:

find ./ -type f -iname "*.asp" -or -iname "*.html" -or -iname "*.htm"

Я получаю все файлы в списке!

Если я добавлю -print0 и передам дальше что-то

find ./ -type f -iname "*.asp" -or -iname "*.html" -or -iname "*.htm" -print0 | xargs -0 -n200 echo

Я снова получаю “неполный” список.

Оказалось, я не группировал “или” параметры find в скобках. Таким образом, это исправило ситуацию для меня:

function grepinpages() {
  find ./ -type f \( -iname "*.asp" -or -iname "*.html" -or -iname "*.htm" \) -print0 | \
    xargs -0 -n200 egrep "${@}" --
}

Так как я указал -print0, он относился только к -iname "*.htm", и никакое действие по умолчанию не предполагалось для других альтернатив, я думаю.

Ответ или решение

Когда вы используете команду find в сочетании с xargs, важно правильно группировать условия с помощью круглых скобок, особенно когда вы применяете логические операторы, такие как -or. В вашем случае, проблема, с которой вы столкнулись при выполнении функции grepinpages, была связана именно с этой причиной.

Проблема

Вы начали с команды:

find ./ -type f -iname "*.asp" -or -iname "*.html" -or -iname "*.htm" -print0 | \
xargs -0 -n200 egrep "${@}" --

При отсутствии круглых скобок вокруг условий, find неправильно интерпретировал структуру команд. Когда вы вызываете -print0, find возвращает только те файлы, которые соответствуют последнему условию, в данном случае, -iname "*.htm". Таким образом, в результате вы получали не полный список всех файлов с расширениями .asp, .html и .htm, а только те, что соответствовали последнему условию.

Решение

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

find ./ -type f \( -iname "*.asp" -or -iname "*.html" -or -iname "*.htm" \) -print0 | \
xargs -0 -n200 egrep "${@}" --

Использование скобок позволяет явно указать, что все три условия относятся к одной группе и оценка будет происходить над всей группой. Теперь find будет правильно интерпретировать, что нужно искать файлы с любым из указанных расширений и выводить их в стандарте, который можно передать дальше через xargs.

Причины возникновения проблемы

При использовании find без группировки, каждая команда выводила отдельный результат, который не учитывал все условия одновременно. В результате, когда вы добавляли -print0, система выполняла его только для последнего условия, игнорируя остальные.

Заключение

Чтобы избежать дальнейших проблем с интерпретацией команд, всегда группируйте логические операции. Это специально важно в таких случаях, как с find. Применяя данный подход, вы значительно упростите задачу поиска и извлечения данных из множества файлов, что особенно критично в сценариях работы с большим количеством данных.

Таким образом, следуя указанному вами синтаксису, вы сможете эффективно и продуктивно находить нужные файлы, извлекая из них информацию без риска потерять данные из-за неверной интерпретации условий.

Оцените материал
Добавить комментарий

Капча загружается...