एक बेहतर पेस्ट कमांड


11

मेरे पास निम्नलिखित दो फाइलें हैं (मैंने डॉट्स के साथ लाइनों को गद्देदार किया है ताकि एक फ़ाइल में प्रत्येक पंक्ति एक ही चौड़ाई हो और इसे अधिक स्पष्ट बनाने के लिए फ़ाइल 1 सभी कैप्स बनाया जाए)।

contents of file1:

ETIAM......
SED........
MAECENAS...
DONEC......
SUSPENDISSE

contents of file2

Lorem....
Proin....
Nunc.....
Quisque..
Aenean...
Nam......
Vivamus..
Curabitur
Nullam...

ध्यान दें कि फ़ाइल 2 फ़ाइल 1 से अधिक लंबी है।

जब मैं यह कमांड चलाता हूं:

paste file1 file2

मुझे यह आउटपुट मिलता है

ETIAM...... Lorem....
SED........ Proin....
MAECENAS... Nunc.....
DONEC...... Quisque..
SUSPENDISSE Aenean...
    Nam......
    Vivamus..
    Curabitur
    Nullam...

निम्नानुसार आउटपुट के लिए मैं क्या कर सकता हूं?

ETIAM...... Lorem....
SED........ Proin....
MAECENAS... Nunc.....
DONEC...... Quisque..
SUSPENDISSE Aenean...
            Nam......
            Vivamus..
            Curabitur
            Nullam...

मैंने कोशिश की

paste file1 file2 | column -t

लेकिन यह ऐसा करता है:

ETIAM......  Lorem....
SED........  Proin....
MAECENAS...  Nunc.....
DONEC......  Quisque..
SUSPENDISSE  Aenean...
Nam......
Vivamus..
Curabitur
Nullam...

वैसे भी मूल उत्पादन के रूप में बदसूरत लेकिन गलत कॉलम-वार वैसे भी।


2
pasteदूसरी फ़ाइल से लाइनों के सामने टैब का उपयोग कर रहा है। स्तंभों को उचित रूप से संरेखित करने के लिए आपको पोस्टप्रोसेसर का उपयोग करना पड़ सकता है।
unxnut

3
paste file1 file2 | column -tn?
नंजालज

क्या फ़ाइल 1 में हमेशा निश्चित आकार के कॉलम होते हैं?
RSFalcon7

@ RSFalcon7 हाँ, यह करता है।
ट्यूलेंस कोर्डोवा

जवाबों:


17

यह मानते हुए कि आपकी फ़ाइलों में कोई टैब वर्ण नहीं है,

paste file1 file2 | expand -t 13

आर्ग के साथ करने के लिए -tउपयुक्त रूप से file1 में वांछित अधिकतम रेखा की चौड़ाई को कवर करने के लिए चुना है।

ओपी ने और अधिक लचीला समाधान जोड़ा है:

मैंने ऐसा किया था इसलिए यह जादू नंबर 13 के बिना काम करता है:

paste file1 file2 | expand -t $(( $(wc -L <file1) + 2 ))

यह टाइप करना आसान नहीं है लेकिन इसका इस्तेमाल स्क्रिप्ट में किया जा सकता है।


अच्छा! मुझे आपका जवाब पढ़ने से पहले विस्तार के बारे में पता नहीं था :)
TabeaKischka

4

मैंने सोचा था कि awk इसे अच्छी तरह से कर सकता है, इसलिए मैंने "awk read input from two files" लिखा और पाया कि स्टैकओवरफ़्लो पर एक आर्टिकल मिला है जिसे शुरुआती बिंदु के रूप में उपयोग किया जा सकता है।

पहले गाढ़ा संस्करण है, फिर नीचे पूरी तरह से टिप्पणी की गई है। इस कार्य को करने में कुछ मिनट से अधिक समय लगा। मैं होशियार लोगों से कुछ शोधन के बारे में खुशी होगी।

awk '{if(length($0)>max)max=length($0)}
FNR==NR{s1[FNR]=$0;next}{s2[FNR]=$0}
END { format = "%-" max "s\t%-" max "s\n";
  numlines=(NR-FNR)>FNR?NR-FNR:FNR;
  for (i=1; i<=numlines; i++) { printf format, s1[i]?s1[i]:"", s2[i]?s2[i]:"" }
}' file1 file2

और यहाँ ऊपर का पूरी तरह से प्रलेखित संस्करण है।

# 2013-11-05 mike@diehn.net
# Invoke thus:
#   awk -f this_file file1 file2
# The result is what you asked for and the columns will be
# determined by input file order.
#----------------------------------------------------------
# No matter which file we're reading,
# keep track of max line length for use
# in the printf format.
#
{ if ( length($0) > max ) max=length($0) }

# FNR is record number in current file
# NR is record number over all
# while they are equal, we're reading the first file
#   and we load the strings into array "s1"
#   and then go to the "next" line in the file we're reading.
FNR==NR { s1[FNR]=$0; next }

# and when they aren't, we're reading the
#   second file and we put the strings into
#   array s2
{s2[FNR]=$0}

# At the end, after all lines from both files have
# been read,
END {
  # use the max line length to create a printf format
  # the right widths
  format = "%-" max "s\t%-" max "s\n"
  # and figure the number of array elements we need
  # to cycle through in a for loop.
  numlines=(NR-FNR)>FNR?NR-FNR:FNR;
  for (i=1; i<=numlines; i++) {
     printf format, s1[i]?s1[i]:"", s2[i]?s2[i]:""
  }
}

1
+1 यह एकमात्र उत्तर है जो मनमाना इनपुट के साथ काम करता है (अर्थात उन पंक्तियों के साथ जिनमें टैब हो सकते हैं)। मुझे नहीं लगता कि इसमें काफी सुधार / सुधार किया जा सकता है।
डॉन_क्रांति

2

एक बहुत अच्छा समाधान नहीं है लेकिन मैं इसका उपयोग करने में सक्षम था

paste file1 file2 | sed 's/^TAB/&&/'

जहां टैब चरित्र के साथ TAB को बदल दिया जाता है।


&&सेड कमांड में क्या भूमिका है ?
coffeMug

1
एक एकल &डालता है जिसे खोजा जा रहा है (इस मामले में एक टैब)। यह कमांड केवल दो टैब के साथ शुरुआत में टैब को बदलता है।
unxnut

मुझे उबंटू डेबियन पर zsh में यह काम TABकरने के लिए बदलना पड़ा \t। और यह केवल तभी काम करता है जब फ़ाइल 1 में 15 से कम चार वर्ण हों
rubo77

2

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

wcstokdelimटोकन को पहचानने से पहले, विस्तृत वर्णों को छोड़ कर शुरू होता है । -nविकल्प एक algorythm कि में प्रारंभिक चौड़े वर्ण छोड़ नहीं करता है का उपयोग करता है delim

दुर्भाग्य से, यह बहुत पोर्टेबल नहीं है: -nडेबियन-विशिष्ट है, और columnपोसिक्स में नहीं है, यह स्पष्ट रूप से बीएसडी है।


2

पैड्स के लिए आपके द्वारा उपयोग किए जाने वाले डॉट्स को बाहर निकालना:

file1:

ETIAM
SED
MAECENAS
DONEC
SUSPENDISSE

करें 2:

Lorem
Proin
Nunc
Quisque
Aenean
Nam
Vivamus
Curabitur
Nullam

इसे इस्तेमाल करे:

$ ( echo ".TS"; echo "l l."; paste file1 file2; echo ".TE" ) | tbl | nroff | more

और आपको मिलेगा:

ETIAM         Lorem
SED           Proin
MAECENAS      Nunc
DONEC         Quisque
SUSPENDISSE   Aenean
              Nam
              Vivamus
              Curabitur
              Nullam

यह, अन्य समाधानों की तरह, pasteयदि टैब वाली कोई रेखाएँ हैं, तो उचित आउटपुट को प्रिंट करने में विफल होंगे। +1 हालांकि अलग होने के लिए
don_crissti

+1। क्या आप कृपया बताएंगे कि समाधान कैसे काम करता है?
ट्यूलेंस कोर्डोवा

1

एक awkसमाधान जो काफी पोर्टेबल होना चाहिए, और एक अनियंत्रित संख्या में इनपुट फ़ाइलों के लिए काम करना चाहिए:

# Invoke thus:
#   awk -F\\t -f this_file file1 file2

# every time we read a new file, FNR goes to 1

FNR==1 {
    curfile++                       # current file
}

# read all files and save all the info we'll need
{
    column[curfile,FNR]=$0          # save current line
    nlines[curfile]++               # number of lines in current file
    if (length > len[curfile])
            len[curfile] = length   # max line length in current file
}

# finally, show the lines from all files side by side, as a table
END {
    # iterate through lines until there are no more lines in any file
    for (line = 1; !end; line++) {
            $0 = _
            end = 1

            # iterate through all files, we cannot use
            #   for (file in nlines) because arrays are unordered
            for (file=1; file <= curfile; file++) {
                    # columnate corresponding line from each file
                    $0 = $0 sprintf("%*s" FS, len[file], column[file,line])
                    # at least some file had a corresponding line
                    if (nlines[file] >= line)
                            end = 0
            }

            # don't print a trailing empty line
            if (!end)
                    print
    }
}

आप इसे file1 और file2 पर कैसे उपयोग करते हैं? मैंने स्क्रिप्ट को कॉल किया paste-awkऔर कोशिश की paste file1 file2|paste-awkऔर मैंने कोशिश की awk paste-awk file1 file2लेकिन किसी ने काम नहीं किया।
रुबो 7

मुझे मिलता हैawk: Line:1: (FILENAME=file1 FNR=1) Fatal: Division by zero
रुबो 7

@ rubo77: awk -f paste-awk file1 file2कम से कम GNU awk और mawk के लिए काम करना चाहिए।
नवजाल

यह काम करता है, हालांकि यह pasteदो पंक्तियों के बीच कम जगह होने से थोड़ा अलग है । और यदि इनपुट फ़ाइल में सभी पंक्तियाँ समान लंबाई की नहीं हैं, तो यह संरेखित-दाईं पंक्ति में परिणत होगी
rubo77

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