मैं परस्पर आदेशों के बीच डेटा के एक परिपत्र प्रवाह को कैसे लागू कर सकता हूं?


19

मुझे दो प्रकारों की जानकारी है कि कैसे एक दूसरे के साथ कमांड को जोड़ा जा सकता है:

  1. एक पाइप का उपयोग करके (अगले कमांड के एसटीडी-इनपुट में एसटीडी-आउटपुट डालकर)।
  2. टी का उपयोग करके (आउटपुट को कई आउटपुट में विभाजित करें)।

मुझे नहीं पता कि क्या यह सब संभव है, इसलिए मैं एक काल्पनिक कनेक्शन प्रकार आकर्षित करता हूं:

यहाँ छवि विवरण दर्ज करें

इस छद्म कोड में उदाहरण के लिए आदेशों के बीच डेटा के एक परिपत्र प्रवाह को लागू करना कैसे संभव हो सकता है, जहां मैं इसके बजाय चर का उपयोग करता हूं:

pseudo-code:

a = 1    # start condition 

repeat 
{
b = tripple(a)
c = sin(b) 
a = c + 1 
}

जवाबों:


16

परिपत्र I / O लूप के साथ लागू किया गया tail -f

यह एक परिपत्र I / O लूप लागू करता है:

$ echo 1 >file
$ tail -f file | while read n; do echo $((n+1)); sleep 1; done | tee -a file
2
3
4
5
6
7
[..snip...]

यह आपके द्वारा उल्लिखित साइन एल्गोरिथ्म का उपयोग करते हुए परिपत्र इनपुट / आउटपुट लूप को लागू करता है:

$ echo 1 >file
$ tail -f file | while read n; do echo "1+s(3*$n)" | bc -l; sleep 1; done | tee -a file
1.14112000805986722210
.72194624281527439351
1.82812473159858353270
.28347272185896349481
1.75155632167982146959
[..snip...]

यहाँ, bcफ्लोटिंग पॉइंट गणित करता है और s(...)साइन फ़ंक्शन के लिए bc का अंकन है।

इसके बजाय एक परिवर्तनीय का उपयोग करते हुए समान एल्गोरिदम का कार्यान्वयन

इस विशेष गणित उदाहरण के लिए, परिपत्र I / O दृष्टिकोण की आवश्यकता नहीं है। एक बस एक चर अद्यतन कर सकता है:

$ n=1; while true; do n=$(echo "1+s(3*$n)" | bc -l); echo $n; sleep 1; done
1.14112000805986722210
.72194624281527439351
1.82812473159858353270
.28347272185896349481
[..snip...]

12

आप इसके लिए बनाए गए फीफो का उपयोग कर सकते हैं mkfifo। हालांकि ध्यान दें कि गलती से गतिरोध पैदा करना बहुत आसान है। मुझे समझाते हैं कि - अपने काल्पनिक "परिपत्र" उदाहरण को लें। आप इसके इनपुट में कमांड का आउटपुट फीड करते हैं। इस गतिरोध के कम से कम दो तरीके हैं:

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

  2. लिखने के लिए कमांड में आउटपुट का एक गुच्छा होता है। इसे लिखना शुरू कर देता है, लेकिन कर्नेल पाइप बफर भर जाता है। तो यह वहाँ बैठता है, बफर में उनके स्थान की प्रतीक्षा कर रहा है। जैसे ही यह इसके इनपुट को पढ़ेगा, यानी कभी भी ऐसा नहीं होगा, जब तक कि यह ऐसा नहीं हो जाता है जब तक कि यह अपने आउटपुट के लिए जो कुछ भी नहीं लिखता है।

उस ने कहा, यहाँ आप इसे कैसे करते हैं। यह उदाहरण odहेक्स डंप की कभी न खत्म होने वाली श्रृंखला बनाने के लिए है :

mkfifo fifo
( echo "we need enough to make it actually write a line out"; cat fifo ) \ 
    | stdbuf -i0 -o0 -- od -t x1 | tee fifo

ध्यान दें कि अंततः बंद हो जाता है। क्यों? यह गतिरोध, # 2 ऊपर। आप stdbufबफ़रिंग को अक्षम करने के लिए वहां कॉल को भी नोटिस कर सकते हैं । इसके बिना? बिना किसी आउटपुट के डेडलॉक।


धन्यवाद, मुझे इस संदर्भ में बफ़र्स के बारे में कुछ नहीं पता था, क्या आप इसके बारे में अधिक पढ़ने के लिए कुछ कीवर्ड जानते हैं?
अब्दुल अल हज़्रेड

1
@AbdulAlHazred इनपुट / आउटपुट के बफ़रिंग के लिए, stdio बफ़रिंग देखें । एक पाइप में कर्नेल के बफर के लिए, पाइप बफर काम करने लगता है।
derobert

4

सामान्य तौर पर मैं एक मेकफिल (कमांड मेक) का उपयोग करता हूं और अपने आरेख को मेफाइल नियमों में मैप करने का प्रयास करता हूं।

f1 f2 : f0
      command < f0 > f1 2>f2

दोहराव / चक्रीय आदेशों के लिए, हमें एक पुनरावृत्ति नीति को परिभाषित करने की आवश्यकता है। साथ में:

SHELL=/bin/bash

a.out : accumulator
    cat accumulator <(date) > a.out
    cp a.out accumulator

accumulator:
    touch accumulator     #initial value

प्रत्येक makeसमय में एक पुनरावृत्ति का उत्पादन करेगा।


प्यारा दुरुपयोग make, लेकिन अनावश्यक: यदि आप एक मध्यवर्ती फ़ाइल का उपयोग करते हैं, तो इसे प्रबंधित करने के लिए सिर्फ लूप का उपयोग क्यों न करें?
एलेक्सिस

@alexis, मेकफाइल्स शायद ओवरकिल है। मैं छोरों के बारे में बहुत सहज नहीं हूं: मुझे घड़ी की धारणा, हालत को रोकने, या एक स्पष्ट उदाहरण याद आता है। प्रारंभिक आरेखों ने मुझे वर्कफ़्लोज़, और फ़ंक्शन हस्ताक्षर याद किए। जटिल आरेखों के लिए हमें डेटा सम्मेलनों या टाइपफाइल टाइप किए गए नियमों की आवश्यकता होगी। (यह सिर्फ एक अपमानजनक अंतर्ज्ञान है)
जेजो मारा

@alexis, और निश्चित रूप से, मैं आपसे सहमत हूं।
जोजो

मुझे नहीं लगता कि यह दुरुपयोग है - मैक्रोज़ केmake बारे में है जो यहां एक आदर्श अनुप्रयोग है।
मोकेसर

1
@ माइकर्स, हाँ। और हम सभी जानते हैं कि दुर्व्यवहार करने वाले उपकरण यूनिक्स का भूमिगत मैग्ना कार्टा है :)
जेजो मारा

4

आप जानते हैं, मुझे यकीन नहीं है कि आपके डायग्राम के चित्रण के रूप में आपको दोहराए जाने वाले फीडबैक लूप की आवश्यकता है, क्योंकि हो सकता है कि आप कॉपोरोसेस के बीच एक सतत पाइपलाइन का उपयोग कर सकें । फिर से, यह हो सकता है कि इसमें बहुत अधिक अंतर न हो - एक बार एक कोप्रोसेस पर एक लाइन खोलने के बाद आप सामान्य शैली के लूप को लागू कर सकते हैं और साधारण से बहुत कुछ किए बिना जानकारी को लिखना और उससे जानकारी पढ़ना।

पहली जगह में, यह प्रतीत होता है कि bcआप के लिए एक कॉपीराइट के लिए एक प्रमुख उम्मीदवार है। में bcआप कर सकते हैं defineकार्यों कि आपके स्यूडोकोड में के लिए काफी है कि तुम क्या पूछना कर सकते हैं। उदाहरण के लिए, ऐसा करने के लिए कुछ बहुत ही सरल कार्य इस तरह दिख सकते हैं:

printf '%s()\n' b c a |
3<&0 <&- bc -l <<\IN <&3
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
IN

... जो छपेगा ...

b=3
c=.14112000805986722210
a=1.14112000805986722210

लेकिन निश्चित रूप से, यह पिछले नहीं है । जैसे ही printfपाइप के क्विट्स (printfa()\n पाइप के बाद राइट्स ) के सबस्क्रिप्शन को पाइप फटा जाता है और bcइनपुट बंद हो जाता है और वह भी क्विट हो जाता है। यह लगभग उतना उपयोगी नहीं है जितना यह हो सकता है।

@derobert ने पहले ही FIFO का उल्लेख किया है क्योंकि उपयोगिता के साथ एक नामित पाइप फ़ाइल बनाकर किया जा सकता है mkfifo। ये अनिवार्य रूप से सिर्फ पाइप के रूप में अच्छी तरह से हैं, सिवाय सिस्टम कर्नेल के दोनों छोरों पर एक फाइलसिस्टम प्रविष्टि को जोड़ता है। ये बहुत उपयोगी हैं, लेकिन यह अच्छा होगा यदि आप बिना किसी पाइप को जोखिम में डाले इसे फाइलसिस्टम में स्नूप कर सकते हैं।

जैसा कि होता है, आपका खोल यह बहुत कुछ करता है। यदि आप एक शेल का उपयोग करते हैं जो प्रतिस्थापन की प्रक्रिया को कार्यान्वित करता है तो आपके पास एक स्थायी पाइप प्राप्त करने का एक बहुत ही सरल साधन है - इस तरह का कि आप एक पृष्ठभूमि प्रक्रिया को असाइन कर सकते हैं जिसके साथ आप संवाद कर सकते हैं।

में bash, उदाहरण के लिए, आप कैसे प्रक्रिया प्रतिस्थापन काम करता है देख सकते हैं:

bash -cx ': <(:)'
+ : /dev/fd/63

आप देखते हैं कि यह वास्तव में एक प्रतिस्थापन है । खोल विस्तार के दौरान एक मूल्य को प्रतिस्थापित करता है जो एक पाइप के लिंक के मार्ग से मेल खाता है । आप इसका लाभ उठा सकते हैं - आपको उस पाइप का उपयोग करने के लिए विवश होने की जरूरत नहीं है, जो कि प्रतिस्थापन के भीतर जो भी प्रक्रिया चलती है, उसके साथ संवाद करने के लिए ...()

bash -c '
    eval "exec 3<>"<(:) "4<>"<(:)
    cat  <&4 >&3  &
    echo hey cat >&4
    read hiback  <&3
    echo "$hiback" here'

... जो प्रिंट करता है ...

hey cat here

अब मुझे पता है कि अलग-अलग गोले अलग-अलग तरीकों से मैथुन करते हैं - और यह कि एक bashको स्थापित करने के लिए एक विशिष्ट वाक्यविन्यास है (और शायद एक के लिए zshभी) - लेकिन मुझे नहीं पता कि वे चीजें कैसे काम करती हैं। मुझे सिर्फ इतना पता है कि आप उपरोक्त वाक्यविन्यास का उपयोग वस्तुतः दोनों में बिना किसी कठोरता के कर सकते हैं bashऔर zsh- और आप यहाँ पर एक ही तरह का काम कर सकते हैं dashऔर busybox ashयहाँ एक ही उद्देश्य प्राप्त कर सकते हैं -दस्तावेज (क्योंकि dashऔर busyboxयहाँ- अन्य दो के रूप में अस्थायी फ़ाइलों के बजाय पाइप के साथ दस्तावेज़)

तो, जब लागू bc...

eval "exec 3<>"<(:) "4<>"<(:)
bc -l <<\INIT <&4 >&3 &
a=1; b=0; c=0;
define a(){ "a="; return (a = c+1); }
define b(){ "b="; return (b = 3*a); }
define c(){ "c="; return (c = s(b)); }
INIT
export BCOUT=3 BCIN=4 BCPID="$!"

... यह कठिन हिस्सा है। और यह मजेदार हिस्सा है ...

set --
until [ "$#" -eq 10 ]
do    printf '%s()\n' b c a >&"$BCIN"
      set "$@" "$(head -n 3 <&"$BCOUT")"
done; printf %s\\n "$@"

... जो प्रिंट करता है ...

b=3
c=.14112000805986722210
a=1.14112000805986722210
#...24 more lines...
b=3.92307618030433853649
c=-.70433330413228041035
a=.29566669586771958965

... और यह अभी भी चल रहा है ...

echo a >&"$BCIN"
read a <&"$BCOUT"
echo "$a"

... जो सिर्फ मेरे लिए अंतिम मान हो जाता bcहै aबल्कि बुला से a()यह और प्रिंट बढ़ाने के लिए समारोह ...

.29566669586771958965

यह तब तक चलता रहेगा, जब तक कि मैं इसे मार न दूं और इसके आईपीसी पाइप को फाड़ दूं ...

kill "$BCPID"; exec 3>&- 4>&-
unset BCPID BCIN BCOUT

1
बहुत ही रोचक। हाल के बैश और zsh के साथ ध्यान दें कि आपको फ़ाइल डिस्क्रिप्टर को निर्दिष्ट करने की आवश्यकता नहीं है, जैसे कि eval "exec {BCOUT}<>"<(:) "{BCIN}<>"<(:)काम करता है
Thor
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.