it-swarm-ru.tech

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

У меня есть дамп SQL ~ 23000 строк, содержащий несколько баз данных. Мне нужно извлечь определенный раздел этого файла (то есть данные для одной базы данных) и поместить его в новый файл. Я знаю номера начала и конца строки нужных мне данных.

Кто-нибудь знает команду Unix (или серию команд), чтобы извлечь все строки из файла, скажем, между строками 16224 и 16482, а затем перенаправить их в новый файл?

447
Adam J. Forster
sed -n '16224,16482p;16483q' filename > newfile

Из руководства пользователя :

п - Распечатайте пространство шаблона (к стандартному выводу). Эта команда обычно используется только в сочетании с параметром командной строки -n.

n - Если автоматическая печать не отключена, напечатайте пространство шаблона, затем, независимо от этого, замените пространство шаблона следующей строкой ввода. Если больше нет входных данных, чем sed выходит без обработки команды.

q - Выйдите из sed без обработки каких-либо команд или ввода . Обратите внимание, что текущее пространство шаблона печатается, если автоматическая печать не отключена с опцией -n.

а также

Адреса в сценарии sed могут быть в любой из следующих форм:

число Указание номера строки будет соответствовать только этой строке на входе.

Диапазон адресов можно указать, указав два адреса через запятую (,). Диапазон адресов соответствует строкам, начинающимся с где первый адрес совпадает, и продолжается до второго адрес совпадает (включительно).

681
boxxar
sed -n '16224,16482 p' orig-data-file > new-file

Где 16224,16482 - номер начальной и конечной строки включительно. Это 1-индексированный. -n подавляет отображение ввода как вывода, что вам явно не нужно; числа указывают диапазон строк, на которых должна работать следующая команда; команда p печатает соответствующие строки.

195
JXG

Довольно просто, используя голову/хвост:

head -16482 in.sql | tail -258 > out.sql

используя sed:

sed -n '16482,16482p' in.sql > out.sql

используя awk:

awk 'NR>=10&&NR<=20' in.sql > out.sql
78
manveru

Вы можете использовать 'vi' и затем следующую команду:

:16224,16482w!/tmp/some-file

В качестве альтернативы: 

cat file | head -n 16482 | tail -n 258

Правка: - Просто чтобы добавить объяснение, вы используете head -n 16482 для отображения первых 16482 строк, затем используйте tail -n 258 , чтобы получить последние 258 строк из первого вывода. 

25
Mark Janssen

Есть другой подход с awk:

awk 'NR==16224, NR==16482' file

Если файл огромен, может быть полезно exit после прочтения последней требуемой строки. Таким образом, он не будет без необходимости читать файл до конца:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
20
fedorqui
Perl -ne 'print if 16224..16482' file.txt > new_file.txt
14
mmaibaum
 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2
8
Cetra

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

5
cubex
cat dump.txt | head -16224 | tail -258

должен сделать свое дело. Недостатком этого подхода является то, что вам нужно выполнить арифметику, чтобы определить аргумент для tail и учесть, хотите ли вы, чтобы между ними была добавлена ​​конечная строка или нет.

5
JP Lodine

Быстро и грязно:

head -16428 < file.in | tail -259 > file.out

Вероятно, не лучший способ сделать это, но это должно работать.

Кстати: 259 = 16482-16224 + 1.

3
jan.vdbergh

Я собирался опубликовать трюк с головой/хвостом, но на самом деле я бы просто запустил Emacs. ;-)

  1. esc-x Гото-линия ret 16224
  2. отметка (ctrl-space)
  3. esc-x Гото-линия ret 16482
  4. esc-w

откройте новый выходной файл, ctl-y сохраните

Давайте посмотрим, что происходит.

3
sammyo

Даже мы можем сделать это, чтобы проверить в командной строке:

cat filename|sed 'n1,n2!d' > abc.txt

Например:

cat foo.pl|sed '100,200!d' > abc.txt
2
Chinmoy Padhi

Используя Ruby:

Ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf
2
Carl Blakeley

Я хотел бы использовать:

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR содержит номер записи (строки) строки, читаемой из файла.

2
Paddy3118

Я написал программу на Haskell под названием splitter , которая делает именно это: есть прочитайте мою публикацию в блоге .

Вы можете использовать программу следующим образом:

$ cat somefile | splitter 16224-16482

И это все, что нужно сделать. Вам понадобится Haskell для его установки. Просто:

$ cabal install splitter

И вы сделали. Я надеюсь, что вы найдете эту программу полезной.

2
Robert Massaioli

Это может работать для вас (GNU sed):

sed -ne '16224,16482w newfile' -e '16482q' file

или воспользоваться bash:

sed -n $'16224,16482w newfile\n16482q' file
1
potong

Я написал небольшой скрипт bash, который вы можете запустить из командной строки, при условии, что вы обновляете свой PATH, чтобы включить его каталог (или вы можете поместить его в каталог, который уже содержится в PATH).

Использование: $ pinch filename start-line end-line

#!/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
1
Nerdfighter

Я хотел сделать то же самое из скрипта, использующего переменную, и достиг этого, поместив кавычки вокруг переменной $, чтобы отделить имя переменной от p:

sed -n "$first","$count"p imagelist.txt >"$imageblock"

Я хотел разделить список на отдельные папки, нашел начальный вопрос и ответил на полезный шаг. (команда split не является опцией для старой ОС, на которую я должен перенести код).

1
KevinY

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

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
0
Kemin Zhou

Стоя на плечах boxxar, мне нравится это:

sed -n '<first line>,$p;<last line>q' input

например.

sed -n '16224,$p;16482q' input

$ означает «последняя строка», поэтому первая команда заставляет sed печатать все строки, начинающиеся со строки 16224, а вторая команда sed quit after print line 16428. (Добавление 1 для диапазона q- в решении boxxar не является необходимым.)

Мне нравится этот вариант, потому что мне не нужно указывать номер конечной строки дважды. И я измерил, что использование $ не оказывает вредного влияния на производительность.

0
Tilman Vogel

Работа с ключами -n в ответах. Вот другой способ, если вы склонны.

cat $filename | sed "${linenum}p;d";

Это делает следующее:

  1. передать содержимое файла (или подать текст так, как вы хотите).
  2. sed выбирает данную строку, печатает ее
  3. для удаления строк требуется d, иначе sed будет предполагать, что все строки будут в конечном итоге напечатаны. то есть без d вы получите все строки, напечатанные выбранной строкой, напечатанные дважды, потому что у вас есть часть $ {linenum} p, запрашивающая ее печать. Я почти уверен, что -n в основном делает то же самое, что и d здесь.
0
ThinkBonobo