बाइट ऑफसेट से लाइन नंबर प्राप्त करें


12

फ़ाइल के लिए बाइट ऑफ़सेट होना।

क्या कोई उपकरण है जो इस बाइट के लिए लाइन नंबर देता है?

  • बाइट की गिनती शून्य से शुरू होती है, जैसे: पहली बाइट 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, यहाँ के +1रूप में tail1.
 बी से मायने रखता है । wc -l file
 सी। फिर tail -n+num कहां numहैa - b + 1

लेकिन ... क्या एक बहुत, सामान्य उपकरण है, जो मुझे numसीधे दे सकता है ?


संपादित करें, गलत: या अधिक स्पष्ट:

head -c+offset file | wc -l

2
बाइनरी फ़ाइलों में लाइनें नहीं हैं।
Kusalananda

@ कुसलानंद: इस संदर्भ में लाइनें 0x0aबाइट्स द्वारा अलग किए गए डेटा हैं ।
user367890

3
शायद नहीं जो आप पूछ रहे हैं, लेकिन विम के पास इसके लिए एक फ़ंक्शन है। यह 1 से ऑफसेट को गिनता है, इसलिए :echo byte2line(offset+1):।
सातु कटुरा

@SatoKatsura: हाँ, और धन्यवाद। पहले विम के साथ कोशिश की। लेकिन + vim -bऔर vim+ set binaryखुली फ़ाइल के साथ भी यह दूषित हो गया। (आह। अचानक मुझे याद है कि कौन सा प्लगइन इसे गड़बड़ करता है)। लेकिन, वैसे भी, जैसा कि मैं बैचों में इसका उपयोग करता हूं और स्क्रिप्ट की एक श्रृंखला के संयोजन में विम को जल्दी छोड़ दिया गया था। लेकिन +1 वैसे भी।
user367890

@ user367890 एक बाइनरी फ़ाइल 0xaकहीं भी हो सकती है। एक बाइनरी फ़ाइल में लाइनों की अवधारणा अर्थहीन है।
user207421

जवाबों:


14

आपके उदाहरण में,

001
002
003
004

बाइट नंबर 8 दूसरी न्यूलाइन है, न 0कि अगली लाइन पर।

निम्नलिखित आपको $bबाइट्स के बाद पूर्ण लाइनों की संख्या देगा :

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

यह रिपोर्ट करेंगे 2साथ b8 करने के लिए सेट है और यह रिपोर्ट करेंगे 1साथ b7 के लिए सेट।

ddउपयोगिता, जिस तरह से इसे यहाँ प्रयोग किया जाता है, फ़ाइल से पढ़ने जाएगा data.in, और पढ़ा जाएगा $bआकार 1 बाइट के ब्लॉक।

जैसा कि "इकारस" सही टिप्पणी में नीचे इंगित करता है, का उपयोग bs=1करना अक्षम है। यह अधिक कुशल है, इस विशेष मामले में, स्वैप bsऔर count:

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

यह पहले ddकमांड के समान प्रभाव डालेगा, लेकिन $bबाइट्स के केवल एक ब्लॉक को पढ़ेगा ।

wcउपयोगिता मायने रखता है नई-पंक्तियों, और एक "पंक्ति" यूनिक्स में हमेशा एक नई पंक्ति से समाप्त हो जाता है। तो उपरोक्त कमांड अभी भी कहेगी 2यदि आप b12 (निम्न न्यूलाइन) से कम पर सेट करते हैं। आप जिस परिणाम की तलाश कर रहे हैं, वह इसलिए है कि उपरोक्त पाइपलाइन की संख्या जो भी हो, प्लस 1।

यह स्पष्ट रूप से ASCII पाठ से पहले आपकी फ़ाइल के बाइनरी ब्लॉब भाग में रैंडम न्यूलाइन्स की गणना करेगा। यदि आप पता था कि जहां ASCII बिट शुरू होता है, आप जोड़ सकते skip="$offset"करने के लिए ddआदेश है, जहां $offsetबाइट की संख्या फ़ाइल में छोड़ रहा है।


@don_crisstihead: unknown option -- c
Kusalananda

@ कुसलानंद आप बीएसडी के मुखिया का उपयोग कर रहे हैं, विकल्प अलग हैं
सर्गी कोलोडियाज़नी

@ शेर :-) मुझे इस बात की अच्छी जानकारी है। हम नहीं जानते कि थियो ओपी क्या उपयोग करता है, इसलिए मैं पोसिक्स से चिपका हुआ हूं।
Kusalananda

1
जैसा कि मैंने Q में उल्लेख किया है: बाइट गिनती 0 से शुरू होती है, 1 से नहीं, इसलिए 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;

3
$perl -0nE 'say substr($_,0,8)=~ y/\n//'  ex
2
  • perl -0nE expइनपुट slurps में $_और ऍक्स्प निष्पादित करता है
  • substr(string,0,8) पहले 8 बाइट्स का चयन करता है
  • y/\n//हटाता है \nऔर अपना नंबर देता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.