ファイルのn行ごとにのみ保持する方法


71

かなり大きなCSVファイル(75MB)があります。グラフを作成しようとしているだけなので、すべてのデータが必要なわけではありません。

言い換え:n行を削除し、1行を保持してから、n行を削除します。

したがって、ファイルが次のようになった場合:

Line 1
Line 2
Line 3
Line 4
Line 5
Line 6

n = 2の場合、出力は次のようになります。

Line 3
Line 6

これsedを行うことができるように思えますが、私はその方法を理解できていません。bashコマンドが理想的ですが、私はどんな解決策も受け入れています。


2
1、4、7などではなく、1、3、6などの行が本当に必要ですか?
イルマリカロネン

2
CSVファイルであるため、最初の行にメタデータ(フィールド名)が含まれていると想定しています。その場合、質問は「最初からn行ごとに」でなければなりません。
iglvzx

7
1、3、6はまだ意味がありません!
WIM

1
n = 2が三角形の数値のマジック値(
1、3、6、10、15、21

4
質問を更新して、求めているもの(「n番目の行ごと」、「n = 2」)と目的の出力(行3、行6)の一貫性を保つことができますか?将来の読者は混乱するでしょう。
キーストンプソン

回答:


121
~ $ awk 'NR == 1 || NR % 3 == 0' yourfile
Line 1
Line 3
Line 6

NR(レコード数)変数は、デフォルトの動作がRS(レコードセパレーター)の改行であるため、レコードの行数です。パターンとアクションは、awkのデフォルト形式ではオプションです'pattern {actions}'。パターン部分のみを指定すると、パターンの条件のawkすべてのフィールドが書き込ま$0れますtrue


8
デフォルトのおかげで、あなたもそれほど必要ありません:awk 'NR == 1 || NR % 3 == 0'
ケビン

@selman:Kevinのソリューションが気に入ったら、答えを更新することを検討してください。
キーストンプソン

4
なぜそうなるのかを説明するのに気をつけますか?誰かが少しそれを微調整したい場合は、その後、うまくいけば、あなたの説明は彼らがそうするのに役立ちますその方法
イヴォFlipse

このアプローチでは、1行目と2行目はそのままであることがわかりました。これはawk 'NR == 1 || NR % 2 == 0' myfile.txt | wc -l、元のファイルの行数が偶数であるときに奇数になることで確認されます。@kev回答は、私のテストケースで最適に機能します。
ダニエルダクーニャ

58

sed これも行うことができます:

$ sed -n '1p;0~3p' input.txt
Line 1
Line 3
Line 6

man sed次の~ように説明します:

first〜step最初の行から始まるすべてのステップの行に一致します。たとえば、「sed -n 1〜2p」は入力ストリームのすべての奇数行を印刷し、アドレス2〜5は2行目から5行ごとに一致します。最初はゼロにすることができます。この場合、sedはstepと同等であるかのように動作します。(これは拡張機能です。)


6
このコマンドを説明してもらえますか?
QED

1
@qed説明:1p最初の行を0~3p印刷し、3行目から3行ごと1pに印刷します(したがって、1行目を印刷する必要があります)。ただし、これ0~3は標準ではなく、GNU sed拡張機能であることに注意してください。
Arkku

「これは拡張機能です。」どのバージョンを使用していますか?
ビクター

この答えは、Windows PowerShellにとって非常に役立ちました。私はそれをそのように広げました:sed -n '1p;0~10p' '.\in.txt' > out.txt縮小されたファイルを出力ファイルに印刷すること。
キムリフ

22

Perlもこれを行うことができます。

while (<>) {
    print  if $. % 3 == 1;
}

このプログラムは、入力の最初の行を出力し、その後3行ごとに出力します。

少し説明すると、このようなループで<>使用されると入力行を反復する行入力演算子whileです。特殊変数に$.は、これまでに読み込まれた行数が含まれ%、モジュラス演算子です。

このコードは、-n-eスイッチを使用して、ワンライナーとしてさらにコンパクトに記述できます。

perl -ne 'print if $. % 3 == 1'  < input.txt  > output.txt

-eながらスイッチは、コマンドラインパラメータとして実行するPerlのコードの一部をとり-n、スイッチが暗黙的にコードをラップwhile上に示したようなループ。


編集:私は最初にあなたが望んでいたと仮定として、実際に...むしろライン1、4、7、10、より、例のようにライン1、3、6、9、...を取得するには、交換してください$. % 3 == 1$. == 1 or $. % 3 == 0


7

Bashスクリプトを使用して実行する場合は、次を試してください。

#!/bin/sh

echo Please enter the file name
read fname
echo Please enter the Nth lines that you want to keep
read n

exec<$fname
value=0
while read line
do
    if [ $(( $value % $n )) -eq 0 ] ; then
        echo -e "$line" >> new_file.txt
    fi
        let value=value+1 
done
echo "Check the 'new_file.txt' that has been created in this directory";

「read_lines.sh」という名前で保存し、bashファイルに+ xパーミッションを忘れずに付与してください。

chmod +x ./read_lines.sh

1
これを標準出力で出力するようにした場合、引数からスキップする行数を読み取って、標準入力からファイルを読み取ると、より簡単で便利になります。することで、new_file.txtを作成でき./read_lines.sh > new_file.txtます。
rjmunro

4

プロセスを生成しない純粋なbashのソリューションは次のとおりです。

{ for f in {1..2}; do read line; done;
  while read line; do
    echo $line;
    for f in {1..2}; do read line; done;
  done; } < file

最初の行はファイルの先頭でwhile2行スキップし、次の行を印刷して2行スキップします。

ファイルが小さい場合、これはプロセスを開始しないため、ジョブを実行する非常に効率的な方法です。ファイルが大きい場合は、sedよりもioの処理が効率的であるため、使用する必要がありbashます。


1

Pythonバージョン(Python 2とPython 3の両方):

python2 -c "print(''.join(open('file.txt').readlines()[::3]))"

[::3]より詳細に制御するには、開始、終了、およびステップサイズのパラメーターに置き換えます。たとえば[10:36:5]、10、15、...、35行を出力します。

readlines()行末を保持しているため、選択したステップサイズで元の最終行が出力されない限り、この呼び出しの出力は空の最終行で終了する場合があります。

ストリームバージョンも可能です(ここでは、ストリームの終了後にのみ出力します)。

python -c "import sys;print(''.join(list(sys.stdin)[::3]))" < file.txt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.