linux - 3> और 1 का मतलब 4> और 3 5> और 3 आदि है?




bash shell (2)

एक tee बग?

जॉन कुगेलमैन का जवाब ठीक है, लेकिन जैसा कि समस्या जटिल है, मैं थोड़ा आगे जाऊंगा:

bash -c 'exec 2> >(exec sed -ue "s/^/StdErr: /");
    exec 1> >(exec sed -ue "s/^/StdOut: /");
    tee /dev/fd/{2..6} <<<foo'
StdErr: foo
StdOut: foo
StdErr: foo
StdErr: foo
StdErr: foo
StdErr: foo

दिखा रहा है इनपुट ( foo ) 5x * STDERR * पर और 1x STDOUT पर muliplied। तो सभी /dev/fd/2 /dev/fd/{3..6} /dev/fd/2 /dev/fd/{3..6} को /dev/fd/2 /dev/fd/{3..6} जाता है।

strace -o >(grep dev/fd) -e openat tee /dev/fd/{2..6} <<<foo 4>/dev/null
foo
foo
foo
foo
openat(AT_FDCWD, "/dev/fd/2", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
openat(AT_FDCWD, "/dev/fd/3", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 5
openat(AT_FDCWD, "/dev/fd/4", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
openat(AT_FDCWD, "/dev/fd/5", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 7
openat(AT_FDCWD, "/dev/fd/6", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 8

तो tee 5 ( 2..6 + STDOUT = 6 , - 1x / dev / null => 5 foo में भाग लिया) के बजाय tty पर 4x इनपुट का उत्पादन करें:

  1. Access /dev/fd/2 , फ़ाइल डिस्क्रिप्टर 3 खोलना ... और इसलिए /dev/fd/3 बनाएं , फिर
  2. पहुँच /dev/fd/3 , जो अब मौजूद है, पिछले ऑपरेशन से, फ़ाइल डिस्क्रिप्टर 5 खोलने (क्योंकि /dev/fd/4 को कमांड लाइन द्वारा /dev/null से /dev/null गया है ... और इसलिए /dev/fd/5 बनाएँ) , फिर
  3. पहुंच /dev/fd/4 (कमांड लाइन द्वारा /dev/null से बाँधा) और /dev/fd/6 बनाएँ , फिर
  4. पहुँच /dev/fd/5 , जो अब मौजूद है, (3 से बंधे, 2 से बंधे ...), फिर
  5. अभिगमन /dev/fd/6 , जो अब मौजूद है, लेकिन /dev/fd/4 विच में बाँध /dev/null से बाँधा गया है।

अपेक्षित उत्पादन हो सकता है:

tee /dev/fd/{2..6} <<<foo
foo
tee: /dev/fd/3: No such file or directory
tee: /dev/fd/4: No such file or directory
tee: /dev/fd/5: No such file or directory
tee: /dev/fd/6: No such file or directory
foo

Ouptut के साथ STDERR पर 1 बार और STDOUT पर 1 बार, और 4 त्रुटि लाइनों के साथ।

इसलिए tee शुरू होने से पहले लक्ष्यों के अस्तित्व की जांच न करें। लेकिन यह एक बग है ?!

जैसा कि फ़ाइल write mode में एक फ़ाइल खोलना ठीक हो सकता है भले ही फ़ाइल मौजूद न हो (नई फ़ाइल बनाना)।

जॉन कुगेलमैन की टिप्पणी से समझने के लिए टाइम-ऑफ-चेक-टाइम-ऑफ- यूज़ (TOCTOU) रेस कंडिशन को पढ़ना समझ में आता है कि प्री-चेक करना एक गलत विचार क्यों है

तो अगर एक बग, मुझे लगता है कि संदर्भित /dev/fd/ सीधे tee द्वारा है तो बग यहां (कमांड लाइन पर) है। ... नहीं एक tee बग, बस एक छोटी गाड़ी उपयोगकर्ता ;-)

मुझे उम्मीद है

echo foo | tee /proc/self/fd/{3..6} 3>&1

/ proc / self / fd / 4 जैसी त्रुटियों के साथ असफल होने के लिए : ऐसी कोई फ़ाइल या निर्देशिका आदि नहीं है, लेकिन मेरे आश्चर्य के लिए, यह आउटपुट करता है

foo
foo
foo
foo
foo

यह 3>&1 की तरह है, सभी निम्नलिखित विवरणकर्ताओं को stdout पर पुनर्निर्देशित किया जाना चाहिए, सिवाय इसके कि अगर मैं 3 को किसी अन्य चीज़ में बदलता हूं तो यह काम नहीं करता

$ echo foo | tee /proc/self/fd/{3..6} 4>&1
tee: /proc/self/fd/3: No such file or directory
tee: /proc/self/fd/5: No such file or directory
tee: /proc/self/fd/6: No such file or directory
foo
foo
$ echo foo | tee /proc/self/fd/{4..6} 4>&1
tee: /proc/self/fd/5: No such file or directory
tee: /proc/self/fd/6: No such file or directory
foo
foo

क्या इस व्यवहार के लिए कोई स्पष्टीकरण है?


strace सिस्टम कॉल के इस क्रम को दिखाता है:

$ strace -o strace.log tee /proc/self/fd/{3..6} 3>&1
...
$ cat strace.log
...
openat(AT_FDCWD, "/proc/self/fd/3", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
openat(AT_FDCWD, "/proc/self/fd/4", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 5
openat(AT_FDCWD, "/proc/self/fd/5", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
openat(AT_FDCWD, "/proc/self/fd/6", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 7
...

पहली पंक्ति खुलती है /proc/self/fd/3 और इसे अगला उपलब्ध fd नंबर बताता है, 4. /proc/self/fd/3 एक विशेष पथ है। इसे खोलने का एक प्रभाव है, जैसा कि dup एफडी 3: एफडी 4 अंक एक ही जगह के लिए एफडी 3, ट्टी।

प्रत्येक क्रमिक openat() कॉल के लिए एक ही बात होती है। जब धूल fds 4, 5, 6 और 7 को बसाती है तो सभी fd 3 के डुप्लिकेट होते हैं।

  • 1 → ट्टी
  • 3 → ट्टी
  • 4 → ट्टी
  • 5 → ट्टी
  • 6 → ट्टी
  • 7 → ट्टी

ध्यान दें कि 3>&1 पुनर्निर्देशन महत्वपूर्ण नहीं है। यह महत्वपूर्ण है कि हम टी को खोलने /proc/self/fd/N लिए पूछ रहे हैं जहां एन पहले से उपयोग में है। यदि हमें 3>&1 से छुटकारा मिलता है तो हमें वही परिणाम प्राप्त करना चाहिए और इसके बजाय /proc/self/fd/2 चाहिए। चलो देखते हैं:

$ echo foo | tee /proc/self/fd/{2..6}
foo
foo
foo
foo
foo
foo

की पुष्टि की! एक ही परिणाम।

हम एक ही fd संख्या को बार-बार दोहरा सकते हैं। हम एक ही परिणाम प्राप्त करते हैं जब हम fd 6 हिट करते हैं। जब तक यह आखिरी तक पहुंचता है तब तक इसने 6 को संभव बनाने के लिए पर्याप्त विवरण खोले हैं।

$ echo foo | tee /proc/self/fd/{2,2,2,2,6}
foo
foo
foo
foo
foo
foo




proc-filesystem