लाइन नंबरों की लंबी सूची के आधार पर लाइनों को छोड़ दें


3

मेरे पास लाइन नंबरों (35389208) की एक लंबी सूची है जो मुझे अपनी फ़ाइल में नहीं चाहिए। लाइन नंबर से मेरा मतलब है कि मेरी फाइल में लाइन है (जैसे लाइन 277)। मेरी पंक्ति संख्याओं की सूची जो मैं नहीं चाहता, वह दिखती है:

277
278
279
280
289
290
291
292
321
322
....

इन लाइन नंबरों को मेरी फ़ाइल से बाहर करने का सबसे अच्छा तरीका क्या है? पर्ल सीड या ऑक (या कुछ और) में समाधान।

जवाबों:


1

आप के साथ एक regex का उपयोग करने की कोशिश कर सकते हैं sed:

sed '/^[0-9]*$/d' filename.txt

यह उन पंक्तियों को हटा देगा जिनमें केवल आपकी फ़ाइल से उनमें नंबर हैं।

निम्न पर्ल स्क्रिप्ट फ़ाइल से n -th लाइन को हटा देगी input.txtऔर बाकी को आउटपुट देगी stdout। लाइन संख्या में निर्दिष्ट किया जा सकता है line_numbers.txt:

#!/usr/bin/perl

my @lines_to_exclude;

open(my $fh_line_numbers, "<", "line_numbers.txt") or die "Failed to open file: $!\n";
while(<$fh_line_numbers>) { 
  chomp; 
  push @lines_to_exclude, $_;
} 
close $fh_line_numbers;

my $linecounter = 1;

open (my $fh_datafile, '<', 'input.txt') or die "Cannot open $filename: $!";

while ( my $line = <$fh_datafile> ) {

  if ( ! ( $linecounter ~~ @lines_to_exclude ) ) {
    print $line;
  }

  $linecounter++;
}

close($fh_datafile);

( ~~ऑपरेटर केवल perl> = 5.10 में उपलब्ध है)


क्षमा करें, मुझे लगता है कि आपने गलत समझा। मेरे पास लाइन नंबरों की एक सूची है और मैं अपनी फ़ाइल से उन लाइन नंबरों को छोड़ना चाहता हूं। इसलिए अगर मेरी फ़ाइल का नाम फ़ाइल है। तो मैं 277,278,279 ... आदि को छोड़ना चाहता हूं। उन पंक्तियों में आवश्यक रूप से संख्या 277 आदि नहीं है।
बोडोनोविक


मैं एक पटकथा के रूप में अच्छी तरह से कर रहा था। अगर मेरा काम सही नहीं हुआ तो मैं तुम्हें एक कोशिश दूंगा।
बोदोनोविक

1

यदि मेमोरी में सभी पंक्ति संख्याओं को पढ़ना एक विकल्प है, तो आप इसे इस तरह से कर सकते हैं awk:

awk 'FNR == NR { h[$1]; next } !(FNR in h)' line-numbers.txt input.txt

यदि आपके पास सीमित मेमोरी उपलब्ध है और आपकी line-numbers.txtफ़ाइल संख्यात्मक रूप से सॉर्ट की गई है, तो आप इसे इस तरह से कर सकते हैं:

हटाना-lines.awk

BEGIN {  
  lines_file = "line-numbers.txt"
  if(!(getline n < lines_file)) { 
    print "Unable to open lines file " lines_file > "/dev/stderr" 
    exit 
  } 
} 

FNR != n

FNR == n {
  getline n < lines_file
}

इसे इस तरह चलाएं:

awk -f delete-lines.awk input.txt

परीक्षण जिसमें line-numbers.txtशामिल हैं:

277
278
279
280
289
290
291
292
321
322

और input.txtद्वारा दर्शाया गया है seq 325

मेमोरी में लाइन-नंबरों के साथ सबसे पहले:

seq 325 | awk 'FNR == NR { h[$1]; next } !(FNR in h)' line-numbers.txt -

तब एक बार में एक पंक्ति-संख्याओं को पढ़ा जा सकता है

seq 325 | awk -f delete-lines.awk -

दोनों मामलों में आउटपुट (274 के माध्यम से लाइनें 1 छोड़ दी जाती हैं):

.
.
.
275
276
281
282
283
284
285
286
287
288
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
323
324
325

0

लाइन की शुरुआत में संख्या को हटाने के लिए

sed 's/^[0-9]*//g' filename.txt

मेरी टिप्पणी नीचे पढ़ें
bdeonovic

0

यह आपके लिए काम कर सकता है (GNU sed):

sed 's/.*/&d/' line-numbers-to-delete-file | sed -f - file-to-be-shortened

फ़ाइल से एक स्क्रिप्ट बनाएं जिसमें हटाने के लिए लाइनें हैं और इसे उस फ़ाइल का उपयोग करके sed की आवृत्ति पर फ़ीड करें जिसे आप इनपुट के रूप में छोटा करना चाहते हैं।


0

ध्यान दें कि प्रयास 2 में अतिरिक्त कोड को छोड़कर, सभी कोड वास्तव में ओपी द्वारा पूछे गए के विपरीत करते हैं। जैसा कि आप प्रयास 2 में देख सकते हैं, आज्ञाओं को अनुकूलित करना आसान है।

मेरे पास इसमें 1.108.752 लाइनों के साथ एक टेक्स्टफाइल था, आकार में लगभग 83 एमबी। मैं इसमें से ४६. wanted४४ रेखाएँ प्राप्त करना चाहता था, १५ वीं और १.१०th. line१६ वीं पंक्ति के बीच, जो औसतन हर २४ वीं पंक्ति है।

tl; डॉ;

दूसरा प्रयास पहले की तुलना में तेज है। तीसरा केवल कम लाइनों के लिए काम करता है।

पहला प्रयास (बुरा)

मैं चाहता हूं कि हर पंक्ति के लिए, sedटेक्स्टफाइल की शुरुआत से लाइनें पढ़ता है, लेकिन उन्हें प्रिंट नहीं करता ( -n)। जब यह मेरे इच्छित लाइन पर पहुंच जाता है p, तो इसे प्रिंट करें ( ), फिर qफ़ाइल के अंत में पढ़ने के बजाय छोड़ें ( )। फिर अगले लिनन के लिए फिर से करें।

जाहिर है, यह प्रत्येक रन में थोड़ा अधिक समय लेता है, क्योंकि sedहर बार पहले की तुलना में अधिक लाइनों से गुजरना पड़ता है।

अगर मैंने उस सही गणना की, तो मेरे मामले में जो कुल मिलाकर लगभग 307332472188 टेक्स्टफाइल से गुजरता है। अरे मेरा।

ध्यान दें कि इस दृष्टिकोण के लिए लाइनों का क्रम लिनेनस फ़ाइल में अप्रासंगिक है:

while read line; do
    sed -n "${line}{p;q}" "${INFILE}"
done

परिणाम समय: 2568.80s user 256.10s system 92% cpu 51:00.37 total। अच्छा नहीं।

दूसरा प्रयास (बेहतर)

यह फ़ाइल से लिनन्र्स पढ़ता है और pइस लाइन को प्रिंट करने के लिए (फिर से, फिर से जोड़ता है )। इस तार को आगे की तरफ लगाया जाता है, जो sedएक फ़ाइल ( -f) से पढ़ता है , जिसे यहाँ STDINलिखा गया है -, जो कि हर बार पहली से आउटपुट है sed, जो वास्तव में मुद्रित होने वाली लिननंबर है:

sed 's/$/p/' "${LINENUMS}" | sed -n -f - "${INFILE}"

परिणाम समय: 146.54s user 0.18s system 100% cpu 2:26.70 total। काफी अच्छा!

आप चाहते हैं नहीं (ओपी की तरह करना चाहता था) linefile से लाइनों प्रिंट, थोड़ा आदेश ताकि linenumbers किया जा रहा है बदल d के बजाय eleted पी rinted, और प्रिंट के बजाय उन्हें (-n) को हटाने के अन्य सभी लाइनों:

sed 's/$/d/' "${LINENUMS}" | sed -f - "${INFILE}"

तीसरा प्रयास (बैडर)

यह मेरे लिए बिल्कुल भी काम नहीं कर रहा था क्योंकि मेरे पास बहुत सारी लाइनें थीं जिन्हें मैं निकालना चाहता था। यह (बहुत) कम लाइनों के लिए यद्यपि काम करना चाहिए, लेकिन मैं उस सीमा को नहीं जानता।

मैंने सीड के लिए एक लंबी स्ट्रिंग बनाने की कोशिश की, जिससे मुझे उम्मीद थी कि मैं sedकेवल एक बार फाइल के माध्यम से जाऊँगा!

sed -n "12p;15p;24p;345p;...;12345;" ${INFILE}"

लेकिन इससे 420076वर्णों के बारे में एक तार लंबा हो जाएगा, जो कि पंप में sedबस के लिए नेतृत्व करता है sed: Argument list is too long। जो समझ में आता है।

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