web-dev-qa-db-ja.com

Unix上のテキストファイルから所定の範囲の行を抽出する方法を教えてください。

いくつかのデータベースに相当するデータを含む23000行までのSQLダンプがあります。このファイルの特定のセクション(つまり単一のデータベースのデータ)を抽出し、それを新しいファイルに配置する必要があります。必要なデータの開始行番号と終了行番号の両方を知っています。

16224行から16482行の間にあるファイルからすべての行を抽出し、それらを新しいファイルにリダイレクトするというUnixコマンド(または一連のコマンド)を知っている人はいますか?

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

sedのマニュアルから

p - パターンスペースを(標準出力に)出力します。このコマンドは通常、-nコマンドラインオプションと組み合わせてのみ使用されます。

n - 自動印刷が無効になっていない場合は、パターンスペースを印刷してから、パターンスペースを次の入力行に置き換えます。それ以上入力がない場合、sedはそれ以上コマンドを処理せずに終了します。

q - これ以上コマンドや入力を処理せずにsedを終了します。自動印刷が-nオプションで無効にされていない場合、現在のパターンスペースが印刷されることに注意してください。

Sedスクリプトのアドレスは、次のいずれかの形式になります。

number 行番号を指定すると、入力内のその行だけに一致します。

アドレス範囲は、2つのアドレスをコンマ(、)で区切って指定することで指定できます。アドレス範囲は、最初のアドレスが一致する位置から始まる行に一致し、2番目のアドレスが一致するまで続きます。

703
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
81
manveru

'vi'を使用してから次のコマンドを使用できます。

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

あるいは

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

編集: - 説明を加えるために、 head -n 16482 を使用して最初の16482行を表示し、次に tail -n 258 を使用して最初の出力から最後の258行を取り出します。

26
Mark Janssen

awkには別のアプローチがあります。

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

ファイルが巨大な場合は、最後の目的の行を読んだ後でexitを実行するのが良いでしょう。このように、それは不必要に以下の行を読みません:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
21
fedorqui
Perl -ne 'print if 16224..16482' file.txt > new_file.txt
15
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の引数を決定し、 'between'に終了行を含めるかどうかを考慮するために算術演算を行う必要があることです。

5
JP Lodine

早くて汚い:

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

おそらく最善の方法ではありませんが、うまくいくはずです。

BTW:259 = 16482-16224 + 1。

3
jan.vdbergh

私は splitter と呼ばれるHaskellプログラムを書きました。これはまさにこれを行います:リリースブログの投稿で を読んでください

次のようにプログラムを使用できます。

$ cat somefile | splitter 16224-16482

そして、それだけです。 Haskellをインストールする必要があります。ただ:

$ cabal install splitter

これで完了です。このプログラムがお役に立てば幸いです。

3

私はヘッド/テールトリックを投稿しようとしていましたが、実際には私はおそらく単にemacsを起動させるでしょう。 ;-)

  1. esc - x 後藤行 ret 16224
  2. マーク(ctrl - space
  3. esc - x 後藤行 ret 16482
  4. esc - w

新しい出力ファイルを開く、ctl-y save

何が起こっているのか見てみましょう。

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

Boxxarの肩の上に立って、私はこれが好きです:

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

例えば.

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

$は "最後の行"を意味するので、最初のコマンドはsedに行16224で始まるすべての行を印刷させ、2番目のコマンドはsed after printing行16428にします。 (boxxarのソリューションでq- rangeに1を追加する必要はないようです。)

終了行番号を2回指定する必要がないので、この方法が好きです。そして私は、$を使用してもパフォーマンスに悪影響がないことを測定しました。

2
Tilman Vogel

私は使うだろう:

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

FNRには、ファイルから読み取られている行のレコード(行)番号が含まれています。

2
Paddy3118

これはうまくいくかもしれません(GNU sed)。

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

またはbashを利用する:

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

PATHをそのディレクトリを含むように更新する限り(またはPATHに既に含まれているディレクトリに置くことができる限り)、コマンドラインから実行できる小さなbashスクリプトを書きました。

使用法:$ 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
1
Nerdfighter

私は変数を使ってスクリプトから同じことをしたいと思っていて、pから変数名を分けるために$変数を囲むことによってそれを達成しました:

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

リストを別々のフォルダに分割して、最初の質問を見つけて便利な手順に答えたかったのです。 (splitコマンドは私がコードを移植しなければならない古いOS上のオプションではありません)。

1
KevinY

テキストファイルからテキストの行を抽出する方法について説明しているので、特定のパターンに一致するすべての行を抽出するという特別な場合を挙げます。

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

[Data]行と残りを印刷します。 line1からパターンまでのテキストが必要な場合は、次のように入力します。sed -n '1、/ Data/p' myfile。さらに、2つのパターンがわかっている場合(テキスト内で一意であることが望ましい)、範囲の開始行と終了行の両方をmatchで指定できます。

sed -n '/BEGIN_MARK/,/END_MARK/p' myfile
0
Kemin Zhou

Accept answerの-nは機能します。あなたが傾いている場合に備えて、これは別の方法です。

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

これにより、次のことが行われます。

  1. ファイルの内容をパイプインします(または必要なテキストを入力します)。
  2. sedは与えられた行を選択してそれを印刷します
  3. dは行を削除するのに必要で、そうでなければsedは結局すべての行が印刷されると仮定します。つまり、dを指定しないと、$ {linenum} p部分に印刷するように要求されているため、選択した行で印刷されたすべての行が2回印刷されます。私は-nが基本的にここでのdと同じことをしていると確信しています。
0
ThinkBonobo