कैसे एक चर के रूप में 2> / देव / अशक्त पारित करने के लिए?


13

मेरे पास यह कोड है जो काम करता है:

# Hide irrelevant errors so chrome doesn't email us in cron
if [[ $fCron == true ]] ; then
    google-chrome --headless --disable-gpu --dump-dom \
        "$RobWebAddress" > "$DownloadName" 2>/dev/null
else
    # Get silly error messages when running from terminal
    google-chrome --headless --disable-gpu --dump-dom \
        "$RobWebAddress" > "$DownloadName"
fi

अगर मैं इसे इस तरह छोटा करने की कोशिश करूं:

# Hide irrelevant errors so chrome doesn't email us in cron
local HideErrors
[[ $fCron == true ]] && HideErrors="2>/dev/null"

google-chrome --headless --disable-gpu --dump-dom \
    "$RobWebAddress" > "$DownloadName" "$HideErrors"

मुझे त्रुटि संदेश मिले:

[0826/043058.634775:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.672587:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
[0826/043058.711640:ERROR:headless_shell.cc(597)] Open multiple tabs is only supported when remote debugging is enabled.
(... SNIP ...)

एक हार्ड-कोडेड तर्क क्यों काम करता है लेकिन एक चर के रूप में एक तर्क नहीं है?


2 संपादित करें:

वर्तमान में मुझे दूसरे उत्तर के वैकल्पिक सुझाव के साथ सफलता मिली:

# Redirect errors when cron is used to /dev/null to reduce emails
ErrorPipe=/dev/stderr
[[ $fCron == true ]] && ErrorPipe=/dev/null

google-chrome --headless --disable-gpu --dump-dom \
                "$RobWebAddress" > "$DownloadName" 2>"$ErrorPipe"

1 संपादित करें:

पहले उत्तर के आधार पर, मुझे पहले से ही शामिल प्रोग्राम हेडर को इंगित करना चाहिए:

[[ $fCron != true ]] &&
    exec 2> >(grep -v 'GtkDialog mapped without a transient parent' >&2)

आप [[ $fCron == true ]] && exec 2>/dev/nullइसके बजाय कोशिश कर सकते हैं
स्टीलड्राइव

.. मोटे तौर पर, यह इसलिए है क्योंकि शेल चर का विस्तार करने से पहले पुनर्निर्देशन स्थापित करता है, मुझे लगता है। उदाहरण के लिए बैश
स्टडआउट

जवाबों:


19

विस्तार करने से आप पुनर्निर्देशन का कारण नहीं बन सकते हैं, यह "$HideErrors"है कि जैसे प्रतीकों को >विशेष रूप से पैरामीटर विस्तार द्वारा उत्पादित किए जाने के बाद इलाज नहीं किया जाता है । यह वास्तव में बहुत अच्छा है, क्योंकि इस तरह के प्रतीक पाठ में दिखाई देते हैं जिन्हें आप शाब्दिक रूप से विस्तारित और उपयोग करना चाहते हैं।

यह आप धारण करते हैं या नहीं $HideErrors। पैरामीटर विस्तार का परिणाम शब्द के विभाजन और ग्लोबिंग के अधीन होता है जब विस्तार निर्विवाद होता है, लेकिन यह है।


इसके बारे में क्या करना है, सशर्त पुनर्निर्देशन प्राप्त करने के कई तरीके हैं। एक बहुत ही सरल आदेश के लिए, यह उचित हो सकता है कि संपूर्ण कमांड को दो बार लिखें, एक बार - caseया if- elseकंस्ट्रक्शन की प्रत्येक शाखा में । हालांकि, यह जल्द ही बोझ बन जाता है, और आपके द्वारा दिखाई गई कमांड निश्चित रूप से एक ऐसा मामला है जहां यह आदर्श नहीं होगा।

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

पुनर्निर्देशन के बजाय कमांड स्टोर करें। एक चर में पुनर्निर्देशन को स्टोर करने और पैरामीटर विस्तार को लागू करने के बजाय, शेल फ़ंक्शन में कमांड स्टोर करें । फिर एक caseया if- लिखें else, जिसमें फ़ंक्शन को एक शाखा पर पुनर्निर्देशन और दूसरे पर इसके बिना कहा जाता है।

यदि आप अपने कमांड को उस कोड के रूप में अवधारणा बनाते हैं जिसे आप एक बार लिखना चाहते हैं लेकिन कई परिस्थितियों में चलाते हैं, तो एक फ़ंक्शन प्राकृतिक समाधान है। यह वही है जो मैं आमतौर पर करता हूं। इसमें न तो सबस्क्रिप्शन की जरूरत है और न ही मैनुअल स्टोरेज और स्टेट को रीसेट करने की।

आपके कोड के साथ:

launch() {
    google-chrome --headless --disable-gpu --dump-dom \
        "$RobWebAddress" > "$DownloadName"
}

case $fCron in
true)  launch 2>/dev/null;;
*)     launch;; # Get silly error messages when running from terminal
esac

यदि आप चाहें, तो आप जो चाहें, या if- जैसे चाहें रिक्ति लागू कर सकते elseहैं। ध्यान दें कि launchस्वचालित रूप से कॉलर RobWebAddressऔर DownloadNameचर का उपयोग करता है , भले ही वे स्थानीय चर हों, क्योंकि बैश गतिशील रूप से सबसे प्रोग्रामिंग भाषाओं के विपरीत, जो लेक्सिक रूप से स्कोप हैं।

एक सब-कमांड में कमांड चलाएँ और सशर्त रूप से पुनर्निर्देशन लागू करें execयह क्या है के बारे में टिप्पणी की steeldriver , लेकिन अंदर ( )प्रभाव स्थानीय रखने के लिए । जब builtin कोई तर्क के साथ चलाया जाता है, यह एक नई प्रक्रिया के साथ वर्तमान खोल को प्रतिस्थापित नहीं करता, लेकिन इसके बजाय मौजूदा खोल करने के लिए अपने पुनर्निर्देशन के किसी भी लागू होता है।exec

(यह भी संभव है कि मानक त्रुटि क्या थी, इसे ट्रैक रखना और इसे फिर से स्थापित करना, बिना सबस्क्रिप्शन का उपयोग किए और इस प्रकार वर्तमान शेल के वातावरण को संशोधित करने की क्षमता का त्याग किए बिना। मैं उस विवरण को अन्य उत्तरों पर छोड़ दूंगा, हालांकि।)

आपके कोड के साथ:

(
    # Suppress silly error messages unless running from terminal
    case $fCron in true) exec 2>/dev/null;; esac

    google-chrome --headless --disable-gpu --dump-dom \
        "$RobWebAddress" > "$DownloadName"
)

समापन के बाद ), मानक त्रुटि प्रभाव में है जो कुछ भी पहले था, क्योंकि यह वास्तव में केवल उपधारा में पुनर्निर्देशित किया जा रहा है, और मूल शेल में नहीं। यह, मौजूदा शेल वेरिएबल्स के साथ भी ठीक काम करता है, क्योंकि सबस्क्रिप्शन वालों को इसकी एक कॉपी मिलती है। हालांकि मैं एक शेल फ़ंक्शन का उपयोग करना पसंद करता हूं, मैं मानता हूं कि इस विधि को कम कोड की आवश्यकता हो सकती है।

दोनों पद्धतियाँ इस बात पर ध्यान दिए बिना काम करती हैं कि फ़ाइल या डिवाइस मानक त्रुटि क्या है, जिसमें शेल कार्यों पर लागू पुनर्निर्देशन के मामले शामिल हैं, जो उस कोड को कहते हैं जिसमें सशर्त व्यवहार होता है, साथ ही मामला (आपके संपादन में उल्लिखित) जिसमें मानक त्रुटि होती है संपूर्ण स्क्रिप्ट पहले से ही पहले से पुनर्निर्देशित हो चुकी है या । पथ प्रतिस्थापन प्रक्रिया प्रतिस्थापन द्वारा उत्पादित किया गया था कोई समस्या नहीं है।exec 2>&fdexec 2> path


FYI करें SteelDriver के बारे में कुछ execपता नहीं है कि क्या वह उस पर जवाब की योजना बना रहा है ...
WinEunuuchs2Unix

@ WinEunuuchs2Unix मुझे आशा है कि ऐसा उत्तर अभी भी पोस्ट किया गया है। हालांकि मैं मुख्य रूप से एक फ़ंक्शन का उपयोग करने की सलाह देता हूं, मैंने एक विधि भी शामिल की जिसमें पुनर्निर्देशन शामिल था exec। लेकिन, जैसा कि मैंने पैतृक रूप से उल्लेख किया है, मैंने अधिक परिष्कृत अनुप्रयोगों को कवर नहीं किया है जहां पुरानी फ़ाइल विवरणक को रखा गया है और बिना सबस्क्रिप्शन के बहाल किया गया है। मैंने कम परिष्कृत अनुप्रयोगों को भी कवर नहीं किया , जैसे कि यदि यह स्क्रिप्ट का अंत है तो पुनर्निर्देशन रखना। एक अन्य उत्तर, यदि पोस्ट किया गया है, दोनों को कवर कर सकता है, और शायद अधिक।
एलियाह कगन

मैंने अपना प्रश्न एक मौजूदा के साथ अद्यतन किया है execजो आपके उत्तर को मेरे विचार से प्रभावित नहीं करना चाहिए।
विनयुनुच्स 2 यूनिक्स

@ WinEunuuchs2Unix हाँ, कोई समस्या नहीं होनी चाहिए। मैंने उत्तर के अंत में इसके बारे में एक अनुच्छेद जोड़ा है।
एलियाह कगन

दिलचस्प रहस्योद्घाटन अपने जवाब को पढ़ने, RobWebAddressनिश्चित रूप से वैश्विक संदर्भ है। DownloadNameस्थानीय रूप से परिभाषित किया गया था लेकिन वैश्विक संदर्भ होना चाहिए। किसी कारण से बाल कार्य माता-पिता की स्थानीय परिभाषाओं को प्राप्त करने के लिए ( कार्य DownloadNameकरने के लिए DownloadAsHTML ()कार्य करने के लिए दिखाई दे रहा था जिसे UpdateOne ()स्थानीय के रूप में परिभाषित किया गया है। यह एक कठिन दिन है :(
WinEunuuchs2Unix

4

एक हार्ड-कोडेड तर्क क्यों काम करता है लेकिन एक चर के रूप में एक तर्क नहीं है?

क्योंकि सिंटैक्स आइटम को विस्तृत चर मानों से व्याख्यायित नहीं किया जाता है। यही है, चर विस्तार कमांड लाइन में चर के पाठ के साथ चर संदर्भ को बदलने के समान नहीं है। (सामग्री की तरह ;, |, &&और उद्धरण आदि भी चरों के मान में विशेष नहीं हैं।)

आप क्या कर सकते हैं उपनाम का उपयोग करें, या केवल पुनर्निर्देशन के लक्ष्य को रखने के लिए चर का उपयोग करें।

उपनाम हैं तो वे सिर्फ एक पाठ प्रतिस्थापन कर सकते हैं वाक्यात्मक आइटम, ऑपरेटरों और कीवर्ड की तरह पकड़ो। स्क्रिप्ट में, आपको इसकी आवश्यकता होगी shopt expand_aliases, क्योंकि डिफ़ॉल्ट रूप से वे गैर-इंटरैक्टिव गोले में अक्षम हैं। तो, यह प्रिंट 2(केवल):

#!/bin/bash
shopt -s expand_aliases

alias redir='> /dev/null'
redir echo 1
alias redir=''
redir echo 2

(और आप भी alias jos=if niin=then soj=fiफिनिश में अपने सभी if-बयान लिख सकते हैं और मुझे यकीन है कि स्क्रिप्ट पढ़ने वाला कोई भी व्यक्ति आपसे प्यार करेगा।)

वैकल्पिक रूप से, रीडायरेक्शन को हमेशा लिखें, लेकिन एक चर के साथ लक्ष्य को नियंत्रित करें। तुम्हें पता है, जहां उत्पादन हो जाता है इस मामले में जहां आप बदलना नहीं चाहते के लिए नो-सेशन लक्ष्य होना चाहिए, हालांकि जाएगा लेकिन /dev/stderrउस मामले में काम करना चाहिए। दरअसल, 2> /dev/stderrजिस तरह से लिनक्स /proc/<pid>/fdमूल से स्वतंत्र के रूप में fd के खुलने का व्यवहार करता है , उसे जोड़ने से कोई नुकसान नहीं होता है । यह लिखने की स्थिति की स्थिति को प्रभावित करता है और अगर यह एक नियमित फ़ाइल में जाता है तो आउटपुट को गड़बड़ कर देगा।

इसे एपेंड मोड में काम करना चाहिए, हालांकि (या यदि स्टडर पाइप या टर्मिनल पर जाता है):

#!/bin/sh
exec 2>/tmp/error.log
dst=/dev/null
ls -l /nosuchfile-1 2>> "$dst"     # this doesn't print
dst=/dev/stderr
ls -l /nosuchfile-2 2>> "$dst"
ls -l /nosuchfile-3 2>> "$dst"

इसलिए दोहराने के लिए: 2> /dev/stderrटूट सकता है।


हाहाहा, मैं केवल फिनिश इफ्स का उपयोग अभी से काम पर करूँगा। :>
मिठाई

मुझे वैकल्पिक सुझाव पसंद है। विचार expand_aliasesडरावना है क्योंकि आपके कार्यक्रम को ~/.bashrcमेरे विचार से बंधक बनाया जा सकता है।
विनयुनुच्स 2 यूनिक्स

1
@ WinEunuuchs2Unix, हाँ, expand_aliasesथोड़ा डरावना है। लेकिन ~/.bashrcयह एक समस्या नहीं होनी चाहिए क्योंकि यह केवल इंटरेक्टिव शेल द्वारा पढ़ा जाता है, और .profileजो मित्र इसे कॉल कर सकते हैं वे केवल लॉगिन शेल द्वारा पढ़े जाते हैं। स्क्रिप्ट की तरह नॉनएक्टिव एक्टिव नॉन-लॉगिन गोले उनमें से किसी को भी नहीं चलाना चाहिए। (लेकिन फिर वहाँ है $BASH_ENV, और जाहिरा तौर .bashrcपर पढ़ा जाता है अगर
स्टड

वैसे मैं आपके वैकल्पिक सुझाव को पूरी तरह से समझता हूं और मैं इसे आज रात
आजमाऊंगा

ईमानदारी से कहूं तो मुझे यकीन नहीं है कि अगर मुझे ऐसा करना पड़ा तो मैं इसे किस तरह से लागू करूंगा। मैं शायद किसी फंक्शन या एरे में कमांड स्टोर करूंगा और फिर यह तय करने के लिए ब्रांच करूंगा कि वहां रिडायरेक्शन करना है (किसी फंक्शन का इस्तेमाल दूसरे जवाब में दिखाया गया है)। या कि 2>> "$dst"चाल, लेकिन मुझे अभी पता चला कि यह सामान्य मामले में काम नहीं करता है, इसलिए इसके साथ बेहतर सावधानी बरतें।
ilkachachu

1

प्रश्न का शीर्षक: "चर के रूप में 2> / देव / अशक्त कैसे पारित करें?" यह वास्तव में उपयोग किया जा सकता हैeval

joshua@nova:/tmp$ X=">/dev/null"
joshua@nova:/tmp$ echo $X
>/dev/null
joshua@nova:/tmp$ eval echo $X
joshua@nova:/tmp$ eval echo hi
hi
joshua@nova:/tmp$ eval echo hi $X
joshua@nova:/tmp$ echo hi $X
hi >/dev/null
joshua@nova:/tmp$ 

तो हम फिर से लिख सकते हैं

# Hide irrelevant errors so chrome doesn't email us in cron
local HideErrors
local RobWebAddress2
local DownloadName2
[[ $fCron == true ]] && HideErrors="2>/dev/null"
RobWebAddress2='"$RobWebAddress"'
DownloadName2='>"$DownloadName"'

eval google-chrome --headless --disable-gpu --dump-dom \
    $RobWebAddress2 $DownloadName2 "$HideErrors"

जहाँ अप्रत्यक्ष परिवर्तनीय पहुँच शेष कमांड लाइन पर बहुत जल्द होने से रोकता है।

चर में डबल उद्धरण ठीक काम करते हैं।

joshua@nova:/tmp$ X='"'
joshua@nova:/tmp$ Y='$X'
joshua@nova:/tmp$ eval echo $Y
"
joshua@nova:/tmp$ 

@EliahKagan: प्रश्न शीर्षक: "2> / देव / अशक्त को एक चर के रूप में कैसे पारित करें?"
जोशुआ

ठीक है, यह काम नहीं कर रहा था। मैंने इसे ठीक कर लिया है।
यहोशू

अब फ़ाइल को हमेशा नाम दिया जाता है DownloadName- और शाब्दिक पाठ RobWebAddressहमेशा URL के लिए उपयोग किया जाता है। आप $" "उद्धरण का उपयोग कर रहे हैं । मुझे लगता है कि यह अनजाने में हो सकता है और आप चाहते हैं कि $एस अंदर हो " ", लेकिन आपने इसे दोनों जगहों पर इस तरह से किया है, इसलिए मुझे यकीन नहीं है। मुझे लगता है कि बस > "$DownloadName"इसे ठीक करना चाहिए। लेकिन मैं समझता हूँ कि आप इसे पसंद नहीं कर सकते हैं, क्योंकि गलती से तर्कों और गैर-तर्कों के साथ evalएक कारण यह खतरनाक और व्यापक रूप से हतोत्साहित करने वाला evalव्यवहार है।
एलियाह कगन

@ एलियाकगन: ओह। स्क्रिप्टिंग के लिए मेरा पसंदीदा शेल $ "" उद्धरण नहीं है।
जोशुआ

1
यदि आप इसे ठीक करते हैं, तो यह काम करना चाहिए। और यह हमेशा मनमाना पाठ पर उद्धरण चिपकाने के बारे में सोचना गलत था! यह शाब्दिक तर्कों का निर्माण करता है जो evalमूल्यांकन करने से पहले सहमति देता है। लेकिन मुझे लगता है कि इसे लगाने का एक और तरीका यह है कि यह लिखने का एक शानदार तरीका है जो ओपी कोड eval 'google-chrome --headless --disable-gpu --dump-dom "$RobWebAddress" > "$DownloadName" '"$HideErrors"की उपस्थिति जैसा दिखता है । और सामान्य तौर पर, ऐसे कार्यों का उपयोग evalकरना जिनकी आवश्यकता नहीं है, यह खराब है(इस बहाने से कोई नहीं - और न ही यह भी बताता है - मेरे पुराने उत्तर की गलतता और शत्रुता।)
एलियाह कगन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.