बैश में डू-डू लूप का अनुकरण


137

बैश में डू-टाइम लूप का अनुकरण करने का सबसे अच्छा तरीका क्या है?

मैं whileलूप में प्रवेश करने से पहले स्थिति की जांच कर सकता हूं , और फिर लूप में स्थिति की फिर से जांच जारी रख सकता हूं , लेकिन यह डुप्लिकेट कोड है। क्या कोई क्लीनर रास्ता है?

मेरी स्क्रिप्ट का छद्म कोड:

while [ current_time <= $cutoff ]; do
    check_if_file_present
    #do other stuff
done

check_if_file_presentयदि $cutoffसमय के बाद लॉन्च किया जाता है, तो यह प्रदर्शन नहीं करता है और ऐसा करते समय।


क्या आप untilस्विच ढूंढ रहे हैं ?
माइकल गार्डनर

2
@MichaelGardner untilलूप के शरीर को निष्पादित करने से पहले स्थिति का मूल्यांकन भी करेगा
एलेक्स

2
आह, मैं देख रहा हूं, मैंने आपकी कुप्रथा को गलत समझा।
माइकल गार्डनर

जवाबों:


216

दो सरल उपाय:

  1. लूप से पहले एक बार अपना कोड निष्पादित करें

    actions() {
       check_if_file_present
       # Do other stuff
    }
    
    actions #1st execution
    while [ current_time <= $cutoff ]; do
       actions # Loop execution
    done
  2. या:

    while : ; do
        actions
        [[ current_time <= $cutoff ]] || break
    done

9
:बिल्ट इन है, बिल्ट इन बिल्ट इन true। वे दोनों "कुछ भी सफलतापूर्वक नहीं करते हैं"।
loxaxs

2
@xaxs जो कि zsh में सही है, लेकिन Bash में नहीं। बिल्ट-इन है, trueजबकि एक वास्तविक कार्यक्रम :है। पूर्व बस 0(और falseसाथ 1) से बाहर निकलता है बाद वाला बिल्कुल कुछ भी नहीं करता है। आप के साथ जाँच कर सकते हैं which true
फ्लेशग्रिंडर

@ बाशगिंदर बाश :की जगह अब भी प्रयोग करने योग्य है true। इसके साथ प्रयास करें while :; do echo 1; done
एलेक्सी मैजुरा

2
कभी भी कुछ अलग नहीं कहा, केवल वह trueजो बाश में बिल्ट-इन नहीं है। यह आमतौर पर पाया जाने वाला एक कार्यक्रम है /bin
22

type trueबैश में (सभी तरह से बैश 3.2) वापसी करता है true is a shell builtin। यह सच है कि /bin/trueयह एक कार्यक्रम है; जो सत्य नहीं है, वह सत्य trueनहीं है। (tl; dr; true is a bash buildin and a program)
PJ Eby

152

whileपरीक्षण के पहले और बाद में अपने लूप के शरीर को रखें । whileलूप का वास्तविक शरीर एक सेशन नहीं होना चाहिए।

while 
    check_if_file_present
    #do other stuff
    (( current_time <= cutoff ))
do
    :
done

बृहदान्त्र के बजाय, आप उपयोग कर सकते हैं continueयदि आपको लगता है कि अधिक पठनीय है। आप एक कमांड भी डाल सकते हैं जो केवल पुनरावृत्तियों (पहले से पहले या आखिरी के बाद नहीं) के बीच चलेगी , जैसे कि echo "Retrying in five seconds"; sleep 5। या मानों के बीच सीमांकक प्रिंट करें:

i=1; while printf '%d' "$((i++))"; (( i <= 4)); do printf ','; done; printf '\n'

जब आप पूर्णांक की तुलना करते हैं, तो मैंने डबल कोष्ठक का उपयोग करने के लिए परीक्षण को बदल दिया। डबल स्क्वायर ब्रैकेट के अंदर, तुलना ऑपरेटर जैसे कि <=शाब्दिक हैं और उदाहरण के लिए 2 और 10 की तुलना करते समय गलत परिणाम देगा। उन ऑपरेटरों एकल वर्ग कोष्ठक के अंदर काम नहीं करते।


क्या यह सिंगल-लाइन के बराबर है while { check_if_file_present; ((current_time<=cutoff)); }; do :; done? Ie , whileजैसे कि अर्धविराम द्वारा अलग-अलग स्थिति में प्रभावी रूप से अलग किए गए आदेश हैं जैसे कि &&, और द्वारा समूहीकृत {}?
रुस्लान

@Ruslan: घुंघराले ब्रेसिज़ अनावश्यक हैं। आपको डबल कोष्ठक के अंदर परीक्षण के लिए कुछ भी लिंक का उपयोग नहीं करना चाहिए &&या इसके ||बाद से उन्हें प्रभावी रूप से परीक्षण का हिस्सा बनाता है जो नियंत्रण करता है while। जब तक आप कमांड लाइन पर इस निर्माण का उपयोग नहीं कर रहे हैं, मैं इसे एक-लाइनर (स्क्रिप्ट में, विशेष रूप से) के रूप में नहीं करूंगा क्योंकि इरादा अपठनीय है।
अगली सूचना तक रोक दिया गया।

हाँ, मैं इसे एक-लाइनर के रूप में उपयोग करने का इरादा नहीं कर रहा था: केवल यह स्पष्ट करने के लिए कि परीक्षण में आदेश कैसे जुड़े हैं। मैं चिंता कर रहा था कि गैर-शून्य लौटने वाला पहला आदेश पूरी स्थिति को गलत कर सकता है।
रुस्लान

3
@ruslan: नहीं, यह अंतिम वापसी मूल्य है। while false; false; false; true; do echo here; break; doneआउटपुट "यहां"
अगली सूचना तक रोक दिया गया।

@thatotherguy: क्षमता के बीच बहुत अच्छा है! आप एक स्ट्रिंग में सीमांकक सम्मिलित करने के लिए भी इसका उपयोग कर सकते हैं। धन्यवाद!
अगली सूचना तक रोक दिया गया।

2

हम while [[condition]]; do true; doneइस तरह से बैश में एक करते हुए लूप का अनुकरण कर सकते हैं :

while [[ current_time <= $cutoff ]]
    check_if_file_present
    #do other stuff
do true; done

एक उदाहरण के लिए। यहाँ bash स्क्रिप्ट में ssh कनेक्शन प्राप्त करने पर मेरा कार्यान्वयन है :

#!/bin/bash
while [[ $STATUS != 0 ]]
    ssh-add -l &>/dev/null; STATUS="$?"
    if [[ $STATUS == 127 ]]; then echo "ssh not instaled" && exit 0;
    elif [[ $STATUS == 2 ]]; then echo "running ssh-agent.." && eval `ssh-agent` > /dev/null;
    elif [[ $STATUS == 1 ]]; then echo "get session identity.." && expect $HOME/agent &> /dev/null;
    else ssh-add -l && git submodule update --init --recursive --remote --merge && return 0; fi
do true; done

यह आउटपुट को नीचे के रूप में अनुक्रम में देगा:

Step #0 - "gcloud": intalling expect..
Step #0 - "gcloud": running ssh-agent..
Step #0 - "gcloud": get session identity..
Step #0 - "gcloud": 4096 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /builder/home/.ssh/id_rsa (RSA)
Step #0 - "gcloud": Submodule '.google/cloud/compute/home/chetabahana/.docker/compose' (git@github.com:chetabahana/compose) registered for path '.google/cloud/compute/home/chetabahana/.docker/compose'
Step #0 - "gcloud": Cloning into '/workspace/.io/.google/cloud/compute/home/chetabahana/.docker/compose'...
Step #0 - "gcloud": Warning: Permanently added the RSA host key for IP address 'XXX.XX.XXX.XXX' to the list of known hosts.
Step #0 - "gcloud": Submodule path '.google/cloud/compute/home/chetabahana/.docker/compose': checked out '24a28a7a306a671bbc430aa27b83c09cc5f1c62d'
Finished Step #0 - "gcloud"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.