help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-bash] Awkward behavior of empty arrays


From: Cristian Zoicas
Subject: Re: [Help-bash] Awkward behavior of empty arrays
Date: Thu, 7 Sep 2017 11:31:01 +0200
User-agent: Mozilla/5.0 (X11; Linux i686; rv:43.0) Gecko/20100101 Firefox/43.0 SeaMonkey/2.40

> Hm, interesting.  I think your whole message below can be rephrased as: empty 
arrays don't work with set -u.  Is that right?

right...

> If so I agree, and I would consider that a design problem.

... but I prefer this sentence containing the expression "design problem" 
instead
of "empty arrays don't work with set -u". And I would also add the following 
problems:

   * "declare -a A=" creates an array with a single null element;
   * the manual should clarify some missing issues.

> I just tested mksh and it does the same thing as bash.  (mksh is a pksh fork, and 
pdksh was a clone of AT&T ksh, so I
> suspect the behavior originated there.)
>

Probably the original designers wanted to allow for the possibility of using an 
empty array (e.g. declare -a A=() )
at least in a minimal way so they decided that the compromise of allowing to 
test the length of the array but not
the use expansion is a good one. It could makes sense if you don't want to 
allow empty arrays, but I cannot understand
why such arrays should be not allowed.

> set -u is useful with arrays for out-of-bounds checks:
>
> $ set -u
> $ declare -a A=(1 2 3)
> $ echo "${A[2]}"
> $ echo "${A[3]}"
> -bash: A[3]: unbound variable

excelent example. I've not imagined/used set -u for out-of-bound checks.

> But I agree that the empty array check is undesired.  It's also inconsistent 
with the argv array:
>
> $ set -u
> $ set --   # clear argv array
> $ echo "$#"
> 0
> $ argv "$@"  # gives desired empty array of argument, not error
> []

I would  call this inconsistency another "design problem". Here is another 
awkward example based on it:

   set -u;
   for p in "$@"; do echo "$p"; done
   declare -a A=( "$@" )
   for p in "address@hidden"; do echo "$p"; done
   echo address@hidden

Anything works well until the @ array is empty.


$@ behaves  very well (I  would say perfectly)  with respect to  the for
loop even when it is empty. In the example below

   set -u;
   set --;
   for i in "$@"; do
      echo "i=${i}";
   done

The statements in the for loop are not iterated.

I want to use this occasion to mention another issue related to the expanssion 
of the single possible
empty array, $@, (because it is not possible to expand other empty arrays when 
set -u.)

Lets' see what happens in the following cases:

1) unset A;   declare A=;   for v in ${A}; do echo "v="; done

   # A is declared WITHOUT the array attribute. The statements in the for loop 
are not executed because $A expands to nothing.

2) unset A;   declare A=;   for v in "${A}"; do echo "v="; done

   # A is declared WITHOUT the array attribute . The statements in the for loop 
*are* executed (it
   # is not a problem). bash sees the first " and considers it the beginning of 
a string. Inside the
   # string there is A must be expanded. It expands to null. After A the string 
finishes and thus we
   # get a zero length string.

3) set -u; set -- A B C; for s in "address@hidden"; do echo "s=${s}"; done

   # It prints : "s=XA s=B s=CY" and it behaves as documented. I imagine that a 
similar mechanism as above is engaged. When bash
   # sees "address@hidden" it considers " the beginning of a string, it finds 
the 'X' and considers it a string that must be concatenated with
   # the first element of the array, and the things go ahead as documented.

4) set -u; set -- A C B; for s in "$@"; do echo "s=${s}"; done

   # It prints : "s=A  s=B s=C"

   # similar things as above happen here with the difference that a zero length 
string is concatenated with the first element of the
   # array.

5) set -u; set --; for s in "$@"; do echo "s=${s}"; done

   # it prints nothing. For me (and I hope that for others) this works 
perfectly. But bash does not engage the same mechanisms as above
   # because in this case bash does not find a zero length string between " and 
$ that is concatenated with the empty expanssion
   # and so on, as documented.  The manual should clarify that address@hidden and 
"address@hidden" (or if bash would support other empty arrays that
   # address@hidden and "address@hidden") expand to nothing when the array is 
empty.




> Horrible workaround:
>
> Copy to the argument array:
>
> set -- "address@hidden"
>
> Copy from the arguments array:
>
> declare -a A=( "$@" )
>
> Then use "$@" , for i in "$@", etc. everywhere?
>

thank you.

> -----
> I would also like it if bash would provide a way to safely interpolate empty 
arrays with set -u. Syntax idea:
> echo "${A[@@]}"
> That way there is no extra mode, which is harder to read IMO.
> Andy
>


Cristi





reply via email to

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