`सेट -x` जैसे शेल विकल्पों के मूल्य को कैसे पुनर्स्थापित करें?


47

मैं set -xअपनी स्क्रिप्ट की शुरुआत में और इसे "पूर्ववत करना" चाहता हूं (अंधाधुंध सेट करने से पहले राज्य में वापस जाऊंगा) +x। क्या यह संभव है?

पुनश्च: मैं पहले ही यहाँ जाँच कर चुका हूँ ; जहाँ तक मैं बता सकता हूँ मेरे सवाल का जवाब नहीं लगता था।

जवाबों:


58

सार

रिवर्स करने के लिए set -xबस एक निष्पादित करें set +x। ज्यादातर समय, एक स्ट्रिंग set -strका उलटा एक ही स्ट्रिंग है +: a set +str

सामान्य तौर पर, सभी को पुनर्स्थापित करने के लिए (बैश के बारे में नीचे पढ़ें errexit) शेल विकल्प ( setकमांड के साथ बदला हुआ ) जो आप कर सकते हैं (नीचे दिए गए shoptविकल्पों के बारे में भी पढ़ें ):

oldstate="$(set +o); set -$-"                # POSIXly store all set options.
.
.
set -vx; eval "$oldstate"         # restore all options stored.

लंबा विवरण

दे घुमा के

यह आदेश:

shopt -po xtrace

एक निष्पादन योग्य स्ट्रिंग उत्पन्न करेगा जो विकल्प की स्थिति को दर्शाता है। pझंडा साधन प्रिंट, और oध्वज को निर्दिष्ट है कि हम के बारे में विकल्प (रों) सेट से पूछ रहे हैं setआदेश (के रूप में द्वारा करने का विकल्प (रों) सेट का विरोध shoptआदेश)। आप इस स्ट्रिंग को एक चर में असाइन कर सकते हैं, और प्रारंभिक स्थिति को पुनर्स्थापित करने के लिए अपनी स्क्रिप्ट के अंत में चर को निष्पादित कर सकते हैं।

# store state of xtrace option.
tracestate="$(shopt -po xtrace)"

# change xtrace as needed
echo "some commands with xtrace as externally selected"
set -x
echo "some commands with xtrace set"

# restore the value of xtrace to its original value.
eval "$tracestate"

यह समाधान एक साथ कई विकल्पों के लिए काम करता है:

oldstate="$(shopt -po xtrace noglob errexit)"

# change options as needed
set -x
set +x
set -f
set -e
set -x

# restore to recorded state:
set +vx; eval "$oldstate"

जोड़ने set +vxसे बचा जाता है विकल्प की एक लंबी सूची का मुद्रण।


और, यदि आप कोई विकल्प नाम सूचीबद्ध नहीं करते हैं,

oldstate="$(shopt -po)"

यह आपको सभी विकल्पों का मान देता है। और, यदि आप oध्वज छोड़ते हैं, तो आप shoptविकल्पों के साथ भी ऐसा कर सकते हैं :

# store state of dotglob option.
dglobstate="$(shopt -p dotglob)"

# store state of all options.
oldstate="$(shopt -p)"

यदि आपको यह जांचने की आवश्यकता है कि क्या कोई setविकल्प निर्धारित किया गया है, तो यह करने के लिए सबसे मुहावरेदार (बाश) तरीका है:

[[ -o xtrace ]]

जो अन्य दो समान परीक्षणों से बेहतर है:

  1. [[ $- =~ x ]]
  2. [[ $- == *x* ]]

किसी भी परीक्षण के साथ, यह काम करता है:

# record the state of the xtrace option in ts (tracestate):
[ -o xtrace ] && ts='set -x' || ts='set +x'

# change xtrace as needed
echo "some commands with xtrace as externally selected"
set -x
echo "some commands with xtrace set"

# set the xtrace option back to what it was.
eval "$ts"

एक shoptविकल्प की स्थिति का परीक्षण कैसे करें :

if shopt -q dotglob
then
        # dotglob is set, so “echo .* *” would list the dot files twice.
        echo *
else
        # dotglob is not set.  Warning: the below will list “.” and “..”.
        echo .* *
fi

POSIX

सभी setविकल्पों को संग्रहीत करने के लिए एक सरल, POSIX- संगत समाधान है:

set +o

जिसे पोसिक्स मानक में वर्णित किया गया है :

+ ओ

    एक मानक विकल्प में वर्तमान आउटपुट सेटिंग्स को मानक आउटपुट में लिखें जो शेल के लिए पुन: उत्पन्न करने के लिए उपयुक्त है जो कमांड के समान विकल्प सेटिंग्स को प्राप्त करते हैं।

तो, बस:

oldstate=$(set +o)

setकमांड का उपयोग करके निर्धारित सभी विकल्पों के लिए मानों को संरक्षित करेगा ।

फिर से, उनके मूल मानों के विकल्पों को पुनर्स्थापित करना चर को निष्पादित करने का विषय है:

set +vx; eval "$oldstate"

यह बैश के उपयोग के बराबर है shopt -po। ध्यान दें कि यह सभी संभावित बैश विकल्पों को कवर नहीं करेगा , जैसा कि उनमें से कुछ द्वारा निर्धारित किया गया है ।shopt

विशेष मामला bash

shoptबाश में सूचीबद्ध कई अन्य शैल विकल्प हैं :

$ shopt
autocd          off
cdable_vars     off
cdspell         off
checkhash       off
checkjobs       off
checkwinsize    on
cmdhist         on
compat31        off
compat32        off
compat40        off
compat41        off
compat42        off
compat43        off
complete_fullquote  on
direxpand       off
dirspell        off
dotglob         off
execfail        off
expand_aliases  on
extdebug        off
extglob         off
extquote        on
failglob        off
force_fignore   on
globasciiranges off
globstar        on
gnu_errfmt      off
histappend      on
histreedit      off
histverify      on
hostcomplete    on
huponexit       off
inherit_errexit off
interactive_comments    on
lastpipe        on
lithist         off
login_shell     off
mailwarn        off
no_empty_cmd_completion off
nocaseglob      off
nocasematch     off
nullglob        off
progcomp        on
promptvars      on
restricted_shell    off
shift_verbose   off
sourcepath      on
xpg_echo        off

जिन्हें ऊपर सेट किए गए वैरिएबल से जोड़ा जा सकता है और उसी तरह से बहाल किया जा सकता है:

$ oldstate="$oldstate;$(shopt -p)"
.
.                                   # change options as needed.
.
$ eval "$oldstate" 

यह करना संभव है (यह $-सुनिश्चित करने के लिए जोड़ा जाता है कि errexitसंरक्षित है):

oldstate="$(shopt -po; shopt -p); set -$-"

set +vx; eval "$oldstate"             # use to restore all options.

नोट : प्रत्येक शेल में सेट या अनसेट (विकल्पों में उल्लिखित विभिन्न विकल्पों का उल्लेख नहीं करने के लिए) की सूची बनाने के लिए थोड़ा अलग तरीका है, इसलिए स्ट्रिंग्स शेल के बीच पोर्टेबल नहीं हैं, लेकिन समान शेल के लिए मान्य हैं।

zsh विशेष मामला

zsh5.3 संस्करण के बाद से भी (POSIX के बाद) सही ढंग से काम करता है। पिछले संस्करणों में यह केवल आंशिक रूप से पॉसिक्स का अनुसरण करता set +oथा जिसमें यह एक प्रारूप में विकल्पों को मुद्रित करता था जो कमांड के रूप में शेल के लिए पुन: विवाद के लिए उपयुक्त था, लेकिन केवल सेट विकल्पों के लिए (यह अन-सेट विकल्पों को प्रिंट नहीं करता था )।

mksh विशेष मामला

Mksh (और परिणाम lksh द्वारा) अभी तक (MIRBSD KSH R54 2016/11/11) ऐसा करने में सक्षम नहीं है। Mksh मैनुअल में यह शामिल है:

भविष्य के संस्करण में, सेट + ओ वर्तमान विकल्पों को पुनर्स्थापित करने के लिए पॉसिक्स अनुरूप और प्रिंट कमांड का व्यवहार करेगा।

सेट-विशेष मामला

बाश में, set -e( errexit) का मूल्य उप-गोले के अंदर रीसेट किया जाता है, जिससे set +oएक $ (…) उप-खोल के साथ इसके मूल्य को पकड़ना मुश्किल हो जाता है।

वर्कअराउंड के रूप में, उपयोग करें:

oldstate="$(set +o); set -$-"

21

अल्मक्विस्ट शेल और डेरिवेटिव के साथ ( dash,, नेटबीएसडी / फ्रीबीएसडी shकम से कम) और bash4.4 या इसके बाद के संस्करण के साथ, आप एक फ़ंक्शन के साथ विकल्प को स्थानीय बना सकते हैं local -( $-यदि आपको पसंद है तो चर को स्थानीय बनाएं ):

$ bash-4.4 -c 'f() { local -; set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace

यही कारण है कि पर लागू नहीं होता sourced फ़ाइलें, लेकिन आप को फिर से परिभाषित कर सकते हैं sourceके रूप में source() { . "$@"; }है कि चारों ओर काम करने के लिए।

साथ ksh88, विकल्प परिवर्तन डिफ़ॉल्ट रूप से कार्य करने के लिए स्थानीय कर रहे हैं। इसके साथ ksh93, function f { ...; }सिंटैक्स के साथ परिभाषित कार्यों के लिए केवल यही मामला है (और स्कोप ksh88 सहित अन्य गोले में उपयोग किए जाने वाले गतिशील स्कूपिंग की तुलना में स्थिर है):

$ ksh93 -c 'function f { set -x; echo test; }; f; echo no trace'
+ echo test
test
no trace

में zsh, यह localoptionsविकल्प के साथ किया गया है:

$ zsh -c 'f() { set -o localoptions; set -x; echo test; }; f; echo no trace'
+f:0> echo test
test
no trace

POSIXly, आप कर सकते हैं:

case $- in
  (*x*) restore=;;
  (*) restore='set +x'; set -x
esac
echo test
{ eval "$restore";} 2> /dev/null
echo no trace

हालाँकि कुछ गोले + 2> /dev/nullपुनर्स्थापना पर उत्पादन करेंगे (और यदि आप पहले से सक्षम हैं तो निश्चित रूप से उस निर्माण के निशान को देखेंगे )। वह दृष्टिकोण भी फिर से प्रवेश नहीं करता है (जैसे कि यदि आप किसी फ़ंक्शन में ऐसा करते हैं जो स्वयं या किसी अन्य फ़ंक्शन को कॉल करता है जो उसी चाल का उपयोग करता है)।caseset -x

देखें https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh कैसे एक ढेर है कि चारों ओर है कि काम करता है को लागू करने के लिए (चर और POSIX गोले के लिए विकल्प के लिए स्थानीय क्षेत्र)।

किसी भी शेल के साथ, आप विकल्पों के दायरे को सीमित करने के लिए उप-श्रेणियों का उपयोग कर सकते हैं

$ sh -c 'f() (set -x; echo test); f; echo no trace'
+ echo test
test
no trace

हालांकि, वह सब कुछ (चर, कार्य, उपनाम, पुनर्निर्देशन, वर्तमान कार्य निर्देशिका ...) के दायरे को सीमित करता है, न कि केवल विकल्प।


बैश 4.4 4 दिन पहले (16-सितंबर -2016) आया था, इसलिए शायद आपको इसे खुद को फिर से स्थापित करना होगा, लेकिन क्यों नहीं
edi9999

यह मुझे लगता है कि oldstate=$(set +o)सभी विकल्पों को संग्रहीत करने का एक सरल (और POSIX) तरीका है।
सोरंटार

@sorontar, अच्छी बात यह है कि यह शेल कार्यान्वयन के लिए काम नहीं करता है जैसे pdksh/ mksh(और अन्य pdksh डेरिवेटिव) या zshजहां set +oकेवल डिफ़ॉल्ट सेटिंग्स से विचलन को आउटपुट करता है। यह बैश / डैश / यश के लिए काम करेगा लेकिन पोर्टेबल नहीं होगा।
स्टीफन चेज़लस

13

आप $-शुरुआत में चर को देख सकते हैं कि क्या -xसेट किया गया है या नहीं और फिर इसे एक चर जैसे उदाहरण में सहेजें

if [[ $- == *x* ]]; then
  was_x_set=1
else
  was_x_set=0
fi

से बैश मैनुअल :

($ -, एक हाइफ़न।) मौजूदा विकल्प झंडे के लिए विस्तार के रूप में, आह्वान पर, सेट बिलिन कमांड या शेल द्वारा स्वयं निर्धारित किए गए (जैसे -i विकल्प) के रूप में फैलता है।


7
[[ $SHELLOPTS =~ xtrace ]] && wasset=1
set -x
echo rest of your script
[[ $wasset -eq 0 ]] && set +x

बैश में, $ SHELLOPTS को उन झंडों के साथ सेट किया जाता है जिन्हें चालू किया जाता है। इससे पहले कि आप xtrace को ऑन करें, और पहले से बंद होने पर ही xtrace को रीसेट करें।


5

बस स्पष्ट रूप से बताने के लिए, यदि set -xस्क्रिप्ट की अवधि के लिए प्रभावी होना है, और यह सिर्फ एक अस्थायी परीक्षण उपाय है (स्थायी रूप से उत्पादन का हिस्सा नहीं होना है), तो या तो स्क्रिप्ट w / -xविकल्प का आह्वान करें , जैसे,

$ bash -x path_to_script.sh

... या, -xविकल्प को जोड़कर डीबग आउटपुट को सक्षम करने के लिए स्क्रिप्ट (पहली पंक्ति) को अस्थायी रूप से बदलें :

#!/bin/bash -x
...rest of script...

मुझे एहसास है कि आप जो चाहते हैं उसके लिए शायद यह बहुत व्यापक है, लेकिन यह अस्थायी रूप से स्क्रिप्ट के साथ जटिल किए बिना / अक्षम करने का सबसे सरल और तेज तरीका है, जिसे आप शायद वैसे भी निकालना चाहते हैं (मेरे अनुभव में)।


3

यह POSIX $-विशेष पैरामीटर के माध्यम से दिखाई देने वाले झंडे को बचाने और पुनर्स्थापित करने के लिए कार्य प्रदान करता है । हम localस्थानीय चरों के लिए एक्सटेंशन का उपयोग करते हैं । पोर्टेबल स्क्रिप्ट के अनुरूप POSIX में, वैश्विक चर का उपयोग किया जाएगा (कोई localकीवर्ड नहीं ):

save_opts()
{
  echo $-
}

restore_opts()
{
  local saved=$1
  local on
  local off=$-

  while [ ${#saved} -gt 0 ] ; do
    local rest=${saved#?}
    local first=${saved%$rest}

    if echo $off | grep -q $first ; then
      off=$(echo $off | tr -d $first)
    fi

    on="$on$first"
    saved=$rest
  done

  set ${on+"-$on"} ${off+"+$off"}
}

इसका उपयोग इसी तरह से किया जाता है कि कैसे लिनक्स कर्नेल में झंडे को बचाया और पुनर्स्थापित किया जाता है:

Shell:                                Kernel:

flags=$(save_opts)                    long flags;
                                      save_flags (flags);

set -x  # or any other                local_irq_disable(); /* disable irqs on this core */

# ... -x enabled ...                  /* ... interrupts disabled ... */

restore_opts $flags                   restore_flags(flags);

# ... x restored ...                  /* ... interrupts restored ... */

यह किसी भी विस्तारित विकल्प के लिए काम नहीं करेगा जो कि $-चर में शामिल नहीं हैं ।

बस इस बात पर ध्यान दिया जाता है कि POSIX के पास वह चीज है जिसकी मैं तलाश कर रहा था: का +oतर्क setकोई विकल्प नहीं है, लेकिन एक कमांड जो कमांड का एक गुच्छा डंप करता है, अगर eval-ed विकल्पों को पुनर्स्थापित करेगा। इसलिए:

flags=$(set +o)

set -x

# ...

eval "$flags"

बस।

एक छोटी समस्या यह है कि यदि -xविकल्प को इससे पहले चालू किया जाता है eval, तो set -oआदेशों की एक बदसूरत हड़बड़ाहट देखी जाती है। इसे समाप्त करने के लिए, हम निम्नलिखित कार्य कर सकते हैं:

set +x             # turn off trace not to see the flurry of set -o.
eval "$flags"      # restore flags

1

आप एक उप-शेल का उपयोग कर सकते हैं।

(
   set 
   do stuff
)
Other stuff, that set does not apply to
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.