bug-bash
[Top][All Lists]
Advanced

[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/

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]