Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

[ BUG ] Parameter expansion issue on a defined as an empty string variable, using the "NO UNSET" flag.



Hi,

It appears there is a mix related to the colon use (which forces "set and
not empty strings") and the special ":#" expansion type when using the "set
-u" flag.

Let's consider this example :

#!/bin/zsh
set -u;

typeset youpi="";

echo "plop 1";
echo "youpi 1 ${youpi#*.cfg}";
echo "plop 2";
echo "youpi 2 ${youpi##*.cfg}";
echo "plop 3";
echo "youpi 3 ${youpi%*.cfg}";
echo "plop 4";
echo "youpi 4 ${youpi%%*.cfg}";
echo "plop 5";
echo "youpi 5 ${youpi:#*.cfg}";
echo "plop 6";


% ./test.zsh
plop 1
youpi 1
plop 2
youpi 2
plop 3
youpi 3
plop 4
youpi 4
plop 5
./test.zsh:15: youpi: parameter not set

Here is the manual part of the zshexpn "parameter expansion" section :

       ${name#pattern}
       ${name##pattern}
              If the pattern matches the beginning of the value of name,
then substitute the value of name with the matched portion  deleted;
otherwise,
              just substitute the value of name.  In the first form, the
smallest matching pattern is preferred; in the second form, the largest
matching
              pattern is preferred.

       ${name%pattern}
       ${name%%pattern}
              If the pattern matches the end of the value of name, then
substitute the value of name with the matched portion  deleted;
otherwise,  just
              substitute the value of name.  In the first form, the
smallest matching pattern is preferred; in the second form, the largest
matching pat‐
              tern is preferred.

       ${name:#pattern}
              If the pattern matches the value of name, then substitute the
empty string; otherwise, just substitute the value of name.  If  name  is
an
              array the matching array elements are removed (use the `(M)'
flag to remove the non-matched elements).



The ":#" expansion type doesn't behave like the "#" one at all. If the "#"
one matches, it can be the beginning of the string only while the ":#"
pattern must match the whole string. Hence the colon here can't be
considered as a modifier to tell whether you want or not "the emptiness" be
checked or not.

Here is another way to show this "colon" behavior :

#!/bin/zsh
set -u;

echo "plop 1";
echo "youpi 1 ${youpi+defined}";
echo "plop 2";
echo "youpi 2 ${youpi:+defined and not empty}";

typeset youpi="";

echo "plop 3";
echo "youpi 3 ${youpi+defined}";
echo "plop 4";
echo "youpi 4 ${youpi:+defined and not empty}";

echo "plop 5";
echo "youpi 5 ${(M)youpi:#matches the whole pattern}";

echo "plop 6";

% ./test2.zsh
plop 1
youpi 1
plop 2
youpi 2
plop 3
youpi 3 defined
plop 4
youpi 4
plop 5
./test2.zsh:17: youpi: parameter not set


The workaround is to embed the parameter expansions like this :

echo "${youpi:+${youpi:#my pattern here}}";

*BUT* this is really cumbersome and not documented at all in the manual.

Some technical details :

% zsh --version
zsh 5.0.2 (x86_64-redhat-linux-gnu)
% cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)


I think there should be a fix here to apply the ":#" expansion even on the
empty string and especially not raise an error while using the set -u
option on a defined variable, ever...

Regards,


                       RotoGluOn


Messages sorted by: Reverse Date, Date, Thread, Author