Obtém o número da linha do deslocamento de byte

11

Ter deslocamento de bytes para um arquivo.

Existe uma ferramenta que fornece um número de linha para este byte?

  • Contagem de bytes começando com zero, como em: primeiro byte é 0 não 1.
  • Número da linha que começa com 1.
  • O arquivo pode ter texto simples, blobs "binários", caracteres multibyte, etc. Mas a seção em que estou interessado: Fim do arquivo, tem apenas ASCII.

Exemplo, arquivo:

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

Ter deslocamento de byte 8 que me daria a linha 3 .

Acho que eu poderia usar algo assim para encontrar o número da linha:

a. tail -c+(offset + 1) file | wc -l , aqui +1 como tail contagens de 1.
b. wc -l file
c. Então tail -n+num onde num é a - b + 1

Mas ... existe uma ferramenta bastante comum, que pode me dar num diretamente?

Edite, erre: ou o mais óbvio:

head -c+offset file | wc -l
    
por user367890 31.01.2017 / 19:05

4 respostas

15

No seu exemplo,

001
002
003
004

o número de bytes 8 é a segunda nova linha, não o 0 na linha seguinte.

A seguir, você verá o número de linhas completas após $b bytes:

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

Ele reportará 2 com b definido como 8 e reportará 1 com b definido como 7.

O utilitário dd , como é usado aqui, lerá o arquivo data.in e lerá $b blocos de tamanho 1 byte.

Como o "icarus" aponta corretamente nos comentários abaixo, usar bs=1 é ineficiente. É mais eficiente, neste caso específico, trocar bs e count :

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

Isso terá o mesmo efeito que o primeiro comando dd , mas lerá apenas um bloco de $b bytes.

O utilitário wc conta as novas linhas e uma "linha" no Unix é sempre terminada por uma nova linha. Portanto, o comando acima ainda dirá 2 se você definir b para algo menor que 12 (a seguinte nova linha). O resultado que você está procurando é, portanto, qualquer número dos relatórios acima, mais 1.

Isso obviamente também contará as novas linhas aleatórias na parte do blob binário de seu arquivo que precede o texto ASCII. Se você soubesse onde o bit ASCII é iniciado, você poderia adicionar skip="$offset" ao comando dd , em que $offset é o número de bytes a serem ignorados no arquivo.

    
por 31.01.2017 / 19:19
4

Atualmente, não há ferramenta dedicada como essa, embora isso possa ser feito com facilidade em 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)

O uso é simples:

line4byte.py <FILE> <BYTE>

Execução de teste:

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

Este é um script muito rápido e simples. Não verifica se o arquivo está vazio ou não, então funciona apenas em arquivos não vazios.

    
por 31.01.2017 / 19:22
4

Rastreie os bytes vistos e emita o número da linha atual, caso o deslocamento especificado esteja dentro da soma:

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

Ou por extenso:

#!/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;
    
por 31.01.2017 / 19:29
3
$perl -0nE 'say substr($_,0,8)=~ y/\n//'  ex
2
  • perl -0nE exp usa a entrada em $_ e executa exp
  • substr(string,0,8) seleciona os primeiros 8 bytes
  • y/\n// remove o \n e retorna seu número
por 31.01.2017 / 22:02