Bashで読み取り専用変数の設定を解除するにはどうすればよいですか?
$ readonly PI=3.14
$ unset PI
bash: PI: readonly variable
またはそれは不可能ですか?
実際には、読み取り専用変数の設定を解除できます。しかし、これはハックな方法であることを警告しなければなりません。この回答を推奨事項としてではなく、情報としてのみ追加します。ご自身の責任で使用してください。ubuntu 13.04、bash 4.2.45 でテスト済み。
この方法には、少しのbashソースコードを知ることが含まれ、この回答から継承されています。
$ readonly PI=3.14
$ unset PI
-bash: unset: PI: cannot unset: readonly variable
$ cat << EOF| sudo gdb
attach $$
call unbind_variable("PI")
detach
EOF
$ echo $PI
$
ワンライナーの答えは、 F. Hauriの答えで提供されているように、バッチモードとその他のコマンドラインフラグを使用することです:
$ sudo gdb -ex 'call unbind_variable("PI")' --pid=$$ --batch
sudo
カーネルの ptrace_scope 設定に基づいて、必要な場合とそうでない場合があります。詳細については、vip9937 の回答のコメントを確認してください。
TMOUT の設定を解除したい (自動ログアウトを無効にする) ため、上記の gdb ハックを試しましたが、TMOUT が読み取り専用に設定されているマシンでは、sudo を使用できません。しかし、私は bash プロセスを所有しているので、sudo は必要ありません。ただし、構文は、私が使用しているマシンではうまく機能しませんでした。
ただし、これは機能しました(.bashrcファイルに入れました):
# Disable the stupid auto-logout
unset TMOUT > /dev/null 2>&1
if [ $? -ne 0 ]; then
gdb <<EOF > /dev/null 2>&1
attach $$
call unbind_variable("TMOUT")
detach
quit
EOF
fi
編集 2021-11-10:結果(int)
に追加cast unbind_variable
。
ただし、より単純な構文を使用すると、次のようになります。
$ gdb -ex 'call (int) unbind_variable("PI")' --pid=$$ --batch
関数として、いくつかの改善を加えて:
destroy
機能:または可変メタデータで遊ぶ方法。まれなbashismsの使用法に注意してください:local -n VARIABLE=$1
そして${VARIABLE@a}
...
destroy () {
declare -p $1 &>/dev/null || return -1 # Return if variable not exist
local -n variable=$1
local reslne result flags=${variable@a}
[ -z "$flags" ] || [ "${flags//*r*}" ] && {
unset $1 # Don't run gdb if variable is not readonly.
return $?
}
while read -r resline; do
[ "$resline" ] && [ -z "${resline%%\$1 = *}" ] &&
result=${resline##*1 = }
done < <(
exec gdb 2>&1 -ex 'call (int) unbind_variable("'$1'")' --pid=$$ --batch
)
return $result
}
サンプルとして、これをというbash ソース ファイルにコピーできます。destroy.bash
1 destroy () { 2 local -n variable=$1 3 declare -p $1 &>/dev/null || return -1 # Return if variable not exist 4 local reslne result flags=${variable@a} 5 [ -z "$flags" ] || [ "${flags//*r*}" ] && { 6 unset $1 # Don't run gdb if variable is not readonly. 7 return $? 8 } 9 while read resline; do 10 [ "$resline" ] && [ -z "${resline%\$1 = *}" ] && 11 result=${resline##*1 = } 12 done < <( 13 gdb 2>&1 -ex 'call (int) unbind_variable("'$1'")' --pid=$$ --batch 14 ) 15 return $result 16 }
$flags
。unset
の代わりに、5 行目から 8 行目が実行されます。gdb
while read ... result= ... done
のリターン コードを取得します。call (int) unbind_variable()
gdb
gdb
目の構文( を参照)。--pid
--ex
gdb --help
$result
15 行目でコマンドを返しunbind_variable()
ます。$ . destroy.bash
任意の通常の (読み書き可能) 変数を使用した 1 つ目:
$ declare PI=$(bc -l <<<'4*a(1)')
$ echo $PI
3.14159265358979323844
$ echo ${PI@a} # flags
$ declare -p PI
declare -- PI="3.14159265358979323844"
$ destroy PI
$ echo $?
0
$ declare -p PI
bash: declare: PI: not found
読み取り専用変数を使用した2番目:
$ declare -r PI=$(bc -l <<<'4*a(1)')
$ declare -p PI
declare -r PI="3.14159265358979323844"
$ echo ${PI@a} # flags
r
$ unset PI
bash: unset: PI: cannot unset: readonly variable
$ destroy PI
$ echo $?
0
$ declare -p PI
bash: declare: PI: not found
存在しない変数を持つ3番目:
$ destroy PI
$ echo $?
255
マニュアルページによると:
unset [-fv] [name ...]
... Read-only variables may not be
unset. ...
変数をまだエクスポートしていない場合は、 を使用exec "$0" "$@"
してシェルを再起動できます。もちろん、エクスポートされていない他のすべての変数も失われます。なしで新しいシェルを起動すると、exec
そのシェルの読み取り専用プロパティが失われるようです。
具体的には TMOUT 変数に書き込みます。gdb が利用できない場合の別のオプションは、bash をホーム ディレクトリにコピーし、バイナリの TMOUT 文字列を別のもの (XMOUX など) にパッチすることです。そして、このシェルの追加レイヤーを実行すると、タイムアウトしなくなります。
readonly コマンドは、シェル プロセスが終了するまで最終的かつ永続的なものにします。変数を変更する必要がある場合は、読み取り専用にしないでください。
いいえ、現在のシェルにはありません。それに新しい値を割り当てたい場合は、新しい意味を持つ新しいシェルをフォークする必要があり、read only
.
$ { ( readonly pi=3.14; echo $pi ); pi=400; echo $pi; unset pi; echo [$pi]; }
3.14
400
[]
のマニュアルページからはできませんunset
:
名前ごとに、対応する変数または関数を削除します。オプションが指定されていない場合、または -v オプションが指定されている場合、それぞれの名前はシェル変数を参照します。 読み取り専用変数は設定解除できません。 -f を指定すると、それぞれの名前がシェル関数を参照し、関数定義が削除されます。設定されていない各変数または関数は、後続のコマンドに渡される環境から削除されます。RANDOM、SECONDS、LINENO、HISTCMD、FUNCNAME、GROUPS、または DIRSTACK のいずれかが設定されていない場合、後でリセットされても、それらの特別なプロパティは失われます。名前が読み取り専用でない限り、終了ステータスは true です。