抽象的な

抽象的な

set -xランダムに設定するよりも、スクリプトの先頭で「元に戻す」(設定前の状態に戻る)したいと思います+x。これは可能ですか?

PS:確認しましたここ;私が知っている限り、これは私の質問に対する答えではないようです。

答え1

抽象的な

を元に戻すset -x場合set +x。ほとんどの場合、文字列の反対は:と同じ文字列set -strです。+set +str

通常、すべてのerrexitシェルオプション(bashについては以下を参照)を復元するには(コマンドを使用して変更されますset)、次のことができます(bashshoptオプションについても以下を参照)。

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

十分ですが、bashにはset(or)と一部を介してshopt -poアクセスされる2つのオプションセットがあります。また、bashはshopt -pサブシェルに入ってもset -e持続しません。拡張によって生成されたオプションのリストは、$-シェルに再入力されない可能性があります。

bash で現在の状態全体をキャプチャするには、次のようにします。

oldstate="$(shopt -po; shopt -p)"; [[ -o errexit ]] && oldstate="$oldstate; set -e"

inherit_errexitまたは、フラグ設定が気に入らない場合(そしてbashは≥4.4です):

shopt -s inherit_errexit;    oldstate="$(shopt -po; shopt -p)"

より長い説明

強く打つ

このコマンドは次のとおりです。

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 ]]

これは他の2つの同様のテストよりも優れています。

  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

すべてのオプションを保存するための簡単なPOSIX互換ソリューションはset次のとおりです。

set +o

これはPOSIX規格に記載されているように:

+o

    同じオプション設定を実装するコマンドでシェルに再入力するのに適した形式で、現在のオプション設定を標準出力に書き込みます。

簡単に言えば、

oldstate=$(set +o)

setこのコマンドで設定されたすべてのオプションの値は(一部のシェルでは)保持されます。

同様に、オプションを元の値に復元することは、単に変数を実行する問題です。

set +vx; eval "$oldstate"

これはBashを使用するのと同じですshopt -poいいえ書くみんな可能吹くオプションの一部のみが提供されるためですshopt

バッシュ特別な場合

shoptBashには他の多くのシェルオプションがリストされています。

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

バッシュのset -e特別なケース

set -eBashでは、()の値がerrexitサブシェル内でリセットされるため、set +o$(...)サブシェル内でその値を取得することは困難です。

回避策として、次を使用します。

oldstate="$(set +o)"; [[ -o errexit ]] && oldstate="$oldstate; set -e"

または(ターゲットと競合せずにbashがそれをサポートしている場合)、このinherit_errexitオプションを使用できます。


ノート:各シェルは設定または設定解除オプションのリストを少し異なって作成します(他のオプションが定義されていることは言うまでもありません)、文字列はシェル間で移植可能ではありませんが、同じシェルでは有効です。

zsh特別なケース

zshまた、バージョン5.3(POSIX互換)からもうまく機能します。以前のバージョンでは、set +oシェルにコマンドで再入力するのに適した形式でオプションを印刷するという点で、POSIXに部分的に従いました。置くオプション(印刷されません。未設定オプション)。

mksh特別なケース

mksh(および結果lksh)はまだこれを実行できません(MIRBSD KSH R54 2016/11/11)。 mksh マニュアルには次の内容が含まれています。

今後のリリースでは、set +oがPOSIX仕様で動作し、現在のオプションを復元するコマンドを印刷します。

答え2

Almquistシェルと派生(少なくとも dashNetBSD / FreeBSD)と4.4以降では、オプションを関数のローカル(必要に応じてローカル変数の変数)に設定できます。shbashlocal -$-

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

これは以下には適用されません。源泉ファイルを上書きしてこの問題を解決でき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復元時に出力します(追跡するcaseもちろん、set -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

ただし、これはオプションだけでなく、すべて(変数、関数、エイリアス、リダイレクト、現在の作業ディレクトリ...)の範囲を制限します。

答え3

$-最初に変数を読み込んで設定されて-xいることを確認してから、変数に保存できます。

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

~からバッシュマニュアル:

($-、ハイフン。)呼び出し時に指定された現在のオプションフラグ、組み込み設定によって設定されるか、シェル自体によって設定(例:-iオプション)に拡張されます。

答え4

確実にするために、set -xこれがスクリプト期間中に有効で一時テスト測定にすぎない場合(出力の永続的な部分ではない)、オプションを使用してスクリプトを呼び出します-x

$ bash -x path_to_script.sh

...またはオプションを追加してデバッグ出力を有効にするようにスクリプト(最初の行)を一時的に変更します-x

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

私はこれがあなたが望むものに比べて広すぎることを知っていますが(私の経験によると)、削除したい一時的なエントリでスクリプトを複雑にすることなくアクティブ/無効にする最も簡単で迅速な方法です。

関連情報