<<, <<< और <<bash में क्या अंतर है?


102

बीच क्या अंतर है <<, <<<और < <पार्टी में?


20
कम से कम इन Google-केंद्रित समयों में, इन प्रतीक-आधारित ऑपरेटरों की खोज करना मुश्किल है। क्या कोई खोज इंजन है जहां आप "<< <<< <<" में प्लग कर सकते हैं और कुछ भी उपयोगी हो सकता है?
डेनियल ग्रिस्कॉम

11
@DanielGriscom वहाँ प्रतीक है
डेनिस

1
@DanielGriscom स्टैक एक्सचेंज प्रतीकों का समर्थन करने के लिए इस्तेमाल किया गया था, लेकिन तब कुछ टूट गया और किसी ने कभी इसे तय नहीं किया।
मुरु

जवाबों:


115

यहाँ दस्तावेज़

<<here-documentसंरचना के रूप में जाना जाता है। आप प्रोग्राम को यह बताते हैं कि समाप्त पाठ क्या होगा, और जब भी उस सीमांकक को देखा जाएगा, तो प्रोग्राम आपके द्वारा दिए गए सभी सामान को इनपुट के रूप में पढ़ेगा और उस पर कार्य करेगा।

यहाँ मेरा मतलब है:

$ wc << EOF
> one two three
> four five
> EOF
 2  5 24

इस उदाहरण में हम wcप्रोग्राम को EOFस्ट्रिंग के लिए प्रतीक्षा करने के लिए कहते हैं , फिर पांच शब्दों में टाइप करें, और फिर EOFसंकेत दें कि हम इनपुट दे रहे हैं। वास्तव में, यह wcखुद से चलने , शब्दों में टाइप करने, फिर दबाने के समान हैCtrlD

बैश में ये अस्थायी फ़ाइलों के माध्यम से लागू होते हैं, आमतौर पर फॉर्म में /tmp/sh-thd.<random string>, जबकि डैश में उन्हें गुमनाम पाइप के रूप में लागू किया जाता है। यह straceकमांड के साथ ट्रेसिंग सिस्टम कॉल के माध्यम से देखा जा सकता है । बदलें bashके साथ shकैसे को देखने के लिए /bin/shइस पुनर्निर्देशन प्रदर्शन करती है।

$ strace -e open,dup2,pipe,write -f bash -c 'cat <<EOF
> test
> EOF'

यहाँ स्ट्रिंग

<<<के रूप में जाना जाता है here-string। पाठ में टाइप करने के बजाय, आप एक कार्यक्रम के लिए पाठ के पूर्व-निर्मित स्ट्रिंग देते हैं। उदाहरण के लिए, इस तरह के कार्यक्रम के साथ ही bcहम bc <<< 5*4उस विशिष्ट मामले के लिए उत्पादन प्राप्त करने के लिए कर सकते हैं , कोई आवश्यकता नहीं है कि अंतःक्रियात्मक तरीके से बीसी चलाएं।

यहां बैश में स्ट्रिंग्स को अस्थायी फ़ाइलों के माध्यम से लागू किया जाता है, आमतौर पर प्रारूप में /tmp/sh-thd.<random string>, जिन्हें बाद में अनलिंक किया जाता है, इस प्रकार उन्हें कुछ मेमोरी स्पेस पर अस्थायी रूप से कब्जा कर लिया जाता है, लेकिन /tmpनिर्देशिका प्रविष्टियों की सूची में दिखाई नहीं देते हैं, और प्रभावी रूप से अनाम फ़ाइलों के रूप में मौजूद होते हैं, जो अभी भी हो सकते हैं शेल द्वारा फ़ाइल डिस्क्रिप्टर के माध्यम से संदर्भित किया जा सकता है, और उस फाइल डिस्क्रिप्टर को कमांड द्वारा विरासत में प्राप्त किया जा रहा है और बाद में dup2()फ़ंक्शन के माध्यम से फाइल डिस्क्रिप्टर 0 (स्टडिन) पर डुप्लिकेट किया गया है। इसके माध्यम से देखा जा सकता है

$ ls -l /proc/self/fd/ <<< "TEST"
total 0
lr-x------ 1 user1 user1 64 Aug 20 13:43 0 -> /tmp/sh-thd.761Lj9 (deleted)
lrwx------ 1 user1 user1 64 Aug 20 13:43 1 -> /dev/pts/4
lrwx------ 1 user1 user1 64 Aug 20 13:43 2 -> /dev/pts/4
lr-x------ 1 user1 user1 64 Aug 20 13:43 3 -> /proc/10068/fd

और ट्रेसिंग सिसल्स के माध्यम से (आउटपुट पठनीयता के लिए छोटा हो गया; ध्यान दें कि अस्थायी फाइल को fd 3 के रूप में कैसे खोला जाता है, इसे लिखा गया डेटा, फिर इसे O_RDONLYfd 4 के रूप में ध्वज के साथ फिर से खोला जाता है और बाद में अनलिंक किया जाता है, फिर dup2()fd 0 पर, जिसे catबाद में विरासत में मिला है। ):

$ strace -f -e open,read,write,dup2,unlink,execve bash -c 'cat <<< "TEST"'
execve("/bin/bash", ["bash", "-c", "cat <<< \"TEST\""], [/* 47 vars */]) = 0
...
strace: Process 10229 attached
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
[pid 10229] write(3, "TEST", 4)         = 4
[pid 10229] write(3, "\n", 1)           = 1
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDONLY) = 4
[pid 10229] unlink("/tmp/sh-thd.uhpSrD") = 0
[pid 10229] dup2(4, 0)                  = 0
[pid 10229] execve("/bin/cat", ["cat"], [/* 47 vars */]) = 0
...
[pid 10229] read(0, "TEST\n", 131072)   = 5
[pid 10229] write(1, "TEST\n", 5TEST
)       = 5
[pid 10229] read(0, "", 131072)         = 0
[pid 10229] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=10229, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

राय: संभावित रूप से क्योंकि यहाँ तार अस्थायी पाठ फ़ाइलों का उपयोग करते हैं, यह संभव कारण है कि यहाँ-तार हमेशा एक अनुगामी नई पंक्ति सम्मिलित करते हैं, क्योंकि POSIX परिभाषा द्वारा पाठ फ़ाइल में लाइनें हैं जो newline वर्ण में समाप्त होती हैं।

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

के रूप में tldp.org बताते हैं,

प्रक्रिया प्रतिस्थापन एक प्रक्रिया (या प्रक्रियाओं) के उत्पादन को दूसरी प्रक्रिया के स्टैडेन में फीड करता है।

तो प्रभाव में इस पाइप के समान है stdout , दूसरे के लिए एक आदेश के जैसे echo foobar barfoo | wc। लेकिन ध्यान दें: बैश मैनपेज में आप देखेंगे कि इसे इस रूप में दर्शाया गया है <(list)। तो मूल रूप से आप कई (!) कमांड के आउटपुट को रीडायरेक्ट कर सकते हैं।

नोट: तकनीकी रूप से जब आप कहते हैं कि < <आप एक चीज़ का जिक्र नहीं कर रहे हैं, लेकिन एकल <और प्रक्रिया से दो पुनर्निर्देशन से आउटपुट का पुनर्निर्देशन <( . . .)

अब क्या होता है अगर हम सिर्फ प्रतिस्थापन की प्रक्रिया करते हैं?

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

जैसा कि आप देख सकते हैं, शेल अस्थायी फ़ाइल डिस्क्रिप्टर बनाता है /dev/fd/63जहां आउटपुट जाता है (जो गाइल्स के उत्तर के अनुसार , एक अनाम पाइप है)। इसका मतलब <है कि एक कमांड में इनपुट के रूप में फाइल डिस्क्रिप्टर को रीडायरेक्ट करता है।

बहुत सरल उदाहरण के लिए दो गूंज कमांड से आउटपुट की प्रक्रिया प्रतिस्थापन को wc में बनाना होगा:

$ wc < <(echo bar;echo foo)
      2       2       8

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

साइड नोट: प्रक्रिया प्रतिस्थापन को बशीवाद के रूप में संदर्भित किया जा सकता है (जैसे उन्नत गोले में प्रयोग करने योग्य एक कमांड या संरचना bash, लेकिन POSIX द्वारा निर्दिष्ट नहीं), लेकिन इसे ksh मैन पेज और इस उत्तर सुझाव के kshरूप में बैश के अस्तित्व से पहले लागू किया गया था । गोले की तरह और हालांकि प्रक्रिया प्रतिस्थापन नहीं है। तो हम प्रक्रिया प्रतिस्थापन के बिना किसी अन्य कमांड में कई कमांड के आउटपुट को पुनर्निर्देशित कैसे कर सकते हैं? ग्रुपिंग प्लस पाइपिंग!tcshmksh

$ (echo foo;echo bar) | wc
      2       2       8

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

इसलिए यदि हम पाइपिंग के साथ समूहन कर सकते हैं, तो हमें प्रक्रिया प्रतिस्थापन की आवश्यकता क्यों है? क्योंकि कभी-कभी हम पाइपिंग का उपयोग नहीं कर सकते हैं। नीचे दिए गए उदाहरण पर विचार करें - दो कमांड्स के आउटपुट की तुलना diff(जिसके लिए दो फ़ाइलों की आवश्यकता है, और इस मामले में हम इसे दो फ़ाइल डिस्क्रिप्टर दे रहे हैं)

diff <(ls /bin) <(ls /usr/bin)

7
< <उपयोग किया जाता है जब एक प्रक्रिया प्रतिस्थापन से एक स्टड हो रही है । ऐसा आदेश लग सकता है cmd1 < <(cmd2):। उदाहरण के लिए,wc < <(date)
जॉन 1024

4
हां, प्रक्रिया प्रतिस्थापन को बैश, zsh और AT & T ksh {88,93}
जॉन 1024

2
< < खुद के द्वारा एक चीज नहीं है, प्रक्रिया प्रतिस्थापन के मामले में यह सिर्फ एक <और चीज है जो इसके साथ शुरू होती है<
इम्बिसिस

1
@ एमुरु जहां तक ​​मुझे पता है, <<<पहले इसे 9 आर खोल के यूनिक्स बंदरगाह द्वारा लागू किया गया था , बाद में इसे zsh, bash और ksh93 द्वारा अपनाया गया। मैं तब इसे बशीवाद नहीं कहूंगा।
jlliagre

3
जहां पाइपिंग नहीं किया जा सकता का एक और उदाहरण: echo 'foo' | read; echo ${REPLY}जाएगा नहीं लौटने foo, क्योंकि readएक उप खोल में शुरू कर दिया है - पाइपिंग एक उप खोल शुरू होता है। हालांकि, read < <(echo 'foo'); echo ${REPLY}सही ढंग से रिटर्न foo, क्योंकि कोई उप-शेल नहीं है।
धान लैंडौ

26

< < एक वाक्यविन्यास त्रुटि है:

$ cat < <
bash: syntax error near unexpected token `<'

< <()है प्रक्रिया प्रतिस्थापन ( <()) (पुनर्निर्देशन के साथ संयुक्त <):

एक आकस्मिक उदाहरण:

$ wc -l < <(grep ntfs /etc/fstab)
4
$ wc -l <(grep ntfs /etc/fstab)
4 /dev/fd/63

प्रक्रिया प्रतिस्थापन के साथ, फ़ाइल डिस्क्रिप्टर का मार्ग फ़ाइल नाम की तरह उपयोग किया जाता है। यदि आप सीधे फ़ाइल नाम का उपयोग नहीं करना चाहते (या नहीं कर सकते हैं), तो आप प्रक्रिया प्रतिस्थापन को पुनर्निर्देशन के साथ जोड़ देते हैं।

स्पष्ट होने के लिए, कोई < <ऑपरेटर नहीं है।


मैं आपके जवाब से मिलता हूं कि, <<() से अधिक उपयोगी है <() सही है?
सोलफिश

1
@solfish <()एक फ़ाइल नाम की तरह बात कर देता है, तो यह अधिक आम तौर पर उपयोगी है - < <()stdin जहां यह आवश्यक नहीं हो सकता है की जगह है। में wc, उत्तरार्द्ध अधिक उपयोगी होता है। यह कहीं और कम उपयोगी हो सकता है
muru

12

< <एक सिंटैक्स त्रुटि है, आप शायद मतलब है command1 < <( command2 )जो एक सरल इनपुट पुनर्निर्देशन एक प्रक्रिया प्रतिस्थापन के बाद है और बहुत समान है, लेकिन इसके बराबर नहीं है:

command2 | command1

आपके द्वारा चलाए bashजा रहे अंतर command1को दूसरे मामले में एक उपधारा में चलाया जाता है, जबकि यह पहले वाले में वर्तमान शेल में चलाया जाता है। इसका मतलब है कि सेट किए गए वैरिएबल command1प्रक्रिया प्रतिस्थापन संस्करण के साथ खो नहीं जाएंगे।


11

< <एक सिंटैक्स त्रुटि देगा। उचित उपयोग निम्नानुसार है:

उदाहरणों की मदद से समझाते हुए:

इसके लिए उदाहरण < <():

while read line;do
   echo $line
done< <(ls)

उपरोक्त उदाहरण में, जबकि लूप का इनपुट lsकमांड से आएगा जिसे echoलूप में लाइन और एड द्वारा लाइन पढ़ा जा सकता है ।

<()प्रक्रिया प्रतिस्थापन के लिए प्रयोग किया जाता है। अधिक जानकारी और उदाहरण के लिए <()इस लिंक पर पाया जा सकता है:

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

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