shopt
関数のオプション値を一時的に変更したいと思います。
組み込み関数を使用して設定できるオプションは、関数本体内で設定set
できます。local -
以下はサンプルコードです
#!/bin/bash
# Enable the options globally
set -u
[[ "$SHELLOPTS" =~ nounset ]] && echo "1: nounset enabled"
shopt -s "extglob"
[[ "$BASHOPTS" =~ extglob ]] && echo "1: extglob enabled"
fun () {
#Enable the options locally just in fun
local -
# local BASHOPTS
set +u
[[ "$SHELLOPTS" =~ nounset ]] || echo "2: nounset disabled"
shopt -u "extglob"
[[ "$BASHOPTS" =~ extglob ]] || echo "2: extglob disabled"
}
fun
if [[ "$SHELLOPTS" =~ nounset ]]; then
echo "3: nounset enabled"
else
echo "3: nounset disabled"
fi
if [[ "$BASHOPTS" =~ extglob ]]; then
echo "3: extglob enabled"
else
echo "3: extglob disabled"
fi
出力を含む
1: nounset enabled
1: extglob enabled
2: nounset disabled
2: extglob disabled
3: nounset enabled
3: extglob disabled
ご覧のとおり、オプションはnounset
関数本体に追加するだけでローカライズできます。local -
私は同じshopt
オプションが欲しいです。現在の回避策は、まずオプションが有効になっていることを確認することです。
if ! shopt -q extglob; then
extglobchanged=1
shopt -s extglob
fi
その後、最終的に以前の状態に戻ります。
[[ "$extglobchanged" == 1 ]] && shopt -u extglob
中間コードが失敗する可能性があるすべての状況を処理する必要があるため、これは良い解決策ではありません。 (関数が終了する前に上記の行が実行されていることを確認する必要があります。)
質問:
オプションをローカライズできますかshopt
?
--編集 1--
やる気
私のbashツールキットには、ユーザーにYesまたはNoを問い合わせる機能があります。私はcase
パターンをorに関連付けるためにこの目的のために拡張globを使用します。これは私のコードです
yesnoquery () {
local extglobchanged=0
local returnvalue=2
while true; do
if read -p "$1" answer; then
if ! shopt -q extglob; then
extglobchanged=1
shopt -s extglob #enable for pattern matching
fi
eval '
case "$answer" in
@([Yy]|[Yy][Ee][Ss])) returnvalue=0;; #true
@([Nn]|[Nn][Oo])) returnvalue=1;; #false
* ) echo "Please answer \"y\" or \"n\"";;
esac
'
[[ "$extglobchanged" == 1 ]] && shopt -u extglob #revert changes
[[ "$returnvalue" != 2 ]] && return "$returnvalue"
else
return 2 #reading returned error
fi
done
}
こんな些細なことをするには長い時間がかかるようです。shopt
オプションextglobをローカライズできる場合は、case
likeから直接返すことができます@([Yy]|[Yy][Ee][Ss])) return 0;;
。また、この[[ "$extglobchanged" == 1 ]]...
行とその後の行は必要ありません。
主な問題
現在、関数が終了する可能性があるすべての場所に変更を元に戻すには、手動でコードを追加する必要がありますshopt
。
私の考えは、これらの変更をローカライズする必要があるということですlocal -
。ローカライズのない他のソリューションは完璧です。
これが単に言語制限であれば、これは私の質問に対する答えでもあります。
答え1
はい、可能です:
fun()
{
local -
# store state of all options.
oldstate="$(shopt -p)"
:
:
set +vx; eval "$oldstate"
}
特別な状況がありますerrexit
。
答え2
私のニーズに合った解決策を見つけたようです。サブシェルで関数本体を実行する。サブシェルで関数本体を実行することの長所と短所、および一般的なユースケースもここで数回議論されています。[1][2][サム]。
で述べたように[4]Bashman
ページから取得した関数の一般的な構文は次のとおりです。
[ function ] name () compound-command [redirection]
Aは、Compound comamand
括弧構文を使用して開始された現在のシェルの子プロセスです(list)
。man bash
次のように定義します(ハイライトを追加):
(list)listサブシェル環境で実行します(以下のコマンド実行環境を参照)。変数の割り当てと組み込みコマンドシェルに影響を与える環境完了後、コマンドは無効になります。戻り状態はリストの終了状態です。
私のユースケースには2つのことが必要です。
shopt
オプション変更のローカライゼーション効果extglob
。- 返品状態を維持
サブシェルによるshopt
オプションの変更は、extglob
周囲のシェルに漏れません。また、関数の任意の時点で返すことができます。もちろん、欠点は、サブシェルの起動に追加のリソースが必要であることです。
デモ
今より短い関数は次のようになります。
yesnoquery () (
while true; do
if read -p "$1" answer; then
shopt -s extglob
eval '
case "$answer" in
@([Yy]|[Yy][Ee][Ss]) ) return 0;; #true
@([Nn]|[Nn][Oo]) ) return 1;; #false
* ) echo "Please answer \"yes\" or \"no\"";;
esac
'
else
return 2 #reading returned error
fi
done
)
Caseステートメントでは、一時変数に保存する代わりに直接返すことができます。ローカライズされた変数は必要なくなり、両方の条件が保存されました。
shopt
これらのオプションが実際にローカルであることは、問題のコードサンプルコードですばやく確認できます。
#!/bin/bash
# Enable the options globally
set -u
[[ "$SHELLOPTS" =~ nounset ]] && echo "1: nounset enabled"
shopt -s "extglob"
[[ "$BASHOPTS" =~ extglob ]] && echo "1: extglob enabled"
fun () {
set +u
[[ "$SHELLOPTS" =~ nounset ]] || echo "2: nounset disabled"
shopt -u "extglob"
[[ "$BASHOPTS" =~ extglob ]] || echo "2: extglob disabled"
}
fun
if [[ "$SHELLOPTS" =~ nounset ]]; then
echo "3: nounset enabled"
else
echo "3: nounset disabled"
fi
if [[ "$BASHOPTS" =~ extglob ]]; then
echo "3: extglob enabled"
else
echo "3: extglob disabled"
fi
変更されたのは、すべてここにある括弧(
({
および削除された重複ローカル変数)です。出力
1: nounset enabled
1: extglob enabled
2: nounset disabled
2: extglob disabled
3: nounset enabled
3: extglob enabled
効果が正常にターゲティングされたことを示します。
一般化する
関数本体としてのサブシェル実行環境は、bashシェルオプションの効果をローカライズするのに役立つことが証明されています。この変数を変更しても関数範囲外のコードには影響しないため、case
関数本文内の文はこれから利点を得ることができます。extglob
リソースが不足すると、サブシェルの起動に伴う追加のオーバーヘッドがパフォーマンスを不必要に遅くする可能性があります。