как получить часть файла после строки, которая соответствует выражению grep? (первый матч)

<p>у меня есть файл с около 1000 строк. я хочу получить часть моего файла после строки, которая соответствует моему выражению grep.</p><p>то есть.</p><pre><code>$ cat file | grep 'terminate' // its found on line 534 итак, я хочу файл из строки 535 to line 1000 для дальнейшей обработки.как мне это сделать ?

далее будет напечатана строка, соответствующая terminate до конца файла:sed -n -e '/terminate/,$p' </code></pre><p><strong> объяснено: </strong><code>-n</code> отключает поведение по умолчанию <code>sed</code> печати каждой строки после выполнения на нем своего сценария, <code>-e</code> указывает сценарий на <code>sed</code>, <code>/terminate/,$ - это выбор диапазона адресов (строк), означающий, что первая строка соответствует регулярному выражению terminate (например, grep) в конец файла ($</code>), а <code>p</code> - команда печати, которая печатает текущую строку.</p><p>это выведет из строки, следующей за строкой, соответствующей <code>terminate</code>, до конца файла:<br> (от после соответствующей строки до eof, не включая соответствующую строку)</p><pre><code>sed -e '1,/terminate/d' </code></pre><p><strong> объяснено: </strong><code>1,/terminate/</code> - это выбор диапазона адресов (строк), означающий первую строку для ввода в 1-ю строку, соответствующую регулярному выражению <code>terminate</code>, а <code>d</code> - команда удаления, которая удаляет текущую строку и переходит к следующей строке. поскольку поведение <code>sed</code> по умолчанию заключается в печати строк, оно будет печатать строки после <code>terminate</code> до конца ввода.</p><p><strong> правка: </strong></p><p>если вы хотите строки до <code>terminate</code>:</p><pre><code>sed -e '/terminate/,$d' и если вам нужны обе строки до и после terminate в 2 разных файлах за один проход:sed -e '1,/terminate/w before /terminate/,$w after' file </code></pre><p>файлы before и after будут содержать строку с terminate, поэтому для обработки каждого из них вам необходимо использовать:</p><pre><code>head -n -1 before tail -n +2 after </code></pre><p><strong> edit2: </strong></p><p>если вы не хотите жестко кодировать имена файлов в сценарии sed, вы можете:</p><pre><code>before=before.txt after=after.txt sed -e "1,/terminate/w $before /terminate/,$w $after" file но тогда вам нужно экранировать $</code>, означающий последнюю строку, чтобы оболочка не пыталась расширить переменную <code>$w (обратите внимание, что теперь мы используем двойные кавычки вокруг скрипта вместо одинарных кавычек).я забыл сказать, что новая строка важна после имен файлов в скрипте, так что sed знает, что имена файлов заканчиваются. <strong> изменить: </strong>2016-0530себастьян клеман спросил: «как бы вы заменили жестко закодированный terminate на переменную?»вы должны создать переменную для соответствующего текста, а затем сделать это так же, как в предыдущем примере: matchtext=terminate before=before.txt after=after.txt sed -e "1,/$matchtext/w $before /$matchtext/,\$w $after" file </code></pre><p>использовать переменную для сопоставления текста с предыдущими примерами:</p><pre><code>## print the line containing the matching text, till the end of the file: ## (from the matching line to eof, including the matching line) matchtext=terminate sed -n -e "/$matchtext/,$p" </code></pre><pre><code>## print from the line that follows the line containing the ## matching text, till the end of the file: ## (from after the matching line to eof, not including the matching line) matchtext=terminate sed -e "1,/$matchtext/d" ## print all the lines before the line containing the matching text: ## (from line-1 to before the matching line, not including the matching line) matchtext=terminate sed -e "/$matchtext/,\$d" важными моментами о замене текста переменными в этих случаях являются:  переменные ($variablename</code>), заключенные в <code>single quotes</code> [<code>'</code>], не будут «расширяться», но переменные внутри <code>double quotes</code> [<code>"</code>] будут. таким образом, вы должны изменить все <code>single quotes</code> на <code>double quotes</code>, если они содержат текст, который вы хотите заменить на переменную. </li> <li>диапазоны <code>sed</code> также содержат <code>$, за которым сразу следует буква вроде: $p</code>, <code>$d, $w</code>. они также будут выглядеть как переменные для расширения, поэтому вам нужно экранировать эти символы <code>$ с обратной косой чертой [], например: $p</code>, <code>\$d, $w</code>.</li> </ol>

<p>в качестве простого приближения вы можете использовать</p><pre><code>grep -a100000 terminate file </code></pre><p>который использует <code>terminate</code> и выводит до 100000 строк после этой строки.</p><p>с man страницы</p><blockquote> <p><code>-a num, --after-context=num</code><br></p> <p><strong> вывести num строк конечного контекста после сопоставления строк. </strong> помещает строку, содержащую разделитель группы (-), между смежные группы спичек. с -o или --only-match опция, это не имеет никакого эффекта, и выдается предупреждение.</p> </blockquote>

<p>инструмент для использования здесь - awk:</p><pre><code>cat file | awk 'begin{ found=0} /terminate/{found=1} {if (found) print }' </code></pre><p>как это работает:</p><ol> <li>мы устанавливаем переменную 'found' в ноль, оценивая false</li> <li>если найдено совпадение для 'terminate' с регулярным выражением, мы устанавливаем его равным единице.</li> <li>если наша переменная 'found' имеет значение true, выведите :)</li> </ol><p>другие решения могут потреблять много памяти, если вы используете их для очень больших файлов.</p>

<p>используйте расширение параметров bash следующим образом:</p><pre><code>content=$(cat file) echo "${content#*terminate}" </code></pre>

<p>если я правильно понимаю ваш вопрос, вам нужны строки<strong> после </strong><code>terminate</code>, не включая строку <code>terminate</code>-. <code>awk</code> может сделать это простым способом:</p><pre><code>awk '{if(found) print} /terminate/{found=1}' your\_file </code></pre><p>объяснение:</p><ol> <li>хотя это не лучшая практика, вы можете полагаться на тот факт, что все переменные по умолчанию имеют значение 0 или пустую строку, если она не определена. поэтому первое выражение (<code>if(found) print</code>) не будет печатать ничего, с чего можно начать.</li> <li>после того, как печать завершена, мы проверяем, является ли это стартовой линией (которая не должна быть включена).</li> </ol><p>это напечатает все строки<strong> после </strong>строки <code>terminate</code>-.</p><hr><p><strong> обобщение: </strong></p><ul> <li>у вас есть файл со строками<strong> start </strong>- и<strong> end </strong>-, и вы хотите, чтобы между этими линиями были строки<strong> исключая </strong>/<strong> start </strong>- и<strong> end </strong>- строки.</li> <li>строки<strong> start </strong>- и<strong> end </strong>- могут быть определены регулярным выражением, совпадающим со строкой.</li> </ul><p>пример:</p><pre><code>$ cat ex_file.txt not this line second line start a good line to include and this line yep end nope more ... never ever $ awk '/end/{found=0} {if(found) print} /start/{found=1}' ex\_file.txt a good line to include and this line yep $ объяснение: если строка<strong> end </strong>- найдена, печать не производится. обратите внимание, что эта проверка выполняется<strong> до </strong>фактической печати, чтобы исключить строку<strong> end </strong>- из результата. вывести текущую строку, если установлена found. если строка<strong> start </strong>- найдена, установите found=1 так, чтобы были напечатаны следующие строки. обратите внимание, что эта проверка выполняется<strong> после </strong>фактической печати, чтобы исключить строку<strong> start </strong>- из результата. заметки: код опирается на тот факт, что по умолчанию все awk-vars имеют значение 0 или пустую строку, если она не определена. это верно, но не может быть лучшей практикой, поэтому вы можете добавить begin{found=0} в начало выражения awk. если найдено несколько блоков<strong> start-end </strong>-, все они печатаются. 

если по какой-либо причине вы хотите отказаться от использования sed, следующая строка выведет строку, соответствующую terminate, до конца файла:tail -n "+$(grep -n 'terminate' file | head -n 1 | cut -d ":" -f 1)" file </code></pre><p>и следующая строка будет напечатана из следующей строки, соответствующей <code>terminate</code>, до конца файла:</p><pre><code>tail -n "+$(($(grep -n 'terminate' file | head -n 1 | cut -d ":" -f 1)+1))" file </code></pre><p>чтобы сделать то, что sed может сделать в одном процессе, требуется 2 процесса, и если файл изменяется между выполнением grep и tail, результат может быть непоследовательным, поэтому я рекомендую использовать sed. более того, если файл не содержит <code>terminate</code>, 1-я команда не выполняется.</p>

<p>есть много способов сделать это с <code>sed</code> или <code>awk</code>:</p><pre><code>sed -n '/terminate/,$p' file это ищет terminate в вашем файле и печатает от этой строки до конца файла.awk '/terminate/,0' file это точно такое же поведение, как и sed.если вам известен номер строки, с которой вы хотите начать печать, вы можете указать ее вместе с nr (номер записи, которая в конечном итоге указывает номер строки):awk 'nr>=535' file пример$ seq 10 > a #generate a file with one number per line, from 1 to 10 $ sed -n '/7/,$p' a 7 8 9 10 $ awk '/7/,0' a 7 8 9 10 $ awk 'nr>=7' a 7 8 9 10 </code></pre>

<p>grep -a 10000000 'terminate' файл </p><ul> <li>намного, намного быстрее, чем sed, особенно при работе с действительно большими файлами. он работает до 10 миллионов строк (или что-то еще, что вы вставляете), так что нет ничего страшного в том, чтобы сделать его достаточно большим, чтобы справиться со всем, что вы ударили.</li> </ul>

<p>это может быть одним из способов сделать это. если вы знаете, в какой строке файла у вас есть grep word и сколько строк в вашем файле:</p><p>файл grep -a466 'terminate'</p>

<p>альтернативы отличному ответу <code>sed</code> от jfgagne, которые не содержат совпадающей строки:</p><ul> <li><code>awk '/terminate/ {y=1;next} y'</code> ( <a href="https://stackoverflow.com/a/18166628">https://stackoverflow.com/a/18166628</a> )</li> <li><code>awk '/terminate/ ? c++ : c'</code> ( <a href="https://stackoverflow.com/a/23984891">https://stackoverflow.com/a/23984891</a> )</li> <li><code>perl -ne 'print unless 1 .. /terminate/'</code> ( <a href="https://stackoverflow.com/a/18167194">https://stackoverflow.com/a/18167194</a> )</li> </ul>