Re: manpage note? weird strings that appear to be equal but create haywire comparisons?

2009-09-01 Thread Linda Walsh

Chet Ramey wrote:

Note that [[ and [ return different results when the vars are unquoted.


Yes.  There are two differences.

First, the operands in [[ do not undergo all word expansions.  The
arguments to [, since it's a builtin, do.  That doesn't really matter
to this example, but it's worth noting.

Second, the = and != operators in [[ perform pattern matching (= is
the same as ==).  You have to quote the rhs to force string matching.



In pattern matching, the backslash has a special meaning: it quotes the
next character.

---
 That makes sense -- but I was attributing it to the backslash being
within double quotes vs. single quotes, paralleling the expansion
of variables.  *sigh*


 So when $v is unquoted, the pattern matcher treats the
pairs of backslashes in $v as one backslash quoting another, and the
strings match.  When using [, bash does straight string comparison, and
the strings are not identical.

---
 That, I did not know. I thought it had to do with whether or
not you enclosed the string in single quotes or double quotes there,
too...

 I think I'm getting string rules from various languages confused at
times...*sigh*







Re: manpage note? weird strings that appear to be equal but create haywire comparisons?

2009-08-26 Thread Chet Ramey
Linda Walsh wrote:

> But then I tested equality on the strings and that's the confusing
> part. I have an idea of what's going on but boy do string compares look
> confused.  They perform same on cygwin
> (bashv=3.2.49(22)-release (i686-pc-cygwin)) and Suse11.1:
> (bashv=3.2.39(1)-release (x86_64-suse-linux-gnu)
> 
> Using the simple form:
>if  ; then echo = "True" else echo False ; fi
> I get:
> for c=C:\Windows\System32, and v=C:\Windows\System32

(If you use the assignments above, v is actually assigned
the string C:\\Windows\\System32)

> expr = [[ "$c" = "$v" ]]  : "False"
> expr = [ "$c" = "$v" ]: "False"
> expr = [[ "$c" != "$v" ]] : "True"
> expr = [ "$c" != "$v" ]   : "True"
> expr = [[ $c = $v ]]  : "True"
> expr = [ $c = $v ]: "False"
> expr = [[ $c != $v ]] : "False"
> expr = [ $c != $v ]   : "True"
> 
> Note that [[ and [ return different results when the vars are unquoted.

Yes.  There are two differences.

First, the operands in [[ do not undergo all word expansions.  The
arguments to [, since it's a builtin, do.  That doesn't really matter
to this example, but it's worth noting.

Second, the = and != operators in [[ perform pattern matching (= is
the same as ==).  You have to quote the rhs to force string matching.
In pattern matching, the backslash has a special meaning: it quotes the
next character.  So when $v is unquoted, the pattern matcher treats the
pairs of backslashes in $v as one backslash quoting another, and the
strings match.  When using [, bash does straight string comparison, and
the strings are not identical.

Chet

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/




Re: manpage note? weird strings that appear to be equal but create haywire comparisons?

2009-08-26 Thread Linda Walsh


Greg Wooledge wrote:

On Wed, Aug 26, 2009 at 02:45:39AM -0700, Linda Walsh wrote:

I had a var 'c' set to (no quotes in the var):   'C\windows\system32'


How did you assign this value?  Did you read it from a file?  Did you
type a specific bash command?


--
I typed it in at the prompt as:

 # c='C:\Windows\System32'



 # echo  $v |hexdump -C
   43 3a 5c 77 69 6e 64 6f  77 73 5c 73 79 73 74 65  


This isn't trustworthy, because you did not quote $v. 

---
   Didn't bother quoting it because quoted or unquoted, it gave the
same output in this case, but in general, you are right.



# printf -v v "%q" $c


Same problem here -- unquoted $c means you're not necessarily getting
the variable's exact contents.

---
   Again, same response as above (made no diff in this case,
but in general, quoting "is good" :-).




for c=C:\Windows\System32, and v=C:\Windows\System32


Even with the unquoted $v here, you should have seen the double backslashes:

$ echo $v
C:\\Windows\\System32

So your output doesn't match your script.  Something strange is afoot.

---
Oh...yeah, forgot about my 'xpg_echo' option...that explains echo
but that wasn't my "ponderance", -- I knew about the internal 
contents varying (from tracing the script during debugging, ie '+x').


   Note, I'm not saying 'echo' has a bug or there is a problem with
how bash stores things internally.  Remember, I did mention that I 
"an idea" of what was going on with the 'echo' stuff -- meaning (one is 
«'C:\windows\system32'» and the other is «C:\\windows\\system32»), 
but my email header was to indicate (perhaps unclearly) whether or not

such behavior was worthy of a ‘manpage note’ for the unwary -- especially
the difference in the test ops mentioned below, which, I'm not entirely
clear, yet, about why they give the different results they give.

   I understand why the quoted versions "$c" = "$v" both say 'different',
(their internal representation is different).  But the unquoted 
differences appear a bit odd.  I can make guesses, and rationalizations,

but those would be those.


Since we don't really know WHAT your variables contain, any analysis
of that output is a waste of time,

---
   Sure ya do!  I just typed:

# c='C:\windows\system32'



although Pierre gave some decent
pointers about the general difference between [ and [[.

---
   Indeed...(and verily!)



On Wed, Aug 26, 2009 at 01:17:07PM +0300, Pierre Gaston wrote:

Now I'm not too sure why var='"*'"; [[ \* = $var ]] is false while
var='\*' [[ \* = $var ]] is true


Assuming the first part was supposed to be var='"*"' ...

---
   Oops...sorry, my bad.  I really miscommunicated.

   What I meant that I found it odd/confusing that the 
True/False indicators for these ops were different:


for (really, when echo'ing correctly ('just ought to have used printf!')
c=«'C:\windows\system32'» and v=«C:\\windows\System32»
  «[[ $c  = $v ]]»   and   «[ $c  = $v ]»
(and complements)
  «[[ $c != $v ]]»   and   «[ $c != $v ]»

My guess?  the [[/]] op dequotes the internally stored form, which in
one case, I think, may contain the actual single quote char?, but then
the equality test strips the quotes for comparison?

Whereas the [] ops know about internal forms and are comparing the
strings: "'C:\windows\system32'" w/ "C:\windows\system32", 
so it's not stripping the "SQ"s off the 1st string?


Just a guess...
Linda









Re: manpage note? weird strings that appear to be equal but create haywire comparisons?

2009-08-26 Thread Pierre Gaston
On Wed, Aug 26, 2009 at 4:19 PM, Greg Wooledge  wrote:

> Assuming the first part was supposed to be var='"*"' ...
>
yup

>
> The bash command [[ \* = $var ]] returns true if $var contains a glob
> pattern against which a literal asterisk * can be matched.  (By the way,
> you don't need the \ there.  No glob expansion is done inside [[...]] so
> you could use a plain * on the left hand side.)
>

> If $var contains \* then the match is successful.  \* as a glob describes
> a literal asterisk, which is what we're trying to match.


> $ var='\*'; [[ * = $var ]]; echo $?
> 0
>
> If $var contains "*" (double quote, asterisk, double quote), then
> the double quotes are considered part of the glob pattern.  A bare
> asterisk won't match that glob, because it doesn't have double quotes
> attached to it.
>

> imadev:~$ var='"*"'; [[ * = $var ]]; echo $?
> 1
>
> It only matches double quote, asterisk, double quote:
>
> $ var='"*"'; [[ \"*\" = $var ]]; echo $?
> 0


Thanks, I agree with that, I'm sorry I should have been more explicit,
what was not clear to me was where this special role of the \ is explained,
Because if you use literals  [[ something = \* ]] is the same as [[
something = "*" ]]

I found my explanation in the manual under "Pattern Matching":
"A backslash escapes the following character; the escaping backslash is
discarded when  matching."

PS, for Linda, http://mywiki.wooledge.org/BashFAQ/031 has more information
about the differences between [[ and [


Re: manpage note? weird strings that appear to be equal but create haywire comparisons?

2009-08-26 Thread Greg Wooledge
On Wed, Aug 26, 2009 at 04:36:42PM +0300, Pierre Gaston wrote:
> Thanks, I agree with that, I'm sorry I should have been more explicit,
> what was not clear to me was where this special role of the \ is explained,
> Because if you use literals  [[ something = \* ]] is the same as [[
> something = "*" ]]

The difference is whether it's being read by the parser or not.  When you
put the quotes directly into the command like that, the parser sees them,
acknowledges their function, and removes them.  When they're part of a
variable substitution, they're not removed.




Re: manpage note? weird strings that appear to be equal but create haywire comparisons?

2009-08-26 Thread Greg Wooledge
On Wed, Aug 26, 2009 at 02:45:39AM -0700, Linda Walsh wrote:
> I was scripting and fixing some permissions in Win,
> and had a var 'c' set to (no quotes in the var):   'C\windows\system32'

How did you assign this value?  Did you read it from a file?  Did you
type a specific bash command?

>  # echo  $v |hexdump -C
>    43 3a 5c 77 69 6e 64 6f  77 73 5c 73 79 73 74 65  

This isn't trustworthy, because you did not quote $v.  The variable
might have leading or trailing whitespace, which the unquoted parameter
expansion would remove before echo gets it.

There's also glob expansion to worry about.  Your variable might contain
C:\windows\sy?tem3* for all we know.

> # printf -v v "%q" $c

Same problem here -- unquoted $c means you're not necessarily getting
the variable's exact contents.

> # echo  $v |hexdump -C

And here.

> TestProg: (interactive shell...)
> 
> {
> c='C:\Windows\System32'
> printf -v v "%q" "$c"

Finally, quotes!

Here's what your v variable should contain after that:

$ c='C:\Windows\System32'; printf -v v %q "$c"; echo "$v"
C:\\Windows\\System32

But your test script says:

> export c v 
> echo  for c=$c, and v=$v

And your alleged output says:

> for c=C:\Windows\System32, and v=C:\Windows\System32

Even with the unquoted $v here, you should have seen the double backslashes:

$ echo $v
C:\\Windows\\System32

So your output doesn't match your script.  Something strange is afoot.

> Note that [[ and [ return different results when the vars are unquoted.

Since we don't really know WHAT your variables contain, any analysis
of that output is a waste of time, although Pierre gave some decent
pointers about the general difference between [ and [[.


On Wed, Aug 26, 2009 at 01:17:07PM +0300, Pierre Gaston wrote:
> Now I'm not too sure why var='"*'"; [[ \* = $var ]] is false while
> var='\*' [[ \* = $var ]] is true

Assuming the first part was supposed to be var='"*"' ...

The bash command [[ \* = $var ]] returns true if $var contains a glob
pattern against which a literal asterisk * can be matched.  (By the way,
you don't need the \ there.  No glob expansion is done inside [[...]] so
you could use a plain * on the left hand side.)

If $var contains \* then the match is successful.  \* as a glob describes
a literal asterisk, which is what we're trying to match.

$ var='\*'; [[ * = $var ]]; echo $?
0

If $var contains "*" (double quote, asterisk, double quote), then
the double quotes are considered part of the glob pattern.  A bare
asterisk won't match that glob, because it doesn't have double quotes
attached to it.

imadev:~$ var='"*"'; [[ * = $var ]]; echo $?
1

It only matches double quote, asterisk, double quote:

$ var='"*"'; [[ \"*\" = $var ]]; echo $?
0




Re: manpage note? weird strings that appear to be equal but create haywire comparisons?

2009-08-26 Thread Pierre Gaston
On Wed, Aug 26, 2009 at 12:45 PM, Linda Walsh wrote:
> I was scripting and fixing some permissions in Win,
> and had a var 'c' set to (no quotes in the var):   'C\windows\system32'


> I first bumped into this using the printf -v var "%q" feature, where
> I expected it to doublequote the back slashes. But instead, it looked
> like I got the same value assigned to v as though I'd just done a 'c=v'
>
> # printf -v v "%q" $c
> # echo  $v |hexdump -C
>   43 3a 5c 77 69 6e 64 6f  77 73 5c 73 79 73 74 65
>  |C:\windows\syste|
> 0010  6d 33 32 0a  0014

here is what I get:
$ echo $v | hexdump -C
  43 3a 5c 5c 57 69 6e 64  6f 77 73 5c 5c 53 79 73  |C:\\Windows\\Sys|
0010  74 65 6d 33 32 0a |tem32.|
0016

if you run your test prog after setting  "set -x"  (or run it with
bash -x testprog)
you will see the double \\.



> Note that [[ and [ return different results when the vars are unquoted.

The bash keyword [[ and [ are different in several ways (word
splitting does not occur for instance)
in your example the difference is that = inside [[ ]] does pattern matching.
(note that in the case of bash [ is also a builtin)

*  If you quote the right hand side variable, then the expression is
taken literally, the test becomes:

[[ 'C:\Windows\System32' != 'C:\\Windows\\System32' ]]

and it's false.

* If you don't quote the right hand side variable, then the expression
is taken as a pattern, the test becomes

[[ 'C:\Windows\System32' != C:\\Windows\\System32 ]]

in this glob the the \ is consider as escaping the other \ and the 2
variables are equal.

That explaine the differences.

Now I'm not too sure why var='"*'"; [[ \* = $var ]] is false while
var='\*' [[ \* = $var ]] is true




manpage note? weird strings that appear to be equal but create haywire comparisons?

2009-08-26 Thread Linda Walsh

I was scripting and fixing some permissions in Win,
and had a var 'c' set to (no quotes in the var):   'C\windows\system32'

 # echo  $v |hexdump -C
   43 3a 5c 77 69 6e 64 6f  77 73 5c 73 79 73 74 65  |C:\windows\syste|
 0010  6d 33 32 0a   |m32.|
 0014

I first bumped into this using the printf -v var "%q" feature, where
I expected it to doublequote the back slashes. But instead, it looked
like I got the same value assigned to v as though I'd just done a 'c=v'

# printf -v v "%q" $c
# echo  $v |hexdump -C
  43 3a 5c 77 69 6e 64 6f  77 73 5c 73 79 73 74 65  |C:\windows\syste|
0010  6d 33 32 0a  
0014


But then I tested equality on the strings and that's the confusing
part. I have an idea of what's going on but boy do string compares look
confused.  They perform same on cygwin
(bashv=3.2.49(22)-release (i686-pc-cygwin)) and Suse11.1:
(bashv=3.2.39(1)-release (x86_64-suse-linux-gnu)

Using the simple form:
   if  ; then echo = "True" else echo False ; fi
I get:

for c=C:\Windows\System32, and v=C:\Windows\System32

expr = [[ "$c" = "$v" ]]  : "False"
expr = [ "$c" = "$v" ]: "False"
expr = [[ "$c" != "$v" ]] : "True"
expr = [ "$c" != "$v" ]   : "True"
expr = [[ $c = $v ]]  : "True"
expr = [ $c = $v ]: "False"
expr = [[ $c != $v ]] : "False"
expr = [ $c != $v ]   : "True"

Note that [[ and [ return different results when the vars are unquoted.

TestProg: (interactive shell...)

{
c='C:\Windows\System32'
printf -v v "%q" "$c"
export c v 
echo  for c=$c, and v=$v

for ((qq=2;qq>=0;qq-=2)); do
 if ((qq==2)); then q='"'; else q=''; fi
 for test in '=' '!=' ; do
  for ((op=1;op<=2;++op)) ; do
   if (($op==1)) ; then to="[["; tc="]]" ; else to="["; tc="]"; fi
  expr=$(printf "%s %s%s%s %s %s%s%s %s" "$to" "$q" '$c' "$q" "$test" "$q" '$v' 
"$q" "$tc")
 printf "expr = %-18s : \"" "$expr"
if eval $expr ; then echo True\"  ; else echo False\" ; fi
  done
 done
done;
# vim:et:ts=1:sw=1
}


--
I sorta understand why they wouldn't be entirely equal, but having the
built-in treat them differently than the single brackets is a bit
surprising..



If I put them outside