क्या यह बैश मैनुअल के पुनर्निर्देशन अनुभाग में एक टाइपो है?


13
Note that the order of redirections is significant.  For example, the command

          ls > dirlist 2>&1

   directs both standard output and standard error to the file dirlist, 
   while the command

          ls 2>&1 > dirlist

   directs  only  the  standard  output  to  file  dirlist,  because the 
   standard error was duplicated from the standard output before the standard
   output was redirected to dirlist.

अब, वह आखिरी हिस्सा मुझे भ्रमित कर रहा है। उस स्थिति में, कोई भी मानक त्रुटि टर्मिनल पर प्रिंट की जाएगी और कोई भी STDOUT dirlist फ़ाइल पर जाएगा। ऐसा ही होगा, लेकिन यह नहीं है कि मैं मैनुअल को कैसे समझ सकता हूं।

ऐसा लगता है जैसे यह कहना चाहिए "क्योंकि मानक त्रुटि को मानक आउटपुट से दोहराया गया था, मानक उत्पादन के बाद मानक को पुनर्निर्देशित किया गया था"। यदि STDER को किसी फ़ाइल में निर्देशित करने से पहले STDERR को भेजा गया था, तो क्या फ़ाइल में STDOUT और STDERR नहीं होंगे?

क्या कोई मेरे लिए यह स्पष्ट कर सकता है? क्या मेरी ओर से सिर्फ पढ़ना ही खराब है? दोहराव शब्द का प्रयोग मुझे इस संदर्भ में थोड़ा अजीब लगता है। शायद यही मुझे फेंक रहा है।



1
संचालन के मिश्रण का एक क्लासिक मामला जो "संदर्भ द्वारा मूल्य" बनाम "है।" जब आप किसी फ़ाइल डिस्क्रिप्टर की डुप्लिकेट करते हैं तो यह एक वैल्यू ऑपरेशन होता है। प्रोग्रामिंग में, a = 1; b = a; a = 2आप a == 2 && b == 1सच होने की उम्मीद के बाद । पुनर्निर्देशन असाइनमेंट के 2>&1समान है b = a- यह मूल्य से है, संदर्भ से नहीं। 2>&1अनंत काल के लिए फाइल डिस्क्रिप्टर 1 को फाइल डिस्क्रिप्टर 1 में न डालें - वे अभी भी 2 अलग-अलग फाइल डिस्क्रिप्टर हैं, जो उसी फ़ाइल को इंगित करते हैं।
jw013

जवाबों:


23

डुप्लीकेशन वास्तव में यहाँ का महत्वपूर्ण हिस्सा है।

आइए देखें कि पुनर्निर्देशन से पहले फ़ाइल विवरणक कहां जा रहे हैं। यह आम तौर पर वर्तमान टर्मिनल है, उदाहरण के लिए:

STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1

अब, यदि हम ls -lपुनर्निर्देशन के बिना कॉल करते हैं, तो आउटपुट और त्रुटि संदेश मेरे टर्मिनल पर जाते हैं /dev/pts/1

यदि हम पहली बार STDOUTकिसी फ़ाइल ( ls -l > dirlist) में रीडायरेक्ट करते हैं , तो यह इस तरह दिखता है:

STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1

जब हम फिरSTDERR से फ़ाइल डिस्क्रिप्टर ( ) के डुप्लिकेट पर पुनर्निर्देशित करते हैं, तो एक डुप्लिकेट पर जाता है :STDOUTls -l > dirlist 2>&1STDERR/home/bon/dirlist

STDOUT ---> /home/bon/dirlist
STDERR ---> /home/bon/dirlist

यदि हम पहले फ़ाइल डिस्क्रिप्टर ( ) के STDERRडुप्लिकेट पर पुनर्निर्देशित करेंगे :STDOUTls -l 2>&1

STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1

और फिर STDOUT एक फ़ाइल ( ls -l 2>&1 > dirlist) में, हमें यह मिलेगा:

STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1

यहाँ, STDERRअभी भी टर्मिनल जा रहा है।

आप देखें, मैन पेज में ऑर्डर सही है।


परीक्षण पुनर्निर्देशन

अब, आप खुद को परख सकते हैं। उपयोग करते हुए ls -l /proc/$$/fd/, आप देखते हैं कि कहां STDOUT(fd 1 के साथ) और STDERR(fd 2 के साथ), वर्तमान प्रक्रिया के लिए जा रहे हैं:

$ ls -l /proc/$$/fd/
total 0
lrwx------ 1 bon bon 64 Jul 24 18:19 0 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 18:19 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 07:41 2 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 18:19 255 -> /dev/pts/1

चलिए एक छोटी सी शेल स्क्रिप्ट बनाते हैं जो यह दर्शाती है कि आपकी फ़ाइल डिस्क्रिप्टर कहाँ इंगित की गई है। इस तरह, हम हमेशा lsकॉलिंग शेल से किसी भी पुनर्निर्देशन सहित, कॉल करते समय राज्य प्राप्त करते हैं ।

$ cat > lookfd.sh
#!/bin/sh
ls -l /proc/$$/fd/
^D
$ chmod +x lookfd.sh

(के साथ CtrlD, आप एक अंतिम फ़ाइल भेजते हैं और इसलिए catकमांड पढ़ने से रोकते हैं STDIN।)

अब, पुनर्निर्देशन के अलग-अलग संयोजनों के साथ इस स्क्रिप्ट को कॉल करें:

$ ./lookfd.sh 
total 0
lrwx------ 1 bon bon 64 Jul 24 19:08 0 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:08 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:08 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:08 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh > foo.out
$ cat foo.out 
total 0
lrwx------ 1 bon bon 64 Jul 24 19:10 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:10 1 -> /home/bon/foo.out
lrwx------ 1 bon bon 64 Jul 24 19:10 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:10 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh 2>&1 > foo.out
$ cat foo.out 
total 0
lrwx------ 1 bon bon 64 Jul 24 19:10 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:10 1 -> /home/bon/foo.out
lrwx------ 1 bon bon 64 Jul 24 19:10 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:10 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh > foo.out 2>&1
$ cat foo.out 
total 0
lrwx------ 1 bon bon 64 Jul 24 19:11 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:11 1 -> /home/bon/foo.out
l-wx------ 1 bon bon 64 Jul 24 19:11 2 -> /home/bon/foo.out
lr-x------ 1 bon bon 64 Jul 24 19:11 255 -> /home/bon/lookfd.sh

आप देख सकते हैं, कि फ़ाइल डिस्क्रिप्टर 1 (के लिए STDOUT) और 2 (के लिए STDERR) भिन्न हैं। मज़े के लिए, आप रिडायरेक्ट भी कर सकते STDINहैं और परिणाम देख सकते हैं :

$ ./lookfd.sh < /dev/zero
total 0
lr-x------ 1 bon bon 64 Jul 24 19:18 0 -> /dev/zero
lrwx------ 1 bon bon 64 Jul 24 19:18 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:18 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:18 255 -> /home/bon/lookfd.sh

(पाठक के लिए छोड़ दिया गया सवाल: फाइल डिस्क्रिप्टर 255 पॉइंट कहाँ है? ;-))


+1 - उत्कृष्ट उत्तर। बहुत अच्छी तरह से लिखित और भयानक उदाहरण। धन्यवाद!!!
स्लम

मैं देखता हूं, मुझे लगता है कि मेरी गलतफहमी यह थी कि पुनर्निर्देशन सभी निम्नलिखित आदेशों के लिए लगातार होगा, ताकि बाकी लाइन के लिए कोई भी STDERR STDOUT पर चला जाए।
ग्रीग लेवेंटल

2

नहीं, मैनुअल सही है।

अगर पहले 1 अंक टर्मिनल के लिए, और 2 भी टर्मिनल के लिए, तो:

command  2>&1   1>somewhere

पुनर्निर्देशन मूल्यांकनकर्ता बाएं से दाएं होगा।

तो यह FIRST मूल्यांकन करेगा 2>&1, और इस प्रकार FIRST कॉपी जो fd 1(यानी the terminal, आमतौर पर / dev / tty की फ़ाइल विवरणक ) को इंगित करता था 2

तो उस बिंदु पर fd 2अब इंगित करता है कि fd कहाँ 1इंगित करता है ( the terminal)

और जब यह 1>somewhereभाग का मूल्यांकन करता है , और इस तरह से फ़ाइल विवरणक की प्रतिलिपि करेगा somewherefd 1(तो उस बिंदु पर, fd 1अब इंगित करता है somewhere, और fd 2अभी भी इंगित करता है the terminal)

तो यह वास्तव में 1 को "कहीं" और 2 को टर्मिनल में प्रिंट करता है, क्योंकि 2 को 1 BEFORE से दोहराया गया था 1 को बदल दिया गया है।

अन्य आदेश:

command  1>somewhere 2>&1

पहले fd 1को रीडायरेक्ट करेगा somewhere, और फिर उसी संदर्भ को fd 2 में कॉपी करेगा, इसलिए अंत में 2 को भी इंगित करता है somewhere। लेकिन वे अभी से "लिंक" नहीं हैं। प्रत्येक को अभी भी अलग से पुनर्निर्देशित किया जा सकता है।

उदाहरण के लिए:

command  1>somewhere 2>&1
exec 2>/dev/null

उस एक के अंत में, fd 1इंगित करता है somewhere, और fd 2को निर्देशित किया जाता है/dev/null

एफडी के लिए सामान्य नाम 1एसटीडीयूएस (मानक आउटपुट) है, और एफडी के लिए सामान्य नाम 2एसटीडीआरआर (मानक त्रुटि है, क्योंकि इसका उपयोग आमतौर पर एसटीडीयूएस के साथ हस्तक्षेप किए बिना त्रुटियों को प्रदर्शित करने के लिए किया जाता है)


@ माइकल- mrozek: संपादन के लिए धन्यवाद, लेकिन मैं "डुप्लिकेट" के बजाय "डुप्लिकेट" के रूप में "कॉपी" कहने पर जोर देता हूं, जिससे कोई यह विश्वास कर सके कि अब से दोनों "एक ही बात" हैं, जो सच नहीं है। ex:: cmd 1>somewhere 2>&1 ; exec 2>/dev/nullनिष्पादन के बाद, केवल 2 को / dev / null में पुनर्निर्देशित किया गया है (1 अभी भी "कहीं" जा रहा है)। मुझे "fd 1" के बजाय "क्या 1 अंक" कहने के लिए एक तरीके के साथ आने में मदद की ज़रूरत है, हालांकि ... जैसा कि भ्रामक भी है ...
ओलिवियर दुलाक

1
मुझे नहीं पता तुम्हारा क्या मतलब है; आप वह हैं जिसने इसे "कॉपी" से "डुप्लिकेट" में बदल दिया। मैंने जो कुछ किया था, वह सब कुछ पूंजीकृत और प्रारूपित करने के लिए था, मैंने एक शब्द नहीं बदला
माइकल मोर्ज़ेक

दोह ... ^ ^ क्षमा करें। और मैंने और अधिक सटीक बनाने के लिए फिर से सुधार करने के लिए संपादित किया कि क्या ^ ^ में कॉपी किया गया है
ओलिवियर दुलक

1

मुझे लगता है कि यहां भ्रमित करने वाला हिस्सा गलतफहमी है कि stdout को पुनर्निर्देशित करने की क्षमता वास्तव में दो धाराओं को जोड़ती है।

एक पूरी तरह से उचित विचार है लेकिन जब आप लिखते हैं तो क्या होता 2>&1है स्टादर एक स्टैबाउट पर एक तिरछी नज़र रखता है और उसी जगह पर लिखता है। इसलिए यदि आप बाद में stdout को कहीं और लिखने के लिए कहते हैं तो इससे stderr के गंतव्य पर कोई प्रभाव नहीं पड़ता है जो पहले ही स्थानांतरित हो चुका है।

मुझे लगता है कि यह अपने आप में एक उलटी बात है लेकिन यह है कि यह कैसे काम करता है। सेट करें जहां आप पहले लिखना चाहते हैं फिर सभी को "मुझे कॉपी करें" बताएं। आशा है कि स्पष्ट ...


0

दोहराव ...

महत्वपूर्ण है, लेकिन इस अर्थ में कि यह बहुत भ्रम का स्रोत है । यह वास्तव में बहुत सरल है। यह जवाब सिर्फ एक "कट्टरपंथी" चित्रण है।

स्वीकृत उत्तर अच्छा है, लेकिन बहुत लंबा है और यह "दोहराव" पर जोर देता है।

क्यू बुद्धिमानी से समाप्त होता है:

दोहराव शब्द का प्रयोग मुझे इस संदर्भ में थोड़ा अजीब लगता है। शायद यही मुझे फेंक रहा है।

मैं बैश नोटेशन का उपयोग करता हूं और "एक" और "दो" को फाइलहैंडल "1" और "2" के रूप में परिभाषित करता हूं। (आउटपुट) पुनर्निर्देशन ऑपरेटर >एक असाइनमेंट है =&और का $अर्थ "मूल्य" है।

आदमी उदाहरणों को काटता है (डिफ़ॉल्ट रूप से "1" जोड़ा गया)

ls 1>dirlist 2>&1      # both to dirlist
ls 2>&1 1>dirlist      # 1 to dirlist, 2 stays on tty/screen 

बनना:

one=dirlist  two=$one

तथा

two=$one   one=dirlist

और यहां तक ​​कि यह मेरे लिए गैर-स्वचालित है, और कुछ अन्य जो मुझे लगता है। पहली पंक्ति आपको छोड़ती है $oneऔर $twoदोनों में "डर्लिस्ट" होता है। बेशक।

दूसरी पंक्ति एक बेकार असाइनमेंट के साथ शुरू होती है। दोनों अपनी दिशा के रूप में "टीटीवाई" (थोड़ा प्रतीकात्मक) के साथ परिभाषा से शुरू करते हैं ; इस असाइनमेंट से कोई मूल्य नहीं बदला जाता है, और फ़ाइलहैंडल के साथ चर के साथ, कुछ भी जादुई रूप से जुड़ा नहीं है। परिवर्तनीय twoनिम्नलिखित से प्रभावित नहीं होता है one=dirlist। बिलकूल नही।

यहां (6 साल पहले) सोमबॉडी ने "कॉपी" या "डुप्लिकेट" के बजाय "बिंदु" का सुझाव दिया, और फिर एहसास हुआ: यह भी भ्रामक होगा।

इस दोहराव या सूचक अर्थ की आवश्यकता भी नहीं है। शायद यह एम्परसेंड है जिस पर अधिक ध्यान देने की आवश्यकता है। ऑपरेटर / टोकन / जो भी "का मूल्य"।

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

ls 1>2& 2>/dev/null

यह स्वाभाविक रूप से " कॉपी" / "डुप्लिकेट" 1 से 2 के रूप में पढ़ता है , और फिर दोनों एक साथ अशक्त करने के लिए । लेकिन विचार गलत है, और वाक्यविन्यास भी। (लेकिन कोई सिंटैक्स त्रुटि नहीं है, यह मान्य है)

इसकी योजना बनाने का सही तरीका यह है कि दोनों में से किसी को भी अशक्त करने के लिए, और फिर अन्य को समान जगह पर पुनर्निर्देशित करें:

ls 1>/dev/null 2>&1
# or 
ls 2>/dev/null 1>&2

(अग्रणी "1" को छोड़ा जा सकता है)

(एसीसी को ठीक करें। ए बहुत लंबा नहीं है, लेकिन बहुत अधिक सूची है - या: बहुत अच्छा दृश्य, इतना अच्छा स्पष्टीकरण नहीं)

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