केवल अंतिम कॉलम कैसे प्रिंट करें?


25
echo -e 'one two three\nfour five six\nseven eight nine'
one two three
four five six
seven eight nine

मैं कुछ "मैजिक" कैसे प्राप्त कर सकता हूं?

three
six
nine

अद्यतन: मुझे इस विशिष्ट तरीके से इसकी आवश्यकता नहीं है, मुझे एक सामान्य समाधान की आवश्यकता है, ताकि एक पंक्ति में कितने कॉलम हों, उदाहरण के लिए: awk हमेशा अंतिम कॉलम प्रदर्शित करता है।


2
लांस पूछने से पहले अपने प्रश्नों पर शोध करें। आपकी पोस्ट की विषय पंक्ति के लिए Google खोजना स्निपेंट्स में उत्तर दिखाता है। "Awk last column" की खोज परिणाम 1 से शुरू होने वाले कई शानदार उत्तर देता है। इसके अलावा, यह 5 मिनट का awk प्राइमर सभी तरह से पढ़ने लायक है, ताकि आप जान सकें कि भविष्य में क्या संभव है।
कालेब

जवाबों:


6

इसे केवल 'bash'बिना 'sed', 'awk'या , के साथ भी किया जा सकता है 'perl':

echo -e 'one two three\nfour five six\nseven eight nine' |
  while IFS=" " read -r -a line; do
    nb=${#line[@]}
    echo ${line[$((nb - 1))]}
  done

हम्म, या यह भी, आपके इनपुट को वास्तव में अंतरिक्ष-पृथक ... | while read -r line; do echo ${line##* }; done
माना

@glenn: यह मेरा पहला विचार था, लेकिन जब मैंने 'रीड' मैनुअल पढ़ा, तो मैंने यह ऐरे फंक्शन देखा, जो मुझे उपयोगी लगा। यह किसी भी क्षेत्र को दाईं ओर से अनुक्रमित करने के लिए आसानी से संशोधित किया जा सकता है।
jfg956

2
bashएरे इंडेक्स अंकगणितीय मूल्यांकन का विषय है, इसलिए echo ${line[nb - 1]}यह पर्याप्त है। के बारे में बोलते हुए bash, आप बस "एनबी" चीजों को छोड़ सकते हैं echo ${line[-1]}:। बाद में एक अधिक पोर्टेबल विकल्प echo ${line[@]: -1]}:। ( स्टीफन चेज़ेलस की टिप्पणी को नकारात्मक सूचकांक पर कहीं और देखें।)
मैनटवर्क

53

प्रयत्न:

echo -e 'one two three\nfour five six\nseven eight nine' | awk '{print $NF}'

मैंने 17:28 बजे Q
लांसबैन्स

कृपया ध्यान दें कि awk 99 फ़ील्ड्स तक सीमित है ...: / यह सिर्फ पिछले दिनों में मुझे काटता है ( ps -ef | awk '{ print $NF }'कुछ लाइनों को काट दिया गया था ...) पर्ल में वह सीमा नहीं है। ( gnu.org/software/autoconf/manual/autoconf-2.67/html_node/… : "पारंपरिक Awk में एक रिकॉर्ड में 99 फ़ील्ड्स की सीमा होती है। चूंकि कुछ Awk कार्यान्वयन, जैसे Tru64's, इनपुट को विभाजित करते हैं, भले ही आप संदर्भित न करें। इस समस्या को दरकिनार करने के लिए स्क्रिप्ट के किसी भी क्षेत्र में, एक असामान्य चरित्र के लिए 'FS' सेट करें और विभाजन का उपयोग करें। ")
ओलिवियर दुलक

@OlivierDulac क्या awkकार्यान्वयन है कि सीमा है? मैंने यह कभी नहीं देखा। मेरा mawkपीछा करेगा 32768लेकिन मैं gawkऔर igawkखुशी से लाखों लोगों से निपट सकता हूं । यहां तक ​​कि मेरे बिजीबॉक्स awkलाखों से निपट सकते हैं। मैं कभी नहीं आया हूँ awkकि 100 क्षेत्रों के साथ सौदा नहीं कर सकता, यह एक छोटी संख्या है, सब के बाद। क्या आप सुनिश्चित हैं कि जानकारी अभी भी प्रासंगिक है? सोलारिस पर भी?
टेराडॉन

@terdon, मेरी टिप्पणी में लिंक देखें ^ ^ (और मेरा विश्वास करो, कुछ "विरासत" प्रणाली कुछ वातावरणों में एक loooooooog समय बचा सकती है। कुछ पर, टार हैपिली एक्सट्रैक्ट टू "/", बैश में कुछ उपयोगी नहीं है। बिल्डिंस (न ही $ BASH_SOURCE, उदाहरण के लिए), NF> 99, आदि पर awk choke ... :()
ओलिवियर दुलैक

@ ऑलिवरड्युलक मेला। मैं अभी इसके पार नहीं आया हूं। मुझे आशा है कि यह आज गायब हो गया है क्योंकि 99 एक छोटी संख्या है।
terdon

14

यह आपके विचार से आसान है।

$ echo one two three | awk '{print $NF}'
three

11

प्रयास करें grep( awkरेगेक्स के उपयोग की तुलना में कम / सरल, लेकिन 3x धीमा ):

grep -o '\S\+$' <(echo -e '... seven eight nine')

या या exइससे भी अधिक धीमा, लेकिन यह संपूर्ण बफर को प्रिंट करने के बाद प्रिंट करता है, अधिक उपयोगी है जब इसे जगह में सॉर्ट या संपादित करने की आवश्यकता होती है:

ex -s +'%s/^.*\s//g' -c'%p|q!' <(echo -e '... seven eight nine')
ex +'%norm $Bd0' -sc'%p|q!' infile

यथा-स्थान बदलने के लिए, की जगह -sc'%p|q!'के साथ -scwq

या bash:

while read line; do arr=($line); echo ${arr[-1]}; done < someinput

प्रदर्शन

के माध्यम से उत्पन्न 1GB फ़ाइल को देखते हुए:

$ hexdump -C /dev/urandom | rev | head -c1G | pv > datafile

मैंने पार्सिंग टाइम आँकड़ों का प्रदर्शन किया है (~ 3x भाग गया और सबसे कम लिया, MBP OS X पर परीक्षण किया गया):

  • का उपयोग कर awk:

    $ time awk '{print $NF}' datafile > /dev/null
    real    0m12.124s
    user    0m10.704s
    sys 0m0.709s
  • का उपयोग कर grep:

    $ time grep -o '\S\+$' datafile > /dev/null
    real    0m36.731s
    user    0m36.244s
    sys 0m0.401s
    
    $ time grep -o '\S*$' datafile > /dev/null
    real    0m40.865s
    user    0m39.756s
    sys 0m0.415s
  • का उपयोग कर perl:

    $ time perl -lane 'print $F[-1]' datafile > /dev/null
    real    0m48.292s
    user    0m47.601s
    sys 0m0.396s
  • rev+ का उपयोग कर cut:

    $ time (rev|cut -d' ' -f1|rev) < datafile > /dev/null
    $ time rev datafile | cut -d' ' -f1 | rev > /dev/null
    real    1m10.342s
    user    1m19.940s
    sys 0m1.263s
  • का उपयोग कर ex:

    $ time ex +'%norm $Bd0_' -sc'%p|q!' datafile > /dev/null
    real    3m47.332s
    user    3m42.037s
    sys 0m2.617s
    $ time ex +'%norm $Bd0' -sc'%p|q!' datafile > /dev/null
    real    4m1.527s
    user    3m44.219s
    sys 0m6.164s
    $ time ex +'%s/^.*\s//g' -sc'%p|q!' datafile > /dev/null
    real    4m16.717s
    user    4m5.334s
    sys 0m5.076s
  • का उपयोग कर bash:

    $ time while read line; do arr=($line); echo ${arr[-1]}; done < datafile > /dev/null
    real    9m42.807s
    user    8m12.553s
    sys 1m1.955s

6
... | perl -lane 'print $F[-1]'

मुख्य बिंदु: सरणी -aमें ऑटोसप्लिट फ़ील्ड @F; -lचॉप $/(इनपुट रिकॉर्ड सेपरेटर) बंद कर देता है और इसे $\(आउटपुट रिकॉर्ड सेपरेटर) में सहेज देता है । क्योंकि कोई ऑक्टल नंबर प्रदान नहीं किया गया है -l, मूल $/प्रिंट (लाइन एंडिंग) में लगाया जाता है; -nलूप कोड; -eइसके तुरंत बाद कोड निष्पादित करें। देखते हैं man perlrun
जोनाथन कोमार

5

इसका उपयोग करके भी किया जा सकता है 'sed':

echo -e 'one two three\nfour five six\nseven eight nine' | sed -e 's/^.* \([^ ]*\)$/\1/'

अद्यतन करें:

या अधिक बस:

echo -e 'one two three\nfour five six\nseven eight nine' | sed -e 's/^.* //'

अधिक बस बेहतर है!
mdpc

@ mdpc: मैं सहमत हूं, लेकिन जैसा कि अधिक जटिल समाधान पहले से ही पोस्ट किया गया था, मैंने इसे रखने का फैसला किया।
jfg956

5

या उपयोग कर रहा है cut:

echo -e 'one two three\nfour five six\nseven eight nine' | cut -f 3 -d' '

हालांकि यह 'सामान्य समाधान' की आवश्यकता को पूरा नहीं करता है। revदो बार उपयोग करने से हम इसे हल कर सकते हैं:

echo -e 'one two three\nfour five six\nseven eight nine' | rev | cut -f 1 -d' ' | rev

मुझे नहीं लगता कि सभी यूनिक्स (एआईएक्स, सोलारिस, ...) पर 'रेव' पाया जा सकता है या सभी लिनक्स पर स्थापित है, लेकिन अच्छा वैकल्पिक समाधान है।
jfg956

1
+1 डबल रेव के लिए, लेकिन एक साइड नोट के रूप में, rev'वाइड' कैरेक्टर के साथ काम नहीं करता, केवल सिंगल बाइट वाले, जहां तक ​​मैं जानता हूं।
मार्सिन

2

यदि awkआप कम से कम एक स्तंभ है, तो आप पहले जांच कर सकते हैं।

echo | awk '{if (NF >= 1) print $NF}'

echo 1 2 3 | awk '{if (NF >= 1) print $NF}'

3
या कम मौखिक रूप से awk 'NF{print $NF}'
मैनेटवर्क

1

पर्ल में यह निम्नानुसार किया जा सकता है:

#!/usr/bin/perl

#create a line of arbitrary data
$line = "1 2 3 4 5";

# splt the line into an array (we call the array 'array', for lolz)
@array = split(' ', $line);

# print the last element in the array, followed by a newline character;
print "$array[-1]\n";

उत्पादन:

$ perl last.pl
5
$

आप एक फ़ाइल के माध्यम से भी लूप कर सकते हैं, एक उदाहरण स्क्रिप्ट जो मैंने एक फाइल पार्स करने के लिए लिखी थी, जिसे बजट कहा जाता है

बजट में डेटा उदाहरण।

Rent              500
Food              250
Car               300
Tax               100
Car Tax           120
Mag Subscription  15

(आप केवल "अंतिम" कॉलम को पकड़ने के लिए देख सकते हैं, केवल कॉलम 2 नहीं)

लिपी:

#!/usr/bin/perl
$budgetfile = "budget.dat";
open($bf, $budgetfile)
        or die "Could not open filename: $filename $!";


print "-" x 50, "\n";
while ( $row = <$bf> ) {
        chomp $row;
        @r = split (' ', $row);
        print "$row ";
        $subtotal += $r[-1];
        print "\t$subtotal\n";
}
print "-" x 50, "\n";
print "\t\t\t Total:\t$subtotal\n\n";

मुझे एहसास हुआ कि किसी और ने पहले ही टिप्पणी की थी, इसके बारे में खेद है, कम से कम मेरे पास कुछ उदाहरण हैं, उम्मीद है कि यह वैसे भी चर्चा में जोड़ता है।
urbansumo
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.