Надежный способ открытия файлов, полученных в результате find … -exec grep … {} \+

Больше awk -ness

     awk '/LEC05/{ name[$2]++ } END { n = asorti( name,sname ); for ( i in sname ) print sname[i]}' input.txt
5
07.09.2020, 18:34
2 ответа
vim $(find path/ -exec grep -l 'pattern' {} +)

— это подстановка команды без кавычек, поэтому в ее результате будет выполняться разделение слов по пробелам, а также расширение имени пути. То есть, если файл a bсовпадает, Vim неправильно откроет aи b. Если файл *соответствует, увы, который будет расширен на каждый файл в соответствующем каталоге. Подходящим решением является

find path/ -type f -exec grep -q 'pattern' {} \; -exec vim {} +

Grep работает в qрежиме uiet. :Для каждого файла используется только его возвращаемое значение. Если 0, в этом файле найдено совпадение, и файл передается в Vim.

{} \;означает, что Grep будет анализировать один файл за раз. Если бы мы использовали {} +, все файлы были бы переданы в качестве аргументов Grep, а найденное совпадение в любого из этих файлов привело бы к статусу выхода 0, поэтому все эти файлы были бы открыты в Vim.. С другой стороны, {} +используется для Vim, так что каждый найденный файл попадает в один буфер в одном процессе Vim. Вы можете попробовать изменить их, чтобы почувствовать разницу.

Если вам нужно ускорить процесс:

  • Если 'pattern'не является регулярным выражением, а является фиксированным шаблоном, добавьте флаг -Fв Grep.

  • grep -lZ,Xargs и специальные конструкции оболочки также должны -ускорить процесс, если они у вас есть, см. ответ Stéphane Chazelas .

И здесь другие похожие варианты использования с Xargs, Find и Vim.

13
18.03.2021, 23:06

С инструментами GNU (ваш --color=alwaysуже является расширением GNU )и оболочкой с поддержкой замены процессов в стиле Ksh -:

xargs -r0a <(grep -rlZ pattern.) vim

Или:

xargs -r0a <(find.... -exec grep -lZ pattern {} +) vim

Сzsh:

vim ${(0)"$(find.... -exec grep -lZ pattern {} +)"}

С bash4.4+:

readarray -td '' files < <(find.... -exec grep -lZ pattern {} +)
vim "${files[@]}"

Они минимизируют количество grepвыполняемых вызовов. Суть в том, чтобы указать grepвыводить имена файлов с разделителями NUL -, чтобы их можно было надежно разделить на отдельные аргументы для vimс помощью GNU xargs -0или флага расширения параметра zsh's 0или bash- readarray -td ''.

В zshвы также можете:

vim./**/*(...e['grep -q pattern $REPLY'])

(где ...заменяет дополнительные квалификаторы, которые вы можете добавить, например, findподход ).

Однако это означает, что, как и в подходах, использующих find -exec grep -q pattern {} ';', один вызов grepбудет выполняться для каждого файла, что значительно замедлит его работу.

Ваш первый подход будет работать в zshпри условии, что вы заменили --color=alwaysна -Zи изменили значение IFSна IFS=$'\0'вместо IFS=$' \r\n\0'по умолчанию. Я бы не стал работать в других оболочках, так как они не поддерживают сохранение NUL в переменных, не говоря уже о $IFS, а также выполняли бы генерацию имени файла для слов, полученных в результате разделения, которое вам нужно отключить с помощью set -o noglobили set -f.

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

6
18.03.2021, 23:06

Теги

Похожие вопросы