शैल: यह जाँचना कि क्या एक स्ट्रिंग में एक निर्दिष्ट वर्ण है [डुप्लिकेट]
#!/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
मुझसे यहां क्या गलत हो रहा है ?
जवाब
आपका मुख्य मुद्दा यह है कि आप [[ ... ]]
एक स्क्रिप्ट में निष्पादित पैटर्न का उपयोग कर रहे हैं /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
जिसमें उनके पास पत्र है, और फिर इनमें से प्रिंट करता है जिसमें कोई नहीं है a
। a
चरित्र के लिए परीक्षण का उपयोग करके किया जाता है 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
यह सभी देखें:
- व्हॉट्सएप या अन्य विशेष पात्रों पर मेरी शेल स्क्रिप्ट क्यों चोक करती है?
- डबल-कोटिंग कब आवश्यक है?
- क्यों * नहीं * पार्स `एलएस` (और इसके बजाय क्या करना है)?
- इको से बेहतर क्यों है प्रिंट?
फ़ाइल नाम में प्रिंट करने के लिए 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 की नकल की है [[...]]
ऑपरेटर), का उपयोग कर extglob
ksh88 ग्लोब ऑपरेटरों का समर्थन करने के लिए और nullglob
zsh के असर पाने के लिए N
ग्लोब क्वालीफायर या ksh93
s ' ~(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