नींद की आज्ञा के बिना, बैश में व्यस्त प्रतीक्षा से बचें


19

मुझे पता है कि मैं एक शर्त पर इंतज़ार कर सकता हूँ कि वह क्या कर सकता है:

while true; do
  test_condition && break
  sleep 1
done

लेकिन यह प्रत्येक पुनरावृत्ति (नींद) में 1 उप-प्रक्रिया बनाता है। मैं उन्हें करने से बच सकता था:

while true; do
  test_condition && break
done

लेकिन यह CPU (व्यस्त प्रतीक्षा) का बहुत उपयोग करता है। उप-प्रक्रियाओं और व्यस्त प्रतीक्षा से बचने के लिए, मैं समाधान बेली के साथ आया, लेकिन मुझे यह बदसूरत लगता है:

my_tmp_dir=$(mktemp -d --tmpdir=/tmp)    # Create a unique tmp dir for the fifo.
mkfifo $my_tmp_dir/fifo                  # Create an empty fifo for sleep by read.
exec 3<> $my_tmp_dir/fifo                # Open the fifo for reading and writing.

while true; do
  test_condition && break
  read -t 1 -u 3 var                     # Same as sleep 1, but without sub-process.
done

exec 3<&-                                # Closing the fifo.
rm $my_tmp_dir/fifo; rmdir $my_tmp_dir   # Cleanup, could be done in a trap.

ध्यान दें: सामान्य मामले में, मैं केवल read -t 1 varफीफो के बिना उपयोग नहीं कर सकता , क्योंकि यह स्टडिन का उपभोग करेगा, और अगर स्टड टर्मिनल या पाइप नहीं है तो काम नहीं करेगा।

क्या मैं उप-प्रक्रियाओं से बच सकता हूं और अधिक सुरुचिपूर्ण तरीके से प्रतीक्षा करने में व्यस्त हूं?


1
trueएक बिलिन है और बाश में उप प्रक्रिया नहीं बनाता है। व्यस्त प्रतीक्षा हमेशा खराब होगी।
जोर्डनम

@joranm: आप सही हैं true, सवाल अपडेट किया गया है।
jfg956

बिना फीफो के क्यों नहीं? बस read -t 1 var
ott--

@ott: आप सही कह रहे हैं, लेकिन यह स्टड का उपभोग करेगा। इसके अलावा, यह काम नहीं करेगा यदि स्टडिन एक टर्मिनल या पाइप नहीं है।
jfg956

यदि स्थिरता एक मुद्दा है, तो मैं दृढ़ता sleepसे पहले उदाहरण में साथ जाने का सुझाव दूंगा। दूसरा काम, जबकि यह काम कर सकता है, भविष्य में किसी के लिए भी आसान नहीं होगा। सरल कोड भी सुरक्षित होने की बड़ी संभावनाएं हैं।
Kusalananda

जवाबों:


17

bash(कम से कम v2) के नए संस्करणों में enable -f filename commandname, रनटाइम पर बिलिन लोड (के माध्यम से ) हो सकते हैं । ऐसे कई लोड किए गए बिलिन को बाश स्रोतों के साथ भी वितरित किया जाता है, और sleepउनमें से एक है। उपलब्धता निश्चित रूप से ओएस से ओएस (और यहां तक ​​कि मशीन से मशीन तक) में भिन्न हो सकती है। उदाहरण के लिए, ओपनएसयूएसई पर, इन बिलिन को पैकेज के माध्यम से वितरित किया जाता है bash-loadables

संपादित करें: पैकेज का नाम ठीक करें, न्यूनतम बैश संस्करण जोड़ें।


वाह, यह वही है जिसकी मुझे तलाश है, और मैं लोड करने योग्य बिलिन के बारे में निश्चित रूप से कुछ सीखता हूं: +1। मैं यह कोशिश करूंगा, और फिर भी यह सबसे अच्छा जवाब है।
jfg956

1
यह काम करता हैं ! डेबियन पर, पैकेज बैश-बिलिन है। इसमें केवल स्रोत शामिल हैं और मेकफाइल को संपादित किया जाना चाहिए, लेकिन मैं sleepबिलिन के रूप में स्थापित करने में सक्षम था । धन्यवाद।
jfg956

9

बहुत सारे सबप्रोसेस बनाना एक आंतरिक लूप में एक बुरी चीज है। sleepप्रति सेकंड एक प्रक्रिया बनाना ठीक है। वहाँ कुछ भी गलत नहीं है

while ! test_condition; do
  sleep 1
done

यदि आप वास्तव में बाहरी प्रक्रिया से बचना चाहते हैं, तो आपको पंद्रो को खुला रखने की आवश्यकता नहीं है।

my_tmpdir=$(mktemp -d)
trap 'rm -rf "$my_tmpdir"' 0
mkfifo "$my_tmpdir/f"

while ! test_condition; do
  read -t 1 <>"$my_tmpdir/f"
done

आप प्रति सेकंड मूंगफली की प्रक्रिया के बारे में सही हैं (लेकिन मेरा सवाल इसे हटाने का तरीका खोजने के बारे में था)। छोटे संस्करण के बारे में, यह मेरी तुलना में अच्छा है, इसलिए +1 (लेकिन मैंने mkdirइसे हटा दिया है mktemp(यदि नहीं, तो यह एक दौड़ की स्थिति है))। इसके बारे में भी सच है while ! test_condition;जो मेरे प्रारंभिक समाधान की तुलना में अच्छा है।
jfg956

7

मुझे हाल ही में ऐसा करने की आवश्यकता थी। मैं निम्नलिखित फ़ंक्शन के साथ आया था जो किसी भी बाहरी कार्यक्रम को बुलाए बिना हमेशा के लिए सोने की अनुमति देगा:

snore()
{
    local IFS
    [[ -n "${_snore_fd:-}" ]] || { exec {_snore_fd}<> <(:); } 2>/dev/null ||
    {
        # workaround for MacOS and similar systems
        local fifo
        fifo=$(mktemp -u)
        mkfifo -m 700 "$fifo"
        exec {_snore_fd}<>"$fifo"
        rm "$fifo"
    }
    read ${1:+-t "$1"} -u $_snore_fd || :
}

नोट: मैंने पहले इसका एक संस्करण पोस्ट किया था जो हर बार फ़ाइल डिस्क्रिप्टर को खोलना और बंद कर देगा, लेकिन मैंने पाया कि कुछ सिस्टमों पर ऐसा करने से सैकड़ों बार एक सेकंड में लॉक हो जाता है। इस प्रकार नया समाधान कॉल के बीच फाइल डिस्क्रिप्टर को फंक्शन में रखता है। बैश वैसे भी बाहर निकलने पर साफ कर देगा।

इसे बस / बिन / नींद की तरह कहा जा सकता है, और यह अनुरोधित समय के लिए सोएगा। मापदंडों के बिना कहा जाता है, यह हमेशा के लिए लटका रहेगा।

snore 0.1  # sleeps for 0.1 seconds
snore 10   # sleeps for 10 seconds
snore      # sleeps forever

यहाँ मेरे ब्लॉग पर अत्यधिक विवरण के साथ एक राइटअप है


1
उत्कृष्ट ब्लॉग प्रविष्टि। हालाँकि, मैं वहाँ एक स्पष्टीकरण की तलाश में गया था कि पूरे 10 सेकंड का इंतजार read -t 10 < <(:)करते हुए तुरंत क्यों लौटता है read -t 10 <> <(:), लेकिन मुझे अभी भी यह नहीं मिला है।
अमीर

में read -t 10 <> <(:)क्या करता है <>के लिए खड़े हो?
कोडमेडिक जूल

<> पढ़ने और लिखने के लिए फ़ाइल डिस्क्रिप्टर खोलता है, भले ही अंतर्निहित प्रक्रिया प्रतिस्थापन <(:) केवल पढ़ने की अनुमति देता है। यह एक हैक है जो विशेष रूप से लिनक्स, और लिनक्स का कारण बनता है, यह मानने के लिए कि कोई व्यक्ति इसे लिख सकता है, इसलिए पढ़े जाने वाले इनपुट के इंतजार में लटका रहेगा। यह बीएसडी सिस्टम पर नहीं करेगा, इस स्थिति में वर्कअराउंड किक होगा।
बोल्ट

3

में ksh93या mksh, sleepएक खोल में निर्मित है, तो एक विकल्प के बजाय उन के गोले का उपयोग करने से हो सकता है bash

zshइसमें एक zselectबिल्डिन (लोडेड zmodload zsh/zselect) भी है जो कुछ सैकेंड के सैकंडों तक सो सकता है zselect -t <n>


2

जैसा कि उपयोगकर्ता योय ने कहा है, यदि आपकी स्क्रिप्ट में स्टड खोला गया है, तो नींद 1 के बजाय आप बस उपयोग कर सकते हैं:

read -t 1 3<&- 3<&0 <&3

बैश संस्करण 4.1 और नए में आप फ्लोट नंबर का उपयोग कर सकते हैं, जैसे read -t 0.3 ...

यदि किसी स्क्रिप्ट में स्टड बंद हो जाता है (स्क्रिप्ट कहा जाता है my_script.sh < /dev/null &), तो आपको एक और ओपन किए गए डिस्क्रिप्टर का उपयोग करने की आवश्यकता है, जो कि रीड निष्पादित होने पर आउटपुट का उत्पादन नहीं करता है, जैसे। स्टडआउट :

read -t 1 <&1 3<&- 3<&0 <&3

यदि एक स्क्रिप्ट में सभी डिस्क्रिप्टर बंद हो जाता है ( स्टडिन , स्टडआउट , स्टादर ) (जैसे कि डेमन के रूप में कहा जाता है), तो आपको किसी भी मौजूद फ़ाइल को खोजने की आवश्यकता है जो आउटपुट नहीं पैदा करती है:

read -t 1 </dev/tty10 3<&- 3<&0 <&3

read -t 1 3<&- 3<&0 <&3के रूप में ही है read -t 0। यह सिर्फ टाइमआउट के साथ स्टड से पढ़ रहा है।
स्टीफन चेजलस

1

यह एक लॉगिन शेल के साथ-साथ एक गैर-इंटरैक्टिव शेल से काम करता है।

#!/bin/sh

# to avoid starting /bin/sleep each time we call sleep, 
# make our own using the read built in function
xsleep()
{
  read -t $1 -u 1
}

# usage
xsleep 3

इसने मैक OS X v10.12.6
b01

1
यह अनुशंसित नहीं है। यदि कई स्क्रिप्ट एक ही समय में इसका उपयोग करते हैं तो वे सभी SIGSTOP'ed प्राप्त करते हैं क्योंकि वे सभी स्टडिन पढ़ने की कोशिश करते हैं। इस प्रतीक्षा के दौरान आपका स्टड अवरुद्ध हो जाता है। इसके लिए स्टड का उपयोग न करें। आप नए अलग फ़ाइल डिस्क्रिप्टर चाहते हैं।
Normadize

1
@Normadize यहां एक और जवाब है ( unix.stackexchange.com/a/407383/147685 ) जो मुफ्त फ़ाइल डिस्क्रिप्टर का उपयोग करने की चिंता से संबंधित है। इसका नंगे न्यूनतम संस्करण है read -t 10 <> <(:)
आमिर

0

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

{
echo line | while read line; do
   read -t 1 <&3
   echo "$line"
done
} 3<&- 3<&0

द्वारा प्रेरित: थोड़ी देर के लूप के अंदर बैश में इनपुट पढ़ें


1
यह नींद नहीं कर रहा है, यह अभी भी टर्मिनल से स्टड का उपभोग कर रहा है।
jfg956

0

उपर्युक्त समाधानों पर एक मामूली सुधार (जो मैंने इस पर आधारित है)।

bash_sleep() {
    read -rt "${1?Specify sleep interval in seconds}" -u 1 <<<"" || :;
}

# sleep for 10 seconds
bash_sleep 10

एक पंद्रह की जरूरत को कम कर दिया और इसलिए कोई सफाई नहीं है।


1
यह अनुशंसित नहीं है। यदि कई स्क्रिप्ट एक ही समय में इसका उपयोग करते हैं तो वे सभी SIGSTOP'ed प्राप्त करते हैं क्योंकि वे सभी स्टडिन पढ़ने की कोशिश करते हैं। इस प्रतीक्षा के दौरान आपका स्टड अवरुद्ध हो जाता है। इसके लिए स्टड का उपयोग न करें। आप नए अलग फ़ाइल डिस्क्रिप्टर चाहते हैं।
Normadize

@ नोर्मडाइज़ कभी भी ऐसा नहीं सोचा था; कृपया आप मुझे उस संसाधन के बारे में विस्तार से बता सकते हैं, जहाँ मैं इसके बारे में और अधिक पढ़ सकता हूँ।
कोडमेडिक

@CodeMedic यहाँ एक और जवाब है ( unix.stackexchange.com/a/407383/147685 ) जो मुफ्त फ़ाइल डिस्क्रिप्टर का उपयोग करने की चिंता से संबंधित है। इसका नंगे न्यूनतम संस्करण है read -t 10 <> <(:)
आमिर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.