18
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Bash で readonly した変数を再度編集可能にする

Last updated at Posted at 2018-01-21

readonly とは

  • 変数を編集禁止にする
  • 他言語で言うところの const っぽい使い方ができる
    • グローバル変数を作りがちなシェルスクリプトにおいて有益なコマンド。コーディング規約 にもよく出てくる
使用例
$ MY_MSG='OK Google'

$ readonly MY_MSG

$ MY_MSG='Hey Alexa'
-bash: MY_MSG: readonly variable

書き換えできないことがわかる。

OLDPWD を readonly したら?

OLDPWD: cd する直前のディレクトリが保存される変数

$ pwd
/var

$ cd /opt

$ echo $OLDPWD
/var

こいつに readonly をつけると…

書き換えできない
$ readonly OLDPWD

$ cd ~
-bash: OLDPWD: readonly variable

$ cd /tmp
-bash: OLDPWD: readonly variable

cd 時に OLDPWD を更新しようとするが、readonly でガードされているために cd するたびにエラーメッセージが表示されるようになる。これは困った。

readonly を外すことはできる?

一度セットされた readonly は、基本的にシェルにログインし直すまで外すことができない。
しかし、Stackoverflow にて強引に外す方法が紹介されていたので、上記 OLDPWD の readonly を外せるかどうか試してみた。

強引に外す
# OLDPWD に readonly がついていることを確認
$ cd ~
-bash: OLDPWD: readonly variable

# gdb で Bash の組み込み関数を直接呼ぶ
$ sudo gdb << EOF
attach $$
call unbind_variable("OLDPWD")
detach
EOF
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-92.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) Attaching to process 5224
Reading symbols from /bin/bash...(no debugging symbols found)...done.
Reading symbols from /lib64/libtinfo.so.5...(no debugging symbols found)...done.
Loaded symbols for /lib64/libtinfo.so.5
Reading symbols from /lib64/libdl.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/libdl.so.2
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Reading symbols from /lib64/libnss_files.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/libnss_files.so.2
0x00007f99ba2d165e in waitpid () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install bash-4.1.2-33.el6_7.1.x86_64
(gdb) $1 = 0
(gdb) Detaching from program: /bin/bash, process 5224
(gdb) quit

gdb で行っていることは以下の3つ。

  • attach $$: 今動いている Bash を gdb の操作対象にする。 $$ はシェルの PID
  • call unbind_variable("OLDPWD"): Bash のソース によると「シェル変数 (OLDPWD) をアンセットする」
  • detach: gdb から開放する

以上を行うことで、 cd しても怒られなくなった。

# OLDPWD を確認
$ echo $OLDPWD

# cd しても怒られない
$ cd /tmp

$

readonly を外すというよりは、変数そのものを消し去ったようだ。

備考

上記 Stackoverflow にも書かれているが、変数のアンセットに関しては unset というコマンドが用意されている。
一般的な変数に関しては unset 変数名 で事足りるが、readonly された変数に対してはやはり使えない。

# readonly なし
$ NO_READONLY='foo'
# 消せる
$ unset NO_READONLY
$ echo $NO_READONLY

$

# readonly あり
$ READONLY='bar'
$ readonly READONLY
# 消せない
$ unset READONLY
-bash: unset: READONLY: cannot unset: readonly variable

ということで、readonly 変数に関しては gdb を使った方法しかなさそう。

まとめ

  • 変数に readonly をつけると書き換えられなくなる
  • readonly を一度つけると原則取り消すことができない
  • gdb で Bash の unbind_variable を呼び、強制的に変数を消去することで readonly を取り消すことができる
18
14
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?