grep для 2 слов, существующих в одной строке
Как я могу grep для строк, которые содержат два входных слова в строке? Я ищу строки, которые содержат оба слова, как мне это сделать? Я попробовал трубу вот так:
grep -c "word1" |grep -r "word2" logs
Он просто застревает после первой команды трубы. зачем?
8 ответов:
почему вы проходите
-c
? Это просто покажет количество матчей. Точно так же нет причин использовать-r
. Я предлагаю вам прочитатьman grep
.чтобы grep для 2 слов, существующих в одной строке, просто сделайте:
grep "word1" FILE | grep "word2"
grep "word1" FILE
будет печатать все строки, которые имеют word1 в них из файла, а затемgrep "word2"
будет печатать строки, которые имеют word2 в них. Следовательно, если вы объедините их с помощью трубы, он покажет строки, содержащие как word1, так и слово2.если вы просто хотите подсчитать, сколько строк было 2 слова в одной строке, сделайте:
grep "word1" FILE | grep -c "word2"
кроме того, чтобы ответить на ваш вопрос, почему он застрял: in
grep -c "word1"
, вы не указали файл. Таким образом,grep
ожидает ввода отstdin
, вот почему он, кажется, висит. Вы можете нажать Ctrl+D чтобы отправить EOF (конец файла), чтобы он вышел.
предписание
один простой переписать команду в вопросе:
grep "word1" logs | grep "word2"
первый
grep
находит строки с 'word1' из файла 'logs' и затем передает их во второйgrep
который ищет строки, содержащие 'word2'.однако не обязательно использовать две такие команды. Вы можете использовать расширенную
grep
(grep -E
илиegrep
):grep -E 'word1.*word2|word2.*word1' logs
если вы знаете ,что 'word1' будет предшествовать 'word2' на линия, вам даже не нужны альтернативы и регулярные
grep
будет делать:grep 'word1.*word2' logs
варианты "одна команда" имеют то преимущество, что выполняется только один процесс, и поэтому строки, содержащие "word1", не должны передаваться через канал во второй процесс. Насколько это важно, зависит от того, насколько велик файл данных и сколько строк соответствует "word1". Если файл небольшой, производительность вряд ли будет проблемой, и запуск двух команд в порядке. Если файл большой, но только несколько строк содержат "word1", там не будет много данных, передаваемых по каналу, и использование двух команд прекрасно. Однако, если файл огромен и "word1" встречается часто, то вы можете передавать значительные данные по каналу, где одна команда избегает этих накладных расходов. Против этого регулярное выражение является более сложным; вам может потребоваться проверить его, чтобы узнать, что лучше, но только если производительность действительно имеет значение. Если вы выполняете две команды, вы должны стремиться выбрать менее часто встречающиеся слово, в первом
grep
для минимизации объема данных, обрабатываемых вторым.Диагностика
исходный скрипт:
grep -c "word1" | grep -r "word2" logs
это странная последовательность команд. Первый
grep
собирается подсчитать количество вхождений "word1" на его стандартном входе и распечатать это число на его стандартном выходе. Пока вы не укажете EOF (например, набрав Control-D), он будет сидеть там, ожидая вас, чтобы ввести что-то. Второйgrep
выполняет рекурсивный поиск 'word2' в файлах под каталогомlogs
(или, если это файл, в файлеlogs
). Или, в моем случае, это не удастся, так как нет ни файл, ни каталогlogs
где я запускаю трубопровод. Обратите внимание, что второйgrep
не читает стандартный ввод, так что труба лишняя.С Bash родительская оболочка ждет, пока все процессы в конвейере не выйдут, поэтому она сидит в ожидании
grep -c
чтобы закончить, что он не будет делать, пока вы не укажете EOF. Следовательно, ваш код, кажется, застрял. С Heirloom Shell, второйgrep
завершает и завершает работу, и оболочка снова запрашивает. Теперь у вас есть два запущенных процесса, первыйgrep
и оболочка, и они оба пытаются читать с клавиатуры, и не определено, какой из них получает любую заданную строку ввода (или любую заданную индикацию EOF).обратите внимание, что даже если вы ввели данные в качестве входных данных первый
grep
, вы получите только те строки, которые содержат 'word2', показанные на выходе.
Примечание:
в свое время использовался ответ:
grep -E 'word1.*word2|word2.*word1' "$@" grep 'word1.*word2' "$@"
это вызвало комментарии ниже.
вы можете использовать awk. вроде этого...
cat <yourFile> | awk '/word1/ && /word2/'
порядок не важен. Так что если у вас есть файл, и...
файл с именем file1 с содержит:
word1 is in this file as well as word2 word2 is in this file as well as word1 word4 is in this file as well as word1 word5 is in this file as well as word2
затем,
/tmp$ cat file1| awk '/word1/ && /word2/'
в результате
word1 is in this file as well as word2 word2 is in this file as well as word1
да, awk медленнее.
основная проблема заключается в том, что вы не предоставили первый grep с любым входом. Вам нужно будет изменить порядок вашей команды что-то вроде
grep "word1" logs | grep "word2"
Если вы хотите подсчитать вхождения, то поставьте '-c' на второй grep.
команда grep:
grep -wE "string1|String2|...." file_name
или вы можете использовать:
echo string | grep -wE "string1|String2|...."
чтобы grep два слова одновременно, используйте эту команду оболочки:
eval "</dev/stdin $(printf "|grep '%s'" word1 word2)" FILE
Если вы используете это чаще, это можно определить как псевдоним:
alias grep-all="</dev/stdin $(printf "|grep '%s'" word1 word2)"
затем запустите просто:
grep-all FILE
Если в файле хранится несколько шаблонов, см.:сопоставьте все шаблоны из файла сразу.
кроме того, проверить: как запустить grep с несколькими и шаблонами?