web-dev-qa-db-ja.com

バイトオフセットから行番号を取得する

ファイルのバイトオフセットがある。

このバイトの行番号を提供するツールはありますか?

  • 最初のバイトは1ではなく0です。
  • 1から始まる行番号。
  • ファイルには、プレーンテキスト、「バイナリ」ブロブ、マルチバイト文字などの両方を含めることができます。しかし、私が興味のあるセクション:ファイルの終わり、ASCIIのみがあります。

例、ファイル:

_001
002
003  <<-- first zero on this line is byte 8
004
_

バイトオフセット_8_があると、行__3_になります。

行番号を見つけるためにこのようなものを使用できると思います:

a。 tail -c+(offset + 1) file | wc -l、ここでは_+1_ tailは1から数えるので.
b。 _wc -l file_
c。次に、_tail -n+num_で、numは_a - b + 1_です。

しかし... numを直接提供できるかなり一般的なツールはありますか?


編集、エラー:またはより明白な:

_head -c+offset file | wc -l
_
12
user367890

あなたの例では、

001
002
003
004

バイト番号8は2番目の改行であり、次の行の0ではありません。

以下は、$bバイト後の完全な行数を示します。

$ dd if=data.in bs=1 count="$b" | wc -l

bを8に設定して2を報告し、bを7に設定して1を報告します。

ここでの使用方法であるddユーティリティは、ファイルdata.inから読み取り、サイズ1バイトの$bブロックを読み取ります。

以下のコメントで「イカルス」が正しく指摘しているように、bs=1の使用は非効率的です。この特定のケースでは、bscountを交換する方が効率的です。

$ dd if=data.in bs="$b" count=1 | wc -l

これは最初のddコマンドと同じ効果がありますが、$bバイトの1ブロックのみを読み取ります。

wcユーティリティは改行をカウントし、Unixの「行」は常に改行で終了します。したがって、上記のコマンドは、bを12未満の値に設定した場合でも、2と表示されます(次の改行)。したがって、探している結果は、上記のパイプラインレポートの数に1を加えたものになります。

これにより、ASCIIテキストの前にある、ファイルのバイナリblob部分のランダムな改行もカウントされます。ASCIIビットの開始位置がわかっている場合は、 skip="$offset"ddコマンドに追加できます。ここで、$offsetはファイルにスキップするバイト数です。

14
Kusalananda

現在のところ、そのような専用のツールはありませんが、Pythonではかなり簡単に実行できます。

#!/usr/bin/env python3
import sys
import os

offset = int(sys.argv[2])
newline = 1
with open(sys.argv[1]) as fd:
    fd.seek(offset)
    while True:
        try:
            byte = fd.read(1)
            if byte == '\n': newline+=1
            #print(byte)
            offset = offset - 1
            fd.seek(offset)
        except ValueError:
            break
print(newline)

使い方は簡単です:

line4byte.py <FILE> <BYTE>

テスト走行:

$ cat input.txt
001
002
003
004
$ chmod +x ./line4byte.py                                                     
$ ./line4byte.py input.txt 8                                                  
3

これは非常に素早く簡単なスクリプトです。ファイルが空であるかどうかはチェックしないため、空でないファイルでのみ機能します。

4

指定されたオフセットが合計内にある場合は、表示されたバイトを追跡し、現在の行番号を出力します。

Perl -E '$off=shift;while(<>){$sum+=length;if($sum>=$off){say $.;exit}}' 8 file

または長々と:

#!/usr/bin/env Perl
use strict;
use warnings;
die "Usage: $0 offset file|-\n" if @ARGV != 2;
my $offset = shift;
shift if $ARGV[0] eq '-';
my $sum;
while (readline) {
    $sum += length;
    if ($sum >= $offset) {
        print "$.\n";
        exit;
    }
}
exit 1;
4
thrig
_$Perl -0nE 'say substr($_,0,8)=~ y/\n//'  ex
2
_
  • _Perl -0nE exp_入力を_$__に丸呑みし、expを実行します
  • substr(string,0,8)は最初の8バイトを選択します
  • _y/\n//_は_\n_を削除し、その数を返します
3
JJoao