'कट' का उपयोग करके अंतिम फ़ील्ड कैसे खोजें


310

उपयोग किए बिनाsed या awk, केवल cut , मुझे अंतिम फ़ील्ड कैसे मिलती है जब फ़ील्ड की संख्या अज्ञात है या हर पंक्ति के साथ बदल जाती है?


8
क्या आप cutकमांड के साथ प्यार में हैं :)? कोई अन्य लिनक्स कमांड क्यों नहीं?
जयेश भोई

7
बिना sedया awk: perl -pe 's/^.+\s+([^\s]+)$/$1/'
जोर्डनम


4
@MestreLion कई बार लोग किसी समस्या की भिन्नता का समाधान खोजने के लिए एक प्रश्न पढ़ते हैं। यह एक झूठे आधार के साथ शुरू होता है जो cutकुछ ऐसा करता है जिसका समर्थन करता है। लेकिन मुझे लगा कि यह उपयोगी है, इसमें यह पाठक को उस कोड पर विचार करने के लिए मजबूर करता है जिसका पालन करना आसान है। मैं एक त्वरित, उपयोग करने के लिए आसान तरीका चाहते थे cutके लिए कई वाक्यविन्यास का उपयोग करने की जरूरत के बिना awk, grep, sed, आदि revबात चाल किया; बहुत सुंदर, और कुछ मैंने कभी नहीं सोचा (भले ही अन्य स्थितियों के लिए क्लंकी हो)। मुझे अन्य उत्तरों से अन्य दृष्टिकोण पढ़ना भी पसंद था।
बीजर

3
यहाँ एक वास्तविक जीवन की समस्या आई: मैं एक स्रोत ट्री में सभी अलग-अलग फ़ाइल एक्सटेंशनों को खोजना चाहता हूँ, जिनके साथ .gitattributes फ़ाइल को अपडेट करना है। तो find | cut -d. -f<last>प्राकृतिक झुकाव है
स्टडॉग

जवाबों:


679

आप कुछ इस तरह की कोशिश कर सकते हैं:

echo 'maps.google.com' | rev | cut -d'.' -f 1 | rev

व्याख्या

  • rev "maps.google.com" को उलट देता है moc.elgoog.spam
  • cut डॉट (यानी '।') को सीमांकक के रूप में उपयोग करता है, और पहला फ़ील्ड चुनता है, जो है moc
  • अंत में, हम इसे प्राप्त करने के लिए फिर से रिवर्स करते हैं com

6
यह केवल उपयोग नहीं कर रहा है, cutलेकिन इसके बिना sedया awk
जयेश भोई

7
@tom ओपी ने पिछले कुछ घंटों में सिर्फ इससे ज्यादा सवाल पूछे हैं। ओपी के साथ हमारी बातचीत के आधार पर हम जानते हैं कि awk / sed / etc। उसके होमवर्क में अनुमति नहीं है, लेकिन संशोधित करने के लिए एक संदर्भ नहीं बनाया गया है। तो यह एक शॉट के लायक था
zedfoxus

4
@ ज़फस मैं देख रहा हूँ। revबाद में एक और छड़ी करना चाह सकते हैं ।
टॉम

17
डबल revमहान आदर्श!
फोर्ड गुओ

6
विस्मयकारी, सरल, परिपूर्ण, स्पष्टीकरण के लिए भी धन्यवाद - पाइप्ड कमांड्स की लंबी श्रृंखला में प्रत्येक चरण की व्याख्या करने वाले पर्याप्त लोग नहीं
पेटी

128

एक पैरामीटर विस्तार का उपयोग करें। यह किसी भी प्रकार के बाहरी कमांड की तुलना में बहुत अधिक कुशल है, cut(या grep) शामिल हैं।

data=foo,bar,baz,qux
last=${data##*,}

बाश में देशी स्ट्रिंग हेरफेर के लिए एक परिचय के लिए BashFAQ # 100 देखें ।


3
@ इरविनवेसेल: क्योंकि बैश वास्तव में धीमा है। पाइपलाइन चलाने के लिए बैश का उपयोग करें, बल्क में डेटा संसाधित करने के लिए नहीं। मेरा मतलब है, यह बहुत अच्छा है यदि आपके पास शेल चर में पहले से ही पाठ की एक पंक्ति है, या यदि आप while IFS= read -ra array_var; do :;done <(cmd)कुछ पंक्तियों को संसाधित करने के लिए करना चाहते हैं। लेकिन एक बड़ी फ़ाइल के लिए, Rev। कट | Rev। शायद तेज है! (और निश्चित रूप से awk इससे भी तेज होगा।)
पीटर कॉर्ड्स

2
@PeterCordes, awk एक बड़ी फ़ाइल के लिए तेज़ होगा, निश्चित रूप से, लेकिन स्थिर-कारक स्टार्टअप लागत को पार करने के लिए यह बहुत अच्छा इनपुट लेता है। (वहाँ भी गोले मौजूद हैं - जैसे ksh93 - awk के करीब प्रदर्शन के साथ, जहां इस उत्तर में दिया गया सिंटैक्स वैध रहता है; बैश असाधारण रूप से सुस्त है, लेकिन यह केवल उपलब्ध विकल्प के करीब भी नहीं है)।
चार्ल्स डफी

1
धन्यवाद @PeterCordes; हमेशा की तरह मुझे लगता है कि प्रत्येक उपकरण के उपयोग के मामले हैं।
इरविन वेसल्स

1
यह bashस्क्रिप्ट के अंदर एक एकल चर को ट्रिम करने का सबसे तेज़ और सबसे संक्षिप्त तरीका है (यह मानते हुए कि आप पहले से ही bashस्क्रिप्ट का उपयोग कर रहे हैं )। बाहरी कुछ भी कहने की जरूरत नहीं है।
केन शार्प

1
@Balmipour, ... हालाँकि, जो भी OS आप इसे प्रदान कर रहे हैं , उसके rev लिए विशिष्ट है - यह सभी UNIX प्रणालियों में मानकीकृत नहीं है। आदेशों और उपयोगिताओं पर POSIX अनुभाग के लिए अध्याय सूची देखें - यह वहां नहीं है। और ${var##prefix_pattern}है नहीं तथ्य बैश विशेष में; यह POSIX श मानक में है , खंड २.६.२ (जुड़ा हुआ) का अंत देखें, इसलिए rev, इसके विपरीत , यह हमेशा किसी भी संगत शेल पर उपलब्ध है।
चार्ल्स डफी

89

सिर्फ इस्तेमाल करना संभव नहीं है cut। यहाँ एक तरीका है grep:

grep -o '[^,]*$'

अन्य सीमांकक के लिए अल्पविराम बदलें।


3
विपरीत करने के लिए, और अंतिम क्षेत्र को छोड़कर सब कुछ grep -o '^.*,'
एरियल

2
यह विशेष रूप से उपयोगी था, क्योंकि revमेरे मामले में एक मुद्दा मल्टीबाइट यूनिकोड वर्ण जोड़ें।
ब्राइस

3
मैं MinGW पर ऐसा करने की कोशिश कर रहा था, लेकिन मेरा grep संस्करण -o का समर्थन नहीं करता है, इसलिए मैंने उपयोग किया sed 's/^.*,//'जो सभी पात्रों को खाली स्ट्रिंग के साथ अंतिम अल्पविराम सहित और बदल देता है।
TamaMcGlinn

46

जाग के बिना? ... लेकिन यह जाग के साथ बहुत आसान है:

echo 'maps.google.com' | awk -F. '{print $NF}'

AWK एक और अधिक शक्तिशाली उपकरण है जो आपकी जेब में है। -F यदि क्षेत्र विभाजक के लिए NF खेतों की संख्या है (अंतिम के सूचकांक के लिए भी खड़ा है)


2
यह सार्वभौमिक है और यह हर बार अपेक्षा के अनुरूप काम करता है। इस परिदृश्य में, cutओपी के अंतिम आउटपुट को प्राप्त करने के लिए एक चम्मच "कट" स्टेक का उपयोग करने के समान है (वाक्य का उद्देश्य :))। awkस्टेक चाकू है।
Hickory420

3
उपयोग की echoलंबी फ़ाइलों के लिए स्क्रिप्ट को धीमा कर सकता है कि आवश्यक उपयोग से बचें awk -F. '{print $NF}' <<< 'maps.google.com'
अनिल_एम

14

इसके कई तरीके हैं। आप भी इस का उपयोग कर सकते हैं।

echo "Your string here"| tr ' ' '\n' | tail -n1
> here

जाहिर है, tr कमांड के लिए रिक्त स्थान इनपुट को आपके द्वारा आवश्यक सीमांकक के साथ प्रतिस्थापित किया जाना चाहिए।


धन्यवाद! कुछ जो काम करता है बिजीबॉक्स sh 1.0.0 :)
केविनफ़

1
यह मेरे लिए सबसे सरल उत्तर की तरह लगता है, कम पाइप और स्पष्ट अर्थ
joeButler

1
यह पूरी फ़ाइल के लिए काम नहीं करेगा, जो कि ओपी का मतलब है।
अमीर

7

यह कुछ भी नहीं लेकिन कटौती का उपयोग करने के लिए संभव एकमात्र समाधान है:

इको "स्ट्रिंग" | कट -d '।' -f2- [बार- बार_फ़ोलिंग_पार्टी_सेवर_ऑन्टर_आउट_ऑफ_मैमोरी :] | कट -d '।' -f2-

इस समाधान का उपयोग करके, फ़ील्ड की संख्या वास्तव में अज्ञात हो सकती है और समय-समय पर भिन्न हो सकती है। हालाँकि, लाइन की लंबाई नई लाइन वर्ण सहित LINE_MAX वर्णों या फ़ील्ड्स से अधिक नहीं होनी चाहिए, फिर फ़ील्ड की एक मनमानी संख्या इस समाधान की वास्तविक स्थिति के रूप में कभी भी भाग नहीं हो सकती है।

हाँ, एक बहुत ही मूर्खतापूर्ण समाधान लेकिन केवल वही जो मुझे लगता है कि कसौटी पर खरा उतरता है।


2
अच्छा लगा। बस आखिरी ले लो। ' "स्ट्रिंग" और यह काम करता है।
मैट

2
मुझे प्यार है जब हर कोई कहता है कि कुछ असंभव है और फिर कोई व्यक्ति काम के जवाब में झंकारता है। भले ही यह वास्तव में बहुत मूर्खतापूर्ण हो।
बीजर

एक cut -f2-लूप में पुनरावृति कर सकता है जब तक कि आउटपुट में परिवर्तन न हो।
loa_in_

4

यदि आपके इनपुट स्ट्रिंग में आगे स्लैश नहीं हैं, तो आप उपयोग कर सकते हैं basenameऔर एक उपधारा:

$ basename "$(echo 'maps.google.com' | tr '.' '/')"

यह उपयोग नहीं करता है sedया awkयह भी उपयोग नहीं करता हैcut , इसलिए यदि मैं इसके शब्द के रूप में प्रश्न के उत्तर के रूप में अर्हता प्राप्त करता हूं, तो मुझे यकीन नहीं है।

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

$ basename "$(echo 'maps.google.com/some/url/things' | tr '/' '|' | tr '.' '/')" | tr '|' '/'

2

निम्नलिखित एक मित्र के सुझाव को लागू करता है

#!/bin/bash
rcut(){

  nu="$( echo $1 | cut -d"$DELIM" -f 2-  )"
  if [ "$nu" != "$1" ]
  then
    rcut "$nu"
  else
    echo "$nu"
  fi
}

$ export DELIM=.
$ rcut a.b.c.d
d

2
आपको echoमज़बूती और मज़बूती से काम करने के लिए तर्कों के चारों ओर दोहरे उद्धरण चिह्नों की आवश्यकता है । देखें stackoverflow.com/questions/10067266/…
ट्रिपल

0

यदि आपके पास filelist.txt नाम की एक फ़ाइल है जो सूची पथ है जैसे कि निम्न: c: /dir1/dir2/file1.h c: /dir1/dir2/dir3/file2.h

तो आप यह कर सकते हैं: Revelelist.txt | cut -d "/" -f1 | फिरना


0

इस पुराने प्रश्न के दृष्टिकोण को केवल मज़े के लिए जोड़ना:

$ cat input.file # file containing input that needs to be processed
a;b;c;d;e
1;2;3;4;5
no delimiter here
124;adsf;15454
foo;bar;is;null;info

$ cat tmp.sh # showing off the script to do the job
#!/bin/bash
delim=';'
while read -r line; do  
    while [[ "$line" =~ "$delim" ]]; do
        line=$(cut -d"$delim" -f 2- <<<"$line")
    done
    echo "$line"
done < input.file

$ ./tmp.sh # output of above script/processed input file
e
5
no delimiter here
15454
info

बैश के अलावा, केवल कट का उपयोग किया जाता है। खैर, और प्रतिध्वनि, मुझे लगता है।


मेह, क्यों न केवल कट को पूरी तरह से हटा दें और केवल बैश का उपयोग करें ... x] while read -r line; do echo ${line/*;}; done <input.fileसमान परिणाम देता है।
काफ मायर्स

-1

मुझे एहसास हुआ कि अगर हम सिर्फ एक अनुगामी परिसीमन सुनिश्चित करते हैं, तो यह काम करता है। इसलिए मेरे मामले में मेरे पास अल्पविराम और व्हॉट्सएप डेलिमिटर हैं। मैं अंत में एक स्थान जोड़ता हूं;

$ ans="a, b"
$ ans+=" "; echo ${ans} | tr ',' ' ' | tr -s ' ' | cut -d' ' -f2
b

और ans="a, b, c"उत्पादन करता है b, जो "हर क्षेत्र के साथ अज्ञात या परिवर्तन की संख्या" की आवश्यकताओं को पूरा नहीं करता है ।
jww
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.