* 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).