Unix 上のテキスト ファイルから所定の範囲の行を抽出するにはどうすればよいですか?

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

質問

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

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

役に立ちましたか?

解決

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

から SEDマニュアル:

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

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

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

そして

sed スクリプト内のアドレスは、次のいずれかの形式にすることができます。

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

アドレス範囲は、コンマ(、)で区切られた2つのアドレスを指定することで指定できます。アドレス範囲は、最初のアドレスが一致する場所から始まる行と一致し、2番目のアドレスが一致するまで続きます(包括的に)。

他のヒント

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

ここで、16224,16482 は開始行番号と終了行番号を含みます。これは 1 インデックス付きです。 -n 明らかに望ましくない入力を出力としてエコーすることを抑制します。数字は、次のコマンドを実行する行の範囲を示します。コマンド p 関連する行を出力します。

head/tail を使用すると非常に簡単です:

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

「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 2 番目のコマンドは sed やめる 印刷ライン 16428. 。(追加 1 のために qboxxar のソリューションの -range は必要ないようです。)

終了行番号を 2 回指定する必要がないので、このバリエーションが気に入っています。そして私はそれを使ってそれを測定しました $ パフォーマンスに悪影響を及ぼしません。

head/tail のトリックを投稿しようとしていましたが、実際には emacs を起動するだけかもしれません。;-)

  1. ESC-バツ 後藤行 レット 16224
  2. マーク (Ctrl-空間)
  3. ESC-バツ 後藤行 レット 16482
  4. ESC-w

新しい出力ファイル、CTL-yセーブを開きます

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

私は使うだろう:

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

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

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

使用法:$ ピンチ ファイル名 開始行 終了行

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

変数を使用してスクリプトから同じことを実行したいと思い、$variable を引用符で囲んで変数名と p を区切ることでそれを実現しました。

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

リストを別々のフォルダーに分割したかったのですが、最初の質問と回答が役立つステップであることがわかりました。(コードを移植する必要がある古い OS では、split コマンドはオプションではありません)。

受け入れ応答の -n は機能します。どうしてもという場合に備えて、別の方法を紹介します。

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

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

  1. ファイルの内容をパイプで入力します (または、必要に応じてテキストをフィードします)。
  2. sed は指定された行を選択し、それを出力します
  3. 行を削除するには d が必要です。そうでない場合、sed は最終的にすべての行が出力されると想定します。つまり、d を指定しないと、${linenum}p 部分で印刷を要求しているため、選択した行によって印刷されるすべての行が 2 回印刷されます。-n は基本的にここの d と同じことをしていると確信しています。

ここではテキスト ファイルからのテキスト行の抽出について説明しているため、特定のパターンに一致するすべての行を抽出するという特殊なケースを取り上げます。

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 つのパターンがわかっている場合 (テキスト内で一意であることが望ましい)、範囲の開始行と終了行の両方を一致で指定できます。

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