डैश में प्रक्रिया प्रतिस्थापन का अनुकरण कैसे करें?


18

में bash, मैं प्रक्रिया प्रतिस्थापन का उपयोग कर सकता हूं और प्रक्रिया के आउटपुट का इलाज कर सकता हूं जैसे कि यह डिस्क पर सहेजी गई फ़ाइल थी:

$ echo <(ls)
/dev/fd/63

$ ls -lAhF <(ls)
lr-x------ 1 root root 64 Sep 17 12:55 /dev/fd/63 -> pipe:[1652825]

दुर्भाग्य से, प्रक्रिया प्रतिस्थापन का समर्थन नहीं किया गया है dash

Process Substitutionडैश में अनुकरण करने का सबसे अच्छा तरीका क्या होगा ?

मैं आउटपुट को एक अस्थायी फ़ाइल के रूप में कहीं सहेजना नहीं चाहता ( /tmp/) और फिर उसे हटाना होगा। क्या कोई वैकल्पिक तरीका है?


आप जो करने की कोशिश कर रहे हैं उसके आधार पर आप पाइप का उपयोग करने में सक्षम हो सकते हैं।
एरिक रेनॉफ

ईमानदारी से, अगर पोर्टेबिलिटी आपकी मुख्य चिंता नहीं है, तो क्या यह आसान नहीं होगा कि आप bashअपने डिवाइस पर इंस्टॉल करें?
अर्कादियुस ड्रब्ज़क

1
उदाहरण जो आप बाउंटी नोटिस में प्रदान करते हैं, वह इस लिंक किए गए उत्तर का विषय होता है । जैसा कि वहां दिखाया गया है, गिल्स के उत्तर का एक सरलीकृत संस्करण ( इसके बजाय /dev/fdऔर उपलब्धता का उपयोग करते हुए माना xz -cd <file>जाता है cat <file> | xz -d) हो सकता है xz -cd "$1" | { xz -cd "$2" | { diff /dev/fd/3 /dev/fd/4; } 3<&0; } 4<&0
fra-san

1
@ fra- सान - कि वास्तव में मैं क्या जरूरत है। आप चाहें तो इसका जवाब दे सकते हैं। धन्यवाद।
मार्टिन वेगाटर 17

जवाबों:


4

वर्तमान इनाम नोटिस में सवाल:

सामान्य उदाहरण बहुत जटिल है। क्या कोई कृपया बता सकता है कि निम्नलिखित उदाहरण को कैसे लागू किया जाए?diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

लगता है कि यहाँ एक उत्तर है

जैसा कि गाइल्स के उत्तर में दिखाया गया है , सामान्य विचार यह है कि "निर्माता" कमांड के आउटपुट को नई डिवाइस फाइल्स 1 में एक पाइपलाइन के विभिन्न चरणों में भेजा जाए , जिससे उन्हें "उपभोक्ता" कमांड उपलब्ध हो, जो संभवतः फ़ाइल नाम को तर्क के रूप में ले सकता है ( यह मानते हुए कि आपका सिस्टम आपको फ़ाइल डिस्क्रिप्टर के रूप में एक्सेस देता है /dev/fd/X)।

आप जो खोज रहे हैं उसे प्राप्त करने का सबसे सरल तरीका संभवतः है:

xz -cd file1.xz | { xz -cd file2.xz | diff /dev/fd/3 -; } 3<&0

( पठनीयता के file1.xzस्थान पर उपयोग करना "$1"और xz -cdइसके बजाय cat ... | xz -dक्योंकि एकल आदेश पर्याप्त है)।

पहले "निर्माता" कमांड का आउटपुट, xz -cd file1.xzएक कंपाउंड कमांड ( {...}) में लगाया जाता है ; लेकिन, अगले कमांड के मानक इनपुट के रूप में तुरंत खपत होने के बजाय, इसे डिस्क्रिप्टर फाइल करने के लिए डुप्लिकेट किया जाता है 3और इस तरह से कंपाउंड कमांड के अंदर सब कुछ सुलभ हो जाता है /dev/fd/3। दूसरे "निर्माता" कमांड का आउटपुट xz -cd file2.xz, जो न तो अपने मानक इनपुट और न ही फ़ाइल डिस्क्रिप्टर से कुछ भी उपभोग करता है 3, फिर "उपभोक्ता" कमांड को पाइप किया जाता है diff, जो इसके मानक इनपुट से और से पढ़ता है /dev/fd/3

पाइपिंग और फाइल डिस्क्रिप्टर डुप्लीकेशन को आवश्यकतानुसार कई "निर्माता" कमांड के लिए डिवाइस फाइल प्रदान करने के लिए जोड़ा जा सकता है, जैसे:

xz -cd file1.xz | { xz -cd file2.xz | { diff /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0

हालांकि यह आपके विशिष्ट प्रश्न के संदर्भ में अप्रासंगिक हो सकता है, यह ध्यान देने योग्य है:

  1. cmd1 <(cmd2) <(cmd3), cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0और ( cmd2 | ( cmd3 | ( cmd1 /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )प्रारंभिक निष्पादन पर्यावरण पर विभिन्न संभावित प्रभाव हैं।

  2. क्या में क्या होता है के विपरीत cmd1 <(cmd2) <(cmd3), cmd3और cmd1में cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0उपयोगकर्ता से किसी भी इनपुट को पढ़ने में सक्षम नहीं होगा। इसके लिए आगे के फाइल डिस्क्रिप्टर की आवश्यकता होगी। मसलन, मैच के लिए

    diff <(echo foo) <(read var; echo "$var")
    

    आपको कुछ इस तरह की आवश्यकता होगी

    { echo foo | { read var 0<&9; echo "$var" | diff /dev/fd/3 -; } 3<&0; } 9<&0
    

1 उन पर अधिक यू एंड एल पर पाया जा सकता है, उदाहरण के लिए अंडरस्टैंडिंग / देव और इसके उपखंड और फाइलों में


12

आप मैन्युअल रूप से प्लंबिंग करके हूड के नीचे जो खोल सकते हैं, उसे पुन: पेश कर सकते हैं। यदि आपके सिस्टम में प्रविष्टियाँ हैं, तो आप फ़ाइल डिस्क्रिप्टर फेरबदल का उपयोग कर सकते हैं: आप अनुवाद कर सकते हैं/dev/fd/NNN

main_command <(produce_arg1) <(produce_arg2) >(consume_arg3) >(consume_arg4)

सेवा

{ produce_arg1 |
  { produce_arg2 |
    { main_command /dev/fd5 /dev/fd6 /dev/fd3 /dev/fd4 </dev/fd/8 >/dev/fd/9; } 5<&0 3>&1 |
    consume_arg3; } 6<&0 4>&1; |
  consume_arg4; } 8<&0 9>&1

मैंने कई इनपुट और आउटपुट को चित्रित करने के लिए अधिक जटिल उदाहरण दिखाया है। यदि आपको मानक इनपुट से पढ़ने की आवश्यकता नहीं है, और प्रक्रिया प्रतिस्थापन का उपयोग करने का एकमात्र कारण यह है कि कमांड को एक स्पष्ट फ़ाइल नाम की आवश्यकता है, तो आप बस उपयोग कर सकते हैं /dev/stdin:

main_command <(produce_arg1)
produce_arg1 | main_command /dev/stdin

बिना , आपको एक नामित पाइप का उपयोग करने की आवश्यकता है । एक नामित पाइप एक निर्देशिका प्रविष्टि है, इसलिए आपको कहीं एक अस्थायी फ़ाइल बनाने की आवश्यकता है, लेकिन वह फ़ाइल सिर्फ एक नाम है, इसमें कोई डेटा नहीं है।/dev/fd/NNN

tmp=$(mktemp -d)
mkfifo "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
produce_arg1 >"$tmp/f1" &
produce_arg2 >"$tmp/f2" &
consume_arg3 <"$tmp/f3" &
consume_arg4 <"$tmp/f4" &
main_command "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
rm -r "$tmp"

2
</dev/fd/8 >/dev/fd/9<&8 >&9लिनक्स पर समतुल्य नहीं हैं और वहाँ से बचा जाना चाहिए।
स्टीफन चेजलस

@ गिल्स - मैं जटिल उदाहरण से भ्रमित हूं। क्या आप बता सकते हैं कि कैसे अनुकरण करना है diff <(cat "$2" | xz -d) <(cat "$1" | xz -d):?
मार्टिन वेगाटर 5

3

क्या कोई कृपया बता सकता है कि निम्नलिखित उदाहरण को कैसे लागू किया जाए?
diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

मुझे लगता है कि नामित पाइप पुनर्निर्देशन की तुलना में अधिक सरल हैं, इसलिए सरलतम शब्दों में:

mkfifo p1 p2               # create pipes
cat "$2" | xz -d > p1 &    # start the commands in the background
cat "$1" | xz -d > p2 &    #    with output to the pipes
diff p1 p2                 # run 'diff', reading from the pipes
rm p1 p2                   # remove them at the end

p1और p2अस्थायी नाम वाले पाइप हैं, उनका नाम कुछ भी हो सकता है।

यह पाइपों को बनाने के लिए स्मार्ट होगा /tmp, जैसे कि एक निर्देशिका में गिल्स का उत्तर दिखाता है, और ध्यान दें कि आपको catयहां ज़रूरत नहीं है, इसलिए:

tmpdir=$(mktemp -d)
mkfifo "$tmpdir/p1" "$tmpdir/p2"
xz -d < "$2" > "$tmpdir/p1" &
xz -d < "$1" > "$tmpdir/p2" &
diff "$tmpdir/p1" "$tmpdir/p2"
rm -r "$tmpdir"

(आप शायद उद्धरण के बिना दूर हो सकते हैं, भी, क्योंकि mktemp"अच्छा" फ़ाइल नाम बनाने की संभावना है।)

पाइप समाधान में यह चेतावनी होती है कि यदि मुख्य diffइनपुट ( ) सभी इनपुट को पढ़ने से पहले मर जाता है, तो पृष्ठभूमि प्रक्रियाओं को लटका दिया जा सकता है।


0

व्हाट अबाउट:

cat "$2" | xz -d | diff /dev/sdtin /dev/stderr 2<<EOT
`cat "$1" | xz -d`
EOT
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.