बाश में कमांड के आउटपुट का पहला शब्द कैसे प्राप्त करें?


126

मेरे पास एक आदेश है, उदाहरण के लिए echo "word1 word2":। मैं एक पाइप डालना चाहता हूं ( |) और कमांड से वर्ड 1 प्राप्त करना चाहता हूं ।

echo "word1 word2" | ....

मुझे नहीं पता कि पाइप के बाद क्या रखा जाए।

जवाबों:


201

यदि आप को व्हाट्सएप से पीछे हटना पड़ता है तो Awk एक अच्छा विकल्प है क्योंकि यह आपके लिए ध्यान रखेगा:

echo "   word1  word2 " | awk '{print $1;}' # Prints "word1"

हालांकि कट इस पर ध्यान नहीं देगा:

echo "  word1  word2 " | cut -f 1 -d " " # Prints nothing/whitespace

यहां 'कट' कुछ भी नहीं / व्हाट्सएप प्रिंट करता है, क्योंकि एक अंतरिक्ष से पहले पहली चीज दूसरी जगह थी।


क्या अर्ध-कोलन आवश्यक है?
एलिस पर्ससेल

1
यह "अग्रणी" व्हाट्सएप होना चाहिए (स्ट्रिंग की शुरुआत में), "अनुगामी" नहीं।
user202729

@AlicePurcell मैंने इसके बिना कोशिश की; और यह मेरे लिए काम किया (MBP 10.14.2)
Samy

1
यह काम नहीं करता है अगर स्ट्रिंग "फर्स्टवर्ड, सेकंडवर्ड" जैसे कि awk कमांड डेलिमिटर स्पेस के रूप में है
रोजर ओबा

@RogerOba यह ओपी का सवाल नहीं था, लेकिन आप -F","अल्पविराम के साथ डिफ़ॉल्ट फ़ील्ड विभाजक (एक स्थान) को ओवरराइड करने के लिए उपयोग कर सकते हैं ।
pjd

70

बाहरी आदेशों का उपयोग करने की आवश्यकता नहीं है। बैश खुद काम कर सकते हैं। "वर्ड 1 वर्ड 2" मान लें कि आप कहीं से मिले हैं और एक चर में संग्रहीत हैं, जैसे

$ string="word1 word2"
$ set -- $string
$ echo $1
word1
$ echo $2
word2

अब आप $ 1, या $ 2 आदि को दूसरे चर पर असाइन कर सकते हैं यदि आप चाहें।


11
केवल शेल निर्मित इन का उपयोग करने के लिए +1 और stdin। @ माट एम। का --मतलब है stdin, इसलिए $stringइसे पारित किया जा रहा है stdinstdinबहस में खाली स्थान के-अलग किया जाता है $1, $2, $3, आदि - बस जब एक बैश कार्यक्रम मूल्यांकन करता तर्क (जैसे की जांच की तरह $1, $2आदि), इस दृष्टिकोण लाभ खोल की प्रवृत्ति के विभाजित करने के लिए ले जाता है stdinबहस में स्वचालित रूप से, के लिए की जरूरत को हटाने awkया cut
कालेब जू

3
@CalebXu स्टड नहीं, setशेल तर्क देता है।
गुइडो

9
word1=$(IFS=" " ; set -- $string ; echo $1)शब्दों के बीच की जगह को सही ढंग से पहचानने के लिए IFS सेट करें। कोष्ठक में लपेटें $ 1 की मूल सामग्री को हटाने से बचने के लिए।
स्टीव पिचर्स

यह टूट गया है क्योंकि यह pathname विस्तार के अधीन है। इसके साथ प्रयास करें string="*"। आश्चर्य।
गनीउरफ_गनीउरफ

32

मुझे लगता है कि एक कुशल तरीका बैश सरणियों का उपयोग है:

array=( $string ) # do not use quotes in order to allow word expansion
echo ${array[0]}  # You can retrieve any word. Index runs from 0 to length-1

इसके अलावा, आप सीधे पाइप-लाइन में सरणियों को पढ़ सकते हैं:

echo "word1 word2" | while read -a array; do echo "${array[0]}" ; done

1
echo " word1 word2 " | { read -a array ; echo ${array[0]} ; }
Boontawee होम

यह टूट गया है क्योंकि यह pathname विस्तार के अधीन है। इसके साथ प्रयास करें string="*"। आश्चर्य।
गनीउरफ_गनीउरफ

whileप्रत्येक पंक्ति में प्रत्येक पहले शब्द को पुनः प्राप्त करने के लिए वाक्यविन्यास का उपयोग करें । अन्यथा, Boontawee होम दृष्टिकोण का उपयोग करें। इसके अलावा, कृपया ध्यान दें कि echo "${array[0]}"विस्तार को रोकने के लिए उद्धृत किया गया है जैसा कि gniourf-gniourf द्वारा देखा गया है।
इसहास

यदि आप सरणी के एक सूचकांक तक पहुँचने की कोशिश करते हैं जो शब्दों की संख्या से अधिक है, तो आपको एक त्रुटि नहीं मिलेगी। आपको बस एक खाली लाइन मिल जाएगी
धूमिल अग्रवाल

26
echo "word1 word2 word3" | { read first rest ; echo $first ; }

इसका फायदा यह है कि बाहरी कमांड का उपयोग नहीं कर रहा है और $ 1, $ 2, आदि को बरकरार रखता है।


चर को छोड़ना $1, $2, …स्क्रिप्ट लेखन के लिए एक अत्यंत उपयोगी विशेषता है!
सर्ज स्ट्रोबंड्ट

14

यदि आप सुनिश्चित हैं कि प्रमुख स्थान नहीं हैं, तो आप बैश पैरामीटर प्रतिस्थापन का उपयोग कर सकते हैं:

$ string="word1  word2"
$ echo ${string/%\ */}
word1

सिंगल स्पेस से बचने के लिए बाहर देखें। प्रतिस्थापन पैटर्न के अधिक उदाहरणों के लिए यहां देखें । यदि आपके पास bash> 3.0 है, तो आप अग्रणी स्थानों से निपटने के लिए नियमित अभिव्यक्ति मिलान का उपयोग भी कर सकते हैं - यहाँ देखें :

$ string="  word1   word2"
$ [[ ${string} =~ \ *([^\ ]*) ]]
$ echo ${BASH_REMATCH[1]}
word1

11

आप जागने की कोशिश कर सकते हैं

echo "word1 word2" | awk '{ print $1 }'

Awk के साथ आपको किसी भी शब्द को पसंद करना बहुत आसान है ($ 1, $ 2, ...)


11

शेल पैरामीटर विस्तार का उपयोग करना %% *

शेल पैरामीटर विस्तार का उपयोग करके यहां एक और समाधान है । यह पहले शब्द के बाद कई रिक्त स्थान का ख्याल रखता है। पहले शब्द के सामने रिक्त स्थान को संभालने के लिए एक अतिरिक्त विस्तार की आवश्यकता होती है।

string='word1    word2'
echo ${string%% *}
word1

string='word1    word2      '
echo ${string%% *}
word1

व्याख्या

के अनुगामी भाग में (किसी भी संख्या में अन्य वर्णों के किसी भी संख्या के बाद एक स्थान) के सबसे लंबे संभव मैच को हटाने का %%संकेत देता है । *string


9

मुझे आश्चर्य हुआ कि गति के संदर्भ में शीर्ष के कितने उत्तर आए। मैंने निम्नलिखित परीक्षण किया:

1 @ मत्तभ का

echo "..." | awk '{print $1;}'

2 @ ghostdog74 का

string="..."; set -- $string; echo $1

3 @ बूंटवी-घर की

echo "..." | { read -a array ; echo ${array[0]} ; }

और 4 @ boontawee- घर की

echo "..." | { read first _ ; echo $first ; }

मैंने उन्हें 215 5-अक्षर शब्दों के साथ एक परीक्षण स्ट्रिंग का उपयोग करते हुए macOS पर एक Zsh टर्मिनल में बैश स्क्रिप्ट में पायथन के समय के साथ मापा। क्या प्रत्येक माप पांच बार (परिणाम सभी 100 छोरों के लिए थे, सर्वश्रेष्ठ 3), और परिणाम औसत थे:

method       time
--------------------------------
1. awk       9.2ms
2. set       11.6ms (1.26 * "1")
3. read -a   11.7ms (1.27 * "1")
4. read      13.6ms (1.48 * "1")

अच्छी नौकरी, मतदाता (वोट (इस लेखन के रूप में) समाधान की गति से मेल खाते हैं!


अजीब है कि आप डैश में 3 को माप सकते हैं, क्योंकि डैश एरेज़ का समर्थन नहीं करता है ( read -aडैश में अमान्य है)।
gniourf_gniourf

हाँ यह अजीब है। मैंने फैसला सुनाया कि एक ने गति परीक्षण किया, फिर सोचा कि "मैं उस एक को क्यों छोडूंगा" और इसे इसमें जोड़ा, इसे अभी हटाते हुए, और मैं बाद में यह सुनिश्चित करने के लिए चीजों को फिर से कर सकता हूं कि मुझसे कोई गलती नहीं हुई थी
हेनरी

6
echo "word1 word2" | cut -f 1 -d " "

कट स्ट्रिंग "" (-d "") द्वारा सीमांकित फ़ील्ड की सूची से 1 फ़ील्ड (-f 1) काटता है।


यह एक तरीका है, लेकिन आपका कट स्टेटमेंट शब्दों के बीच कई रिक्त स्थान को अलग नहीं करेगा यदि वह बाद में शब्द 2 प्राप्त करना चाहता है
ghostdog74

हां, जाग समाधान बेहतर है।
लजुएट

3

read आपका दोस्त है:

  • यदि स्ट्रिंग एक चर में है:

    string="word1 word2"
    read -r first _ <<< "$string"
    printf '%s\n' "$first"
  • यदि आप एक पाइप में काम कर रहे हैं: पहला मामला: आप केवल पहली पंक्ति का पहला शब्द चाहते हैं:

    printf '%s\n' "word1 word2" "line2" | { read -r first _; printf '%s\n' "$first"; }

    दूसरा मामला: आप प्रत्येक पंक्ति का पहला शब्द चाहते हैं:

    printf '%s\n' "word1 word2" "worda wordb" | while read -r first _; do printf '%s\n' "$first"; done

यदि प्रमुख स्थान हैं तो ये कार्य:

printf '%s\n' "   word1 word2" | { read -r first _; printf '%s\n' "$first"; }

0

चूंकि पर्ल में awk की कार्यक्षमता शामिल है, इसलिए इसे पर्ल के साथ भी हल किया जा सकता है:

echo " word1 word2" | perl -lane 'print $F[0]'

0

मैं एक एंबेडेड डिवाइस के साथ काम कर रहा था जिसमें न तो पर्ल, ऑक या पाइथन था और इसके बजाय इसे सेड के साथ किया था। यह पहले शब्द (जो cutऔर bashसमाधान नहीं संभालता) से पहले कई रिक्त स्थान का समर्थन करता है ।

VARIABLE="  first_word_with_spaces_before_and_after  another_word  "
echo $VARIABLE | sed 's/ *\([^ ]*\).*/\1/'

ग्रेपिंग करते समय यह बहुत उपयोगी था ps केवल बैश का उपयोग करके अन्य समाधानों के बाद से प्रोसेस आईडी के लिए पहले रिक्त स्थान को हटाने में सक्षम नहीं था जो psकि संरेखित करता है।

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