바이트 오프셋에서 라인 번호 가져 오기


12

파일에 대한 바이트 오프셋이 있습니다.

이 바이트의 줄 번호를 제공하는 도구가 있습니까?

  • 다음과 같이 0으로 시작하는 바이트 수 : 첫 번째 바이트는 0이 아니라 1입니다.
  • 1로 시작하는 줄 번호
  • 파일에는 일반 텍스트, "이진"얼룩, 멀티 바이트 문자 등이 포함될 수 있습니다. 그러나 관심있는 섹션 : 파일 끝, ASCII 만 있습니다.

예를 들어, 파일 :

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

바이트 오프셋 8이 있으면 줄을 줄 것 3입니다.

줄 번호를 찾기 위해 다음과 같은 것을 사용할 수 있다고 생각합니다.

 ㅏ. tail -c+(offset + 1) file | wc -l여기 +1tail(1)에서 카운트
 나. wc -l file
 씨. 그런 tail -n+numnum입니다a - b + 1

그러나 ... 나를 num직접 줄 수있는 상당히 일반적인 도구가 있습니까?


편집, 오류 : 또는 더 명백한 :

head -c+offset file | wc -l

2
이진 파일에는 줄이 없습니다.
Kusalananda

@Kusalananda :이 문맥의 라인은 0x0a바이트로 구분 된 데이터 입니다.
user367890

3
아마 당신이 요구하는 것은 아니지만 Vim은 그 기능을 가지고 있습니다. 1부터 오프셋을 계산하므로 다음과 같습니다 :echo byte2line(offset+1)..
Satō Katsura

@SatoKatsura : 예, 감사합니다. vim을 먼저 사용해 보았습니다. 그러나도 함께 vim -b하고 vim+ set binary+ 열려있는 파일이 손상되었다. (아, 갑자기 어떤 플러그인이 엉망인지 기억합니다). 그러나 어쨌든, 이것을 일괄 적으로 사용하고 다양한 스크립트와 함께 Vim을 일찍 포기했습니다. 그러나 어쨌든 +1.
user367890

@ user367890 이진 파일은 0xa어디에나 있을 수 있습니다. 이진 파일의 줄 개념은 의미가 없습니다.
user207421

답변:


14

귀하의 예에서

001
002
003
004

바이트 번호 8은 0다음 줄이 아닌 두 번째 줄 바꿈 입니다.

다음은 $b바이트 이후 전체 줄 수를 제공합니다 .

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

그것은보고 2b8로 설정하고 그것을보고 1b7로 설정합니다.

dd유틸리티는 여기에서 사용되는 방식으로 파일 data.in에서 읽고 $b1 바이트 크기의 블록을 읽습니다 .

아래의 설명에서 "icarus"가 올바르게 지적했듯이 사용하는 bs=1것은 비효율적입니다. 이 특별한 경우에는보다 효율적으로 교체 bs하고 count:

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

이것은 첫 번째 dd명령 과 같은 효과가 있지만 한 블록의 $b바이트 만 읽습니다 .

wc유틸리티는 줄 바꿈을 계산하며 Unix의 "줄"은 항상 줄 바꿈으로 종료됩니다. 따라서 위의 명령은 12보다 작은 값 2을 설정 하면 여전히 표시됩니다 b(다음 줄 바꿈). 따라서 찾고있는 결과는 위의 파이프 라인 보고서 수에 1을 더한 값입니다.

이것은 분명히 파일의 바이너리 BLOB 부분에서 ASCII 텍스트 앞에 나오는 임의의 줄 바꿈을 계산합니다. 아스키 비트가 시작 위치를 알았다면, 당신은 추가 할 수 있습니다 skip="$offset"받는 dd명령 $offset바이트의 수가 파일로 건너 뛸 수 있습니다.


@don_crisstihead: unknown option -- c
Kusalananda

@Kusalananda BSD 헤드를 사용하고 있습니다. 옵션이 다릅니다
Sergiy Kolodyazhnyy

@ Serg :-) 나는 그것을 잘 알고 있습니다. OP가 무엇을 사용하는지 모르기 때문에 POSIX를 고수하고 있습니다.
Kusalananda

1
Q에서 언급했듯이 바이트 수는 1이 아닌 0으로 시작하므로 8 == 0 ...
user367890

@ user367890이 경우을 사용하십시오 $(( b - 1 )).
Kusalananda

4

파이썬에서는 상당히 쉽게 수행 할 수 있지만 현재 이와 같은 전용 도구는 없습니다.

#!/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;

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.