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


回答:


12

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

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

または

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

更新:

Mahomedalidが指摘したように、これcatは必要ではなく、少し冗長ですが、それはきれいで読みやすいコマンドを作成します。

場合はcat、あなたを気にしない、より良いsollutionは次のようになります。

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

2
awk NR==20,NR==45 textfileも動作し、簡単に読みます。
ephemient

stdinの使用がもっと好きです、それは他のnixといくつかのグローバルな一貫性を持っています
Stefan

1
コマンドライン引数からの読み取りは他のUNIXユーティリティとも整合性があり、私の主なポイントはawkの,範囲演算子を示すことでした。
ephemient 2010

笑、私は@アダムを意味しました。しかし、はい、私はあなたの提案を気に入っています
Stefan

@ephemientの答えがここで一番良いと思います。そうでなければ、コマンドはかなり不可解です。
レオ・レオポルド・ヘルツ준 영

13

さらにシンプル:

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

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


1
+1いいね、いいね、でも20〜45行目:)
Stefan

1
OK、OK、20,45と編集しました:-)
dkagedal

qコマンド(から始まるすべてのもの;)を削除すると、27169334行のファイルから26995107の1行を抽出するときのパフォーマンスが向上しました。
ルスラン

6

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

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

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

ここと同じテストファイルと同じ手順を使用して、いくつかのベンチマークを示します(行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

...そして、一度だけファイルを読み取ります。


sed/ awk/ perlソリューションは、ファイル全体を読んで、これは巨大なファイルについてですから、彼らは非常に効率的ではないです。指定した範囲の最後の行の後に、いくつかの代替案exitまたはquitを投入しました。

ステファン

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

real    0m2.448s

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

real    0m0.243s

dkagedalsed):

sed -n 1000020,1000045p iplist

real    0m0.947s

sed '1,1000019d;1000045q' iplist

real    0m0.143s

スティーブンD

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

real    0m2.041s

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

real    0m0.369s

+1これがここでの最良の答えだと思います!これでどれだけ時間がかかるかを知っておくといいでしょうawk NR==1000020,NR==1000045 textfileあなたのシステムに。
レオ・レオポルド・ヘルツ준 영

3
ruby -ne 'print if 20 .. 45' file

1
仲間のルビー主義者、あなたは私の投票権を得ます
ステファン

1
私たちがそれをしている間、どうしてpython -c 'import fileinput, sys; [sys.stdout.write(line) for nr, line in enumerate(fileinput.input()) if 19 <= nr <= 44]'ですか?:-Pこれはawk / sedに触発されたPerlをモデルにしたRubyが簡単に実行できるものです。

2

sedとawkはすでに使用されているので、以下にperlソリューションを示します。

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

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

perl -ne 'print if 20..45' textfile

2
これらすべての余分な文字とは何ですか?改行を削除して再度追加する必要はありません。フリップフロップは行番号との比較を想定し、ダイヤモンドオペレーターは引数が指定されている場合はそれを実行します。 perl -ne'print if 20..45' textfile
ephemient

1
いいね -nleは少し反射神経だと思います。残りについては、無知を除けば言い訳はありません。
Steven D
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.