प्रतिस्थापन और पाइप प्रक्रिया


86

मैं सोच रहा था कि निम्नलिखित को कैसे समझा जाए:

एक कमांड के स्टडआउट को दूसरे की स्टड में पाइप करना एक शक्तिशाली तकनीक है। लेकिन, क्या होगा यदि आपको कई कमांड के स्टडआउट को पाइप करने की आवश्यकता है? यह वह जगह है जहाँ प्रक्रिया प्रतिस्थापन आता है।

दूसरे शब्दों में, क्या प्रतिस्थापन प्रतिस्थापन कर सकता है जो कुछ भी पाइप कर सकता है?

प्रतिस्थापन प्रक्रिया क्या कर सकती है, लेकिन पाइप नहीं कर सकता है?

जवाबों:


133

उनके बीच के अंतर को भुनाने का एक अच्छा तरीका है कमांड लाइन पर थोड़ा प्रयोग करना। <चरित्र के उपयोग में दृश्य समानता के बावजूद , यह पुनर्निर्देशित या पाइप की तुलना में बहुत अलग कुछ करता है।

dateपरीक्षण के लिए कमांड का उपयोग करते हैं ।

$ date | cat
Thu Jul 21 12:39:18 EEST 2011

यह एक व्यर्थ उदाहरण है, लेकिन यह दिखाता है कि एसटीडीआईएन catके उत्पादन को स्वीकार किया dateऔर इसे वापस थूक दिया। प्रक्रिया प्रतिस्थापन द्वारा समान परिणाम प्राप्त किए जा सकते हैं:

$ cat <(date)
Thu Jul 21 12:40:53 EEST 2011

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

$ echo <(date)
/proc/self/fd/11

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

$ cat <(date) <(date) <(date)
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011

$ echo <(date) <(date) <(date)
/proc/self/fd/11 /proc/self/fd/12 /proc/self/fd/13

प्रक्रिया प्रतिस्थापन (जो एक फ़ाइल उत्पन्न करता है) और इनपुट पुनर्निर्देशन (जो फ़ाइल को STDIN से जोड़ता है) को संयोजित करना संभव है:

$ cat < <(date)
Thu Jul 21 12:46:22 EEST 2011

यह बहुत ही समान दिखता है, लेकिन इस बार बिल्ली को फ़ाइल नाम के बजाय STDIN स्ट्रीम पारित किया गया था। आप इसे प्रतिध्वनि के साथ आजमाकर देख सकते हैं:

$ echo < <(date)
<blank>

चूंकि गूंज STDIN नहीं पढ़ता है और कोई तर्क पारित नहीं किया गया था, हमें कुछ भी नहीं मिला।

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


अगर मुझे समझ में आया, तो tldp.org/LDP/abs/html/process-sub.html#FTN.AEN18244 का कहना है कि प्रक्रिया प्रतिस्थापन अस्थायी फ़ाइलें बनाता है, न कि पाइप। जहाँ तक मुझे पता है कि नाम अस्थायी फ़ाइलें नहीं बनाते हैं। पाइप में लिखने के लिए डिस्क पर लिखना कभी भी शामिल नहीं है: stackoverflow.com/a/6977599/788700
Adobe

मुझे पता है कि यह उत्तर कानूनी है क्योंकि यह शब्द grok का उपयोग करता है : D
aqn

2
@ Adobe आप इस बात की पुष्टि कर सकते हैं कि अस्थायी फ़ाइल प्रक्रिया प्रतिस्थापन उत्पादन एक नामित पाइप है [[ -p <(date) ]] && echo true:। यह trueतब पैदा होता है जब मैं इसे बैश 4.4 या 3.2 के साथ चलाता हूं।
डी नोवो

24

मुझे लगता है कि आपको bashकिसी अन्य उन्नत शेल के बारे में बात करनी चाहिए , क्योंकि पॉज़िक्स शेल में प्रक्रिया प्रतिस्थापन नहीं है ।

bash मैनुअल पेज रिपोर्ट:

प्रक्रिया प्रतिस्थापन
प्रक्रिया प्रतिस्थापन का समर्थन उन प्रणालियों पर किया जाता है जो पाइप (FIFOs) या नाम / खुली फ़ाइलों का नामकरण करने की विधि का समर्थन करती हैं। यह <(सूची) या> (सूची) का रूप लेता है। प्रक्रिया सूची इसके इनपुट या आउटपुट के साथ एक FIFO या कुछ फ़ाइल / dev / fd से जुड़ी है। इस फ़ाइल का नाम विस्तार के परिणामस्वरूप वर्तमान कमांड के तर्क के रूप में पारित किया गया है। यदि> (सूची) फ़ॉर्म का उपयोग किया जाता है, तो फ़ाइल पर लिखना सूची के लिए इनपुट प्रदान करेगा। यदि <(सूची) फ़ॉर्म का उपयोग किया जाता है, तो सूची के आउटपुट को प्राप्त करने के लिए एक तर्क के रूप में पारित फ़ाइल को पढ़ा जाना चाहिए।

जब उपलब्ध है, तो पैरामीटर और चर विस्तार, कमांड प्रतिस्थापन और अंकगणितीय विस्तार के साथ प्रक्रिया प्रतिस्थापन एक साथ किया जाता है।

दूसरे शब्दों में, और व्यावहारिक दृष्टिकोण से, आप निम्नलिखित की तरह एक अभिव्यक्ति का उपयोग कर सकते हैं

<(commands)

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

while read line; do something; done < <(commands)

अपने सवाल से मुकरते हुए, यह मुझे लगता है कि प्रक्रिया प्रतिस्थापन और पाइप में बहुत आम नहीं है।

यदि आप कई कमांड के आउटपुट को अनुक्रम में पाइप करना चाहते हैं, तो आप निम्न में से किसी एक फॉर्म का उपयोग कर सकते हैं:

(command1; command2) | command3
{ command1; command2; } | command3

लेकिन आप प्रक्रिया प्रतिस्थापन पर पुनर्निर्देशन का भी उपयोग कर सकते हैं

command3 < <(command1; command2)

अंत में, यदि command3कोई फ़ाइल पैरामीटर स्वीकार करता है (स्टड के प्रतिस्थापन में)

command3 <(command1; command2)

तो <() और <<() एक ही प्रभाव बनाता है, है ना?
सोलफिश

@ सलोफिश: अतिश्योक्ति नहीं: फ़िरोज़ का इस्तेमाल कहीं भी किया जा सकता है जहाँ एक फ़ाइल नाम की उम्मीद की जाती है, दूसरा उस फ़ाइलनाम के लिए एक इनपुट पुनर्निर्देशन है
enzotib

23

यहां तीन चीजें हैं जो आप प्रक्रिया प्रतिस्थापन के साथ कर सकते हैं जो अन्यथा असंभव हैं।

एकाधिक प्रक्रिया इनपुट्स

diff <(cd /foo/bar/; ls) <(cd /foo/baz; ls)

बस पाइप के साथ ऐसा करने का कोई तरीका नहीं है।

STDIN का संरक्षण

कहो कि आपके पास निम्नलिखित हैं:

curl -o - http://example.com/script.sh
   #/bin/bash
   read LINE
   echo "You said ${LINE}!"

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

curl -o - http://example.com/script.sh | bash 

लेकिन यह तरीका पूरी तरह से काम करता है।

bash <(curl -o - http://example.com/script.sh)

आउटबाउंड प्रक्रिया प्रतिस्थापन

यह भी ध्यान दें कि प्रक्रिया प्रतिस्थापन दूसरे तरीके से भी काम करता है। तो आप ऐसा कुछ कर सकते हैं:

(ls /proc/*/exe >/dev/null) 2> >(sed -n \
  '/Permission denied/ s/.*\(\/proc.*\):.*/\1/p' > denied.txt )

यह एक जटिल उदाहरण का एक सा है, लेकिन यह स्टडआउट भेजता है /dev/null, जबकि एक स्क्रिप्ट के लिए स्टडर को पाइप करने के लिए फाइलों के नाम निकालने के लिए जिसके लिए "अनुमति अस्वीकृत" त्रुटि प्रदर्शित की गई थी, और फिर THOSE परिणाम को एक फ़ाइल में भेजता है।

ध्यान दें कि पहला कमांड और स्टडआउट पुनर्निर्देशन कोष्ठक ( उपधारा ) में है ताकि केवल THAT कमांड का परिणाम भेजा जाए /dev/nullऔर यह शेष पंक्ति के साथ गड़बड़ न हो।


यह ध्यान देने योग्य है कि diffउदाहरण में आप उस मामले के बारे में परवाह करना चाहते हैं जहां cdविफल हो सकता है diff <(cd /foo/bar/ && ls) <(cd /foo/baz && ls):।
phk

"स्ट्रिपर पाइपिंग करते समय": यह बात नहीं है कि यह पाइपिंग नहीं है , लेकिन एक फेनो फाइल से गुजर रहा है?
गौथियर ५

@ गौथियर नं; कमांड एक पंद्रह नहीं बल्कि फ़ाइल डिस्क्रिप्टर के संदर्भ के साथ प्रतिस्थापित किया जाता है। तो "इको <(इको)" को "/ देव / एफडी / 63" जैसी कुछ उपज चाहिए, जो एक विशेष चरित्र उपकरण है जो एफडी नंबर 63 से पढ़ता या लिखता है।
tylerl

10

यदि कोई कमांड फाइलों की सूची को तर्क के रूप में लेता है और उन फ़ाइलों को इनपुट (या आउटपुट, लेकिन आमतौर पर नहीं) के रूप में संसाधित करता है, तो उन फ़ाइलों में से प्रत्येक एक नामित पाइप या / dev / fd छद्म फाइल हो सकती है, जो प्रक्रिया निर्वाह द्वारा पारदर्शी रूप से प्रदान की जाती है:

$ sort -m <(command1) <(command2) <(command3)

यह क्रमबद्ध करने के लिए तीन कमांड के आउटपुट को "पाइप" करेगा, जैसे कि कमांड लाइन पर इनपुट फाइल की सूची ले सकता है।


1
IIRC <(कमांड) सिंटैक्स एक बैश-केवल सुविधा है।
फिलोमैथ

@ फीलोमथ: यह जेएसएच में भी है।
कालेब

खैर, ZSH सब कुछ है ... (या कम से कम कोशिश करता है)।
फिलोमथ

@ पोलियोमथ: अन्य गोले में प्रक्रिया प्रतिस्थापन कैसे लागू किया जाता है?
कैम

4
@Philomath <(), कई उन्नत शैल विशेषताओं की तरह, मूल रूप से एक ksh विशेषता थी और इसे bash और zsh द्वारा अपनाया गया था। psubविशेष रूप से एक मछली की सुविधा है, पोसिक्स के साथ कुछ नहीं करना है।
गाइल्स

3

यह ध्यान दिया जाना चाहिए कि प्रक्रिया प्रतिस्थापन केवल फॉर्म तक सीमित नहीं है <(command), जो commandफ़ाइल के रूप में आउटपुट का उपयोग करता है । यह उस फॉर्म में हो सकता है >(command)जो किसी फाइल को इनपुट के commandरूप में अच्छी तरह से फीड करता है । @ Enzotib के उत्तर में बैश मैनुअल के उद्धरण में भी इसका उल्लेख किया गया है।

date | catऊपर के उदाहरण के लिए, एक कमांड जो >(command)समान प्रभाव को प्राप्त करने के लिए फॉर्म के प्रोसेस प्रतिस्थापन का उपयोग करता है,

date > >(cat)

ध्यान दें कि >पहले >(cat)आवश्यक है। यह फिर से echo@ कालेब के उत्तर में स्पष्ट रूप से चित्रित किया जा सकता है ।

$ echo >(cat)
/dev/fd/63

तो, अतिरिक्त के बिना >, date >(cat)वही date /dev/fd/63होगा जो स्टेटर को एक संदेश प्रिंट करेगा।

मान लीजिए आपके पास एक प्रोग्राम है जो केवल फ़ाइल नाम को पैरामीटर के रूप में लेता है और प्रक्रिया नहीं करता है stdinया stdout। मैं इसका psub.shवर्णन करने के लिए ओवरसाइम्प्लीफाइड स्क्रिप्ट का उपयोग करूंगा । की सामग्री psub.shहै

#!/bin/bash
[ -e "$1" -a -e "$2" ] && awk '{print $1}' "$1" > "$2"

मूल रूप से, यह परीक्षण करता है कि इसके दोनों तर्क फाइलें हैं (जरूरी नहीं कि नियमित फाइलें) और यदि यह मामला है, तो awk "$1"का "$2"उपयोग करने के लिए प्रत्येक पंक्ति के पहले क्षेत्र को लिखें । फिर, एक कमांड जो अब तक उल्लिखित सभी को जोड़ती है,

./psub.sh <(printf "a a\nc c\nb b") >(sort)

यह छपेगा

a
b
c

और के बराबर है

printf "a a\nc c\nb b" | awk '{print $1}' | sort

लेकिन निम्नलिखित काम नहीं करेगा, और हमें यहां प्रक्रिया प्रतिस्थापन का उपयोग करना होगा,

printf "a a\nc c\nb b" | ./psub.sh | sort

या इसके समकक्ष रूप में

printf "a a\nc c\nb b" | ./psub.sh /dev/stdin /dev/stdout | sort

यदि ./psub.shयह भी पढ़ें stdinकि उपरोक्त वर्णित के अलावा, तो ऐसा कोई समतुल्य रूप मौजूद नहीं है, और उस स्थिति में प्रक्रिया प्रतिस्थापन के बजाय हम कुछ भी उपयोग नहीं कर सकते हैं (बेशक आप एक नामित पाइप या अस्थायी फ़ाइल का उपयोग कर सकते हैं, लेकिन यह एक और है कहानी)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.