web-dev-qa-db-ja.com

テキストファイルからセグメントを取り出すための最良の方法は何ですか?

巨大なテキストファイルから20〜45行目を抽出する良い方法は何ですか。もちろん非対話型です!

13

あなたは試すことができます:

cat textfile | head -n 45 | tail -n 26

または

cat textfile | awk "20 <= NR && NR <= 45" 

更新:

Mahomedalidが指摘したように、catは必要ではなく、少し冗長ですが、クリーンで読みやすいコマンドになります。

catが気になる場合は、次のように解決することをお勧めします。

<textfile awk "20 <= NR && NR <= 45"
12
Stefan

さらに簡単:

sed -n '20,45p;45q' < textfile

-nフラグは、デフォルトの出力を無効にします。 「20,45」は、20行目から45行目までを対象としています。 「p」コマンドは現在の行を出力します。そして、qは行を印刷した後に終了します。

13
dkagedal

これは答えではありませんが、コメントとして投稿することはできません。

それを行う別の(非常に高速な)方法は、mikeservここ によって提案されました:

{ head -n 19 >/dev/null; head -n 26; } <infile

here と同じテストファイルと同じ手順を使用して、いくつかのベンチマークを示します(行1000020-1000045を抽出):

mikeserv

{ head -n 1000019 >/dev/null; head -n 26; } <iplist

real    0m0.059s

ステファン

head iplist -n 1000045 | tail -n 26

real    0m0.054s

これらははるかに高速なソリューションであり、違いはごくわずかです(シングルパスの場合)(私はさまざまな範囲で試しました:数行、数百万行など)。

ただし、パイプなしで実行すると、次のように同様の方法で複数の範囲の行をシークする必要があるアプリケーションに大きな利点があります。

for  pass in 0 1 2 3 4 5 6 7 8 9
do   printf "pass#$pass:\t"
     head -n99 >&3; head -n1
done <<1000LINES 3>/dev/null
$(seq 1000)
1000LINES

...印刷する...

pass#0: 100
pass#1: 200
pass#2: 300
pass#3: 400
pass#4: 500
pass#5: 600
pass#6: 700
pass#7: 800
pass#8: 900
pass#9: 1000

...そしてファイルを1回だけ読み取ります。


他のsed/awk/Perlソリューションはファイル全体を読み取りますが、これは巨大なファイルに関するものであるため、あまり効率的ではありません。指定された範囲の最後の行の後にexitまたはquitといういくつかの選択肢を投入しました。

ステファン

awk "1000020 <= NR && NR <= 1000045" iplist

real    0m2.448s

vs.

awk "NR >= 1000020;NR==1000045{exit}" iplist

real    0m0.243s

dkagedalsed):

sed -n 1000020,1000045p iplist

real    0m0.947s

vs.

sed '1,1000019d;1000045q' iplist

real    0m0.143s

スティーブンD

Perl -ne 'print if 1000020..1000045' iplist

real    0m2.041s

vs.

Perl -ne 'print if $. >= 1000020; exit if $. >= 1000045;' iplist

real    0m0.369s
6
don_crissti
Ruby -ne 'print if 20 .. 45' file
3
user1606

Sedとawkはすでに使用されているため、Perlソリューションは次のとおりです。

Perl -nle "print if ($. > 19 && $. < 46)" < textfile

または、コメントで指摘されているように:

Perl -ne 'print if 20..45' textfile
2
Steven D