शैल: यह जाँचना कि क्या एक स्ट्रिंग में एक निर्दिष्ट वर्ण है [डुप्लिकेट]

Dec 22 2020
#!/bin/sh

TMP=$(cd Folder && ls) for name in $TMP; do

  if [[ "${name}" != *"a"* -a ${name} == *"b"* ]] ;then
   echo $name
  fi

done

मैं उन नामों को आउटपुट करने की कोशिश कर रहा था जिनमें इसके बजाय 'a' नहीं बल्कि 'b' है। यह वह त्रुटि है जो मुझे मिली:

./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found

मुझसे यहां क्या गलत हो रहा है ?

जवाब

5 Kusalananda Dec 22 2020 at 02:19

आपका मुख्य मुद्दा यह है कि आप [[ ... ]]एक स्क्रिप्ट में निष्पादित पैटर्न का उपयोग कर रहे हैं /bin/shजिसके द्वारा इस प्रकार के परीक्षणों का समर्थन नहीं किया जाता है। शेल फ़ाइल से चलाते समय शेल स्क्रिप्ट नामक प्रश्न को भी नहीं मिली त्रुटि फेंकता है। लेकिन अगर मैन्युअल रूप से दर्ज किए गए कमांड काम करते हैं

दूसरा मुद्दा यह है कि आप lsरिक्त स्थान, टैब और newlines पर शब्दों में विभाजित करने और उत्पन्न शब्दों पर फ़ाइल नाम ग्लोबिंग लागू करने से पहले एक एकल स्ट्रिंग के आउटपुट को जोड़ रहे हैं । आप फिर इसके परिणाम पर लूप करें।

बजाय:

#!/bin/sh

cd Folder || exit 1

for name in *b*; do
    [ -e "$name" ] || [ -L "$name" ] || continue
    case $name in (*a*) ;; (*) printf '%s\n' "$name"; esac
done

यह Folderनिर्देशिका में सभी फ़ाइलों पर लूप करता है bजिसमें उनके पास पत्र है, और फिर इनमें से प्रिंट करता है जिसमें कोई नहीं है aaचरित्र के लिए परीक्षण का उपयोग करके किया जाता है case ... esac*a*पैटर्न एक से मेल खाता है aफ़ाइल नाम में चरित्र अगर वहाँ एक है, ऐसी स्थिति में कुछ भी नहीं होता। printfबयान "डिफ़ॉल्ट मामले" जो अगर कोई है निष्पादित हो जाता है aस्ट्रिंग में।

के साथ परीक्षण -eऔर -Lयह सुनिश्चित करने के लिए हैं कि हम किनारे के मामले को पकड़ते हैं जहां लूप पैटर्न कुछ भी मेल नहीं खाता है। उस स्थिति में, पैटर्न अनकैपेंडेड रहेगा, इसलिए यह सुनिश्चित करने के लिए कि हम एक अनएक्सपेन्डेड पैटर्न और एक वास्तविक मौजूदा फ़ाइल के बीच अंतर कर सकते हैं, हम साथ परीक्षण करते हैं -e-Lपरीक्षण एक प्रतीकात्मक कड़ी पाश पैटर्न के रूप में एक ही नाम है कि के आगे बढ़त मामले को पकड़ने के लिए है, लेकिन यह कहीं भी मान्य को इंगित नहीं करता है। bashनीचे दिए गए कोड इस की जरूरत नहीं है, क्योंकि यह का उपयोग करता nullglobखोल विकल्प के बजाय (अनुपलब्ध में /bin/sh)।

*b*पैटर्न के विस्तार पर लूप को चलाने के बजाय जो भी lsआउटपुट का लाभ होता है वह यह है कि इसमें स्पेस, टैब, न्यूलाइन्स और फ़ाइल नाम ग्लोबिंग कैरेक्टर वाले फ़ाइलनामों से निपटने में सक्षम है (फाइलनेम कभी भी एक स्ट्रिंग में नहीं डाले जाते हैं जो फिर कोशिश करें इस पर)।

में bashखोल, तो आप एक साथ एक ही कर सकता है [[ ... ]], पैटर्न मिलान परीक्षण की तरह आप अपने आप को करने की कोशिश की:

#!/bin/bash

cd Folder || exit 1

shopt -s nullglob

for name in *b*; do
    [[ $name != *a* ]] && printf '%s\n' "$name"
done

यह सभी देखें:

  • व्हॉट्सएप या अन्य विशेष पात्रों पर मेरी शेल स्क्रिप्ट क्यों चोक करती है?
  • डबल-कोटिंग कब आवश्यक है?
  • क्यों * नहीं * पार्स `एलएस` (और इसके बजाय क्या करना है)?
  • इको से बेहतर क्यों है प्रिंट?
6 StéphaneChazelas Dec 22 2020 at 02:35

फ़ाइल नाम में प्रिंट करने के लिए Folder, जिनमें शामिल है bऔर नहीं aहै, zshऔर उसके ~( सिवाय / और नहीं ) ग्लोब ऑपरेटर:

#! /bin/zsh -
set -o extendedglob
print -rC1 -- Folder/(*b*~*a*)(N:t)

(हटाने N(के लिए nullglob, यदि आप इसके बजाय चाहते हैं तो एक त्रुटि सूचित किया जहां कोई मिलान फ़ाइल)।

में ksh93(शेल कि कि शुरू की [[...]]ऑपरेटर (जो मानक का हिस्सा नहीं है shअपने वाक्यविन्यास) और &( और ) और !(...)( नहीं ) ऑपरेटरों:

#! /bin/ksh93 -
(
  CDPATH= cd Folder &&
    set -- ~(N)@(*b*&!(*a*)) &&
    (($# > 0)) && printf '%s\n' "$@"
)

साथ bashखोल (जो चाहते zshभी ksh की नकल की है [[...]]ऑपरेटर), का उपयोग कर extglobksh88 ग्लोब ऑपरेटरों का समर्थन करने के लिए और nullglobzsh के असर पाने के लिए Nग्लोब क्वालीफायर या ksh93s ' ~(N)ग्लोब ऑपरेटर और साथ कुछ डबल निषेध |( या ) प्राप्त करने के लिए और :

#! /bin/bash -
(
  shopt -s extglob nullglob
  cd ./Folder &&
    set -- !(!(*b*)|*a*) &&
    (($# > 0)) && printf '%s\n' "$@"
)

मानक shवाक्यविन्यास में:

#! /bin/sh -
(
  CDPATH= cd Folder || exit
  set -- [*]b[*] *b*
  [ "$1/$2" = '[*]b[*]/*b*' ] && exit # detect the case where the pattern
                                      # expands to itself because there's
                                      # no match as there's no nullglob
                                      # equivalent in sh
  shift
  for i do
    case $i in (*a*) ;; (*) set -- "$@" "$i" esac shift done [ "$#" -gt 0 ] && printf '%s\n' "$@"
)

ध्यान दें कि उपयोग किए जाने वाले समाधान cdकाम नहीं करेंगे यदि आपने पहुंच को पढ़ा है, Folderलेकिन इसके लिए खोज एक्सेस नहीं किया है।

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

contains()
  case "$1" in
    (*"$2"*) true;;
    (*) false;;
  esac

के रूप में उपयोग करने के लिए:

if contains foobar o; then
  echo foobar contains o
fi
if ! contains foobar z; then
  echo foobar does not contain o
fi
if
  contains "$file" b &&
    ! contains "$file" a then printf '%s\n' "$file contains b and not a "
fi