Comment annuler la définition d'une variable en lecture seule dans Bash ?
$ readonly PI=3.14
$ unset PI
bash: PI: readonly variable
ou ce n'est pas possible ?
Comment annuler la définition d'une variable en lecture seule dans Bash ?
$ readonly PI=3.14
$ unset PI
bash: PI: readonly variable
ou ce n'est pas possible ?
En fait, vous pouvez annuler une variable en lecture seule . mais je dois vous avertir qu'il s'agit d'une méthode peu pratique. J'ajoute cette réponse, uniquement à titre d'information, et non comme une recommandation. Utilisez-le à vos propres risques. Testé sur ubuntu 13.04, bash 4.2.45.
Cette méthode implique de connaître un peu le code source de bash et elle est héritée de ce réponse.
$ 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
$
Une réponse simple est d'utiliser le mode batch et d'autres drapeaux de ligne de commande, comme indiqué dans le document F. Réponse de Hauri :
$ sudo gdb -ex 'call unbind_variable("PI")' --pid=$$ --batch
sudo
peut ou non être nécessaire en fonction des paramètres de ptrace_scope de votre noyau. Consultez les commentaires de la réponse de vip9937 pour plus de détails.
J'ai essayé le hack gdb ci-dessus parce que je veux désactiver TMOUT (pour désactiver la déconnexion automatique), mais sur la machine où TMOUT est en lecture seule, je ne suis pas autorisé à utiliser sudo. Mais puisque je possède le processus bash, je n'ai pas besoin de sudo. Cependant, la syntaxe ne fonctionne pas tout à fait avec la machine sur laquelle je me trouve.
Cela a pourtant fonctionné (je l'ai mis dans mon fichier .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
Edit 2021-11-10 : Ajouter (int)
a _cast unbind_variable
_ résultat.
Mais avec une syntaxe plus simple :
$ gdb -ex 'call (int) unbind_variable("PI")' --pid=$$ --batch
Avec une certaine amélioration, en tant que fonction :
destroy
fonction :O Comment jouer avec les métadonnées variables . Notez l'utilisation de l'expression "rare". bashismes : local -n VARIABLE=$1
y ${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
}
Vous pouvez le copier dans un fichier source bash appelé destroy.bash
pour l'échantillon...
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
au lieu de gdb
si drapeau en lecture seule pas présentwhile read ... result= ... done
obtenir le code de retour de call (int) unbind_variable()
en gdb
sortiegdb
avec l'utilisation de la syntaxe --pid
y --ex
(voir gdb --help
).$result
de unbind_variable()
commandement.$ . destroy.bash
1er avec toute variable régulière (lecture-écriture) :
$ 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ème avec variable en lecture seule :
$ 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ème avec une variable inexistante :
$ destroy PI
$ echo $?
255
L'utilisation de GDB est terriblement lente, ou peut même être interdite par la politique du système (c'est-à-dire qu'on ne peut pas s'attacher à un processus).
Essayez plutôt ctypes.sh. Il fonctionne en utilisant libffi pour appeler directement unbind_variable() de bash à la place, ce qui est tout aussi rapide que d'utiliser n'importe quel autre builtin de bash :
$ 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
Vous devez d'abord installer ctypes.sh :
$ git clone https://github.com/taviso/ctypes.sh.git
$ cd ctypes.sh
$ ./autogen.sh
$ ./configure
$ make
$ sudo make install
Véase https://github.com/taviso/ctypes.sh pour une description complète et des documents.
Pour les curieux, oui, cela vous permet d'appeler n'importe quelle fonction dans bash, ou n'importe quelle fonction dans n'importe quelle bibliothèque liée à bash, ou même n'importe quelle bibliothèque externe chargée dynamiquement si vous le souhaitez. Bash est maintenant tout aussi dangereux que perl... ;-)
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.