как я могу извлечь предопределенный диапазон строк из текстового файла в unix?

<p>у меня есть дамп sql ~ 23000 строк, содержащий несколько баз данных. мне нужно извлечь определенный раздел этого файла (то есть данные для одной базы данных) и поместить его в новый файл. я знаю номера начала и конца строки нужных мне данных.</p><p>кто-нибудь знает команду unix (или серию команд), чтобы извлечь все строки из файла, скажем, между строками 16224 и 16482, а затем перенаправить их в новый файл?</p>

<pre><code>sed -n '16224,16482p;16483q' filename > newfile </code></pre><p>из <a href="https://www.gnu.org/software/sed/manual/sed.html#common-commands">руководства пользователя</a> :</p><blockquote> <p><strong>п</strong> - распечатайте пространство шаблона (к стандартному выводу). эта команда обычно используется только в сочетании с параметром командной строки -n.</p> <p><strong>n</strong> - если автоматическая печать не отключена, напечатайте пространство шаблона, затем, независимо от этого, замените пространство шаблона следующей строкой ввода. если больше нет входных данных, чем sed выходит без обработки команды.</p> <p><strong>q</strong> - выйдите из <code>sed</code> без обработки каких-либо команд или ввода . обратите внимание, что текущее пространство шаблона печатается, если автоматическая печать не отключена с опцией -n.</p> </blockquote><p> <a href="https://www.gnu.org/software/sed/manual/sed.html#addresses">а также</a> </p><blockquote> <p>адреса в сценарии sed могут быть в любой из следующих форм:</p> <p><strong>число</strong> указание номера строки будет соответствовать только этой строке на входе.</p> <p>диапазон адресов можно указать, указав два адреса через запятую (,). диапазон адресов соответствует строкам, начинающимся с где первый адрес совпадает, и продолжается до второго адрес совпадает (включительно).</p> </blockquote>

<pre><code>sed -n '16224,16482 p' orig-data-file > new-file </code></pre><p>где 16224,16482 - номер начальной и конечной строки включительно. это 1-индексированный. <code>-n</code> подавляет отображение ввода как вывода, что вам явно не нужно; числа указывают диапазон строк, на которых должна работать следующая команда; команда <code>p</code> печатает соответствующие строки.</p>

<p>довольно просто, используя голову/хвост:</p><pre><code>head -16482 in.sql | tail -258 > out.sql </code></pre><p>используя sed:</p><pre><code>sed -n '16482,16482p' in.sql > out.sql </code></pre><p>используя awk:</p><pre><code>awk 'nr>=10&&nr<=20' in.sql > out.sql </code></pre>

<p>вы можете использовать 'vi' и затем следующую команду:</p><pre><code>:16224,16482w!/tmp/some-file </code></pre><p>в качестве альтернативы: </p><pre><code>cat file | head -n 16482 | tail -n 258 </code></pre><p>правка: - просто чтобы добавить объяснение, вы используете<strong> head -n 16482 </strong>для отображения первых 16482 строк, затем используйте<strong> tail -n 258 </strong>, чтобы получить последние 258 строк из первого вывода. </p>

<p>есть другой подход с <code>awk</code>:</p><pre><code>awk 'nr==16224, nr==16482' file </code></pre><p>если файл огромен, может быть полезно <code>exit</code> после прочтения последней требуемой строки. таким образом, он не будет без необходимости читать файл до конца:</p><pre><code>awk 'nr==16224, nr==16482-1; nr==16482 {print; exit}' file </code></pre>

<pre><code>perl -ne 'print if 16224..16482' file.txt > new\_file.txt </code></pre>

<pre><code> # print section of file based on line numbers sed -n '16224 ,16482p' # method 1 sed '16224,16482!d' # method 2 </code></pre>

<p><code>sed -n '16224,16482p' < dump.sql</code></p>

<pre><code>cat dump.txt | head -16224 | tail -258 </code></pre><p>должен сделать свое дело. недостатком этого подхода является то, что вам нужно выполнить арифметику, чтобы определить аргумент для tail и учесть, хотите ли вы, чтобы между ними была добавлена конечная строка или нет.</p>

<p>быстро и грязно:</p><pre><code>head -16428 < file.in | tail -259 > file.out </code></pre><p>вероятно, не лучший способ сделать это, но это должно работать.</p><p>кстати: 259 = 16482-16224 + 1.</p>

<p>я собирался опубликовать трюк с головой/хвостом, но на самом деле я бы просто запустил emacs. ;-)</p><ol> <li><kbd>esc</kbd>-<kbd>x</kbd> гото-линия <kbd>ret</kbd> 16224</li> <li>отметка (<kbd>ctrl</kbd>-<kbd>space</kbd>)</li> <li><kbd>esc</kbd>-<kbd>x</kbd> гото-линия <kbd>ret</kbd> 16482</li> <li><kbd>esc</kbd>-<kbd>w</kbd></li> </ol><p>откройте новый выходной файл, ctl-y сохраните</p><p>давайте посмотрим, что происходит.</p>

<p>даже мы можем сделать это, чтобы проверить в командной строке:</p><pre><code>cat filename|sed 'n1,n2!d' > abc.txt </code></pre><p>например:</p><pre><code>cat foo.pl|sed '100,200!d' > abc.txt </code></pre>

<p>используя ruby:</p><pre><code>ruby -ne 'puts "#{$.}: #{$\_}" if $. >= 32613500 && $. <= 32614500' < gnd.rdf > gnd.extract.rdf </code></pre>

<p>я хотел бы использовать:</p><pre><code>awk 'fnr >= 16224 && fnr <= 16482' my\_file > extracted.txt </code></pre><p>fnr содержит номер записи (строки) строки, читаемой из файла.</p>

<p>я написал программу на haskell под названием <a href="http://hackage.haskell.org/package/splitter">splitter</a> , которая делает именно это: есть <a href="http://robertmassaioli.wordpress.com/2013/07/25/a-line-based-file-splitter-for-the-command-line/">прочитайте мою публикацию в блоге</a> .</p><p>вы можете использовать программу следующим образом:</p><pre><code>$ cat somefile | splitter 16224-16482 и это все, что нужно сделать. вам понадобится haskell для его установки. просто:$ cabal install splitter </code></pre><p>и вы сделали. я надеюсь, что вы найдете эту программу полезной.</p>

<p>это может работать для вас (gnu sed):</p><pre><code>sed -ne '16224,16482w newfile' -e '16482q' file </code></pre><p>или воспользоваться bash:</p><pre><code>sed -n $'16224,16482w newfilen16482q' file 

я написал небольшой скрипт bash, который вы можете запустить из командной строки, при условии, что вы обновляете свой path, чтобы включить его каталог (или вы можете поместить его в каталог, который уже содержится в path).использование: $ pinch filename start-line end-line</p><pre><code>#!/bin/bash # display line number ranges of a file to the terminal. # usage: $ pinch filename start-line end-line # by evan j. coon filename=$1 start=$2 end=$3 error="[pinch error]" # check that the number of arguments is 3 if [ $# -lt 3 ]; then echo "$error need three arguments: filename start-line end-line" exit 1 fi # check that the file exists. if [ ! -f "$filename" ]; then echo -e "$error file does not exist. \n\t$filename" exit 1 fi # check that start-line is not greater than end-line if [ "$start" -gt "$end" ]; then echo -e "$error start line is greater than end line." exit 1 fi # check that start-line is positive. if [ "$start" -lt 0 ]; then echo -e "$error start line is less than 0." exit 1 fi # check that end-line is positive. if [ "$end" -lt 0 ]; then echo -e "$error end line is less than 0." exit 1 fi numoflines=$(wc -l < "$filename") # check that end-line is not greater than the number of lines in the file. if [ "$end" -gt "$numoflines" ]; then echo -e "$error end line is greater than number of lines in file." exit 1 fi # the distance from the end of the file to end-line enddiff=$(( numoflines - end )) # for larger files, this will run more quickly. if the distance from the # end of the file to the end-line is less than the distance from the # start of the file to the start-line, then start pinching from the # bottom as opposed to the top. if [ "$start" -lt "$enddiff" ]; then < "$filename" head -n $end | tail -n +$start else < "$filename" tail -n +$start | head -n $(( end-start+1 )) fi # success exit 0 </code></pre>

<p>я хотел сделать то же самое из скрипта, использующего переменную, и достиг этого, поместив кавычки вокруг переменной $, чтобы отделить имя переменной от p:sed -n "$first","$count"p imagelist.txt >"$imageblock" </code></pre><p>я хотел разделить список на отдельные папки, нашел начальный вопрос и ответил на полезный шаг. (команда split не является опцией для старой ос, на которую я должен перенести код).</p>

<p>поскольку речь идет об извлечении строк текста из текстового файла, я приведу особый случай, когда вы хотите извлечь все строки, которые соответствуют определенному шаблону. </p><pre><code>myfile content: ===================== line1 not needed line2 also discarded [data] first data line second data line ===================== sed -n '/data/,$p' myfile напечатает строку [данные] и остальные. если вы хотите, чтобы текст из строки 1 соответствовал шаблону, введите: sed -n '1,/data/p' myfile. кроме того, если вы знаете два шаблона (лучше быть уникальными в вашем тексте), начальная и конечная линии диапазона могут быть указаны с помощью совпадений.sed -n '/begin_mark/,/end_mark/p' myfile 

стоя на плечах boxxar, мне нравится это:sed -n '<first line>,$p;<last line>q' input </code></pre><p>например.</p><pre><code>sed -n '16224,$p;16482q' input $</code> означает «последняя строка», поэтому первая команда заставляет <code>sed</code> печатать все строки, начинающиеся со строки <code>16224</code>, а вторая команда <code>sed</code> quit<em> after </em>print line <code>16428</code>. (добавление <code>1</code> для диапазона <code>q</code>- в решении boxxar не является необходимым.)</p><p>мне нравится этот вариант, потому что мне не нужно указывать номер конечной строки дважды. и я измерил, что использование <code>$ не оказывает вредного влияния на производительность.

работа с ключами -n в ответах. вот другой способ, если вы склонны.cat $filename | sed "${linenum}p;d"; это делает следующее: передать содержимое файла (или подать текст так, как вы хотите). sed выбирает данную строку, печатает ее для удаления строк требуется d, иначе sed будет предполагать, что все строки будут в конечном итоге напечатаны. то есть без d вы получите все строки, напечатанные выбранной строкой, напечатанные дважды, потому что у вас есть часть $ {linenum} p, запрашивающая ее печать. я почти уверен, что -n в основном делает то же самое, что и d здесь.</li> </ol>