प्रक्रिया प्रतिस्थापन प्राप्त करने के लिए पोर्टेबल (POSIX) तरीका क्या है?


25

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

$ diff <(sort file1) <(sort file2)

हालाँकि, यह निर्माण POSIX नहीं है और इसलिए, पोर्टेबल नहीं है। POSIX- मैत्रीपूर्ण तरीके (यानी जो काम करता है ) में प्रतिस्थापन की प्रक्रिया कैसे प्राप्त की जा सकती है ?/bin/sh

नोट: प्रश्न यह नहीं पूछ रहा है कि दो सॉर्ट की गई फ़ाइलों को कैसे अलग किया जाए - यह प्रक्रिया प्रतिस्थापन का प्रदर्शन करने के लिए केवल एक विवादित उदाहरण है !


mywiki.wooledge.org/ProcessSubstitution के पास एक नोट है कि mywiki.wooledge.org/NamedPipes का इस्तेमाल किया जा सकता है ..
Sundeep


1
POSIX को /bin/shPOSIX शेल होने की आवश्यकता नहीं है , केवल यह कि shकहीं एक कमांड है जिसे सही वातावरण में POSIX कंप्लांट कहा जाता है। उदाहरण के लिए, Solaris 10 पर, /bin/shPOSIX शेल नहीं है, यह एक प्राचीन बॉर्न शेल है और POSIX शेल अंदर है /usr/xpg4/bin/sh
स्टीफन चेज़लस

जवाबों:


17

यह सुविधा kshपहले (ksh86 में प्रलेखित) द्वारा पेश की गई थी और इस /dev/fd/nसुविधा का उपयोग कर रही थी (पहले कुछ बीएसडी और एटी एंड टी सिस्टम में स्वतंत्र रूप से जोड़ा गया था)। में kshऔर ksh93u तक, यह तब तक काम नहीं करेगा जब तक कि आपके सिस्टम के पास / dev / fd / n के लिए समर्थन न हो। zsh, bash और ksh93u+इसके बाद के संस्करण अस्थायी नाम वाले पाइपों का उपयोग कर सकते हैं (SysIII में जोड़े गए पाइपों का नाम) मेरा मानना ​​है कि जहां / dev / fd / n उपलब्ध नहीं हैं।

जहां उपलब्ध सिस्टम पर (POSIX उन लोगों को निर्दिष्ट नहीं करता है), आप स्वयं के साथ प्रक्रिया प्रतिस्थापन ( ) कर सकते हैं :/dev/fd/ndiff <(cmd1) <(cmd2)

{
  cmd1 4<&- | {
    # in here fd 3 points to the reading end of the pipe
    # from cmd1, while fd 0 has been restored from the original
    # stdin (saved on fd 4, now closed as no longer needed)

    cmd2 3<&- | diff /dev/fd/3 -

  } 3<&0 <&4 4<&- # restore the original stdin for cmd2

} 4<&0 # save a copy of stdin for cmd2

हालाँकि जो ksh93लिनक्स पर काम नहीं करता है , वहीं शेल पाइप को सॉकेट के साथ पाइप के बजाय लागू किया जाता है और ओपनिंग /dev/fd/3जहां एक सॉकेट में 3 अंक लिनक्स पर काम नहीं करता है।

हालांकि POSIX निर्दिष्ट नहीं करता है । यह नामित पाइपों को निर्दिष्ट करता है। नामित पाइप सामान्य पाइप की तरह काम करते हैं सिवाय इसके कि आप उन्हें फ़ाइल सिस्टम से एक्सेस कर सकते हैं। यहाँ मुद्दा यह है कि आपको अस्थायी बनाना होगा और बाद में सफाई करनी होगी जो विशेष रूप से मज़बूती से करने के लिए कठिन है विशेष रूप से यह देखते हुए कि अस्थायी फ़ाइलों या निर्देशिकाओं को बनाने के लिए POSIX का कोई मानक तंत्र नहीं है (जैसे कुछ सिस्टम पर पाया जाता है), और सिग्नल हैंडलिंग को आंशिक रूप से करना। (हैंग-अप या किल को साफ करने के लिए) आंशिक रूप से करना भी कठिन है।/dev/fd/nmktemp -d

आप कुछ ऐसा कर सकते हैं:

tmpfifo() (
  n=0
  until
    fifo=$1.$$.$n
    mkfifo -m 600 -- "$fifo" 2> /dev/null
  do
    n=$((n + 1))
    # give up after 20 attempts as it could be a permanent condition
    # that prevents us from creating fifos. You'd need to raise that
    # limit if you intend to create (and use at the same time)
    # more than 20 fifos in your script
    [ "$n" -lt 20 ] || exit 1
  done
  printf '%s\n' "$fifo"
)

cleanup() { rm -f -- "$fifo"; }
fifo=$(tmpfifo /tmp/fifo) || exit

cmd2 > "$fifo" & cmd1 | diff - "$fifo"
rm -f -- "$fifo"

(यहां सिग्नल हैंडलिंग का ध्यान नहीं रखना)।


नामित पाइप उदाहरण मेरे लिए पूरी तरह से स्पष्ट है (मुझे लगता है कि 10 एक मनमानी सीमा है?) लेकिन मैं आपके /dev/fd/nउदाहरण का पता नहीं लगा सकता । डिस्क्रिप्टर 4 को दो बार बंद क्यों किया गया है? (और इसलिए विवरणक 3 है।) मैं हार गया हूं।
वाइल्डकार्ड

@Wildcard, यह उन कमांड के लिए बंद है जिन्हें इसकी आवश्यकता नहीं है। यहाँ, केवल भिन्न की जरूरत है कि fd। 3. किसी को भी fd 4 की आवश्यकता नहीं है, इसका उपयोग केवल मूल स्टैड को cmd2( dup2(0,4)बाहरी पर {...}, dup2(4,0)अंदर के साथ बहाल करने के लिए {...}) प्रचार करने के लिए किया जाता है ।
स्टीफन चेजलस

आप यह mktemp -dसुनिश्चित करने के लिए उपयोग कर सकते हैं कि आप FIFO प्राप्त कर सकते हैं, क्योंकि कोई भी आपके ब्रांड-नई रैंडम अस्थायी निर्देशिका में नहीं लिखा होना चाहिए।
डैनियल एच।

@ डैनियल, मैं पहले ही उल्लेख कर चुका हूं mktemp -d। लेकिन यह एक मानक / POSIX कमांड नहीं है।
स्टीफन चेज़लस

हुह, मुझे यह एहसास नहीं था। उफ़। जल्दी से खोज से पता चलता है कि अधिकांश सिस्टम इसका समर्थन करते हैं, इसलिए यह अभी भी पोर्टेबल हो सकता है, लेकिन यह पॉसिक्स नहीं है।
डैनियल एच

-1

यदि cmd | while read A B Cइसके बजाय उपयोगी चर में खो जाने से बचने की आवश्यकता है , तो:

VAR="before"
while read A B C 
do
  VAR="$A $VAR"
done < <(cmd)
echo "$VAR"

आप उपयोग कर सकते हैं:

VAR="before"
while read A B C 
do
  VAR="$A $VAR"
done << EndOfText
`cmd`
EndOfText
echo "$VAR"

तो सवाल का जवाब देने के लिए:

sort file1 | diff /dev/stdin /dev/stdout 2<<EOT
`sort file2`
EOT
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.