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

StackOverflow https://stackoverflow.com/questions/83329

Вопрос

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

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

Это было полезно?

Решение

sed -n '16224,16482p;16483q' filename > newfile

Из СЭД руководство:

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

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

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

и

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

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

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

Другие советы

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

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

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

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

используя СЭД:

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

используя awk:

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

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

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

Альтернативно:

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

РЕДАКТИРОВАТЬ: - Просто чтобы добавить объяснение, вы используете голова -n 16482 чтобы отобразить первые 16482 строки, затем используйте хвост -n 258 чтобы получить последние 258 строк из первого вывода.

Существует еще один подход с awk:

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

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

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

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

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

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

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

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

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

КСТАТИ:259 = 16482-16224+1.

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

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

$ cat somefile | splitter 16224-16482

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

$ cabal install splitter

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

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

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

Например:

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

Использование рубина:

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

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

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

например

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

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

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

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

  1. выйти-Икс перейти к строке в отставку 16224
  2. отметка (Ctrl-космос)
  3. выйти-Икс перейти к строке в отставку 16482
  4. выйти-ш

Откройте новый выходной файл, CTL-Y Save

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

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

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

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

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

Использование:$ Pinch имя файла начало строки конец строки

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

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

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

или воспользовавшись bash:

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

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

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

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

-n в ответах принятия работает.Вот еще один способ, если вы склонны.

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

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

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

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

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

Я думаю, что это может быть полезным решением.Если имя таблицы — «person», вы можете использовать sed, чтобы получить все строки, необходимые для восстановления таблицы.

sed -n -e '/DROP TABLE IF EXISTS.*`person `/,/UNLOCK TABLES/p' data.sql  > new_data.sql

На основе этот ответ, где отсутствует параметр «DROP TABLE IF EXIST» для восстанавливаемой таблицы, и вам необходимо удалить несколько строк в нижней части нового файла, прежде чем использовать его, чтобы предотвратить удаление следующей таблицы.

Подробную информацию также можно найти здесь

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top