एक स्ट्रिंग के केवल अंतिम 3 वर्णों को मुद्रित करने का आदेश


30

मुझे पता है कि cutकमांड nएक स्ट्रिंग के पहले अक्षर को प्रिंट कर सकता है लेकिन अंतिम nपात्रों का चयन कैसे करें ?

यदि मेरे पास वर्णों की एक चर संख्या है, तो मैं स्ट्रिंग के अंतिम तीन वर्णों को कैसे प्रिंट कर सकता हूं। जैसे।

"असीमित" आउटपुट की आवश्यकता है "टेड"
"987654" आउटपुट की आवश्यकता "654" है
"123456789" आउटपुट की आवश्यकता "789" है

जवाबों:


52

किसी ने स्पष्ट जवाब क्यों नहीं दिया?

sed 's/.*\(...\)/\1/'

... या थोड़ा कम स्पष्ट

grep -o '...$'

जाहिर है, दूसरे में यह खामी है कि कम से कम तीन अक्षर गायब हो जाते हैं; लेकिन सवाल स्पष्ट रूप से इस मामले के लिए व्यवहार को परिभाषित नहीं किया।


6
याgrep -o '.\{3\}$'
अविनाश राज

3
याecho "unlimited" | python -c "print raw_input()[-3:]"
कीरो

8
@ किरो या "echo unlimited" | java -jar EnterpriseWordTrimmer.jar, लेकिन मुझे नहीं लगता कि चरित्र हेरफेर के लिए भारी भाषा में लाना वास्तव में आवश्यक है।
२०:५२ पर wchargin

11
@Chargin आप भूल गएjava -server -Xms300M -Xmx3G -XX:+UseParallelGC -cp /path/to/all/the/jars/ -Dinput.interactive=false -Dinput.pipe=true -Dconfig.file=/path/to/config/last-three-letters.cfg -jar ...
hjk

6
grep -o -P '.{0,3}$'अंतिम 3 वर्णों को प्रिंट करेगा भले ही रेखा में 3 वर्ण कम हों। -Pब्रेसिज़ से बचने के लिए बचा जाता है।
रघु डोड्डा

43

इसे सरल रखते हुए - पूंछ

हमें वर्णों को गिनने के लिए एक नियमित अभिव्यक्ति, या एक से अधिक प्रक्रियाओं की आवश्यकता नहीं होनी चाहिए।
कमांड tail, जिसे अक्सर किसी फ़ाइल की अंतिम पंक्तियों को दिखाने के लिए उपयोग किया जाता है , में एक विकल्प -c( --bytes) होता है, जो इसके लिए सही उपकरण लगता है:

$ printf 123456789 | tail -c 3
789

(जब आप एक शेल में होते हैं, तो यह एक विधि का उपयोग करने के लिए समझ में आता है जैसे कि माइकसर्व के उत्तर में, क्योंकि यह प्रक्रिया शुरू करने से बचाता है tail।)

असली यूनिकोड वर्ण?

अब, आप पिछले तीन पात्रों के लिए पूछते हैं ; यही कारण है कि यह जवाब आपको नहीं देता है: यह अंतिम तीन बाइट्स का उत्पादन करता है !

जब तक प्रत्येक चरित्र एक बाइट है, तब तक tail -cकाम करता है। तो इसका उपयोग चरित्र सेट ASCII, ISO 8859-1या एक संस्करण है , तो इसका इस्तेमाल किया जा सकता है ।

यदि आपके पास यूनिकोड इनपुट है, जैसे सामान्य UTF-8प्रारूप में, तो परिणाम गलत है:

$ printf 123αβγ | tail -c 3
�γ

इस उदाहरण में, UTF-8ग्रीक वर्ण अल्फा, बीटा और गामा का उपयोग करते हुए दो बाइट्स लंबे होते हैं:

$ printf 123αβγ | wc -c  
9

विकल्प -mकम से कम वास्तविक यूनिकोड वर्णों की गणना कर सकता है:

printf 123αβγ | wc -m
6

ठीक है, इसलिए पिछले 6 बाइट्स हमें आखिरी 3 अक्षर देंगे:

$ printf 123αβγ | tail -c 6
αβγ

तो, tailसामान्य पात्रों को संभालने का समर्थन नहीं करता है, और यह भी प्रयास नहीं करता है (नीचे देखें): यह चर आकार लाइनों को संभालता है, लेकिन कोई चर आकार वर्ण नहीं।

आइए इसे इस तरह से रखें: tailसमस्या की संरचना को हल करने के लिए सिर्फ सही है, लेकिन डेटा के प्रकार के लिए गलत है।

GNU कोरुटिल्स

आगे देख रहे हैं, यह पता चला है कि तुमको GNU coreutils, बुनियादी उपकरण के संग्रह की तरह sed, ls, tailऔर cut, अभी तक पूरी तरह अंतरराष्ट्रीयकरण नहीं है। जो मुख्य रूप से यूनिकोड का समर्थन करने के बारे में है।
उदाहरण के लिए, cutचरित्र समर्थन के लिए पूंछ के बजाय उपयोग करने के लिए एक अच्छा उम्मीदवार होगा; इसमें बाइट्स या चार्ट पर काम करने के विकल्प हैं, -c( --bytes) और -m( --chars);

केवल वह -m/ --charsहै, संस्करण के रूप में
cut (GNU coreutils) 8.21, 2013,
कार्यान्वित नहीं किया गया!

से info cut:

`-c CHARACTER-LIST'
`--characters=CHARACTER-LIST'
     Select for printing only the characters in positions listed in CHARACTER-LIST.  
     The same as `-b' for now, but internationalization will change that.


UTF-8 के साथ `cut -c` (` --characters`) का उपयोग नहीं करने के लिए यह उत्तर भी देखें ।


2
वास्तव में, अधिकांश अन्य उत्तर यूनिकोड को ठीक से संभालने के लिए प्रतीत होते हैं, जब तक कि वर्तमान स्थान UTF-8 एन्कोडिंग निर्दिष्ट करता है। केवल आपका और ग्लेन जैकमैन का- cutआधारित समाधान प्रतीत नहीं होता है।
इल्मरी करोनें

@ इल्मारिकारोन सच, संकेत के लिए धन्यवाद। मैंने कुछ अतिरिक्त विवरण के साथ संपादित किया है।
वोल्कर सेगेल

1
ध्यान दें कि POSIX स्पष्ट रूप से निर्दिष्ट करता है कि tailबाइट्स से निपटना चाहिए, और वर्ण नहीं। मैंने एक बार पात्रों का चयन करने के लिए एक नया विकल्प जोड़ने के लिए एक पैच बनाया था, लेकिन मेरा मानना ​​है कि कभी भी विलय नहीं हुआ: - /
मार्टिन टूरनोइज

फ़ाइल-मोड में काम नहीं करता, जैसेtail -c3 -n10 /var/log/syslog
सनकैचर

@Suncatcher मैंने कोशिश की, और यह काम किया। आपको क्या समस्या दिख रही है? आपकी आज्ञा tail -c3 -n10 /var/log/syslogअंतिम 10 पंक्तियों के लिए पूछती है, और जो मेरे लिए काम करती है। आप विकल्प का उपयोग करते हैं -c3, और उसके बाद परस्पर विरोधी विकल्प -n10। बाद का विकल्प प्राथमिकता लेता है।
वोल्कर सिएगल

36

अपने पाठ नामक एक खोल चर में है, तो STRING, आप एक से कर सकते हैं bash, zshया mkshशेल:

printf '%s\n' "${STRING:(-3)}"

या

printf '%s\n' "${STRING: -3}"

जिसमें ksh93 के साथ काम करने का लाभ भी है, जहां से वाक्य रचना आती है।

मुद्दा यह है कि इससे :अलग होना है -, अन्यथा यह ${var:-default}बॉर्न शेल का संचालक बन जाता है ।

zshया yashगोले में बराबर सिंटैक्स है:

printf '%s\n' "${STRING[-3,-1]}"

2
उस तरह के सिंटैक्स / ऑपरेशन को क्या कहा जाता है ताकि मैं और अधिक अनौपचारिक खोज कर सकूं?
ट्यूलेंस कोरडोवा

6
इसे सबस्ट्रिंग एक्सपेंशन कहा जाता है । यह एक प्रकार का पैरामीटर विस्तार है । सामान्य रूप $ {पैरामीटर: ऑफसेट: लंबाई} है , लेकिन लंबाई फ़ील्ड वैकल्पिक है (और, जैसा कि आप देख सकते हैं, यह ऊपर दिए गए उत्तर में छोड़ दिया गया है)। DopeGhoti भी लिखा हो सकता है ${STRING:(-3):3}( लंबाई क्षेत्र निर्दिष्ट ), ${STRING: -3}( :और के बीच एक स्थान के साथ -), या ${STRING: -3:3}
जी-मैन का कहना है कि 'मोनिका'

इस मामले में, लंबाई निर्दिष्ट करना 3कुछ हद तक गलत है क्योंकि यह "अंतिम वर्ण से तीसरे से तीन वर्ण, समावेशी" के लिए पूछ रहा है जो व्यावहारिक रूप में एक समान संचालन होता है "पिछले से तीसरे से आगे के सभी वर्ण" , समावेशी ”।
डोपघोटी

13

का उपयोग कर awk:

awk '{ print substr( $0, length($0) - 2, length($0) ) }' file
ted
654
789

11

यदि स्ट्रिंग एक चर में है, तो आप यह कर सकते हैं:

printf %s\\n "${var#"${var%???}"}"

इस $varतरह के मान से अंतिम तीन वर्णों को अलग करता है :

${var%???}

... और फिर से सिर से स्ट्रिप्स $varसब कुछ है, लेकिन क्या वैसे ही जैसे छीन लिया:

${var#"${var%???}"}

इस विधि में अपसाइड और डाउनसाइड हैं। उज्ज्वल पक्ष पर यह पूरी तरह से पॉस-पोर्टेबल है और किसी भी आधुनिक शेल में काम करना चाहिए। इसके अलावा, अगर $varकम से कम तीन वर्णों के अलावा कुछ नहीं है, लेकिन अनुगामी \newline मुद्रित है। फिर, यदि आप चाहते हैं कि यह उस स्थिति में मुद्रित हो, तो आपको एक अतिरिक्त चरण की आवश्यकता है:

last3=${var#"${var%???}"}
printf %s\\n "${last3:-$var}"

$last3यदि $var3 या उससे कम बाइट्स हो तो उस तरह से केवल खाली होता है। और $varकेवल तभी के लिए प्रतिस्थापित किया जाता है $last3यदि $last3खाली है या unset- और हम जानते हैं कि ऐसा नहीं है unsetक्योंकि हम इसे निर्धारित करते हैं।


यह बहुत साफ है +1। एक तरफ: किसी भी कारण से आप अपने printfप्रारूप तार उद्धृत नहीं करते हैं?
जसोनव्रीयन

सिर्फ उपयोग ${VARNAME:(-3)}(अनुमान bash) क्यों नहीं ?
डोपघोटी

1
स्पष्टीकरण देने के लिए धन्यवाद; समझ में आता है, भले ही यह (मेरे लिए) थोड़ा अजीब लगे ...
jasonwryan

1
@ डोपघोटी - सिर्फ इसलिए कि एक धारणा है कि मैं लगभग कभी नहीं बना हूं। यह bashPOSIX comapibility का दावा करने वाले किसी अन्य शेल में भी काम करता है ।
मोकेसर

3
@odyssey - समस्या यह है cshहै नहीं के बीच में आधुनिक, POSIX संगत गोले मैं यहाँ का उल्लेख है, दुर्भाग्य से। POSIX- शेल कल्पना के बाद मॉडलिंग की जाती है ksh, जो दोनों cshऔर पारंपरिक बॉर्न-शैली के गोले के संयोजन के बाद खुद को मॉडल बनाती है । kshदोनों में cshउत्कृष्ट जॉब-कंट्रोल कार्यक्षमता और पुराने बॉर्न-स्टाइल 'i / o पुनर्निर्देशन शामिल हैं। इसने कुछ चीजों को भी जोड़ा - जैसे कि स्ट्रिंग हेरफेर अवधारणाएं जो मैं ऊपर दिखाता हूं। cshजहाँ तक मुझे पता है, यह किसी भी पारंपरिक काम की संभावना नहीं होगी , मुझे यह कहने के लिए खेद है।
1

7

आप ऐसा कर सकते हैं, लेकिन यह थोड़ा ... अत्यधिक है:

for s in unlimited 987654 123456789; do
    rev <<< $s | cut -c 1-3 | rev
done 
ted
654
789

3

Utf-8 स्ट्रिंग्स के लिए बुलेटप्रूफ समाधान:

utf8_str=$'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' # привет

last_three_chars=$(perl -CAO -e 'print substr($ARGV[0], -3)' "$utf8_str")

या उपयोग करें:

last_three_chars=$(perl -MEncode -CO -e '
  print substr(decode("UTF-8", $ARGV[0], Encode::FB_CROAK), -3)
' "$utf8_str")

विकृत डेटा हैंडलिंग को रोकने के लिए।

उदाहरण:

perl -MEncode -CO -e '
  print substr(decode("UTF-8", $ARGV[0], Encode::FB_CROAK), -3)
' $'\xd0\xd2\xc9\xd7\xc5\xd4' # koi8-r привет

आउटपुट कुछ इस तरह है:

utf8 "\xD0" does not map to Unicode at /usr/lib/x86_64-linux-gnu/perl/5.20/Encode.pm line 175.

लोकेल सेटिंग्स (यानी काम करता है LC_ALL=C) पर निर्भर नहीं करता है । Bash, sed, grep, awk, revकुछ इस तरह की आवश्यकता होती है:LC_ALL=en_US.UTF-8

सामान्य समाधान:

  • बाइट्स प्राप्त करें
  • एन्कोडिंग का पता लगाएं
  • वर्णों को बाइट डिकोड करें
  • चरसें निकालें
  • चरित्र को बाइट्स के लिए एन्कोड करें

आप uchardet के साथ एन्कोडिंग का पता लगा सकते हैं । संबंधित प्रोजेक्ट भी देखें ।

आप पायल में कोडेक्स , पायथन 2.7 में एनकोड के साथ डीकोड / एनकोड कर सकते हैं

उदाहरण :

Utf-16le स्ट्रिंग से अंतिम तीन वर्ण निकालें और इन वर्णों को utf-8 में बदलें

utf16_le_str=$'\xff\xfe\x3f\x04\x40\x04\x38\x04\x32\x04\x35\x04\x42\x04' # привет

chardet <<<"$utf16_le_str"  # outputs <stdin>: UTF-16LE with confidence 1.0

last_three_utf8_chars=$(perl -MEncode -e '
    my $chars = decode("utf-16le", $ARGV[0]);
    my $last_three_chars = substr($chars, -3);
    my $bytes = encode("utf-8", $last_three_chars);
    print $bytes;
  ' "$utf16_le_str"
)

इसे भी देखें: perlunitut , Python 2 Unicode HOWTO


echoआपका बुलेटप्रूफ स्रोत क्या है?
मोकेसर

@mikeserv, decode/encodeमेरा बुलेटप्रूफ स्रोत है। मेरे उत्तर को साफ कर दिया।
एवगेनी वीरशैगिन

यह गारंटी देने के लिए स्थानीय सेटिंग्स पर भी निर्भर करता है कि यह सही ढंग से काम करता है, क्योंकि बाइट्स का एक सेट विभिन्न वर्णों में विभिन्न वर्णों को प्रतिबिंबित कर सकता है। यह "के लिए" काम करता है LC_ALL=Cक्योंकि यह बहुत "गूंगा" सेटिंग है, लेकिन यह तब टूट सकता है जब आप UTF-8 स्ट्रिंग को SHIFT-5, या SHIFT-5 स्ट्रिंग को KOI8, आदि के लिए पास करने की कोशिश करते हैं, आदि
मार्टिन टूरनोइज

@ कारपेटमोकर, धन्यवाद। क्या आप अपनी टिप्पणी समझा सकते हैं? मुझे लगता है कि लगता है कि perl -CAO -e 'print substr($ARGV[0], -3)'काम करता है ठीक। A@ARGV तत्वों को UTF-8 में एन्कोड किए गए तार होने की उम्मीद है, OSTDOUT UTF-8 में होगा।
इवगेनी वीरशैगिन

ऐसा लगता है कि आप असाइनमेंट के बारे में बताते हैंutf8_str
एवगेनी वीरशैगिन

1

"Expr" या "Rev" का उपयोग करने के बारे में क्या?

@ जी-मैन द्वारा प्रदान किए गए एक के समान उत्तर : expr "$yourstring" : '.*\(...\)$' इसमें grep समाधान की तुलना में एक ही दोष है।

एक प्रसिद्ध चाल "रेव" के साथ "कट" को संयोजित करना है: echo "$yourstring" | rev | cut -n 1-3 | rev


revसमाधान की तरह एक बहुत लग रहा है ग्लेन जैकमैन की
जेफ स्कालर

आप ठीक कह रहे हैं @ जेफ_चैलर: मुझे ग्लेन की एक याद आई :-(
गिल्डक्स

0

स्ट्रिंग का आकार प्राप्त करें:

size=${#STRING}

फिर अंतिम n वर्ण का विकल्प प्राप्त करें:

echo ${STRING:size-n:size}

उदाहरण के लिए:

STRING=123456789
n=3
size=${#STRING}
echo ${STRING:size-n:size}

देना होगा:

789

0

tail -n 1 revisions.log | awk '{प्रिंट पदार्थ ($ 0, 0, लंबाई ($ 0) - (लंबाई ($ 0) -13)))' '

अगर आप भीख से पहला तेरह अक्षर छपवाना चाहते हैं


-1

अगर स्ट्रिंग में जगह है तो प्रिंटफ काम नहीं करेगा।

अंतरिक्ष के साथ स्ट्रिंग के लिए नीचे कोड

str="Welcome to Linux"
echo -n $str | tail -c 3

nux


उम, अगर printfकाम नहीं करता है, तो आप कुछ कर रहे हैं बहुत गलत।
Kusalananda

1
@Kusalananda: आदेश है कि सौरभ शो, वे करने की कोशिश की के आधार पर printf $str(बजाय printf "$str"या printf '%s' "$str")। और, हाँ, printf $strहै बहुत गलत। ( echo -n $strज्यादा बेहतर नहीं है।)
जी-मैन का कहना है कि 'मोनिका'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.