複数のデータベースに相当するデータを含む、最大23000行のSQLダンプがあります。このファイルの特定のセクション(つまり、単一のデータベースのデータ)を抽出して、新しいファイルに配置する必要があります。必要なデータの開始行番号と終了行番号の両方を知っています。
例えば、16224と16482の間のファイルからすべての行を抽出し、それらを新しいファイルにリダイレクトするUnixコマンド(または一連のコマンド)を知っている人はいますか?
複数のデータベースに相当するデータを含む、最大23000行のSQLダンプがあります。このファイルの特定のセクション(つまり、単一のデータベースのデータ)を抽出して、新しいファイルに配置する必要があります。必要なデータの開始行番号と終了行番号の両方を知っています。
例えば、16224と16482の間のファイルからすべての行を抽出し、それらを新しいファイルにリダイレクトするUnixコマンド(または一連のコマンド)を知っている人はいますか?
回答:
sed -n '16224,16482p;16483q' filename > newfile
sedマニュアルから:
p-パターンスペースを(標準出力に)印刷します。このコマンドは通常、-nコマンドラインオプションと組み合わせてのみ使用されます。
n-自動印刷が無効になっていない場合は、パターンスペースを印刷してから、パターンスペースを次の入力行で置き換えます。入力がない場合、sedはコマンドを処理せずに終了します。
q-
sed
これ以上コマンドや入力を処理せずに終了します。-nオプションで自動印刷が無効になっていない場合は、現在のパターンスペースが印刷されることに注意してください。
sedスクリプトのアドレスは、次のいずれかの形式にすることができます。
number 行番号を指定すると、入力のその行だけに一致します。
アドレス範囲は、2つのアドレスをコンマ(、)で区切って指定できます。アドレス範囲は、最初のアドレスが一致するところから始まり、2番目のアドレスが(包括的に)一致するまで続きます。
sed -n '16224,16482p;16483q' filename
です。それ以外の場合、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の使用:
sed -n '16482,16482p' in.sql > out.sql
awkを使用:
awk 'NR>=10&&NR<=20' in.sql > out.sql
tail
です。
sed -n 16224,16482p' in.sql >out.sql
とawkコマンドを同じにする必要がありますawk 'NR>=16224&&NR<=16482' in.sql > out.sql
head -16482 in.sql | tail -$((16482-16224)) >out.sql
、計算をbashに任せることも知っておく価値があります
tail -n +16224
計算の削減にも使用できます
'vi'を使用してから、次のコマンドを使用できます。
:16224,16482w!/tmp/some-file
または:
cat file | head -n 16482 | tail -n 258
編集:-説明を追加するために、最初の16482行を表示するにはhead -n 16482を使用し、最初の出力から最後の258行を取得するにはtail -n 258を使用します。
cat
コマンドは必要ありません。head
ファイルを直接読み取ることができます。これは、1つで十分な2つのコマンド(図のように3つ)を使用するため、多くの代替手段よりも低速です。
cat
)200k行、約1Gを抽出します。他の解決策は少なくとも数分を必要とします。また、GNUでの最速のバリエーションはそうtail -n +XXX filename | head XXX
です。
には別のアプローチがありますawk
:
awk 'NR==16224, NR==16482' file
ファイルが大きい場合はexit
、最後に必要な行を読み取った後で問題がなくなる可能性があります。これにより、次の行を不必要に読み取ることがなくなります。
awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
awk 'NR==16224, NR==16482; NR==16482 {exit}' file
print; exit
。よろしくお願いします!
awk 'NR==16224, NR==16482; NR==16482 {exit}' file
cat dump.txt | head -16224 | tail -258
トリックを行う必要があります。このアプローチの欠点は、末尾の引数を決定し、「間」に終了行を含めるかどうかを計算するために計算を行う必要があることです。
cat
コマンドは必要ありません。head
ファイルを直接読み取ることができます。これは、1つで十分な2つのコマンド(図のように3つ)を使用するため、多くの代替手段よりも低速です。
| tail -$((16482 - 16224))
。
boxxarの肩の上に立って、私はこれが好きです。
sed -n '<first line>,$p;<last line>q' input
例えば
sed -n '16224,$p;16482q' input
$
手段「最後の行」、最初のコマンドが行うようsed
行で始まるすべての行に印刷16224
し、2番目のコマンドを作るには、sed
終了後にラインを印刷します16428
。(追加1
のためq
boxxarの溶液中の-rangeが必要ではないようです。)
終了行番号を2回指定する必要がないため、このバリアントが好きです。また、使用$
してもパフォーマンスに悪影響が及ばないことを測定しました。
素早く汚い:
head -16428 < file.in | tail -259 > file.out
おそらくそれを行うための最良の方法ではありませんが、うまくいくはずです。
ところで:259 = 16482-16224 + 1。
私はスプリッターと呼ばれるHaskellプログラムを書きました。これはまさにこれを実行します。私のリリースブログの投稿を読んでください。
次のようにプログラムを使用できます。
$ cat somefile | splitter 16224-16482
そして、それがすべてです。それをインストールするにはHaskellが必要です。ただ:
$ cabal install splitter
これで完了です。このプログラムがお役に立てば幸いです。
splitter
標準入力から読み取り専用?ある意味、それは重要ではありません。cat
コマンドは、それがないか持たないか不必要です。splitter 16224-16482 < somefile
または(ファイル名引数を取る場合)を使用しますsplitter 16224-16482 somefile
。
これをコマンドラインで確認することもできます:
cat filename|sed 'n1,n2!d' > abc.txt
例えば:
cat foo.pl|sed '100,200!d' > abc.txt
cat
これらのどちらでもコマンドは必要ありません。sed
はそれ自体でファイルを完全に読み取ることができます。または、ファイルから標準入力をリダイレクトすることもできます。
ヘッド/テールトリックを投稿しようとしていましたが、実際にはおそらくemacsを起動するだけです。;-)
新しい出力ファイルを開く、ctl-y save
何が起こっているのか見てみましょう。
PATHを更新してディレクトリを含める(またはPATHに既に含まれているディレクトリに配置する)ことができる限り、コマンドラインから実行できる小さなbashスクリプトを作成しました。
使用法:$ 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
wc
コマンドはファイルを2回読み取るため、特にギガバイトのファイルでは、ディスクの帯域幅が浪費されます。あらゆる方法で、これは十分に文書化されていますが、エンジニアリングのやり過ぎでもあります。
acceptの-nは機能します。傾向がある場合の別の方法を次に示します。
cat $filename | sed "${linenum}p;d";
これは次のことを行います。
cat file | sed
は次のように書くとより良いsed file
ここでは、テキストファイルからテキストの行を抽出することについて説明しているので、特定のパターンに一致するすべての行を抽出する特別な場合について説明します。
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