Grep каталог и возвращаемый список с номерами строк

В настоящее время я пытаюсь узнать больше о bash-скриптах и ​​всех этих забавных материалах, и я собрал эту небольшую команду:

find $path | xargs grep -n $pattern | awk '{print $1}' 

Хотя это работает, мне было интересно, если я изобретаю колесо. Есть ли лучший способ поиска по каталогу, grep файлы для шаблона и возврат списка с номерами строк?

Извините заранее, если это неподходящее / не по теме место для публикации этого вопроса.

6 Solutions collect form web for “Grep каталог и возвращаемый список с номерами строк”

Многие варианты grep реализуют рекурсивный вариант. Например, GNU grep

 -R, -r, --recursive Read all files under each directory, recursively; this is equivalent to the -d recurse option. 

Затем вы можете удалить find :

 grep -n -r $pattern $path | awk '{ print $1 }' 

но это больше, чем номер строки. awk печатает первый столбец. Этот пример

 src/main/package/A.java:3:import java.util.Map; src/main/package/A.java:5:import javax.security.auth.Subject; src/main/package/A.java:6:import javax.security.auth.callback.CallbackHandler; 

будут напечатаны как

 src/main/package/A.java:3:import src/main/package/A.java:5:import src/main/package/A.java:6:import 

обратите внимание на :import в каждой строке. Вы можете использовать sed для фильтрации вывода.

Поскольку a : может присутствовать в имени файла, вы можете использовать параметр -Z grep для вывода символа nul (\ 0) после имени файла.

 grep -rZn $pattern $path | sed -e "s/[[:cntrl:]]\([0-9][0-9]*\).*/:\1/" 

с тем же примером, что и раньше, будет

 src/main/package/A.java:3 src/main/package/A.java:5 src/main/package/A.java:6 

Для первой части обратите внимание на то, что xargs работает только в том случае, если в именах файлов нет пробельных символов или \'" . См. Раздел« Как искать слово во всем содержимом каталога в Linux для объяснения и альтернативы ».

Кроме того, всегда ставьте двойные кавычки вокруг переменных подстановок: "$path" . Без двойных кавычек оболочка расширяет пробелы и подстановочные знаки в значении $path , поэтому использование его без кавычек ломается, если у вас есть пробелы или подстановочные знаки в этом имени файла. То же самое касается $pattern (просто для смеха, попробуйте оставить кавычки и найти h* в каталоге, содержащем файлы с именем hi и hello ).

Если ваша версия grep имеет параметр -r для рекурсивного перемещения каталогов, вам не нужно find здесь. Параметр -r присутствует в Linux, FreeBSD, Mac OS X и Cygwin. В противном случае:

 find "$path" -type f -exec grep -Hn "$pattern" {} + | awk -F: '{print $1 ":" $2}' 

Я также исправил ваш awk вызов, чтобы он печатал только имя файла и номера строк. Я также -H параметр -H в grep , чтобы гарантировать, что он всегда печатает имя файла, даже если есть один файл. Этот код предполагает, что имена ваших файлов не содержат : или новые строки; если они могут, все усложняется, и вам лучше либо полагаться на опцию -Z GNU grep, либо обрабатывать файлы по отдельности:

 find "$path" -type f -exec sh -c 'for x; do grep -n "$0" <"$x" | awk -v fn="$x" -F: 'print fn ":" $1'; done' "$pattern" {} + 

Я бы избавился от grep и использовал awk :

 find $path -type f -print0 | xargs -0 awk "/$pattern/{print FILENAME,FNR}" 

Но используя grep и cut :

 find $path -type f -print0 | xargs -0 grep -nH "$pattern" | cut -d: -f1,2 

Включите предложение -type f , чтобы вы не получали ошибок, пытающихся выполнить поиск (в grep или awk) по нерегулярным типам файлов (символические ссылки, каталоги, сокеты). Если вы читаете трубку или сокет, когда другая программа должна быть, то вы можете испортить эту программу.

find ... -print0 | xargs -0 find ... -print0 | xargs -0 получает вокруг пробелов в именах файлов. Он недоступен в любой UNIX-системе, но на большинстве.

Не знаете, что именно вы пытаетесь сделать здесь.

 find $path | xargs grep -n $pattern | awk '{print $1}' 

Для меня это переводит, чтобы найти все файлы в $ path и искать их с пронумерованными строками для шаблона $ pattern и печатать номер строки и первое слово строки, которое соответствует $ pattern. (возможно, не включая сам шаблон $)

Если это так, то вы слегка изобретаете колесо. Вы можете сделать все это непосредственно из команды find без дополнительного штрафа за канал xargs.

 find $path -exec grep -n $pattern {} \; -print | awk '{print $1}' 

или удалите трубу awk для всего содержимого линии.

Использование собственного -exec находки имеет дополнительное преимущество – грамотно обрабатывать пробелы в именах файлов.

проверьте также -c и -n полезные опции.

Вот что я сделал бы:

  • избегайте использования большого количества труб. По возможности используйте обходной путь. Вместо того, чтобы find . | grep -n <> find . | grep -n <> find . | grep -n <> почему бы не использовать -exec ?

    • Вы также можете воспользоваться технологической заменой.

Попробуйте сделать следующее:

 awk '{print $1}' <(find $path -exec grep -n $pattern {} \;) 

NB: Это может работать как есть или с небольшим изменением в зависимости от оболочки и версии find которую вы используете.

  • Как правильно использовать параллель в этой ситуации?
  • Объединить xargs -I с sed
  • Ускорение команды поиска rm с проверкой путем распараллеливания
  • Как я удаляю все файлы в каталоге с конкретными расширениями, за исключением последних 5 из них
  • Как подключить вывод netcat? Проблемы с xargs и кавычками
  • Эффективная генерация stdin в сценарии оболочки
  • Возможно ли, чтобы ls поддерживал порядок своих входов
  • Не удалось создать большой файл tar с трубкой и xargs
  • Передавать аргумент xargs как строку в другую команду с помощью '>'?
  • Разный вывод `find | xargs ls` для той же команды в разных версиях Ubuntu
  • ssh-add добавить все закрытые ключи в .ssh каталог
  • Linux и Unix - лучшая ОС в мире.