एक बैश स्क्रिप्ट के मापदंडों को सत्यापित करना


95

मैं एक बेसिक के साथ आया था ताकि कई फ़ोल्डर्स को हटाने की प्रक्रिया को स्वचालित करने में मदद मिल सके क्योंकि वे अनावश्यक हो जाते हैं।

#!/bin/bash
rm -rf ~/myfolder1/$1/anotherfolder
rm -rf ~/myfolder2/$1/yetanotherfolder
rm -rf ~/myfolder3/$1/thisisafolder

यह इस तरह विकसित है:

./myscript.sh <{id-number}>

समस्या यह है कि यदि आप id-number (जैसा मैंने अभी किया था) में टाइप करना भूल जाते हैं , तो यह संभावित रूप से बहुत सारी चीजों को हटा सकता है जिन्हें आप वास्तव में हटाना नहीं चाहते हैं।

क्या कोई तरीका है जिससे आप कमांड लाइन के मापदंडों के सत्यापन के किसी भी रूप को जोड़ सकते हैं? मेरे मामले में, यह जांचना अच्छा होगा कि क) एक पैरामीटर है, ख) यह संख्यात्मक है, और ग) उस फ़ोल्डर में मौजूद है; स्क्रिप्ट के साथ जारी रखने से पहले।

जवाबों:


158
#!/bin/sh
die () {
    echo >&2 "$@"
    exit 1
}

[ "$#" -eq 1 ] || die "1 argument required, $# provided"
echo $1 | grep -E -q '^[0-9]+$' || die "Numeric argument required, $1 provided"

while read dir 
do
    [ -d "$dir" ] || die "Directory $dir does not exist"
    rm -rf "$dir"
done <<EOF
~/myfolder1/$1/anotherfolder 
~/myfolder2/$1/yetanotherfolder 
~/myfolder3/$1/thisisafolder
EOF

संपादित करें : अगर निर्देशिका पहले से मौजूद है, तो मैंने जांच करने के बारे में याद किया, इसलिए मैंने स्क्रिप्ट को पूरा करने में इसे जोड़ा। इसके अलावा, टिप्पणियों में उठाए गए मुद्दों को संबोधित किया है; नियमित अभिव्यक्ति तय की, से स्विच किया गया== गया eq

जहाँ तक मैं बता सकता हूँ, यह एक पोर्टेबल, POSIX अनुरूप स्क्रिप्ट होनी चाहिए; यह किसी भी बशीज़ का उपयोग नहीं करता है, जो वास्तव में महत्वपूर्ण है क्योंकि /bin/shउबंटू वास्तव में dashइन दिनों है, नहीं bash


पूर्णांक तुलना के लिए '==' के बजाय '-ईक' को सेट + ई और उपयोग करने के लिए याद रखें
बंदूकें

इसे बदल दिया -इक; क्या सेट + ई आपको यहाँ खरीदता है?
ब्रायन कैंपबेल

मैंने अपने उत्तर में दो चीजें पाईं जिन्हें आप भी ठीक करना चाह सकते हैं: पहला SO hilighter $ # के लिए पागल हो गया है (इसे टिप्पणी के रूप में मानते हुए)। मैंने इसे ठीक करने के लिए "$ #" किया। दूसरा, रेगेक्स "foo123bar" से भी मेल खाता है। मैंने इसे ^ [0-9] + $ करके तय किया। आप भी ग्रेप के -x विकल्प का उपयोग करके इसे ठीक कर सकते हैं
litb - Johannes Schaub

1
@ojblass मुझे उन परीक्षणों में से एक याद आ रही थी जिनके बारे में वह पूछ रहा था। इसके अलावा परीक्षण के लिए अपनी निर्देशिकाओं में जोड़कर, जिसने उत्तर के आकार को महत्वपूर्ण रूप से विस्तारित किया क्योंकि वे एक पंक्ति में फिट नहीं हो सकते। क्या आप प्रत्येक निर्देशिका के अस्तित्व के लिए परीक्षण के अधिक कॉम्पैक्ट तरीके का सुझाव दे सकते हैं?
ब्रायन कैंपबेल

1
नीचे दिए गए @Morten नीलसन के उत्तर-टिप्पणी के अनुसार, grep '$ [0-9] + ^' वास्तव में अजीब लग रहा है। क्या यह '^ [0-9] + $' नहीं होना चाहिए?
मार्टिन जुबिक

21

इस shउपाय से Brian Campbell, जबकि कुलीन और अच्छी तरह से निष्पादित, कुछ समस्याएं हैं, इसलिए मैंने सोचा कि मैं अपना bashसमाधान प्रदान करूंगा ।

shएक के साथ समस्याओं :

  • टिल्ड ~/fooheredocs के अंदर आपके होमडायरेक्ट्री तक विस्तृत नहीं होता है। और न ही जब इसे readवक्तव्य द्वारा पढ़ा जाता है या कथन में उद्धृत किया जाता rmहै। जिसका मतलब है कि आपको No such file or directoryत्रुटियाँ मिलेंगी ।
  • grepबुनियादी कार्यों के लिए फोर्किंग बंद करना और इस तरह की चूक है । खासकर तब जब आप बैश के "भारी" वजन से बचने के लिए एक भद्दे खोल का उपयोग कर रहे हों।
  • मैंने कुछ उद्धृत मुद्दों पर भी ध्यान दिया, उदाहरण के लिए उनके पैरामीटर विस्तार के आसपास echo
  • जबकि दुर्लभ, समाधान नए नाम वाले फ़ाइल नाम के साथ सामना नहीं कर सकता। (लगभग कोई समाधान shउनके साथ सामना नहीं कर सकता है - यही कारण है कि मैं लगभग हमेशा पसंद करता हूं bash, यह अच्छी तरह से उपयोग किए जाने पर शोषण करने के लिए कहीं अधिक बुलेटप्रूफ और कठिन है)।

हालांकि, हां, /bin/shअपने हैशबैंग के लिए उपयोग करने का मतलब है कि आपको bashहर कीमत पर आईएमएस से बचना चाहिए , आप bashउबंटू पर या यहां तक ​​कि जब आप ईमानदार हों और #!/bin/bashशीर्ष पर रख सकते हैं, तो आप सभी आईएमएस का उपयोग कर सकते हैं ।

तो, यहाँ एक bashसमाधान है जो छोटा, क्लीनर, अधिक पारदर्शी, शायद "तेज", और अधिक बुलेटप्रूफ है।

[[ -d $1 && $1 != *[^0-9]* ]] || { echo "Invalid input." >&2; exit 1; }
rm -rf ~/foo/"$1"/bar ...
  1. कथन $1में आस-पास के उद्धरण देखें rm!
  2. -dअगर जांच भी असफल हो जायेगी $1खाली है, तो यह है कि एक में दो चेकों है।
  3. मैंने एक कारण के लिए नियमित अभिव्यक्तियों से परहेज किया। यदि आपको =~बैश में उपयोग करना चाहिए , तो आपको नियमित अभिव्यक्ति को एक चर में रखना चाहिए। किसी भी मामले में, खदान जैसे दस्ताने हमेशा बेहतर होते हैं और कहीं अधिक बैश संस्करणों में समर्थित होते हैं।

1
तो क्या ग्लोबिंग पीस $1 != *[^0-9]*बैश विशिष्ट है?
मुस्कराहट

15

मैं बैश का उपयोग करूंगा [[:

if [[ ! ("$#" == 1 && $1 =~ ^[0-9]+$ && -d $1) ]]; then 
    echo 'Please pass a number that corresponds to a directory'
    exit 1
fi

मुझे यह दोष मिला सूचना का एक अच्छा स्रोत है।


13

उपरोक्त उत्तर के रूप में बुलेटप्रूफ नहीं है, हालांकि अभी भी प्रभावी है:

#!/bin/bash
if [ "$1" = "" ]
then
  echo "Usage: $0 <id number to be cleaned up>"
  exit
fi

# rm commands go here

11

उपयोग करें set -uजो स्क्रिप्ट को तुरंत विफल करने के लिए किसी भी परेशान तर्क संदर्भ का कारण होगा।

: कृपया, आलेख देखें - डेविड Pashley.com मजबूत बैश शेल स्क्रिप्ट लेखन


यह कई मामलों में एक महान आसान समाधान है और कार्यों के लिए भी काम करता है। धन्यवाद!
मैनफ्रेड मोजर

9

परीक्षण ( man test) के लिए मैन पेज सभी उपलब्ध ऑपरेटरों को प्रदान करता है जिन्हें आप बश में बूलियन ऑपरेटरों के रूप में उपयोग कर सकते हैं। इनपुट सत्यापन के लिए अपनी स्क्रिप्ट (या फ़ंक्शंस) की शुरुआत में उन झंडों का उपयोग करें जैसे आप किसी अन्य प्रोग्रामिंग भाषा में करेंगे। उदाहरण के लिए:

if [ -z $1 ] ; then
  echo "First parameter needed!" && exit 1;
fi

if [ -z $2 ] ; then
  echo "Second parameter needed!" && exit 2;
fi

8

खाली स्ट्रिंग्स के लिए परीक्षण करने के लिए '-z' का प्रयोग करें और निर्देशिकाओं की जांच के लिए -d।

if [[ -z "$@" ]]; then
    echo >&2 "You must supply an argument!"
    exit 1
elif [[ ! -d "$@" ]]; then
    echo >&2 "$@ is not a valid directory!"
    exit 1
fi

2
आपको डबल [[]] की आवश्यकता क्यों है?
वाहनोमेज़

5

निम्नलिखित की तरह कुछ करके आप बिंदु a और b को सुगठित रूप से मान्य कर सकते हैं:

#!/bin/sh
MYVAL=$(echo ${1} | awk '/^[0-9]+$/')
MYVAL=${MYVAL:?"Usage - testparms <number>"}
echo ${MYVAL}

जो हमें देता है ...

$ ./testparams.sh 
Usage - testparms <number>

$ ./testparams.sh 1234
1234

$ ./testparams.sh abcd
Usage - testparms <number>

इस विधि को ठीक से काम करना चाहिए।


2

एक लाइनर बैश तर्क सत्यापन, निर्देशिका सत्यापन के साथ और बिना

यहाँ कुछ तरीके हैं जो मेरे लिए काम कर चुके हैं। आप उन्हें या तो वैश्विक स्क्रिप्ट नामस्थान में उपयोग कर सकते हैं (यदि वैश्विक नामस्थान में, आप फ़ंक्शन अंतर्निहित चर का संदर्भ नहीं दे सकते हैं)

जल्दी और गंदा एक लाइनर

: ${1?' You forgot to supply a directory name'}

उत्पादन:

./my_script: line 279: 1: You forgot to supply a directory name

Fancier - आपूर्ति समारोह का नाम और उपयोग

${1? ERROR Function: ${FUNCNAME[0]}() Usage: " ${FUNCNAME[0]} directory_name"}

उत्पादन:

./my_script: line 288: 1:  ERROR Function: deleteFolders() Usage:  deleteFolders directory_name

अपने वर्तमान फ़ंक्शन को अव्यवस्थित किए बिना जटिल सत्यापन तर्क जोड़ें

फ़ंक्शन या स्क्रिप्ट के भीतर निम्न पंक्ति जोड़ें जो तर्क प्राप्त करता है।

: ${1?'forgot to supply a directory name'} && validate $1 || die 'Please supply a valid directory'

फिर आप एक सत्यापन कार्य बना सकते हैं जो कुछ ऐसा करता है

validate() {

    #validate input and  & return 1 if failed, 0 if succeed
    if [[ ! -d "$1" ]]; then
        return 1
    fi
}

और एक फंक्शन फ़ंक्शन जो स्क्रिप्ट को विफलता पर रोक देता है

die() { echo "$*" 1>&2 ; exit 1; }

अतिरिक्त तर्कों के लिए, प्रारूप की नकल करते हुए, एक अतिरिक्त पंक्ति जोड़ें।

: ${1?' You forgot to supply the first argument'}
: ${2?' You forgot to supply the second argument'}

1

पुरानी पोस्ट लेकिन मुझे लगा कि मैं वैसे भी योगदान दे सकता हूं।

एक स्क्रिप्ट यकीनन जरूरी नहीं है और वाइल्ड कार्ड के लिए कुछ सहिष्णुता के साथ कमांड लाइन से बाहर किया जा सकता है।

  1. कहीं भी मेल खाना। उप "फ़ोल्डर" की किसी भी घटना को दूर करने देता है

    $ rm -rf ~/*/folder/*
  2. शैल iterated। विशिष्ट प्री और पोस्ट फ़ोल्डर को एक लाइन से हटा दें

    $ rm -rf ~/foo{1,2,3}/folder/{ab,cd,ef}
  3. शैल iterated + var (BASH परीक्षण किया गया)।

    $ var=bar rm -rf ~/foo{1,2,3}/${var}/{ab,cd,ef}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.