zsh-users
 help / color / mirror / code / Atom feed
* counting trouble
@ 2018-04-04 18:21 Ray Andrews
  2018-04-05  1:15 ` Bart Schaefer
  0 siblings, 1 reply; 5+ messages in thread
From: Ray Andrews @ 2018-04-04 18:21 UTC (permalink / raw)
  To: Zsh Users

I have a function that attempts a unique filename match for the argument 
and warns you if what you have entered can't be disambiguated.  It's 
easy if there are multiple matcheswhich is of course 'unsuccessful' but 
at least gives an honest report of the ambiguity:


     tmp=( $1*(N) )

     if [[ "$#tmp" > 1 ]]; then

         echo "count is: $#tmp"

         print -rl " More than one match:\n ${tmp[@]}\n"

fi

Alas, if there is only one match then the count becomes a countnot of 
lines but of characterswhich is a nasty gotcha.

Hacking away I find this works:

     [ -e "$1" ] && tmp=( "${(f)${1}}" ) || tmp=( ${1}*(N) )
     ...

... the first assignment forces the line count.  But that's surely 
monstrous.  I've tried a single assignment but nothing seems legal as 
far as getting the wildcard inside the '${(f) ...}' construction.  I'd 
have expected this to work: " ${(f)${1}*} " but it doesn't. Is something 
civilized possible?  I've sorta figured out that the wildcard is no 
longer a wildcard in there, but what to do?



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: counting trouble
  2018-04-04 18:21 counting trouble Ray Andrews
@ 2018-04-05  1:15 ` Bart Schaefer
  2018-04-05  2:07   ` Ray Andrews
  0 siblings, 1 reply; 5+ messages in thread
From: Bart Schaefer @ 2018-04-05  1:15 UTC (permalink / raw)
  To: Ray Andrews; +Cc: Zsh Users

On Wed, Apr 4, 2018 at 11:21 AM, Ray Andrews <rayandrews@eastlink.ca> wrote:
>
>     tmp=( $1*(N) )
>
>     if [[ "$#tmp" > 1 ]]; then
>
> Alas, if there is only one match then the count becomes a count not of lines
> but of characters which is a nasty gotcha.

That can't be all there is to it.  $#array only becomes a count of
characters if the context forces the array into string form.  Which
admittedly can happen in some non-obvious ways, but what you've shown
above is not one of those ways.  What are you really doing?

> Hacking away I find this works:
>
>     [ -e "$1" ] && tmp=( "${(f)${1}}" ) || tmp=( ${1}*(N) )

Umm ...  [ -e "$1" ] will only succeed for a single literal file name,
not a pattern, and the (f) flag means to split on newlines, so unless
you have a file with newlines embedded in the name (in which case this
is entirely broken a different way) there's no reason for ${(f)...}
there at all.  And none of this has anything to do with how [[ $#tmp >
1 ]] would work after the assignment.

> expected this to work: " ${(f)${1}*} " but it doesn't.

Expected it to do what?  Filename generation like ${1}* out in the
open (so to speak)?  What led you to expect that?  In any case
filename generation would never produce a newline-separated string
(again barring files with newlines in the name), so (f) would not do
anything to the result.

Please don't think about globbing as returning "lines".  It doesn't.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: counting trouble
  2018-04-05  1:15 ` Bart Schaefer
@ 2018-04-05  2:07   ` Ray Andrews
  2018-04-05  4:48     ` Bart Schaefer
  0 siblings, 1 reply; 5+ messages in thread
From: Ray Andrews @ 2018-04-05  2:07 UTC (permalink / raw)
  To: zsh-users

On 04/04/18 06:15 PM, Bart Schaefer wrote:
> On Wed, Apr 4, 2018 at 11:21 AM, Ray Andrews <rayandrews@eastlink.ca> wrote:
>>
>> That can't be all there is to it.  $#array only becomes a count of
>> characters if the context forces the array into string form.  Which
>> admittedly can happen in some non-obvious ways, but what you've shown
>> above is not one of those ways.  What are you really doing?
I'll take another look, that's a good clue anyway.
>
>> Hacking away I find this works:
>>
>>      [ -e "$1" ] && tmp=( "${(f)${1}}" ) || tmp=( ${1}*(N) )
> Umm ...  [ -e "$1" ] will only succeed for a single literal file name,
Exactly the point of it.   I found I had to handle an exact match 
specially.  I'm sure there's a better way.
> expected this to work: " ${(f)${1}*} " but it doesn't.
> Expected it to do what?  Filename generation like ${1}* out in the
> open (so to speak)?
Yeah, but as I said, I've figured out that that won't happen, it's not a 
glob 'inside'.  So how would I get the results of the glob 'inside' as 
well as the single match not counting characters? .... but you've just 
said that shouldn't be happening, so I'll follow that clue.

> What led you to expect that?  In any case
> filename generation would never produce a newline-separated string
> (again barring files with newlines in the name), so (f) would not do
> anything to the result.
>
> Please don't think about globbing as returning "lines".  It doesn't.
>
But:

    tmp=( ${1}*(N) )

... seems to give me exactly that -- an array split on lines with no 
worries about spaces in filenames.  And '$#' counts the number of files 
just as I want.

   print -l "${tmp[@]}\n"

... does exactly what I'm expecting (bottom example):

15 /aWorking/Zsh/Source/Wk 3 $ . try; find_match try,12
Exact match found: "try,12"

15 /aWorking/Zsh/Source/Wk 3 $ . try; find_match try,1
Unique match found: "try,1"

15 /aWorking/Zsh/Source/Wk 3 $ . try; find_match try,14
Exact match found: "try,14,interim"

15 /aWorking/Zsh/Source/Wk 3 $ . try; find_match try,*

ERROR: No wildcards please

15 /aWorking/Zsh/Source/Wk 3 $ . try; find_match try,

ERROR: 18:: 15 matches for "try,", please disambiguate or copy manually:
try,1
try,10,working
try,11,very nice, help text
try,12
try,13
try,14,interim
try,15,important noglob and messages
try,2,exact match handled
try,3,now add declare
try,4,no ls
try,5,shakeout bugs
try,6,interim safe
try,7,now with find_match
try,8
try,9,working
===========================================

What would be manna from heaven is to be able to look at an array and 
'see' the construction of it -- how it's split, if one could see the 
newlines and/or spaces in both input and output that would be huge.  
Even after several years I still find myself throwing syntax at things 
hopefully but almost randomly until eventually something works.  If I 
could see the hidden structure of both input and output there'd be a lot 
less guessing.



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: counting trouble
  2018-04-05  2:07   ` Ray Andrews
@ 2018-04-05  4:48     ` Bart Schaefer
  2018-04-05 13:45       ` Ray Andrews
  0 siblings, 1 reply; 5+ messages in thread
From: Bart Schaefer @ 2018-04-05  4:48 UTC (permalink / raw)
  To: zsh-users

On Apr 4,  7:07pm, Ray Andrews wrote:
}
} On 04/04/18 06:15 PM, Bart Schaefer wrote:
} > Please don't think about globbing as returning "lines".  It doesn't.
}
} But:
} 
}     tmp=( ${1}*(N) )
} 
} ... seems to give me exactly that -- an array split on lines

But it's NOT lines, any more than the elements of a C array are lines
(and internally, to zsh at least, it *IS* a C array of nul-terminated
strings -- other shells such as bash use a linked list, etc.).

In the shell grammar sense, it's an array of "shell words".

A directory does not contain "lines", it contains file names.  When you
use a glob, you're extracting the matching file names one by one, not
grepping a text stream of all those names and then splitting it up at
line breaks.

}    print -l "${tmp[@]}\n"
} 
} ... does exactly what I'm expecting

But print is receiving individual "shell words" as its argument list,
one array element per word.  The -l option causes print to *add* the
line breaks.  If you replace -l with -N you don't get line breaks,
you get nul bytes.

(Except given that construction plus print's usual interpretation of
backslash-escapes, you've pasted an extra newline on the final word.)
 
} What would be manna from heaven is to be able to look at an array and 
} 'see' the construction of it -- how it's split, if one could see the 
} newlines and/or spaces in both input and output that would be huge.

There's no perfect way to do that because there's intentionally no
character that you could use to show where the words begin and end
that can't also theoretically appear IN one of the words.  You could
step in with a debugger like gdb and use it to display the internal
memory allocations.

If you know you're writing to an ANSI color terminal and you know the
array doesn't contain color changing sequences, you can try something
like this:

    autoload colors
    colors
    wstart="$bg[black]$fg[green]<<$reset_color"
    wend="$bg[black]$fg[yellow]>>$reset_color"
    printf "${wstart}%s${wend}" "${array[@]}"
    print

Adjust wstart and wend until you have something you think is visible
enough.

} If I could see the hidden structure of both input and output there'd
} be a lot less guessing.

I'm not sure what you consider to be an "input" and what an "output".


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: counting trouble
  2018-04-05  4:48     ` Bart Schaefer
@ 2018-04-05 13:45       ` Ray Andrews
  0 siblings, 0 replies; 5+ messages in thread
From: Ray Andrews @ 2018-04-05 13:45 UTC (permalink / raw)
  To: zsh-users

On 04/04/18 09:48 PM, Bart Schaefer wrote:
> But it's NOT lines, any more than the elements of a C array are lines
Ok, I suppose it's worth keeping clear.  In practical terms tho 3/4 of 
my grief with zsh is line/splitting issues.  I can see that this problem 
is fundamental to the way the shells work so no salvation is possible, 
but some way of really getting a grip on things would sure be welcome.
>
> In the shell grammar sense, it's an array of "shell words".
New concept!  Mind, I know what you mean, an array is element based, not 
'terminator' based (except for the null of course).  Thing is, that if 
we could just 'see' the structure things would become more clear.  
Interesting that in C none of this is any sort of issue at all, it's 
always entirely transparent.
> }    print -l "${tmp[@]}\n"
> }
> } ... does exactly what I'm expecting
>
> But print is receiving individual "shell words" as its argument list,
> one array element per word.  The -l option causes print to *add* the
> line breaks.  If you replace -l with -N you don't get line breaks,
> you get nul bytes.
Right, it is worth getting that straight.  I've tended to think of \n's 
as being actually 'in' the data structure.  And that also makes it clear 
why I should stop trying to make echo act on newlines -- they ain't 
there!  But besides output formatting, we also have actual data 
manipulations and the whole thing is invisible.
>
> There's no perfect way to do that because there's intentionally no
> character that you could use to show where the words begin and end
> that can't also theoretically appear IN one of the words.
Jesus! How was this sort of thing permitted back in the day? Astonishing 
that you guys made it all work.
> } If I could see the hidden structure of both input and output there'd
> } be a lot less guessing.
>
> I'm not sure what you consider to be an "input" and what an "output".
>
I mean the way we can read in one data structure and save it to another 
with a different construction.  In view of the above, I'm beginning to 
suspect that half the time my way of getting things to format has been 
via trying to change the data structure itself rather than simply 
controlling output formatting.  This might be easier than I've made it 
-- we don't 'act' on the newlines, we 'print -l' to get each element on 
a new line.  That's quite huge. Of course there can be 'real' newlines 
here and there and that way lies madness.

BTW you were right, in the 'count' issue it does seem I somehow 
stringified the element -- more invisible spells and curses.

print -l ... yes, now I get it.



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2018-04-05 13:45 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-04 18:21 counting trouble Ray Andrews
2018-04-05  1:15 ` Bart Schaefer
2018-04-05  2:07   ` Ray Andrews
2018-04-05  4:48     ` Bart Schaefer
2018-04-05 13:45       ` Ray Andrews

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).