एक चर में मानक त्रुटि कैसे संग्रहीत करें


182

मान लीजिए कि मेरे पास निम्नलिखित की तरह एक स्क्रिप्ट है:

useless.sh

echo "This Is Error" 1>&2
echo "This Is Output" 

और मेरे पास एक और शेल स्क्रिप्ट है:

alsoUseless.sh

./useless.sh | sed 's/Output/Useless/'

मैं "दिस इज़ एरर", या बेकार के किसी भी अन्य stderr को एक चर में कैप्चर करना चाहता हूँ। चलो इसे ERROR कहते हैं।

ध्यान दें कि मैं कुछ के लिए stdout का उपयोग कर रहा हूं। मैं stdout का उपयोग जारी रखना चाहता हूं, इसलिए stdout में पुनर्निर्देशित करना इस मामले में, सहायक नहीं है।

इसलिए, मूल रूप से, मैं करना चाहता हूं

./useless.sh 2> $ERROR | ...

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

मुझे यह भी पता है कि मैं कर सकता था

./useless.sh 2> /tmp/Error
ERROR=`cat /tmp/Error`

लेकिन यह बदसूरत और अनावश्यक है।

दुर्भाग्य से, अगर कोई जवाब यहाँ नहीं है, तो मैं यही करने जा रहा हूँ।

मुझे उम्मीद है कि एक और तरीका है।

किसी के पास कोई बेहतर विचार है?


4
क्या वास्तव में के लिए stdout का उपयोग करना चाहते हैं? क्या आप इसे कंसोल पर देखना चाहते हैं? या क्या आप इसे आउटपुट पर कैप्चर / रीडायरेक्ट कर रहे हैं? अगर यह सिर्फ कंसोल के लिए है, तो आप कंसोल और स्टडर को रीडायरेक्ट करने के लिए स्टडआउट को रीडायरेक्ट करें:ERROR=$(./useless.sh | sed 's/Output/Useless/' 2>&1 1>/dev/ttyX)
टिम केर्स्टन

जवाबों:


91

इस प्रकार यह त्रुटि फ़ाइल को पकड़ने के लिए neater होगा:

ERROR=$(</tmp/Error)

शेल इसे पहचानता है और catडेटा प्राप्त करने के लिए ' ' नहीं चलाना पड़ता है ।

बड़ा सवाल कठिन है। मुझे नहीं लगता कि ऐसा करने का कोई आसान तरीका है। आपको पूरी पाइपलाइन को उप-शेल में बनाना होगा, अंततः इसके अंतिम मानक आउटपुट को एक फ़ाइल में भेजना होगा, ताकि आप त्रुटियों को मानक आउटपुट पर पुनर्निर्देशित कर सकें।

ERROR=$( { ./useless.sh | sed s/Output/Useless/ > outfile; } 2>&1 )

ध्यान दें कि अर्ध-बृहदान्त्र की आवश्यकता है (क्लासिक गोले में - बॉर्न, कोर्न - निश्चित रूप से; शायद बैश में भी)। {}संलग्न कमांड पर ' ' I / O पुनर्निर्देशन करता है। जैसा कि लिखा गया है, यह त्रुटियों को sedभी पकड़ लेगा ।

चेतावनी: औपचारिक रूप से अनुपयोगी कोड - अपने जोखिम पर उपयोग करें।


1
मुझे उम्मीद थी कि मुझे पता नहीं था कि वास्तव में कुछ पागल चाल होगी, लेकिन ऐसा लगता है कि यह ऐसा है। धन्यवाद।
psycotica0

9
यदि आपको मानक आउटपुट की आवश्यकता नहीं है, तो आप /dev/nullइसके बजाय इसे अनुप्रेषित कर सकते हैं outfile(यदि आप मेरे जैसे हैं, तो आपको Google के माध्यम से यह प्रश्न मिला है, और ओपी के समान आवश्यकताएं नहीं हैं)
मार्क इरिच

2
अस्थायी फ़ाइलों के बिना उत्तर के लिए, यहां देखें ।
टॉम हेल

1
यहां इसे फ़ाइलों पर पुनर्निर्देशित किए बिना करने का एक तरीका है; यह अदला-बदली के साथ खेलता है stdoutऔर stderrआगे और पीछे। लेकिन सावधान रहना , के रूप में यहां कहा गया है: बैश में, यह बेहतर होगा कि फ़ाइल वर्णनकर्ता 3 अप्रयुक्त है ग्रहण करने के लिए नहीं "
Golar Ramblar

69

alsoUseless.sh

यह आपको अपनी useless.shस्क्रिप्ट के आउटपुट को कमांड के माध्यम से पाइप करने की अनुमति देगा जैसे कि sedऔर stderrनामांकित चर में सहेजें error। पाइप का परिणाम stdoutप्रदर्शन के लिए या किसी अन्य कमांड में पाइप करने के लिए भेजा जाता है ।

ऐसा करने के लिए आवश्यक पुनर्निर्देशन को प्रबंधित करने के लिए यह कुछ अतिरिक्त फ़ाइल डिस्क्रिप्टर सेट करता है।

#!/bin/bash

exec 3>&1 4>&2 #set up extra file descriptors

error=$( { ./useless.sh | sed 's/Output/Useless/' 2>&4 1>&3; } 2>&1 )

echo "The message is \"${error}.\""

exec 3>&- 4>&- # release the extra file descriptors

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

3
मैं दोनों stderrऔर stdoutचर में कैसे कब्जा करूंगा ?
गिंगी

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

1
@ t00bs: readएक पाइप से इनपुट स्वीकार नहीं करता है। आप जो प्रदर्शित करने की कोशिश कर रहे हैं उसे प्राप्त करने के लिए आप अन्य तकनीकों का उपयोग कर सकते हैं।
अगली सूचना तक रोक दिया गया।

2
सरल हो सकता है, के साथ: त्रुटि = $ (./useless.sh | sed '/ आउटपुट / बेकार /' 2> और 1 1> & 3)
Jocelyn

64

Stdout, stdout को / dev / null, और उसके बाद backticks का उपयोग करने या $()पुनर्निर्देशित stderr पर कब्जा करने के लिए पुनर्निर्देशित stderr:

ERROR=$(./useless.sh 2>&1 >/dev/null)

8
यही कारण है कि मैंने अपने उदाहरण में पाइप को शामिल किया। मैं अभी भी मानक आउटपुट चाहता हूं, और मैं चाहता हूं कि यह अन्य चीजें करें, अन्य स्थानों पर जाएं।
psycotica0

कमांड के लिए जो आउटपुट को केवल स्टॉडर में भेजता है, इसे कैप्चर करने का सरल तरीका, उदाहरण के लिएPY_VERSION="$(python --version 2>&1)"
जॉन मार्क

9

इस प्रश्न के लिए बहुत सारे डुप्लिकेट हैं, जिनमें से कई में थोड़ा सरल उपयोग परिदृश्य है जहां आप एक ही समय में stderr और stdout और बाहर निकलने के कोड को कैप्चर नहीं करना चाहते हैं ।

if result=$(useless.sh 2>&1); then
    stdout=$result
else
    rc=$?
    stderr=$result
fi

सामान्य परिदृश्य के लिए काम करता है जहां आप सफलता के मामले में या तो उचित उत्पादन की उम्मीद करते हैं, या विफलता के मामले में stderr पर एक नैदानिक ​​संदेश।

ध्यान दें कि शेल का नियंत्रण विवरण पहले से ही $?हुड के नीचे की जांच करता है; ऐसा कुछ भी जो दिखता है

cmd
if [ $? -eq 0 ], then ...

कहने का सिर्फ एक अनाड़ी, अनैतिक तरीका है

if cmd; then ...

यह मेरे लिए काम किया: my_service_status = $ (सेवा my_service स्थिति 2> & 1) धन्यवाद !!
1935 में JRichardsz

6
# command receives its input from stdin.
# command sends its output to stdout.
exec 3>&1
stderr="$(command </dev/stdin 2>&1 1>&3)"
exitcode="${?}"
echo "STDERR: $stderr"
exit ${exitcode}

1
commandयहाँ एक बुरा विकल्प है, क्योंकि वास्तव में उस नाम से एक बेसिन है। yourCommandअधिक स्पष्ट होने के लिए इसे या ऐसे बना सकते हैं ।
चार्ल्स डफी

4

पाठक के लाभ के लिए, यह नुस्खा यहाँ

  • एक चर में stderr को पकड़ने के लिए ऑनलाइनर के रूप में फिर से उपयोग किया जा सकता है
  • अभी भी कमांड के रिटर्न कोड तक पहुंच देता है
  • एक अस्थायी फ़ाइल डिस्क्रिप्टर 3 का बलिदान करता है (जो आपके द्वारा बदला जा सकता है)
  • और इस अस्थायी फ़ाइल डिस्क्रिप्टर को आंतरिक कमांड में उजागर नहीं करता है

यदि आप stderrकुछ commandमें पकड़ना चाहते varहैं तो आप कर सकते हैं

{ var="$( { command; } 2>&1 1>&3 3>&- )"; } 3>&1;

बाद में आप यह सब है:

echo "command gives $? and stderr '$var'";

अगर commandसरल है (कुछ ऐसा नहीं है a | b) तो आप भीतर को छोड़ {}सकते हैं:

{ var="$(command 2>&1 1>&3 3>&-)"; } 3>&1;

एक आसान पुन: प्रयोज्य- bashसंयोजन में लिपटे (शायद संस्करण 3 और इसके लिए ऊपर की आवश्यकता है local -n):

: catch-stderr var cmd [args..]
catch-stderr() { local -n v="$1"; shift && { v="$("$@" 2>&1 1>&3 3>&-)"; } 3>&1; }

व्याख्या की:

  • local -nउपनाम "$ 1" (जिसके लिए चर है catch-stderr)
  • 3>&1 वहाँ stdout अंक को बचाने के लिए फ़ाइल डिस्क्रिप्टर 3 का उपयोग करता है
  • { command; } (या "$ @") तब आउटपुट कैप्चरिंग के भीतर कमांड निष्पादित करता है $(..)
  • कृपया ध्यान दें कि सटीक क्रम यहां महत्वपूर्ण है (इसे गलत तरीके से करने से फाइल डिस्क्रिप्टर गलत तरीके से बदल जाता है):
    • 2>&1stderrआउटपुट कैप्चरिंग पर रीडायरेक्ट करता है$(..)
    • 1>&3"बाहरी" stdoutपर $(..)वापस कैप्चर करने वाले आउटपुट से रीडायरेक्ट करता है stdoutजो फ़ाइल डिस्क्रिप्टर 3 में सेव किया गया था। ध्यान दें कि stderrअभी भी एफडी 1 से पहले बताया गया है: आउटपुट कैप्चरिंग के लिए$(..)
    • 3>&-फिर फ़ाइल डिस्क्रिप्टर 3 को बंद कर देता है क्योंकि इसकी कोई आवश्यकता नहीं है, जैसे कि commandअचानक कोई अज्ञात फ़ाइल डिस्क्रिप्टर दिखाई नहीं देता है। ध्यान दें कि बाहरी शेल में अभी भी FD 3 खुली है, लेकिन commandइसे नहीं देखेंगे।
    • उत्तरार्द्ध महत्वपूर्ण है, क्योंकि कुछ प्रोग्राम lvmअप्रत्याशित फ़ाइल विवरणकर्ताओं के बारे में शिकायत करते हैं। और lvmशिकायत करता है stderr- बस जिसे हम पकड़ने जा रहे हैं!

आप इस नुस्खा के साथ किसी भी अन्य फ़ाइल डिस्क्रिप्टर को पकड़ सकते हैं, यदि आप तदनुसार अनुकूलित करते हैं। फ़ाइल डिस्क्रिप्टर 1 को छोड़कर (यहाँ पुनर्निर्देशन तर्क गलत होगा, लेकिन फ़ाइल डिस्क्रिप्टर 1 के लिए आप बस var=$(command)सामान्य रूप से उपयोग कर सकते हैं )।

ध्यान दें कि यह बलिदान फ़ाइल डिस्क्रिप्टर 3 है। यदि आपको उस फ़ाइल डिस्क्रिप्टर की आवश्यकता होती है, तो नंबर बदलने के लिए स्वतंत्र महसूस करें। लेकिन ध्यान रखें, कि कुछ गोले (1980 के दशक से) के बाद 99>&1तर्क के रूप में समझ सकते हैं (यह कोई समस्या नहीं है )।99>&1bash

यह भी ध्यान दें कि एक चर के माध्यम से इस FD 3 को विन्यास योग्य बनाना आसान नहीं है। यह चीजों को बहुत अपठनीय बनाता है:

: catch-var-from-fd-by-fd variable fd-to-catch fd-to-sacrifice command [args..]
catch-var-from-fd-by-fd()
{
local -n v="$1";
local fd1="$2" fd2="$3";
shift 3 || return;

eval exec "$fd2>&1";
v="$(eval '"$@"' "$fd1>&1" "1>&$fd2" "$fd2>&-")";
eval exec "$fd2>&-";
}

सुरक्षा नोट: पहले 3 तर्कों को catch-var-from-fd-by-fdतीसरे पक्ष से नहीं लिया जाना चाहिए। हमेशा उन्हें "स्थिर" फैशन में स्पष्ट रूप से दें।

तो नहीं-नहीं-नहीं catch-var-from-fd-by-fd $var $fda $fdb $command, ऐसा कभी मत करो!

यदि आप एक परिवर्तनशील चर नाम से गुजरते हैं, तो कम से कम इसे निम्नानुसार करें: local -n var="$var"; catch-var-from-fd-by-fd var 3 5 $command

यह अभी भी हर शोषण के खिलाफ आपकी रक्षा नहीं करेगा, लेकिन कम से कम सामान्य स्क्रिप्टिंग त्रुटियों का पता लगाने और बचने में मदद करता है।

टिप्पणियाँ:

  • catch-var-from-fd-by-fd var 2 3 cmd.. के समान है catch-stderr var cmd..
  • shift || returnयदि आप सही तर्क देना भूल जाते हैं, तो बदसूरत त्रुटियों को रोकने के लिए बस कुछ तरीका है। शायद शेल को समाप्त करना एक और तरीका होगा (लेकिन इससे कमांडलाइन से परीक्षण करना कठिन हो जाता है)।
  • दिनचर्या ऐसी लिखी गई थी, जिसे समझना ज्यादा आसान है। कोई फ़ंक्शन को फिर से लिख सकता है जैसे कि इसकी आवश्यकता नहीं है exec, लेकिन फिर यह वास्तव में बदसूरत हो जाता है।
  • इस दिनचर्या को गैर के लिए भी फिर से लिखा जा सकता है, bashजैसे कि इसकी कोई आवश्यकता नहीं है local -n। हालाँकि तब आप स्थानीय चर का उपयोग नहीं कर सकते हैं और यह बहुत बदसूरत हो जाता है!
  • यह भी ध्यान दें कि evalएस एक सुरक्षित फैशन में उपयोग किया जाता है। आमतौर evalपर खतरनाक माना जाता है। हालांकि इस मामले में यह "$@"(मनमाना आदेशों को निष्पादित करने के लिए) उपयोग करने से ज्यादा बुराई नहीं है । हालाँकि कृपया यहाँ दिखाए गए अनुसार सटीक और सही उद्धरण का उपयोग करना सुनिश्चित करें (अन्यथा यह बहुत खतरनाक हो जाता है )।

3

यहाँ है कि मैं यह कैसे किया:

#
# $1 - name of the (global) variable where the contents of stderr will be stored
# $2 - command to be executed
#
captureStderr()
{
    local tmpFile=$(mktemp)

    $2 2> $tmpFile

    eval "$1=$(< $tmpFile)"

    rm $tmpFile
}

उपयोग उदाहरण:

captureStderr err "./useless.sh"

echo -$err-

यह एक अस्थायी फ़ाइल का उपयोग करता है । लेकिन एक समारोह में कम से कम बदसूरत सामान लपेटा जाता है।


@ShadowWizard मेरी तरफ थोड़ा संदेह। फ्रांसीसी में, बृहदान्त्र आमतौर पर एक स्थान से पहले होता है। मैं गलती से अंग्रेजी के उत्तरों के साथ यही नियम लागू करता हूं । जाँच के बाद यह , मुझे पता है कि मैं इस गलती को फिर से नहीं होगा।
स्टीफन

@ स्टेफ़न चीयर्स, इस पर भी यहाँ चर्चा की गई है । :)
शैडो विजार्ड इयर फॉर यू

1
इसका उपयोग करने की तुलना में सुरक्षित तरीके हैं eval। उदाहरण के लिए, printf -v "$1" '%s' "$(<tmpFile)"यदि आपके TMPDIRचर को एक दुर्भावनापूर्ण मान पर सेट किया गया है (या आपके गंतव्य चर नाम में ऐसा कोई मान है) तो मनमाना कोड चलाने का जोखिम नहीं है ।
चार्ल्स डफी

1
इसी तरह, rm -- "$tmpFile"से अधिक मजबूत है rm $tmpFile
चार्ल्स डफी

2

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

#! / Bin / bash

समारोह बेकार
    /tmp/useless.sh | sed 's / आउटपुट / बेकार /'
}

त्रुटि = $ (बेकार)
इको $ एरोर

अन्य सभी प्रकार के आउटपुट पुनर्निर्देशन को एक अस्थायी फ़ाइल द्वारा समर्थित होना चाहिए।


2

POSIX

STDERR को कुछ पुनर्निर्देशन जादू के साथ कैप्चर किया जा सकता है:

$ { error=$( { { ls -ld /XXXX /bin | tr o Z ; } 1>&3 ; } 2>&1); } 3>&1
lrwxrwxrwx 1 rZZt rZZt 7 Aug 22 15:44 /bin -> usr/bin/

$ echo $error
ls: cannot access '/XXXX': No such file or directory

ध्यान दें कि कमांड (यहाँ ls) के STDOUT की पाइपिंग अंतरतम के अंदर की गई है { }। यदि आप एक साधारण कमांड निष्पादित कर रहे हैं (जैसे, पाइप नहीं), तो आप इन आंतरिक ब्रेस को निकाल सकते हैं।

आप पाइपिंग के रूप में आदेश के बाहर पाइप नहीं में एक subshell बनाता कर सकते हैं bashऔर zsh, और subshell में चर के लिए काम वर्तमान खोल करने के लिए उपलब्ध नहीं होगा।

दे घुमा के

में bash, यह बेहतर होगा कि फाइल डिस्क्रिप्टर 3 का उपयोग न किया जाए:

{ error=$( { { ls -ld /XXXX /bin | tr o Z ; } 1>&$tmp ; } 2>&1); } {tmp}>&1; 
exec {tmp}>&-  # With this syntax the FD stays open

ध्यान दें कि यह काम नहीं करता है zsh


सामान्य विचार के लिए इस उत्तर के लिए धन्यवाद ।


क्या आप विवरण के साथ इस पंक्ति को समझा सकते हैं? समझ नहीं आया 1> & $ tmp; {त्रुटि = $ ({{ls -ld / XXXX / bin | tr o Z;} 1> & $ tmp;} २> & १); } {tmp}> & 1;
थियागो कॉनरेडो

1

इस पोस्ट ने मुझे अपने स्वयं के उद्देश्यों के लिए एक समान समाधान के साथ आने में मदद की:

MESSAGE=`{ echo $ERROR_MESSAGE | format_logs.py --level=ERROR; } 2>&1`

तब तक जब तक हमारा संदेश खाली स्ट्रिंग नहीं होता है, तब तक हम इसे अन्य सामान पर भेजते हैं। यह हमें बताएगा कि क्या हमारा फॉर्मेट_लॉग्स्की कुछ प्रकार के अजगर अपवाद के साथ विफल हो गया है।


1

कब्जा और प्रिंट stderr

ERROR=$( ./useless.sh 3>&1 1>&2 2>&3 | tee /dev/fd/2 )

टूट - फूट

आप $()stdout को पकड़ने के लिए उपयोग कर सकते हैं , लेकिन आप इसके बजाय stderr पर कब्जा करना चाहते हैं। इसलिए आप स्टडआउट और स्टैडर को स्वैप करें। मानक स्वैप एल्गोरिथ्म में अस्थायी भंडारण के रूप में fd 3 का उपयोग करना।

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

नोट: यह एक एकल पंक्ति और आदेश मामलों में पुनर्निर्देशन का एक बहुत कुछ है। पाइपलाइन के अंत में $()स्टडआउट को पकड़ रहा है teeऔर पाइप लाइन ही मार्गों ./useless.shके स्टडआउट के teeबाद से हम स्टड की अदला-बदली करते हैं और इसके लिए स्टैडआउट करते हैं ./useless.sh

./Useless.sh के स्टडआउट का उपयोग करना

ओपी ने कहा कि वह अभी भी (केवल प्रिंट नहीं) का उपयोग करना चाहते हैं, जैसे ./useless.sh | sed 's/Output/Useless/'

कोई समस्या नहीं है बस इसे आगे बढ़ना stdout और stderr गमागमन। मैं इसे एक फ़ंक्शन या फ़ाइल (भी- useless.sh) में स्थानांतरित करने की सलाह देता हूं और कहा जाता है कि ऊपर लाइन में ./useless.sh की जगह।

हालाँकि, यदि आप stdout और stderr को कैप्चर करना चाहते हैं, तो मुझे लगता है कि आपको अस्थायी फ़ाइलों पर वापस जाना $()होगा क्योंकि यह केवल एक समय में एक ही करेगा और यह एक सबस्लेम बनाता है जिसमें से आप चर नहीं लौटा सकते।


1

टॉम हेल के जवाब पर थोड़ा सा इशारा करते हुए, मैंने पुनर्निर्देशन योग को आसान पुन: उपयोग के लिए एक फ़ंक्शन में लपेटना संभव पाया है। उदाहरण के लिए:

#!/bin/sh

capture () {
    { captured=$( { { "$@" ; } 1>&3 ; } 2>&1); } 3>&1
}

# Example usage; capturing dialog's output without resorting to temp files
# was what motivated me to search for this particular SO question
capture dialog --menu "Pick one!" 0 0 0 \
        "FOO" "Foo" \
        "BAR" "Bar" \
        "BAZ" "Baz"
choice=$captured

clear; echo $choice

इसे और सरल बनाना संभव है। विशेष रूप से अच्छी तरह से परीक्षण नहीं किया गया है, लेकिन यह बैश और ksh दोनों के साथ काम करता है।


0

यदि आप एक अस्थायी फ़ाइल के उपयोग को बायपास करना चाहते हैं तो आप प्रक्रिया प्रतिस्थापन का उपयोग करने में सक्षम हो सकते हैं। मैंने अभी तक काम नहीं किया है। यह मेरा पहला प्रयास था:

$ .useless.sh 2> >( ERROR=$(<) )
-bash: command substitution: line 42: syntax error near unexpected token `)'
-bash: command substitution: line 42: `<)'

फिर मैंने कोशिश की

$ ./useless.sh 2> >( ERROR=$( cat <() )  )
This Is Output
$ echo $ERROR   # $ERROR is empty

तथापि

$ ./useless.sh 2> >( cat <() > asdf.txt )
This Is Output
$ cat asdf.txt
This Is Error

तो प्रक्रिया प्रतिस्थापन आम तौर पर सही काम कर रहा है ... दुर्भाग्य से, जब भी मैं एसटीडीआईएन को एक चर में पकड़ने के प्रयास में >( )कुछ के साथ अंदर लपेटता हूं, तो मैं $()सामग्री खो देता हूं $()। मुझे लगता है कि यह इसलिए है क्योंकि $()एक उप प्रक्रिया शुरू की है जो अब फाइल डिस्क्रिप्टर में / dev / fd तक अभिगम नहीं करती है, जो मूल प्रक्रिया के स्वामित्व में है।

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


1
अगर आपने किया ./useless.sh 2> >( ERROR=$( cat <() ); echo "$ERROR" )तो आपको इसका आउटपुट दिखाई देगा ERROR। मुसीबत यह है कि प्रक्रिया प्रतिस्थापन एक उप-शेल में चलाया जाता है, इसलिए उप-शेल में निर्धारित मूल्य मूल शेल को प्रभावित नहीं करता है।
जोनाथन लेफ्लर

0
$ b=$( ( a=$( (echo stdout;echo stderr >&2) ) ) 2>&1 )
$ echo "a=>$a b=>$b"
a=>stdout b=>stderr

3
यह एक अच्छा विचार लगता है, लेकिन मैक OSX 10.8.5 पर, यह प्रिंट करता हैa=> b=>stderr
हीथ बॉर्डर्स

3
मैं @HeathBorders से सहमत हूँ; यह दिखाए गए आउटपुट का उत्पादन नहीं करता है। यहां परेशानी यह है कि aमूल्यांकन किया जाता है और एक उप-शेल में असाइन किया जाता है, और उप-शेल में असाइनमेंट पैरेंट शेल को प्रभावित नहीं करता है। (उबंटू 14.04 एलटीएस के साथ-साथ मैक ओएस एक्स 10.10.1 पर परीक्षण किया गया।)
जोनाथन

विंडोज GitBash में भी ऐसा ही है। तो, यह काम नहीं करता है। ( GNU bash, version 4.4.12(1)-release (x86_64-pc-msys))
किर्बी

SLE 11.4या तो काम नहीं करता है और @JonathanLeffler द्वारा वर्णित प्रभाव पैदा करता है
स्मार्बर

हालांकि यह कोड इस प्रश्न का उत्तर दे सकता है, कि यह कोड क्यों और / या इस बारे में अतिरिक्त संदर्भ प्रदान करता है कि यह प्रश्न इसके दीर्घकालिक मूल्य में सुधार करता है।
β.βοιτ.βε


0

अपने आदेशों को प्रमाणित करने में त्रुटि के लिए :

execute [INVOKING-FUNCTION] [COMMAND]

execute () {
    function="${1}"
    command="${2}"
    error=$(eval "${command}" 2>&1 >"/dev/null")

    if [ ${?} -ne 0 ]; then
        echo "${function}: ${error}"
        exit 1
    fi
}

झुक विनिर्माण में प्रेरित :


मुहावरेदार समाधान के अंदर असाइनमेंट को खत्म करना है if। मुझे एक अलग समाधान पोस्ट करें।
ट्रिपल


0

YellowApple के जवाब में सुधार :

यह किसी भी वैरिएबल में स्टैडर को कैप्चर करने के लिए एक बैश फ़ंक्शन है

stderr_capture_example.sh:

#!/usr/bin/env bash

# Capture stderr from a command to a variable while maintaining stdout
# @Args:
# $1: The variable name to store the stderr output
# $2: Vararg command and arguments
# @Return:
# The Command's Returnn-Code or 2 if missing arguments
function capture_stderr {
  [ $# -lt 2 ] && return 2
  local stderr="$1"
  shift
  {
    printf -v "$stderr" '%s' "$({ "$@" 1>&3; } 2>&1)"
  } 3>&1
}

# Testing with a call to erroring ls
LANG=C capture_stderr my_stderr ls "$0" ''

printf '\nmy_stderr contains:\n%s' "$my_stderr"

परिक्षण:

bash stderr_capture_example.sh

आउटपुट:

 stderr_capture_example.sh

my_stderr contains:
ls: cannot access '': No such file or directory

इस फ़ंक्शन का उपयोग किसी dialogकमांड के लौटे विकल्प को पकड़ने के लिए किया जा सकता है ।

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