[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: 'declare -i var=var' for var initially declared in calling scope
From: |
Chet Ramey |
Subject: |
Re: 'declare -i var=var' for var initially declared in calling scope |
Date: |
Mon, 24 Jun 2024 15:24:30 -0400 |
User-agent: |
Mozilla Thunderbird |
On 6/17/24 10:38 PM, Zachary Santer wrote:
Bash Version: 5.2
Patch Level: 26
Release Status: release
Description:
It just occurred to me that I could take advantage of arithmetic
evaluation being performed when a variable with the -i integer
attribute is assigned a value to create a visual distinction between
working with regular variables and variables representing integers,
i.e.:
local this_var="words words words"
local var[index]="${this_var}"
local -r -i BIT_FLAG=2#0100
local -i value=BIT_FLAG
After doing this, var[index] will be set to "words words words" and
value will be set to 4.
Going a step further and passing integer arguments to functions as the
name of the variable, rather than passing its value with a parameter
expansion of that variable, we run into a problem. I would expect
func1 () and func2 () below to be equivalent. However, we see that
when setting a local variable with the integer attribute, using the
name of a variable at calling scope with the same name, the local
variable is always assigned the value 0, if I'm not using an
arithmetic expansion.
I wondered if the call to 'local' was already referencing the local
variable that it was in the process of declaring, which I imagine
would've been unset at the time. 'set -o nounset' didn't cause it to
error out, though.
Of course 'declare -i other=other' is a no-op, but it doesn't break.
Repeat-By:
$ cat integer-scope
#!/usr/bin/env bash
set -o nounset
main () {
printf 'foo :\n'
declare -i foo=1
func1 foo
func2 foo
printf 'bar :\n'
declare -i bar=2
func1 bar
func2 bar
printf '"${baz}" :\n'
declare -i baz=3
func1 "${baz}"
func2 "${baz}"
printf 'other :\n'
declare -i other=4
declare -i other=other
declare -p other
}
func1 () {
declare -i bar="${1}"
declare -p bar
}
func2 () {
declare -i bar="$(( ${1} ))"
declare -p bar
}
main
$ ./integer-scope
foo :
declare -i bar="1"
declare -i bar="1"
`declare' is a builtin, so its arguments are expanded before it is called.
In the first example, you get what is essentially
declare -i bar; bar=foo
(to make it clear that the variable is created with the specified
attributes before it's assigned to).
Since the integer attribute is set, foo is treated as an expression, the
variable with that name in the nearest scope gets expanded, and you have
bar=1.
In the second, you have the same thing (foo is not a variable local to
func2's scope), but with a different syntax for the arithmetic evaluation
that doesn't rely on the assignment to do it implicitly, so it's
declare -i bar; bar=1
bar :
declare -i bar="0"
declare -i bar="2"
Same thing. You have
declare -i bar; bar=bar
(the variable is created before being assigned to). Since bar is a local
variable at the current scope and it's unset, when the assignment is
performed, it has value 0, and that gets assigned.
Again, in the second example, since the arithmetic expansion is performed
first, before the local variable is created, you use the variable in the
nearest scope and get essentially
declare -i bar; bar=2
"${baz}" :
declare -i bar="3"
declare -i bar="3"
This is the same as the first example.
other :
declare -i other="4"
In this example, main is creating a local variable and then using its
value in the next assignment.
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU chet@case.edu http://tiswww.cwru.edu/~chet/
OpenPGP_signature.asc
Description: OpenPGP digital signature