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

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

ファイルのバイトオフセットがあります。

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

  • バイト数は次のように0から始まります。最初のバイトは 1 ではなく 0 です。
  • 行番号は1から始まります。
  • ファイルには、プレーンテキスト、「バイナリ」ブロブ、マルチバイト文字などを含めることができます。しかし、私が興味を持っているのは、ファイルの終わり、ASCIIだけです。

はい、ファイル:

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

バイトオフセットがある場合は8ラインが表示されます3

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

 ㅏ。tail -c+(offset + 1) file | wc -l、ここでは1から計算が+1始まります。氏。だからどこtail
wc -l file
tail -n+numnuma - b + 1

numしかし、私に直接提供できるかなり一般的なツールがありますか?


編集、エラー:またはより明確です:

head -c+offset file | wc -l

答え1

あなたの例では

001
002
003
004

0バイト番号8は、次の行ではなく2番目の改行文字です。

$b以下は、バイトの後の完全な行番号を提供します。

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

2レポートはb8に設定され、レポートは71に設定されますb

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

"icarus"は、以下のコメントで正しく指摘したように、bs=1使用するのに非常に非効率的です。この特別なケースでは、合計を変更する方がbs効率的ですcount

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

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

このwcユーティリティは、Unixで「行」が常に終了する改行文字を計算します。したがって、12より低い値(改行文字の下)に2設定すると、上記のコマンドは引き続き表示されます。bしたがって、探している結果は、上記のパイプラインが報告する数値に1を加えたものです。

明らかに、これはASCIIテキストの前にあるファイルのバイナリブロブ部分にある任意の改行文字も計算します。 ASCIIビットの開始位置がわかっている場合は、ファイルに移動するバイト数をコマンドskip="$offset"に追加できます。dd$offset

答え2

現在これには専用のツールはありませんが、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

これは非常に高速で簡単なスクリプトです。ファイルが空であることを確認しないため、空でないファイルでのみ機能します。

答え3

与えられたオフセットが合計内にある場合、表示されたバイトを追跡し、現在の行番号をエクスポートします。

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

$perl -0nE 'say substr($_,0,8)=~ y/\n//'  ex
2
  • perl -0nE exp入力を飲み込んで$_expを実行する
  • substr(string,0,8) 最初の8バイトを選択
  • y/\n//その番号を削除し\nて返します。

関連情報