किसी फाइल में सबसे लंबी लाइन कैसे प्रिंट करें?


35

मैं एक फाइल में सबसे लंबी लाइन को प्रिंट करने की सबसे सरल विधि की तलाश कर रहा हूं। मैंने कुछ गुगली की और आश्चर्यजनक रूप से इसका जवाब नहीं मिला। मैं अक्सर एक फाइल में सबसे लंबी लाइन की लंबाई प्रिंट करता हूं, लेकिन मुझे नहीं पता कि वास्तव में सबसे लंबी लाइन कैसे प्रिंट करें। क्या कोई फ़ाइल में सबसे लंबी लाइन को प्रिंट करने के लिए कोई समाधान प्रदान कर सकता है? अग्रिम में धन्यवाद।


1
जब कई "सबसे लंबी" रेखाएँ होती हैं तो क्या होता है ?. क्योंकि आप एक साधारण अधिकतम लंबाई से अधिक चाहते हैं, क्या आप उन सभी उदाहरणों को देखना चाहते हैं जो समान लंबी हैं?
पीटर.ओ.

जवाबों:


39
cat ./text | awk ' { if ( length > x ) { x = length; y = $0 } }END{ print y }'

UPD : टिप्पणियों में सभी सलाह का सारांश

awk 'length > max_length { max_length = length; longest_line = $0 } END { print longest_line }' ./text 

3
यह है, दोनों एक और कमांड बुला रहे हैं ( cat), और एक पाइप का उपयोग करना महंगा ऑपरेशन है, यह उल्लेख नहीं करना कि यह सिर्फ फ़ाइल पढ़ने के लिए awk के लिए अधिक कुशल है। प्रदर्शन निहितार्थ निश्चित रूप से ध्यान देने योग्य हैं यदि यह अक्सर किया जाता है, और यहां तक ​​कि, आप पूरी तरह से दुरुपयोग कर रहे हैं cat
क्रिस डाउन

7
@laebshade पूरी तरह से एक कारण है - यह तो आपको याद रखने की जरूरत नहीं है कि कौन से कमांड फाइलनाम लेते हैं और कौन सी नहीं, या परवाह नहीं है कि कौन सी कमांड पहले पाइपलाइन में निष्पादित होने जा रही है। यदि आप एक स्क्रिप्ट लिखने जा रहे हैं, जो अक्सर चला जाता है, हर तरह से इस तरह से कुछ के बारे में चिंता मत करो। यदि आप किसी फ़ाइल में सबसे लंबी पंक्ति को खोजने के लिए एक-बंद चीज़ लिख रहे हैं, तो अतिरिक्त प्रक्रिया और भेजी गई समय की राशि पूरी तरह से अप्रासंगिक है। यह मूर्खतापूर्ण है कि लोगों को यहाँ तो यह से ग्रस्त हैं, यह अविश्वसनीय रूप से मामूली है
माइकल Mrozek

4
@ कीथ थॉम्पसन: catयहाँ बेकार नहीं है। यह कंप्यूटर के लिए बेकार हो सकता है लेकिन एक मानव पाठक के लिए यह मूल्य प्रदान कर सकता है। पहला संस्करण स्पष्ट रूप से इनपुट दिखाता है। प्रवाह अधिक स्वाभाविक है (बाएं से दाएं)। दूसरे मामले में आप नहीं जानते कि जब तक आप विंडो को स्क्रॉल नहीं करते तब तक इनपुट क्या है।
jfs

1
@JFSebastian यदि आप इसे बाईं ओर चाहते हैं, तो भी आपको आवश्यकता नहीं है cat< file commandठीक काम करता है।
क्रिस डाउन 3

3
@JFSebastian: एक आदेश की शुरुआत में एक पुनर्निर्देशन लिखा जा सकता है कि तथ्य कुछ अस्पष्ट है; मैंने कोशिश की हर खोल के < filename commandबराबर है filename < command। लेकिन एक बार जब आप इसके बारे में जान जाते हैं, तो आप इसका फायदा उठा सकते हैं जब लंबी पाइप लिखते हैं जो स्पष्ट रूप से डेटा प्रवाह की दिशा दिखाती है (बिना किसी अतिरिक्त आदेश के):< input-file command1 | command2 | command3 > output-file
कीथ थॉम्पसन

6
cat filename | awk '{ print length }' | sort -n | tail -1

+1 इसके कई दिलचस्प समाधान थे लेकिन यह सबसे सरल था। (यह बिल्ली को बिना पढ़े हुए फ़ाइल को पढ़ने की अनुमति देकर सरल होगा, लेकिन वक्रोक्ति क्यों?)
user1683793

5
sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file

यह पहले कमांड प्रतिस्थापन के अंदर फाइल को पढ़ता है और सबसे लंबी लाइन की लंबाई को आउटपुट करता है, (पहले, expandरिक्त स्थान पर टैब को धर्मान्तरित करता है, शब्दार्थ को दूर करने के लिए wc -L- लाइन में प्रत्येक टैब 1 से लाइन की लंबाई के बजाय 8 जोड़ देगा )। इस लंबाई को तब एक sedअभिव्यक्ति में प्रयोग किया जाता है जिसका अर्थ है "वर्णों की इस संख्या को एक रेखा खोजें, इसे प्रिंट करें, फिर छोड़ दें"। तो यह वास्तव में इष्टतम हो सकता है क्योंकि सबसे लंबी रेखा फ़ाइल के शीर्ष के पास है, हेहेह (भयानक और रचनात्मक टिप्पणियों के लिए धन्यवाद)।

एक और, मैंने पहले सोचा था कि सेड एक (बाश में):

#!/bin/bash
while read -r line; do
    (( ${#line} > max )) && max=${#line} && longest="$line"
done
echo "$longest"

2
यह विधि बहुत महंगी और धीमी है।
क्रिस डाउन

2
@ क्रिस नीचे: ओह हाँ यह है। लेकिन सवाल सॉर्ट विधि के बारे में था, सबसे कुशल नहीं। छोटे से मध्यम फ़ाइलों या गैर-महत्वपूर्ण कार्यों के लिए अच्छी तरह से काम करता है।
एटा

3
चेतावनी : WC के विकल्प -L, --max-line-lengthआदमी पृष्ठ के अनुसार, सबसे लंबे समय तक लाइन की लंबाई प्रिंट, लेकिन अगर आप गहरी (में जब आप के रूप में खुदाई गलत / अप्रत्याशित परिणाम), तो आपको लगता है कि इस विकल्प वृद्धि के साथ लंबाई 8 से प्रत्येक के लिए 1 टैब वर्ण \x09 इस यूनिक्स और लिनक्स क्यू / ए
पीटर.ओ.

पुनश्च। आपका उत्तर सभी "समान रूप से सबसे लंबी" लाइनों को प्रिंट करेगा, जो शायद एक अच्छी बात है ... प्रति टैब केवल 1 चार्ट को गिनने के लिए wc को बाध्य करने के लिए, यह काम करता है। sed -rn "/.{$(<file expand -t1 |wc -L)}/p" file
पीटर।

1
read lineशाब्दिक चार के रूप में बैकस्लैश-एस्केप्ड वर्ण, जैसे की व्याख्या करेगा \Aresloves को Aजो पाठ्यक्रम को प्रभावी ढंग से की एक वास्तविक की तुलना में कम बाइट-उपयोग रिपोर्ट करती है, ... इसे रोकने के लिए भाग निकले व्याख्या, उपयोग: read -r line। । । । इसके अलावा, पहली "सबसे लंबी लाइन" के बाद p{p;q}sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file
छोड़े

4

यहाँ एक पर्ल समाधान है:

perl -e 'while(<>){
           $l=length;  
           $l>$m && do {$c=$_; $m=$l}  
         } print $c' file.txt 

या, यदि आप सभी लंबी लाइनों को मुद्रित करना चाहते हैं

perl -e 'while(<>){
           $l=length;
           push @{$k{$l}},$_;
           $m=$l if $l>$m;
         } print @{$k{$m}}' file.txt 

चूंकि मेरे पास करने के लिए कुछ भी बेहतर नहीं था, मैंने 625M टेक्स्ट फाइल पर कुछ बेंचमार्क चलाए। हैरानी की बात है, मेरे पर्ल समाधान दूसरों की तुलना में लगातार तेज था। दी गई, स्वीकृत awkसमाधान के साथ अंतर छोटा है, लेकिन यह वहाँ है। जाहिर है, कई लाइनों को हल करने वाले समाधान धीमे हैं, इसलिए मैंने सबसे तेजी से, सबसे तेजी से हल किया है।

सबसे लंबी लाइनों में से केवल एक प्रिंट करें:

$ time perl -e 'while(<>){
           $l=length;  
           $l>$m && do {$c=$_; $m=$l}  
         } print $c' file.txt 
real    0m3.837s
user    0m3.724s
sys     0m0.096s



$ time awk 'length > max_length { max_length = length; longest_line = $0 }
 END { print longest_line }' file.txt
real    0m5.835s
user    0m5.604s
sys     0m0.204s



$ time sed -rn "/.{$(<file.txt expand -t1 |wc -L)}/{p;q}" file.txt 
real    2m37.348s
user    2m39.990s
sys     0m1.868s

सभी लंबी लाइनों को प्रिंट करें:

$ time perl -e 'while(<>){
           $l=length;
           push @{$k{$l}},$_;
           $m=$l if $l>$m;
         } print @{$k{$m}}' file.txt 
real    0m9.263s
user    0m8.417s
sys     0m0.760s


$ time awk 'length >x { delete y; x=length }
     length==x { y[NR]=$0 } END{ for (z in y) print y[z] }' file.txt
real    0m10.220s
user    0m9.925s
sys     0m0.252s


## This is Chris Down's bash solution
$ time ./a.sh < file.txt 
Max line length: 254
Lines matched with that length: 2
real    8m36.975s
user    8m17.495s
sys     0m17.153s

3

पहली सबसे लंबी लाइन ग्रीप

grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt 

यह अभ्यास के बिना पढ़ने के लिए कमांड असामान्य रूप से कठिन है क्योंकि यह शेल- और रेक्सएक्सपी सिंटैक्स को मिलाता है।
स्पष्टीकरण के लिए, मैं पहले सरलीकृत स्यूडोकोड का उपयोग करूंगा। से शुरू होने वाली रेखाएं ##शेल में नहीं चलती हैं।
यह सरलीकृत कोड फ़ाइल नाम F का उपयोग करता है, और पठनीयता के लिए उद्धरण और regexps के कुछ हिस्सों को छोड़ देता है।

यह काम किस प्रकार करता है

कमांड के दो भाग हैं, एक grep- और एक wcमंगलाचरण:

## grep "^.{$( wc -L F )}$" F

wcएक प्रक्रिया विस्तार में प्रयोग किया जाता है, $( ... ), तो यह पहले से चलाया जाता है grep। यह सबसे लंबी रेखा की लंबाई की गणना करता है। शेल एक्सपोज़र सिंटैक्स को एक अभिव्यक्ति तरीके से नियमित अभिव्यक्ति पैटर्न सिंटैक्स के साथ मिलाया जाता है, इसलिए मैं प्रक्रिया विस्तार को विघटित करूंगा:

## wc -L F
42
## grep "^.{42}$" F

यहां, प्रक्रिया विस्तार को उस मान के साथ बदल दिया गया था, grepजिसका उपयोग कमांडलाइन बनाते हुए किया जाएगा। अब हम नियमित अभिव्यक्ति को अधिक आसानी से पढ़ सकते हैं: यह लाइन के प्रारंभ ( ^) से अंत ( $) तक बिल्कुल मेल खाता है । उनके बीच की अभिव्यक्ति न्यूलाइन को छोड़कर किसी भी चरित्र से मेल खाती है, जिसे 42 बार दोहराया गया। संयुक्त, वह रेखाएँ जिनमें 42 अक्षर होते हैं।


अब, वास्तविक शेल कमांड पर वापस: grepविकल्प -E( --extended-regexp) {}पठनीयता के लिए बचने की अनुमति नहीं देता है। पहली पंक्ति मिलने के बाद विकल्प -m 1( --max-count=1) इसे बंद कर देता है। <में wcआदेश को रोकने के लिए अपने stdin के लिए फ़ाइल लिखता है, wcलंबाई के साथ एक साथ फ़ाइल नाम मुद्रण से।

कौन सी सबसे लंबी रेखाएं?

दो बार होने वाले फ़ाइलनाम के साथ उदाहरणों को अधिक पठनीय बनाने के लिए, मैं fफ़ाइल नाम के लिए एक चर का उपयोग करूंगा ; $fउदाहरण में प्रत्येक को फ़ाइल नाम से बदला जा सकता है।

f="file.txt"

पहली लंबी लाइन दिखाएं - पहली लाइन जो सबसे लंबी लाइन जितनी लंबी हो:

grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"

सभी लंबी लाइनों को दिखाएं - सभी लाइनें जो सबसे लंबी लाइन के रूप में लंबी हैं:

grep -E "^.{$(wc -L <"$f")}\$" "$f" 

अंतिम लंबी लाइन दिखाएं - आखिरी लाइन जो सबसे लंबी लाइन है:

tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"

एकल लंबी लाइन दिखाएँ - अन्य सभी लाइनों की तुलना में सबसे लंबी लाइन, या विफल:

[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f" 

(अंतिम कमांड अन्य की तुलना में अधिक अक्षम है, क्योंकि यह पूरी grep कमांड को दोहराता है। इसे स्पष्ट रूप से विघटित किया जाना चाहिए ताकि इसके wcद्वारा लिखी गई लाइनों और आउटपुट grepको वेरिएबल्स में बचाया जा सके।
ध्यान दें कि सभी लंबी लाइनें वास्तव में सभी लाइनें हो सकती हैं। एक चर में बचत के लिए, केवल पहली दो पंक्तियों को रखने की आवश्यकता है।)


वाह बढ़िया जवाब, इससे बहुत कुछ सीखने को मिला। धन्यवाद
कुछ

2

निम्नलिखित उदाहरण होने जा रहा था, और होना चाहिए था, dmitry.malikov के उत्तर के लिए एक टिप्पणी , लेकिन दृश्यमान टिप्पणी स्थान के बेकार उपयोग के कारण, मैंने इसे यहां प्रस्तुत करने के लिए चुना है, जहां यह कम से कम देखा जाएगा। ..

यह डमित्री की सिंगल-पास जाग विधि का एक सरल रूपांतर है ।
यह सभी "समान लंबी" लाइनों को प्रिंट करता है। (नोट delete arrayएक gawk एक्सटेंशन है)।

awk 'length >x { delete y; x=length }
     length==x { y[NR]=$0 } END{ for (z in y) print y[z] }' file

1

शुद्ध बैश में:

#!/bin/bash

_max_length=0
while IFS= read -r _line; do
    _length="${#_line}"
    if (( _length > _max_length )); then
        _max_length=${_length}
        _max_line=( "${_line}" )
    elif (( _length == _max_length )); then
        _max_line+=( "${_line}" )
    fi
done

printf 'Max line length: %d\n' "${_max_length}"
printf 'Lines matched with that length: %d\n' "${#_max_line[@]}"
(( ${#_max_line[@]} )) && printf '%s\n' '----------------' "${_max_line[@]}"

के रूप में, कोड अमान्य परिणाम वापस कर सकता है। सेटिंग _max_line[0]=${_line}किसी भी पहले से संचित छोटी "सबसे लंबी लाइनों" unset _max_lineको नहीं
हटाती है

@ उसके लिए धन्यवाद, बहुत जल्दी लिखा गया था। फिक्स्ड।
क्रिस डाउन

0

मैंने इसके लिए एक छोटी सी शेल स्क्रिप्ट विकसित की है। यह लंबाई, लाइन # को प्रदर्शित करता है और लंबाई से खुद को लाइन करता है जो कि 80 वर्णों की तरह एक विशेष आकार से अधिक है:

#!/bin/sh

# Author: Surinder

if test $# -lt 2
then
   echo "usage: $0 length file1 file2 ..."
   echo "usage: $0 80 hello.c"
   exit 1
fi

length=$1

shift

LONGLINE=/tmp/longest-line-$$.awk

cat << EOF > $LONGLINE
  BEGIN {
  }

  /.*/ {
    current_length=length(\$0);
    if (current_length >= expected_length) {
       printf("%d at line # %d %s\n", current_length, NR, \$0);
    }
  }

  END {
  }
EOF

for file in $*
do
  echo "$file"
  cat $file | awk -v expected_length=$length -f $LONGLINE |sort -nr
done

rm $LONGLINE

https://github.com/lordofrain/tools/blob/master/longest-line/longest-line.sh


1
आपके द्वारा किए जा सकने वाले कुछ सुधार हैं। अपने चर को उद्धृत करें । यह किसी भी फ़ाइल नाम पर टूट जाएगा जिसमें व्हाट्सएप या अन्य अजीब अक्षर हैं। का उपयोग करना $*शायद ही कभी एक अच्छा विचार है, आप चाहते हैं"$@"/.*/अपने में awkके बाद से है कि अच्छी तरह से खाली लाइनों से मेल खाता है कुछ नहीं करता। \$0यदि आप एकल बोली लगाते हैं तो आप बच निकलने से बच सकते हैं 'EOF'। खाली BEGIN{}ब्लॉक का उपयोग क्यों करें ? अंत में, आप की जरूरत नहीं है cat, बसawk . . . "$file" | . . .
terdon

1
तुम भी बस सीधे awk में पूरी बात करना couuld:awk -vmax=15 '{len=length($0); if(len>=max){printf("%s, %d at line # %d %s\n", FILENAME, len, NR, $0);}}' file*
terdon

-3

आप उपयोग कर सकते हैं wc:

wc -L fileName

3
कृपया प्रश्न फिर से पढ़ें। आवश्यक आउटपुट सबसे लंबी लाइन ही होती है, सबसे लंबी लाइन की लंबाई नहीं। इसके अलावा पीटर की टिप्पणी को देखें wc -L
मैनेटवर्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.