बैश में, मैं कैसे जांच सकता हूं कि क्या कुछ मूल्य के साथ एक स्ट्रिंग शुरू होती है?


744

मैं यह जांचना चाहूंगा कि क्या कोई स्ट्रिंग "नोड" जैसे "नोड001" से शुरू होती है। कुछ इस तरह

if [ $HOST == user* ]
  then
  echo yes
fi

मैं इसे सही तरीके से कैसे कर सकता हूं?


मुझे यह जांचने के लिए भावों को संयोजित करने की आवश्यकता है कि HOST या तो "user1" है या "नोड" से शुरू होता है

if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi

> > > -bash: [: too many arguments

मैं इसे सही तरीके से कैसे कर सकता हूं?


7
अभिव्यक्तियों को संयोजित करने के लिए बहुत लुभाएं नहीं। यह दो अलग-अलग सशर्त होने के लिए बदसूरत लग सकता है, हालांकि आप बेहतर त्रुटि संदेश दे सकते हैं और अपनी स्क्रिप्ट को डीबग करना आसान बना सकते हैं। इसके अलावा, मैं बैश सुविधाओं से बचूंगा। स्विच जाने का रास्ता है।
१।

जवाबों:


1072

एडवांस बैश स्क्रिप्टिंग गाइड पर यह स्निपेट कहता है:

# The == comparison operator behaves differently within a double-brackets
# test than within single brackets.

[[ $a == z* ]]   # True if $a starts with a "z" (wildcard matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

तो आपके पास यह लगभग सही था; आपको डबल ब्रैकेट की आवश्यकता थी , एकल ब्रैकेट की नहीं।


अपने दूसरे प्रश्न के संबंध में, आप इसे इस प्रकार लिख सकते हैं:

HOST=user1
if  [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes1
fi

HOST=node001
if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes2
fi

जो गूंज उठेगा

yes1
yes2

बैश के ifसिंटैक्स का उपयोग (IMO) के लिए किया जाना कठिन है।


12
रेगेक्स के लिए आपका क्या मतलब है [[$ a = ~ ^ z। *]]?
JStrahl

3
तो क्या इसके बीच एक कार्यात्मक अंतर है [[ $a == z* ]]और [[ $a == "z*" ]]? दूसरे शब्दों में: क्या वे अलग तरीके से काम करते हैं? और जब आप कहते हैं कि विशेष रूप से आपका क्या मतलब है "$ a z के बराबर है"?
नील्स बोम

5
आपको कथन विभाजक की आवश्यकता नहीं है ";" यदि आप अपनी लाइन पर "तब" डालते हैं
यजा

6
बस पूर्णता के लिए: यह जांचने के लिए कि क्या एक स्ट्रिंग [[ $a == *com ]]
ENDS के

4
ABS संदर्भों का एक दुर्भाग्यपूर्ण विकल्प है - यह बहुत W3Schools है जो बैश है, पुरानी सामग्री और बुरे अभ्यास के उदाहरणों से भरा है; freenode #bash चैनल कम से कम 2008 से इसके उपयोग को हतोत्साहित करने की कोशिश कर रहा है । BashFAQ # 31 पर पुन: इंगित करने का कोई मौका ? (मैंने भी बैश-हैकर्स की विकी का सुझाव दिया होगा, लेकिन यह अब थोड़ा नीचे हो गया है)।
चार्ल्स डफी

207

यदि आप बैश (v3 +) के हालिया संस्करण का उपयोग कर रहे हैं, तो मैं सुझाव देता हूं कि बैश रेगेक्स तुलना ऑपरेटर =~, उदाहरण के लिए,

if [[ "$HOST" =~ ^user.* ]]; then
    echo "yes"
fi

मैच के लिए this or thatएक regex, उपयोग में |, उदाहरण के लिए,

if [[ "$HOST" =~ ^user.*|^host1 ]]; then
    echo "yes"
fi

नोट - यह 'उचित' नियमित अभिव्यक्ति वाक्यविन्यास है।

  • user*का मतलब है useऔर शून्य-या-अधिक घटनाओं r, इसलिए useऔर userrrrमेल खाएगा।
  • user.*मतलब userऔर किसी भी चरित्र की शून्य-या-अधिक घटनाएं, इसलिए user1, userXमेल खाएगी।
  • ^user.*साधन user.*$ HOST की शुरुआत में पैटर्न से मेल खाते हैं ।

यदि आप नियमित अभिव्यक्ति सिंटैक्स से परिचित नहीं हैं, तो इस संसाधन का संदर्भ लें ।


धन्यवाद, ब्रेबस्टर! मैंने मूल पोस्ट में एक नया सवाल जोड़ा कि कैसे क्लूज़ में अभिव्यक्तियों को संयोजित किया जाए।
टिम

2
इसका अफ़सोस कि स्वीकृत उत्तर नियमित अभिव्यक्ति के वाक्य विन्यास के बारे में कुछ नहीं कहता है।
कार्लोसोस

20
FYI करें बैश =~ऑपरेटर केवल नियमित अभिव्यक्ति का मिलान करता है जब दाहिने हाथ की तरफ अनचाहा हो। यदि आप दाहिने हाथ की ओर उद्धृत करते हैं "पैटर्न के किसी भी हिस्से को स्ट्रिंग के रूप में मिलान करने के लिए बाध्य करने के लिए उद्धृत किया जा सकता है।" (१.) सुनिश्चित करें कि नियमित अभिव्यक्ति को हमेशा सही संयुक्त राष्ट्र के उद्धरण पर रखें और (२.) यदि आप अपनी नियमित अभिव्यक्ति को एक चर में संग्रहीत करते हैं, तो पैरामीटर विस्तार करते समय दाहिने हाथ की ओर से उद्धरण न करें।
ट्रेवर बॉयड स्मिथ

145

मैं हमेशा shबैश एक्सटेंशन का उपयोग करने के बजाय POSIX के साथ छड़ी करने की कोशिश करता हूं , क्योंकि स्क्रिप्टिंग का एक प्रमुख बिंदु पोर्टेबिलिटी है (इसके अलावा प्रोग्राम कनेक्ट करने, उन्हें बदलने के बजाय)।

में sh, "is-prefix" स्थिति के लिए जाँच करने का एक आसान तरीका है।

case $HOST in node*)
    # Your code here
esac

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

if case $HOST in node*) true;; *) false;; esac; then
    # Your code here
fi

या उससे भी कम

if case $HOST in node*) ;; *) false;; esac; then
    # Your code here
fi

या उससे भी कम (सिर्फ !एक भाषा तत्व के रूप में प्रस्तुत करने के लिए - लेकिन यह अब खराब शैली है)

if ! case $HOST in node*) false;; esac; then
    # Your code here
fi

यदि आप स्पष्ट होना पसंद करते हैं, तो अपना स्वयं का भाषा तत्व बनाएँ:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }

क्या यह वास्तव में काफी अच्छा नहीं है?

if beginswith node "$HOST"; then
    # Your code here
fi

और चूंकि shमूल रूप से केवल नौकरियां और स्ट्रिंग-सूचियां हैं (और आंतरिक रूप से प्रक्रियाएं, जिसमें से नौकरियां बनाई जाती हैं), अब हम कुछ हल्की गतिशील प्रोग्रामिंग भी कर सकते हैं:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
checkresult() { if [ $? = 0 ]; then echo TRUE; else echo FALSE; fi; }

all() {
    test=$1; shift
    for i in "$@"; do
        $test "$i" || return
    done
}

all "beginswith x" x xy xyz ; checkresult  # Prints TRUE
all "beginswith x" x xy abc ; checkresult  # Prints FALSE

यह सुरुचिपूर्ण है। ऐसा नहीं है कि मैं shकिसी भी गंभीर चीज का उपयोग करने की वकालत करता हूं - यह वास्तविक दुनिया की आवश्यकताओं पर बहुत जल्दी टूट जाता है (कोई लंबोदा नहीं है, इसलिए हम स्ट्रिंग्स का उपयोग करते हैं। लेकिन स्ट्रिंग्स के साथ नेस्टिंग फ़ंक्शन कॉल संभव नहीं है, आदि)


12
+1 न केवल यह पोर्टेबल है, यह पठनीय, मुहावरेदार और सुरुचिपूर्ण (शेल स्क्रिप्ट के लिए) भी है। यह भी स्वाभाविक रूप से कई पैटर्न तक फैली हुई है; case $HOST in user01 | node* ) ...
ट्रिपल

क्या इस प्रकार के कोड स्वरूपण के लिए कोई नाम है? if case $HOST in node*) true;; *) false;; esac; then मैंने इसे इधर-उधर देखा है, मेरी नजर से यह लगता है कि थोड़े उखड़े हुए हैं।
नील्स बॉम

@NielsBom मैं वास्तव में क्या आप प्रारूपित करके मतलब पता नहीं है, लेकिन मेरी बात यह है कि खोल कोड बहुत ज्यादा है था composable । बीकाऊज़ caseकमांड्स कमांड हैं, वे अंदर जा सकते हैं if ... then
जो तो

मैं यह भी नहीं देख पा रहा हूं कि यह क्यों है, मैं इसके लिए पर्याप्त शेल स्क्रिप्ट नहीं समझता हूं :-) मेरा सवाल यह है कि यह कोड गैर-मिलान वाले कोष्ठक और दोहरे अर्धविराम का उपयोग कैसे करता है। यह शेल स्क्रिप्ट की तरह कुछ भी नहीं दिखता है जो मैंने पहले देखा है, लेकिन मुझे श स्क्रिप्ट से अधिक बैश स्क्रिप्ट देखने के लिए इस्तेमाल किया जा सकता है ताकि यह हो सके।
नील्स बॉम

नोट: यह beginswith() { case "$2" in "$1"*) true;; *) false;; esac; }अन्यथा होना चाहिए अगर $1इसमें शाब्दिक है *या ?यह गलत उत्तर दे सकता है।
LLFourn

80

आप केवल उस स्ट्रिंग का हिस्सा चुन सकते हैं जिसे आप जांचना चाहते हैं:

if [ "${HOST:0:4}" = user ]

अपने अनुवर्ती प्रश्न के लिए, आप एक इस्तेमाल कर सकते हैं या :

if [[ "$HOST" == user1 || "$HOST" == node* ]]

8
आप doublequote चाहिए${HOST:0:4}
जो तो

@ जो तो: क्या कारण है?
पीटर मोर्टेंसन

@PeterMortensen, कोशिश करेंHOST='a b'; if [ ${HOST:0:4} = user ] ; then echo YES ; fi
जो

60

मैं पहले से ही पोस्ट किए गए अन्य तरीकों को पसंद करता हूं, लेकिन कुछ लोग उपयोग करना पसंद करते हैं:

case "$HOST" in 
    user1|node*) 
            echo "yes";;
        *)
            echo "no";;
esac

संपादित करें:

मैंने ऊपर केस स्टेटमेंट में आपके विकल्प जोड़े हैं

आपके संपादित संस्करण में आपके पास बहुत सारे ब्रैकेट हैं। इसे ऐसा दिखना चाहिए:

if [[ $HOST == user1 || $HOST == node* ]];

धन्यवाद, डेनिस! मैंने मूल पोस्ट में एक नया सवाल जोड़ा कि कैसे क्लूज़ में अभिव्यक्तियों को संयोजित किया जाए।
टिम

11
"कुछ लोगों को पसंद है ...": यह एक संस्करण और गोले भर में अधिक पोर्टेबल है।
कार्लोसैयम

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

और मेरे मामले में, मुझे पहले उद्धरणों को छोड़ना पड़ा): "/ *") काम नहीं किया, / *) ने किया। (मैं / के साथ शुरू होने वाले तार की तलाश कर रहा हूँ, (अर्थात, पूर्ण पथ)
जोसिहायोडर-निष्क्रिय को छोड़कर ..

36

जबकि मुझे यहां अधिकांश उत्तर काफी सही लगते हैं, उनमें से कई में अनावश्यक बशीज़ हैं। POSIX पैरामीटर विस्तार आपको वह सब देता है जो आपको चाहिए:

[ "${host#user}" != "${host}" ]

तथा

[ "${host#node}" != "${host}" ]

${var#expr}स्ट्रिप्स सबसे छोटे उपसर्ग से मेल खाता exprहै ${var}और वापस आता है। इसलिए अगर ${host}करता है नहीं के साथ शुरू user( node), ${host#user}( ${host#node}) के रूप में ही है ${host}

exprfnmatch()इस प्रकार वाइल्डकार्ड की अनुमति देता है , ${host#node??}और दोस्त भी काम करते हैं।


2
मेरा तर्क है कि बशीवाद [[ $host == user* ]]आवश्यक हो सकता है, क्योंकि यह कहीं अधिक पठनीय है [ "${host#user}" != "${host}" ]। जैसे कि आप उस वातावरण को नियंत्रित करते हैं जहां स्क्रिप्ट निष्पादित होती है (नवीनतम संस्करणों को लक्षित करें bash), पूर्व बेहतर है।
x- यूरी

2
@ एक्स-यूरी फ्रैंकली, मैं बस इसे एक has_prefix()समारोह में पैक करूँगा और फिर कभी इसे नहीं देखूंगा।
धक्के

30

चूंकि #बाश में एक अर्थ है, मैं निम्नलिखित समाधान के लिए मिला।

इसके अलावा मुझे रिक्त स्थान को दूर करने के लिए "" के साथ तार पैक करना बेहतर लगता है, आदि।

A="#sdfs"
if [[ "$A" == "#"* ]];then
    echo "Skip comment line"
fi

यह वही था जो मुझे चाहिए था। धन्यवाद!
इओने बिज़ुआ

धन्यवाद, मैं भी सोच रहा था कि कैसे एक स्ट्रिंग शुरू करने के साथ मेल खाता है blah: , ऐसा लगता है कि यह उत्तर है!
एंथ्रोपिक सेप

12

Mark Rushakoff के उच्चतम रैंक उत्तर में एक छोटे से अधिक सिंटैक्स विवरण जोड़ना।

भाव

$HOST == node*

के रूप में भी लिखा जा सकता है

$HOST == "node"*

प्रभाव समान है। बस सुनिश्चित करें कि वाइल्डकार्ड उद्धृत पाठ के बाहर है। अगर वाइल्डकार्ड है उद्धरण के अंदर है तो इसकी शाब्दिक व्याख्या की जाएगी (अर्थात वाइल्डकार्ड के रूप में नहीं)।


8

@OP, आपके दोनों सवालों के लिए आप केस / एसैक का उपयोग कर सकते हैं:

string="node001"
case "$string" in
  node*) echo "found";;
  * ) echo "no node";;
esac

दूसरा सवाल

case "$HOST" in
 node*) echo "ok";;
 user) echo "ok";;
esac

case "$HOST" in
 node*|user) echo "ok";;
esac

या बैश 4.0

case "$HOST" in
 user) ;&
 node*) echo "ok";;
esac

ध्यान दें कि ;&केवल बैश में उपलब्ध है = = 4.
अगली सूचना तक रोका गया।

6
if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi

, क्योंकि सभी का काम नहीं करता है [, [[और testएक ही nonrecursive व्याकरण को पहचानते हैं। अपने बैश मैन पेज पर अनुभाग CONDITIONAL EXPRESSIONS देखें ।

एक तरफ के रूप में, SUSv3 कहते हैं

KornShell-व्युत्पन्न सशर्त कमांड (डबल ब्रैकेट [[]] ) को प्रारंभिक प्रस्ताव में शेल कमांड भाषा विवरण से हटा दिया गया था। आपत्तियां उठाई गईं कि असली समस्या परीक्षण कमांड ( [ ) का दुरुपयोग है , और इसे शेल में डालना समस्या को ठीक करने का गलत तरीका है। इसके बजाय, उचित दस्तावेज और एक नया शेल आरक्षित शब्द ( ! ) पर्याप्त हैं।

टेस्ट कि कई की आवश्यकता होती है परीक्षा के संचालन के अलग-अलग आमंत्रण का उपयोग कर खोल स्तर पर किया जा सकता है परीक्षण आदेश और खोल Logicals, बजाय त्रुटि प्रवण का उपयोग कर -ओ का झंडा परीक्षण

आपको इसे इस तरह से लिखना होगा, लेकिन परीक्षण इसका समर्थन नहीं करता है:

if [ $HOST == user1 -o $HOST == node* ];
then
echo yes
fi

परीक्षण = स्ट्रिंग समानता के लिए उपयोग करता है , और इससे भी महत्वपूर्ण बात यह है कि यह पैटर्न मिलान का समर्थन नहीं करता है।

case/ esacपैटर्न मिलान के लिए अच्छा समर्थन है:

case $HOST in
user1|node*) echo yes ;;
esac

इसका अतिरिक्त लाभ है कि यह बैश पर निर्भर नहीं करता है, और वाक्यविन्यास पोर्टेबल है। से एकल यूनिक्स विशिष्टता , शैल कमांड भाषा :

case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac

1
[और testबैश बिलिन के साथ-साथ बाहरी कार्यक्रम भी हैं। कोशिश करो type -a [
अगली सूचना तक रोक दिया गया।

"यौगिक या" के साथ समस्याओं को समझाने के लिए बहुत धन्यवाद, @ अन्याय किसी - किसी चीज़ के लिए ठीक लग रहा था! चीयर्स! पीएस नोट (ओपी से असंबंधित) if [ -z $aa -or -z $bb ]:; ... " बैश: [: -or: बाइनरी ऑपरेटर अपेक्षित " देता है; हालांकि if [ -z "$aa" -o -z "$bb" ] ; ...गुजरता है।
सदाउ

2

grep

प्रदर्शन को भूलकर, यह POSIX है और caseसमाधान की तुलना में अच्छा लग रहा है :

mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
  echo matches
fi

स्पष्टीकरण:


2

मैंने इसे एक कॉल करने योग्य कार्य करने के लिए @ markrushakoff का उत्तर दिया:

function yesNo {
  # Prompts user with $1, returns true if response starts with y or Y or is empty string
  read -e -p "
$1 [Y/n] " YN

  [[ "$YN" == y* || "$YN" == Y* || "$YN" == "" ]]
}

इसे इस तरह उपयोग करें:

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] y
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] Y
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] yes
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n]
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] n
false

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] ddddd
false

यहां एक अधिक जटिल संस्करण है जो एक निर्दिष्ट डिफ़ॉल्ट मान प्रदान करता है:

function toLowerCase {
  echo "$1" | tr '[:upper:]' '[:lower:]'
}

function yesNo {
  # $1: user prompt
  # $2: default value (assumed to be Y if not specified)
  # Prompts user with $1, using default value of $2, returns true if response starts with y or Y or is empty string

  local DEFAULT=yes
  if [ "$2" ]; then local DEFAULT="$( toLowerCase "$2" )"; fi
  if [[ "$DEFAULT" == y* ]]; then
    local PROMPT="[Y/n]"
  else
    local PROMPT="[y/N]"
  fi
  read -e -p "
$1 $PROMPT " YN

  YN="$( toLowerCase "$YN" )"
  { [ "$YN" == "" ] && [[ "$PROMPT" = *Y* ]]; } || [[ "$YN" = y* ]]
}

इसे इस तरह उपयोग करें:

$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi

asfd [y/N]
false

$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi

asfd [y/N] y
true

$ if yesNo "asfd" y; then echo "true"; else echo "false"; fi

asfd [Y/n] n
false

-5

एक और चीज जो आप कर सकते हैं वह यह catहै कि आप क्या गूंज रहे हैं और पाइप के साथinline cut -c 1-1

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