как выполнить поиск для нескольких шаблонов с шаблоном, имеющим символ трубы?

<p>я хочу найти все строки в нескольких файлах, которые соответствуют одному из двух шаблонов. я попытался найти шаблоны, которые я ищу, набрав</p><pre><code>grep (foo|bar) *.txt </code></pre><p>но shell интерпретирует <code>|</code> как канал и жалуется, когда <code>bar</code> не является исполняемым файлом.</p><p>как я могу найти несколько шаблонов в одном наборе файлов?</p>

<p>во-первых, вам нужно защитить шаблон от расширения оболочкой. самый простой способ сделать это - заключить в него одинарные кавычки. одинарные кавычки предотвращают расширение чего-либо между ними (включая обратную косую черту); единственное, что вы не можете сделать, - это использовать одинарные кавычки в шаблоне.</p><pre><code>grep -- 'foo*' *.txt </code></pre><p>(также обратите внимание на <code>--</code> end-of-option-marker для остановки некоторых реализаций <code>grep</code>, включая gnu <code>grep</code>, от обработки файла с именем <code>-foo-.txt</code> например (это было бы расширено shell от <code>*.txt</code>) для использования в качестве опции (хотя здесь следует аргумент, не являющийся опцией)).</p><p>если вам нужна одиночная цитата, вы можете написать ее как <code>'\''</code> (конец строкового литерала, литеральная кавычка, открытый строковый литерал).</p><pre><code>grep -- 'foo*'\''bar' *.txt </code></pre><p>во-вторых, grep поддерживает как минимум два синтаксиса для шаблонов. старый синтаксис по умолчанию ( <a href="https://en.wikipedia.org/wiki/regular\_expression#posix\_basic\_and\_extended">основные регулярные выражения</a> ) не поддерживает чередование (<code>|</code>), хотя в некоторых версиях оно имеет расширение, но написано с обратной косой чертой.</p><pre><code>grep -- 'foo\|bar' *.txt </code></pre><p>переносимым способом является использование более нового синтаксиса <a href="https://en.wikipedia.org/wiki/regular\_expression#posix\_extended">расширенные регулярные выражения</a> . вам нужно пройти <code>-e</code> возможность <code>grep</code> выбрать его (ранее это было сделано с помощью отдельной команды <code>egrep</code>²)</p><pre><code>grep -e -- 'foo|bar' *.txt </code></pre><p>другой возможностью, когда вы просто ищете какой-либо из нескольких шаблонов (в отличие от построения сложного шаблона с использованием дизъюнкции), является передача нескольких шаблонов в <code>grep</code>. вы можете сделать это, предшествуя каждому шаблону <code>-e</code> вариант.</p><pre><code>grep -e foo -e bar -- *.txt </code></pre><p>или поместите шаблоны в несколько строк:</p><pre><code>grep -- 'foo bar' *.txt </code></pre><p>или сохраните эти шаблоны в файле, по одному на строку и запустите</p><pre><code>grep -f that-file -- *.txt </code></pre><p>обратите внимание, что если <code>*.txt</code> расширяется до одного файла, <code>grep</code> не будет ставить префикс совпадающих строк с его именем, как при наличии более одного файла. чтобы обойти это, в некоторых реализациях <code>grep</code>, таких как gnu <code>grep</code>, вы можете использовать <code>-h</code> или с любой реализацией вы можете передать <code>/dev/null</code> как дополнительный аргумент.</p><hr><p><sup>\_ некоторые реализации <code>grep</code> поддерживают даже больше, чем perl-совместимые с <code>-p</code>, или <em> дополненные </em> с <code>-x</code>, <code>-k</code> для подстановочных знаков ksh ...</sup></p><p><sup>² в то время как <code>egrep</code> устарела в posix и иногда больше не встречается в некоторых системах, в некоторых других системах, таких как solaris, когда утилиты posix или gnu не установлены, то <code>egrep</code> ваш единственный вариант, так как <code>/bin/grep</code> не поддерживает ни одного из <code>-e</code>, <code>-f</code>, <code>-e</code>, <code>\|</code> или многострочные шаблоны</sup></p>

<pre><code>egrep "foo|bar" *.txt </code></pre><p>или</p><pre><code>grep "foo\|bar" *.txt grep -e "foo|bar" *.txt </code></pre><p>выборочно цитируя справочную страницу gnu-grep:</p><pre><code> -e, --extended-regexp interpret pattern as an extended regular expression (ere, see below). (-e is specified by posix.) matching control -e pattern, --regexp=pattern use pattern as the pattern. this can be used to specify multiple search patterns, or to protect a pattern beginning with a hyphen (-). (-e is specified by posix.) </code></pre><p>(...)</p><pre><code> grep understands two different versions of regular expression syntax: “basic” and “extended.” in gnu grep, there is no difference in available functionality using either syntax. in other implementations, basic regular expressions are less powerful. the following description applies to extended regular expressions; differences for basic regular expressions are summarized afterwards. </code></pre><p>в начале я не читал дальше, поэтому я не узнал тонких различий:</p><pre><code>basic vs extended regular expressions in basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the backslashed versions \?, \+, \{, \|, \(, and \). </code></pre><p>я всегда использовал egrep и ненужные парены, потому что я учился на примерах. теперь я узнал что-то новое. :)</p>

<p>как сказал tc1, <code>-f</code> кажется приемлемым вариантом:</p><pre><code>$> cat text some text foo another text bar end of file $> patterns="foo bar" $> grep -f "${patterns}" text foo bar </code></pre>

<p>во-первых, вам нужно использовать кавычки для специальных символов. во-вторых, даже в этом случае <code>grep</code> не будет понимать чередование напрямую; вам нужно будет использовать <code>egrep</code> или (только с gnu <code>grep</code>)) <code>grep -e</code>.</p><pre><code>egrep 'foo|bar' *.txt </code></pre><p>(скобки не нужны, если чередование не является частью большего регулярного выражения.)</p>

<p>если вам не нужны регулярные выражения, гораздо быстрее использовать <code>fgrep</code> или <code>grep -f</code> с несколькими параметрами -e, например:</p><pre><code>fgrep -efoo -ebar *.txt </code></pre><p><code>fgrep</code> (альтернативно <code>grep -f</code>) намного быстрее, чем обычный grep, потому что он ищет фиксированные строки вместо регулярных выражений.</p>

<p>вы можете попробовать приведенную ниже команду, чтобы получить результат:</p><pre><code>egrep 'rose.*lotus|lotus.*rose' some\_file </code></pre>

<p>труба (<code>|</code>) является специальным символом оболочки, поэтому его необходимо либо экранировать (<code>\|</code>) или указано в соответствии с руководством ( <a href="https://linux.die.net/man/1/bash"><code>man bash</code></a> ):</p><blockquote> <p><strong> цитирование используется для удаления специального значения </strong> определенных символов или слов в командной консоли. его можно использовать для отключения специальной обработки для специальных символов, для предотвращения распознавания зарезервированных слов как таковых и для предотвращения расширения параметров.</p> <p><strong> заключение символов в двойные кавычки сохраняет буквальное значение </strong> всех символов в кавычках</p> <p>обратная косая черта без кавычек (<code>\</code>) это escape-символ.</p> </blockquote><p>смотрите: <a href="https://stackoverflow.com/q/15783701/55075">какие символы нужно экранировать в bash?</a> </p><p>вот несколько примеров (с использованием еще не упомянутых инструментов):</p><ul> <li> <p>используя <a href="http://blog.burntsushi.net/ripgrep/"><code>ripgrep</code></a> :</p> <ul> <li><code>rg "foo|bar" *.txt</code></li> <li><code>rg -e foo -e bar *.txt</code></li> </ul> </li> <li> <p>с помощью <a href="https://git-scm.com/docs/git-grep"><code>git grep</code></a> :</p> <ul> <li> <p><code>git grep --no-index -e foo --or -e bar</code></p> <p><sup>примечание: он также поддерживает логические выражения, такие как <code>--and</code>, <code>--or</code> а также <code>--not</code>.</sup></p> </li> </ul> </li> </ul><p>для операции and на строку см .: <a href="https://unix.stackexchange.com/q/55359/21471">как запустить grep с несколькими шаблонами and?</a> </p><p>для операции and для файла см .: <a href="https://stackoverflow.com/q/49762772/55075">как проверить, что в файле есть несколько строк или регулярных выражений?</a> </p>

<p>дешевый и веселый способ поиска нескольких шаблонов:</p><pre><code>$ echo "foo" > ewq ; echo "bar" >> ewq ; grep -h -f ewq *.txt ; rm ewq </code></pre>

<p>у меня были журналы доступа, где даты были тупо отформатированы: [30/jun/2013: 08: 00: 45 +0200]</p><p>но мне нужно было отобразить это как: 30 июня 2013 года 08:00:45</p><p>проблема в том, что, используя "or" в моем выражении grep, я получал два выражения соответствия в двух отдельных строках.</p><p>вот решение:</p><pre><code>grep -in myurl\_of\_interest *access.log | \ grep -eo '(\b[[:digit:]]{2}/[[:upper:]][[:lower:]]{2}/[[:digit:]]{4}|[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\b)' \ | paste - - -d" " > myaccess.log </code></pre>

<p>tl; dr: если вы хотите сделать больше вещей после сопоставления с одним из нескольких шаблонов, заключите их как в <code>\(pattern1\|pattern2\)</code></p><p>пример: я хочу найти все места, где переменная, которая содержит имя "date", определяется как string или int. (например, "int crondate =" или "string textformatteddatestamp ="):</p><pre>\_<code>cat myfile | grep '\(int\|string\) [a-za-z\_]*date[a-za-z\_]* =' </code>\_</pre><p>с \_<code>grep -e</code>\_ вам не нужно избегать скобок или канала, то есть <code>grep -e '(int|string) [a-za-z\_]*date[a-za-z\_]* ='</code></p>

<p>это работает для меня</p><pre class="lang-none prettyprint-override"><code>root@gateway:/home/sshuser# aws ec2 describe-instances --instance-ids i-2db0459d |grep 'state\|tag' **state** 80 stopped **state**reason client.userinitiatedshutdown client.userinitiatedshutdown: user initiated shutdown **tags** name magento-testing root@gateway:/home/sshuser# </code></pre>

<p>есть несколько способов сделать это.</p><ol> <li><code>grep 'foo\|bar' *.txt</code></li> <li><code>egrep 'foo|bar' *.txt</code></li> <li><code>find . -maxdepth 1 -type f -name "*.txt" | xargs grep 'foo\|bar'</code></li> <li><code>find . -maxdepth 1 -type f -name "*.txt" | xargs egrep 'foo|bar'</code></li> </ol><p>3-й и 4-й вариант будут работать только в файлах и избегать каталогов, имеющих <code>.txt</code> в их именах.<br> таким образом, согласно вашему варианту использования, вы можете использовать любой из вариантов, упомянутых выше.<br> спасибо!!</p>

<p>добавить к <a href="https://unix.stackexchange.com/a/37314/100397">ответ @ geekosaur's</a> , если у вас есть несколько шаблонов, которые также содержат вкладки и пробел, вы используете следующую команду</p><pre><code>grep -e "foo[[:blank:]]|bar[[:blank:]]" </code></pre><p>где <code>[[:blank:]]</code> является re символьным классом, который представляет собой пробел или символ табуляции</p>