बैश - फ़ाइल की प्रत्येक पंक्ति को जोड़ी


10

यह प्रश्न इस और इस प्रश्न से दृढ़ता से संबंधित है । मेरे पास एक फ़ाइल है जिसमें कई लाइनें हैं जहां प्रत्येक पंक्ति एक फ़ाइल का पथ है। अब मैं प्रत्येक पंक्ति को प्रत्येक अलग पंक्ति (स्वयं नहीं) के साथ जोड़ना चाहता हूं । साथ ही एक जोड़ी मेरे उद्देश्यों के लिए A Bएक B Aजोड़ी के बराबर है, इसलिए इनमें से केवल एक संयोजन का उत्पादन किया जाना चाहिए।

उदाहरण

files.dat शॉर्टहैंड नोटेशन में इस तरह पढ़ता है, प्रत्येक अक्षर एक फ़ाइल पथ (पूर्ण या सापेक्ष) है

a
b
c
d
e

तो मेरा परिणाम कुछ इस तरह दिखना चाहिए:

a b
a c
a d
a e
b c
b d
b e
c d
c e
d e

अधिमानतः मैं इसे बश में हल करना चाहूंगा। अन्य प्रश्नों के विपरीत, मेरी फ़ाइल सूची छोटी (लगभग 200 लाइनें) है, इसलिए लूप और रैम क्षमता का उपयोग करने से कोई समस्या नहीं होती है।


क्या इसे बैश में होना उचित है, या बस बैश कमांडलाइन के माध्यम से कुछ उपलब्ध है? अन्य उपयोगिताओं को पाठ को संसाधित करने के लिए बेहतर रूप से तैनात किया गया है।
जेफ स्कालर

@JeffSchaller बैश कमांडलाइन के माध्यम से कुछ सुलभ। मैं थोड़ा अस्पष्ट था, माफ करना
Enno

यह लगभग एक कोड गोल्फ बन रहा है : P
रिचर्ड डे विट

3
एक सामान्य नियम के रूप में, जब तक आपको कुछ गैर-तुच्छ करने की आवश्यकता होती है, तो BASH पर अपनी पसंदीदा स्क्रिप्टिंग भाषा का उपयोग करें। यह कम नाजुक होगा (उदाहरण के लिए, विशेष वर्ण या रिक्त स्थान के खिलाफ), और जब भी आपको इसकी आवश्यकता होती है, तो इसका विस्तार करना बहुत आसान है (यदि आपको तीन की आवश्यकता है, या उनमें से कुछ को फ़िल्टर करें)। पाइथन या पर्ल को लगभग किसी भी लिनक्स बॉक्स में स्थापित किया जाना चाहिए, इसलिए वे अच्छे विकल्प हैं (जब तक कि आप एम्बेडेड सिस्टम पर काम नहीं कर रहे हैं, जैसे कि अलग डेमो)।
डेविड

जवाबों:


7

इस कमांड का उपयोग करें:

awk '{ name[$1]++ }
    END { PROCINFO["sorted_in"] = "@ind_str_asc"
        for (v1 in name) for (v2 in name) if (v1 < v2) print v1, v2 }
        ' files.dat

PROCINFOgawkविस्तार हो सकता है । यदि आपका awkसमर्थन नहीं करता है, तो बस PROCINFO["sorted_in"] = "@ind_str_asc"लाइन से बाहर निकलें और आउटपुट को पाइप करें sort(यदि आप आउटपुट को क्रमबद्ध करना चाहते हैं)।

(इसके लिए इनपुट को सॉर्ट करने की आवश्यकता नहीं है।)


8
$ join -j 2 -o 1.1,2.1 file file | awk '!seen[$1,$2]++ && !seen[$2,$1]++'
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e

यह मानता है कि इनपुट फ़ाइल में किसी भी लाइन में कोई व्हाट्सएप नहीं है। यह भी मानता है कि फ़ाइल सॉर्ट की गई है

joinआदेश फ़ाइल की पंक्तियों से भरा पार उत्पाद बनाता है। यह गैर-मौजूदा फ़ील्ड पर फ़ाइल को स्वयं से जोड़कर करता है। गैर-मानक -j 2द्वारा प्रतिस्थापित किया जा सकता है -1 2 -2 2(लेकिन -j2तब तक नहीं जब तक कि आप GNU का उपयोग न करें join)।

awkआदेश इसी का परिणाम पढ़ता है और केवल वे परिणाम जोड़े है जो अभी तक नहीं देखा गया हैं आउटपुट।


"फ़ाइल को क्रमबद्ध किया गया" से आपका क्या अभिप्राय है? किस मापदंड से छांटा गया?
एननो

@ इन्नो ने sort -bइसे सॉर्ट करने का तरीका बताया । joinछँटाई इनपुट फ़ाइलों की आवश्यकता है।
Kusalananda

8

एक pythonसमाधान। इनपुट फ़ाइल को itertools.combinationsमानक पुस्तकालय से खिलाया जाता है, जो 2-लंबाई के ट्यूपल्स उत्पन्न करता है जो मानक आउटपुट पर मुद्रित और मुद्रित होते हैं।

python3 -c 'from itertools import combinations
with open("file") as f:
    lines = (line.rstrip() for line in f)
    lines = ("{} {}".format(x, y) for x, y in combinations(lines, 2))
    print(*lines, sep="\n")
'

6

यदि आपने rubyस्थापित किया है:

$ ruby -0777 -F'\n' -lane '$F.combination(2) { |c| puts c.join(" ")}' ip.txt
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e
  • -0777 संपूर्ण फ़ाइल को स्लुर करना चाहिए (ठीक होना चाहिए क्योंकि यह ओपी में उल्लिखित है कि फ़ाइल का आकार छोटा है)
  • -F'\n' न्यूलाइन पर आधारित विभाजन, इसलिए प्रत्येक लाइन में एक तत्व होगा $F सरणी
  • $F.combination(2) संयोजन उत्पन्न करें 2एक समय में तत्व
  • { |c| puts c.join(" ")} आवश्यकतानुसार प्रिंट करें
  • यदि इनपुट फ़ाइल में डुप्लिकेट हो सकते हैं, तो उपयोग करें $F.uniq.combination(2)


एक बार में 3 तत्वों के लिए:

$ ruby -0777 -F'\n' -lane '$F.combination(3) { |c| puts c.join(" ")}' ip.txt
a b c
a b d
a b e
a c d
a c e
a d e
b c d
b c e
b d e
c d e


के साथ perl(सामान्य नहीं)

$ perl -0777 -F'\n' -lane 'for $i (0..$#F) {
                             for $j ($i+1..$#F) { 
                               print "$F[$i] $F[$j]\n" } }' ip.txt
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e


साथ में awk

$ awk '{ a[NR]=$0 }
       END{ for(i=1;i<=NR;i++)
              for(j=i+1;j<=NR;j++)
                print a[i], a[j] }' ip.txt 
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e

5

यहाँ शुद्ध खोल में एक है।

test $# -gt 1 || exit
a=$1
shift
for f in "$@"
do
  echo $a $f
done
exec /bin/sh $0 "$@"

उदाहरण:

~ (137) $ sh test.sh $(cat file.dat)
a b
a c
a d
a e
b c
b d
b e
c d
c e
d e
~ (138) $ 

1
कमांड प्रतिस्थापन <file.dat xargs test.shtest.sh $(cat file.dat)
स्ट्रिपिंग

1

Perlहम इसका उपयोग कर सकते हैं जैसा कि दिखाया गया है:

$ perl -lne '
     push @A, $_}{
     while ( @A ) {
        my $e = shift @A;
        print "$e $_" for @A;
     }
' input.txt
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.