Set -x gibi kabuk seçeneklerinin değeri nasıl geri alınır?


47

Ben istiyorum set -xkörlemesine ayar sonradan bunun yerine (ben ayarladıktan önceki haline geri dönmek) Senaryomun başında ve "geri alma" da +x. Mümkün mü?

Not: Zaten burada kontrol ettim ; Bu, söyleyebileceğim kadarıyla sorumu cevaplamadı.

Yanıtlar:


58

Soyut, Özet

set -xSadece bir tersine çevirmek için a set +x. Bir dizgenin tersi çoğu zaman set -stra +: ile aynı dizgedir set +str.

Genel olarak, hepsini geri yüklemek için (bash hakkında aşağıda okuyun errexit) kabuk seçeneklerini ( setkomutla değiştirildi ) yapabilecekleriniz (bash shoptseçenekleri hakkında aşağıda da okuyun ):

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

Daha uzun açıklama

darbe

Bu komut:

shopt -po xtrace

seçeneğin durumunu yansıtan yürütülebilir bir dize oluşturur. pBayrak araçları yazdırmak ve obiz tarafından seçeneği (s) kümesi hakkında soruyorsun bayrak belirtir set(tarafından seçeneği (ler) kümesine karşı komuta shoptkomuta). Bu dizeyi bir değişkene atayabilir ve ilk durumu geri yüklemek için değişkeni komut dosyanızın sonunda yürütebilirsiniz.

# 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"

Bu çözüm aynı anda birden fazla seçenek için çalışıyor:

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"

Ekleme set +vx, uzun bir seçenekler listesinin yazdırılmasını engeller.


Ve, seçenek adlarını listelemezseniz,

oldstate="$(shopt -po)"

size tüm seçeneklerin değerlerini verir. oBayraktan dışarı çıkarsanız, aynı şeyleri shoptseçeneklerle de yapabilirsiniz:

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

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

Bir setseçeneğin ayarlanıp ayarlanmadığını test etmeniz gerekirse, bunu yapmanın en salak (Bash) yolu şudur:

[[ -o xtrace ]]

diğer iki benzer testten daha iyidir:

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

Testlerden herhangi biriyle bu işe yarar:

# 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"

Bir shoptseçeneğin durumunu nasıl test edeceğiniz aşağıda açıklanmaktadır :

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

Tüm setseçenekleri saklamak için POSIX uyumlu basit bir çözümdür :

set +o

olan POSIX standardında tarif edildiği gibidir:

+ o

    Mevcut seçenek ayarlarını standart çıktıya, aynı seçenek ayarlarını elde eden komutlar gibi kabuğa yeniden giriş yapmak için uygun bir formatta yazın.

Yani, basitçe:

oldstate=$(set +o)

setkomutu kullanarak ayarlanan tüm seçeneklerin değerlerini koruyacaktır .

Yine, seçenekleri orijinal değerlerine geri yüklemek, değişkenin yürütülmesinden ibarettir:

set +vx; eval "$oldstate"

Bu, Bash'in kullanımına tam olarak eşdeğerdir shopt -po. O edeceği Not değil kapsayacak tüm olası Bash bu bazıları tarafından oluşturulduğu takdirde seçenekleri shopt.

bash özel durum

shoptBash'da listelenen birçok başka kabuk seçeneği vardır :

$ 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

Bunlar yukarıda ayarlanan değişkene eklenebilir ve aynı şekilde geri yüklenebilir:

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

Bunu yapmak mümkündür ( korunmasını $-sağlamak errexitiçin eklenmiştir ):

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

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

Not : Her kabuğun ayarlanmış veya ayarlanmamış seçeneklerin listesini oluşturmak için biraz farklı bir yolu vardır (tanımlanmış farklı seçeneklerden bahsetmiyorum), bu nedenle dizeler kabuklar arasında taşınabilir değildir, ancak aynı kabuk için geçerlidir.

zsh özel durum

zshayrıca 5.3 sürümünden bu yana (POSIX’ten sonra) doğru şekilde çalışır Önceki sürümlerde sadece kısmen ile POSIX izledi set +oo komutları gibi kabuğuna reinput için uygun bir formatta seçenekleri basılmış ki, ama sadece set seçenekleri (Bu baskı yoktu un-set seçenekleri).

mksh özel durum

Mksh (ve sonuç olarak lksh) henüz bunu yapamamıştır (MIRBSD KSH R54 2016/11/11). Mksh kılavuzu bunu içerir:

Gelecekteki bir sürümde, + o ayarının geçerli seçenekleri geri yüklemek için POSIX uyumlu davranması ve komutları yazdırması gerekir.

set -e özel durum

Bash'te, set -e( errexit) değeri alt kabuklarda sıfırlanır, bu da değerini set +o$ (…) alt kabuğunda yakalamayı zorlaştırır .

Çözüm olarak, şunları kullanın:

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

21

Almquist kabuğu ve türevleri ( dash, shen azından NetBSD / FreeBSD ) ve bash4.4 veya üstü ile, bir işlev için yerel olarak seçenekler yapabilirsiniz local -(isterseniz $-değişkeni yerel yap):

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

Bu kaynaklı dosyalar için geçerli değildir , ancak sourcebunun source() { . "$@"; }üzerinde çalışacak şekilde yeniden tanımlayabilirsiniz .

İle ksh88, seçenek değişiklikleri varsayılan olarak işlev için yereldir. Bu ksh93, sadece function f { ...; }sözdizimi ile tanımlanan işlevler için geçerlidir (ve kapsam, ksh88 dahil diğer kabuklarda kullanılan dinamik kapsamayla karşılaştırıldığında statiktir):

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

In zsh, bu localoptionsseçeneği ile bitti :

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

POSIXly şunları yapabilirsiniz:

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

Bununla birlikte, bazı kabuklar + 2> /dev/nullgeri yükleme işleminde bir çıktı verecektir (ve zaten etkinleştirildiyse bu yapının izini görürsünüz ). Bu yaklaşım aynı zamanda yeniden giriş yapmaz (bunu, kendisini ya da aynı numarayı kullanan başka bir işlevi çağıran bir işlevde yaparsanız).caseset -x

Etrafında çalışan bir yığının nasıl uygulanacağına ilişkin https://github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh (POSIX kabukları için değişkenler ve seçenekler için yerel kapsam) bölümüne bakın .

Herhangi bir kabukla, seçeneklerin kapsamını sınırlamak için alt kabuklar kullanabilirsiniz

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

Ancak bu, sadece seçeneklerin değil, her şeyin kapsamını da sınırlar (değişkenler, işlevler, takma adlar, yönlendirmeler, geçerli çalışma dizini ...).


bash 4.4 4 gün önce yayınlandı (16 eylül-2016), bu yüzden muhtemelen kendiniz derlemek zorunda
kalacaksınız

Bana öyle geliyor ki oldstate=$(set +o)tüm seçenekleri saklamanın daha basit (ve POSIX) bir yolu.
sorontar

@sorontar, pdksh/ mksh(ve diğer pdksh türevleri) gibi kabuk uygulamaları için çalışmayan ya zshda set +oyalnızca varsayılan ayarlardan sapmaları çıktıran iyi bir nokta . Bu bash / dash / yash için işe yarar ancak taşınabilir değildir.
Stéphane Chazelas 21:16

13

Ayarlanmış $-olup olmadığını görmek için değişkeni başında okuyabilir -xve ardından bir değişkene kaydedebilirsiniz.

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

Gönderen Bash kılavuzda :

($ -, bir tire.) Çağrıldığında, set yerleşik komutu ile veya kabuğun kendisi tarafından (-i seçeneği gibi) ayarlanan geçerli seçenek bayraklarına genişletir.


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

Kısaca, $ SHELLOPTS açık olan bayraklarla ayarlanır. Xtrace'i açmadan önce kontrol edin ve yalnızca önceden kapalıysa xtrace'ı sıfırlayın.


5

Açıkça belirtmek gerekirse set -x, betiğin süresi boyunca geçerli olacaksa ve bu sadece geçici bir test önlemidir (çıktının kalıcı bir parçası olmamalıdır), ya da betiği w / -xseçeneği ile çağırın;

$ bash -x path_to_script.sh

... veya, -xseçeneği ekleyerek hata ayıklama çıktısını etkinleştirmek için betiği (ilk satır) geçici olarak değiştirin :

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

Bunun muhtemelen istedikleriniz için çok geniş bir vuruş olduğunu fark ettim, ancak senaryoyu (benim deneyimlerime göre) muhtemelen kaldırmak isteyeceğiniz geçici şeylerle aşırı karmaşık hale getirmeden, etkinleştirmenin / devre dışı bırakmanın en basit ve en hızlı yolu.


3

Bu, POSIX $-özel parametresiyle görünen bayrakları kaydetme ve geri yükleme işlevlerini sağlar . localYerel değişkenler için uzantı kullanıyoruz . POSIX uyumlu bir taşınabilir komut dosyasında, genel değişkenler kullanılır ( localanahtar kelime yok ):

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"}
}

Bu, kesme bayraklarının Linux çekirdeğinde nasıl kaydedildiğine ve geri yüklendiğine benzer şekilde kullanılır:

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 ... */

Bu, $-değişkende ele alınmayan genişletilmiş seçeneklerin hiçbirinde işe yaramaz .

Sadece POSIX'in aradığım şeye sahip olduğunu fark ettim: +oargümanı setbir seçenek değil, eğer varsa eval, seçenekleri geri yükleyecek bir sürü komuttan oluşan bir komut . Yani:

flags=$(set +o)

set -x

# ...

eval "$flags"

Bu kadar.

Küçük bir sorun, eğer -xseçenek bundan önce döndürülürse eval, çirkin bir set -okomut dalgası görülür. Bunu ortadan kaldırmak için aşağıdakileri yapabiliriz:

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

1

Bir alt kabuk kullanabilirsiniz.

(
   set 
   do stuff
)
Other stuff, that set does not apply to
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.