Bash에서 읽기 전용 변수 설정 해제
Bash에서 읽기 전용 변수를 설정 해제하는 방법은 무엇입니까?
$ readonly PI=3.14
$ unset PI
bash: PI: readonly variable
아니면 불가능합니까?
실제로 읽기 전용 변수를 설정 해제 할 수 있습니다 . 그러나 나는 이것이 해키 방법이라는 것을 경고해야한다. 이 답변을 추천이 아닌 정보로만 추가하십시오. 자신의 책임하에 사용하십시오. 우분투 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
$
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
man 페이지에 따르면 :
unset [-fv] [name ...]
... Read-only variables may not be
unset. ...
아직 변수를 내 보내지 않은 경우을 사용 exec "$0" "$@"
하여 셸을 다시 시작할 수 있습니다. 물론 내 보내지 않은 다른 모든 변수도 손실됩니다. 를 사용하지 않고 새 셸을 시작하면 exec
해당 셸에 대한 읽기 전용 속성이 손실 되는 것 같습니다 .
곧 : anishsane의 답변에서 영감을 얻음
그러나 단순한 구문으로 :
gdb -ex 'call unbind_variable("PI")' --pid=$$ --batch
기능으로 약간의 개선이 있습니다.
내 destroy
기능 :
또는 가변 메타 데이터로 재생하는 방법 . 희귀 한 bashisms의 사용법에 유의하십시오 : local -n VARIABLE=$1
그리고 ${VARIABLE@a}
...
destroy () {
local -n variable=$1
declare -p $1 &>/dev/null || return -1 # Return if variable not exist
local reslne result flags=${variable@a}
[ -z "$flags" ] || [ "${flags//*r*}" ] && {
unset $1 # Don't run gdb if variable is not readonly.
return $?
}
while read resline; do
[ "$resline" ] && [ -z "${resline%\$1 = *}" ] &&
result=${resline##*1 = }
done < <(
gdb 2>&1 -ex 'call 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 unbind_variable("'$1'")' --pid=$$ --batch 14 ) 15 return $result 16 }
- 2 행 은 제출 된 변수에 대한 로컬 참조 를 만듭니다 .
- 줄 3 존재하지 않는 변수에서 실행 방지
- 4 행은 매개 변수의 속성 (메타)을
$flags
. - 읽기 전용 플래그가 없는 경우 5 ~ 8 행이 실행
unset
됩니다.gdb
- 9-12 행 은 출력 에서
while read ... result= ... done
리턴 코드를 얻습니다.call unbind
gdb
- 13 라인
gdb
의 사용과 구문--pid
및--ex
(참조gdb --help
). - 15 리턴 라인
$result
의call unbind
명령을 사용합니다.
사용:
source destroy.bash
# 1st with any regular (read-write) variable:
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
# now with read only variable:
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
# and with non existant variable
destroy PI
echo $?
255
특히 TMOUT 변수에 대한 wrt. gdb를 사용할 수없는 경우 또 다른 옵션은 bash를 홈 디렉토리에 복사하고 바이너리의 TMOUT 문자열을 XMOUX와 같은 다른 것으로 패치하는 것입니다. 그런 다음이 추가 셸 레이어를 실행하면 시간이 초과되지 않습니다.
readonly 명령은 쉘 프로세스가 종료 될 때까지 최종적이고 영구적입니다. 변수를 변경해야하는 경우 읽기 전용으로 표시하지 마십시오.
No, not in the current shell. If you wish to assign a new value to it, you will have to fork a new shell where it will have a new meaning and will not be considered as read only
.
$ { ( readonly pi=3.14; echo $pi ); pi=400; echo $pi; unset pi; echo [$pi]; }
3.14
400
[]
In zsh,
$ typeset +r PI
(Yes, I know the question says bash. But when you Google for zsh, you also get a bunch of bash questions.)
Using GDB is terribly slow. Try ctypes.sh instead. It works by using libffi to directly call bash's unbind_variable() instead, which is every bit as fast as using any other bash builtin:
$ readonly PI=3.14
$ unset PI
bash: unset: PI: cannot unset: readonly variable
$ source ctypes.sh
$ dlcall unbind_variable string:PI
$ declare -p PI
bash: declare: PI: not found
First you will need to install ctypes.sh:
$ git clone https://github.com/taviso/ctypes.sh.git
$ cd ctypes.sh
$ ./autogen.sh
$ ./configure
$ make
$ sudo make install
See https://github.com/taviso/ctypes.sh for a full description and docs.
For the curious, yes this lets you call any function within bash, or any function in any library linked to bash, or even any external dynamically-loaded library if you like. Bash is now every bit as dangerous as perl... ;-)
You can't, from manual page of unset
:
For each name, remove the corresponding variable or function. If no options are supplied, or the -v option is given, each name refers to a shell variable. Read-only variables may not be unset. If -f is specifed, each name refers to a shell function, and the function definition is removed. Each unset variable or function is removed from the environment passed to subsequent commands. If any of RANDOM, SECONDS, LINENO, HISTCMD, FUNCNAME, GROUPS, or DIRSTACK are unset, they lose their special properties, even if they are subsequently reset. The exit status is true unless a name is readonly.
One other way to "unset" a read-only variable in Bash is to declare that variable read-only in a disposable context:
foo(){ declare -r PI=3.14; baz; }
bar(){ local PI=3.14; baz; }
baz(){ PI=3.1415927; echo PI=$PI; }
foo;
bash: PI: readonly variable
bar;
PI=3.1415927
While this is not "unsetting" within scope, which is probably the intent of the original author, this is definitely setting a variable read-only from the point of view of baz() and then later making it read-write from the point of view of baz(), you just need to write your script with some forethought.
$ PI=3.17
$ export PI
$ readonly PI
$ echo $PI
3.17
$ PI=3.14
-bash: PI: readonly variable
$ echo $PI
3.17
What to do now?
$ exec $BASH
$ echo $PI
3.17
$ PI=3.14
$ echo $PI
3.14
$
A subshell can inherit the parent's variables, but won't inherit their protected status.
참고URL : https://stackoverflow.com/questions/17397069/unset-readonly-variable-in-bash
'developer tip' 카테고리의 다른 글
일부 코드를 실행 한 다음 대화 형 노드로 이동 (0) | 2020.11.07 |
---|---|
C # 4.0에서 작업을 절전 (또는 지연)하는 방법은 무엇입니까? (0) | 2020.11.07 |
Java의 enum에서 문자열 값 가져 오기 (0) | 2020.11.07 |
헤드리스 인터넷 브라우저? (0) | 2020.11.07 |
알 수없는 수의 인수를 자바 스크립트 함수에 전달 (0) | 2020.11.07 |