zsh-users
 help / color / mirror / code / Atom feed
* triviality regarding $# counts
@ 2024-04-11  0:56 Ray Andrews
  2024-04-12  4:55 ` Lawrence Velázquez
  0 siblings, 1 reply; 40+ messages in thread
From: Ray Andrews @ 2024-04-11  0:56 UTC (permalink / raw)
  To: Zsh Users

[-- Attachment #1: Type: text/plain, Size: 2568 bytes --]

This practice text is in a variable 'temp' and I want to count the 
number of lines inside a function that will also print the text exactly 
as shown, and do a bunch of other stuff.

--------------------------------------------------------------------
xz-utils:
/usr/bin/xzgrep
/usr/share/man  /de/man1/xzgrep.1.gz    # Hafta be careful not to split 
here.
/usr/share/man  /ko/man1/xzgrep.1.gz    # ... or here.
/usr/share/man/man1/xzgrep.1.gz
/usr/share/man/pt_BR/man1/xzgrep.1.gz
/usr/share/man/ro/man1/xzgrep.1.gz
/usr/share/man/uk/man1/xzgrep.1.gz
/usr/bin/xzegrep
/usr/bin/xzfgrep
/usr/share/man/de/man1/lzegrep.1.gz
/usr/share/man/de/man1/lzfgrep.1.gz
/usr/share/man/uk/man1/xzegrep.1.gz
/usr/share/man/uk/man1/xzfgrep.1.gz

zsh-common:
/usr/share/doc/zsh-common/examples/Functions/zpgrep
/usr/share/zsh/functions/Completion/Debian/_grep-excuses
/usr/share/zsh/functions/Completion/Unix/_grep
/usr/share/zsh/functions/Completion/Unix/_ngrep
/usr/share/zsh/functions/Completion/Unix/_pgrep

zstd:
/usr/bin/zstdgrep
/usr/share/man/man1/zstdgrep.1.gz
-----------------------------------------------------------------------------------

This works: (Again, this is deep in a function and I have to use eval.)

     output=$( eval "$@" )   # '$@' will expand to 'print -l $temp' 
which is the text above.
     temp=( $( eval $@ ) )    # To get the correct count I need to force 
an array.
     linecount=$#temp
     print -rl -- $output
     print  $linecount

Various experiments trying to get the correct linecount (23) *and* get 
it printing correctly all end up with waterboarding problems. If I do it 
in two stages as above, it's ok, but is seems very clumsy.  Different 
efforts at quoting or using ' ${(@f) ....} ' and various other tricks 
yield me a linecount of 1, 3, 23, 25, 26, or 738.  And output that 
deletes the blank lines, or forces everything into one 'line/element'.  
Basically I need the array form to to get the line count, but it won't 
print properly as an array.  Not that it's worth much trouble, but is it 
possible to get the variable  to print correctly *and* show the count of 
lines without having to eval it twice?  schematically:

     output=????$( eval ???)??? # Whatever the correct code might be.
     linecount=$#output
     print -rl -- $output
     print  $linecount

... as it is, it seems that '$#' never counts the lines of output as it 
actually prints.  In practice it's hardly a problem but still it bothers 
me.  '$#' seems mostly to want to count characters (738).



[-- Attachment #2: Type: text/html, Size: 3390 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-11  0:56 triviality regarding $# counts Ray Andrews
@ 2024-04-12  4:55 ` Lawrence Velázquez
  2024-04-12 14:48   ` Ray Andrews
  0 siblings, 1 reply; 40+ messages in thread
From: Lawrence Velázquez @ 2024-04-12  4:55 UTC (permalink / raw)
  To: zsh-users

On Wed, Apr 10, 2024, at 8:56 PM, Ray Andrews wrote:
> This works: (Again, this is deep in a function and I have to use eval.)

If eval really is necessary (to be frank, I don't trust your judgment
on this), show us examples that require it, instead of the misleading
Rube Goldberg machines you've been offering.


>     output=$( eval "$@" )   # '$@' will expand to 'print -l $temp' 
> which is the text above.
>     temp=( $( eval $@ ) )    # To get the correct count I need to force 
> an array.
>     linecount=$#temp
>     print -rl -- $output
>     print  $linecount

The count is correct by accident.  Your unquoted command substitution
drops the two empty lines but splits the two lines you say should not
be split.

	% orig='abc
	quote> 
	quote> def ghi
	quote> jkl mno
	quote> 
	quote> pqr'
	% arr=($(print -r -- $orig))
	% typeset -p arr
	typeset -a arr=( abc def ghi jkl mno pqr )


> Various experiments trying to get the correct linecount (23)

There are 25 lines, not 23.


> Different efforts at quoting or using ' ${(@f) ....} ' and various 
> other tricks yield me a linecount of 1, 3, 23, 25, 26, or 738.  And 
> output that deletes the blank lines, or forces everything into one 
> 'line/element'.  Basically I need the array form to to get the line 
> count, but it won't print properly as an array.  Not that it's worth 
> much trouble, but is it possible to get the variable  to print 
> correctly *and* show the count of lines without having to eval it 
> twice?

	% cat foo.zsh
	orig='abc

	def ghi
	jkl mno

	pqr'

	# The sensible way to split on LFs.
	#arr=("${(@f)orig}")

	# A very silly way to split on LFs.  Use double quotes to
	# prevent the result of $(...) from being split and to retain
	# empty words in the result of ${(@)...}.
	arr=("${(@f)$(print -r -- $orig)}")

	typeset -p arr
	print -r -- $#arr

	# Use double-quoted $arr[@] to retain empty elements.  Use
	# "print -C1" to avoid printing an empty line if "arr" is empty.
	print -rC1 -- "$arr[@]"

	% zsh ./foo.zsh
	typeset -a arr=( abc '' 'def ghi' 'jkl mno' '' pqr )
	6
	abc

	def ghi
	jkl mno

	pqr
	%


> ... as it is, it seems that '$#' never counts the lines of output as it 
> actually prints.

You both populate and print your array incorrectly.  For the umpteenth
time, you should use "typeset -p" to inspect your variables' values.


-- 
vq


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

* Re: triviality regarding $# counts
  2024-04-12  4:55 ` Lawrence Velázquez
@ 2024-04-12 14:48   ` Ray Andrews
  2024-04-12 19:09     ` Bart Schaefer
  0 siblings, 1 reply; 40+ messages in thread
From: Ray Andrews @ 2024-04-12 14:48 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 3005 bytes --]



On 2024-04-11 21:55, Lawrence Velázquez wrote:

> If eval really is necessary (to be frank, I don't trust your judgment
> on this), show us examples that require it, instead of the misleading
> Rube Goldberg machines you've been offering.
I don't trust it neither, and I taught Rube everything he knows. 
Seriously, you won't sympathize, but the tinkerer's approach was the 
only one available to me at least until I had enough ad hoc code built 
up that sorta works to begin to start to try to understand it formally.  
And my efforts to find patterns of behavior -- as you know better than 
anyone -- lead me to false conclusions all the time.  The manual is 
useless as pedagogy.  If there was 'zsh school' I'd enroll and learn my 
shell ABC's properly from the ground up. But there isn't.  So I hack 
away.  But please understand I *hate* being me.  I like competence :(
> The count is correct by accident.  Your unquoted command substitution
> drops the two empty lines but splits the two lines you say should not
> be split.
Right, I'm aware of that possibility at least in theory.  Word splitting 
lurks.
> 	% orig='abc
> 	quote>
> 	quote> def ghi
> 	quote> jkl mno
> 	quote>
> 	quote> pqr'
> 	% arr=($(print -r -- $orig))
> 	% typeset -p arr
> 	typeset -a arr=( abc def ghi jkl mno pqr )
It will take me a long time to understand that.

> 	% cat foo.zsh
> 	orig='abc
>
> 	def ghi
> 	jkl mno
>
> 	pqr'
>
> 	# The sensible way to split on LFs.
> 	#arr=("${(@f)orig}")
>
> 	# A very silly way to split on LFs.  Use double quotes to
> 	# prevent the result of $(...) from being split and to retain
> 	# empty words in the result of ${(@)...}.
> 	arr=("${(@f)$(print -r -- $orig)}")
>
> 	typeset -p arr
> 	print -r -- $#arr
>
> 	# Use double-quoted $arr[@] to retain empty elements.  Use
> 	# "print -C1" to avoid printing an empty line if "arr" is empty.
> 	print -rC1 -- "$arr[@]"
>
> 	% zsh ./foo.zsh
> 	typeset -a arr=( abc '' 'def ghi' 'jkl mno' '' pqr )
> 	6
> 	abc
>
> 	def ghi
> 	jkl mno
>
> 	pqr
> 	%
I think I can chew on that, backatcha later.

> You both populate and print your array incorrectly. For the umpteenth
> time, you should use "typeset -p" to inspect your variables' values.
>
I keep typeset -p close at all times now.  But there are times when I'm 
still baffled.  Like an alchemist.  Sheesh, just yesterday I was 
attempting to transform this:

typeset -g var="
abc

     def ghi
     jkl mno

     pqr
"

... into an array that retained the same 'shape' -- that prints verbatim 
-- and typeset -p showed newlines being transubstantiated into dollar 
signs!  God knows how.

For now, what I'm wishing for is a nice, focused essay: "How to use '$#' 
to count whatever it is you want to count -- characters, words, lines, 
paragraphs (at one point my count was '3' which I'd approximate to being 
a paragraph) ... and all with or without spaces and/or empty lines. " 
Should run about  ten pages but it would be everything there is to know 
about '$#'.


[-- Attachment #2: Type: text/html, Size: 4464 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-12 14:48   ` Ray Andrews
@ 2024-04-12 19:09     ` Bart Schaefer
  2024-04-13  1:13       ` Ray Andrews
  0 siblings, 1 reply; 40+ messages in thread
From: Bart Schaefer @ 2024-04-12 19:09 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Fri, Apr 12, 2024 at 7:49 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> For now, what I'm wishing for is a nice, focused essay: "How to use '$#' to count whatever it is you want to count -- characters, words, lines, paragraphs (at one point my count was '3' which I'd approximate to being a paragraph) ... and all with or without spaces and/or empty lines. "

None of that is about $#.  $# just counts either characters in a
string or elements in an array, full stop.

What you're asking for is a dissertation on how to split text into
arrays.  I have no idea what you mean by "without spaces" and there's
no inherent definition of a "paragraph" so the best you could get from
this is characters, words, and lines -- but even for words you need to
explain whether you mean "shell words" (separated by $IFS characters)
or something else, including whether quotes matter.  Further, you seem
to be starting from scalar text sometimes, and text that's already
split into an array other times -- in the latter case you have to
explain whether and how you want the array re-joined into a block of
text before re-splitting.

The shell is not a word processor and doesn't understand your
conceptualization of text formatting.


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

* Re: triviality regarding $# counts
  2024-04-12 19:09     ` Bart Schaefer
@ 2024-04-13  1:13       ` Ray Andrews
  2024-04-13  1:33         ` Mark J. Reed
  2024-04-13  1:35         ` Bart Schaefer
  0 siblings, 2 replies; 40+ messages in thread
From: Ray Andrews @ 2024-04-13  1:13 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 2398 bytes --]


On 2024-04-12 12:09, Bart Schaefer wrote:
> None of that is about $#. $# just counts either characters in a
> string or elements in an array, full stop.
Right, it's a question of getting the splitting correct.
> What you're asking for is a dissertation on how to split text into
> arrays.  I have no idea what you mean by "without spaces" and there's
> no inherent definition of a "paragraph"
I know it, thus the air-quotes, In one of my tests I had three 
consecutive outputs from aptitude written to the array and at some point 
the count was 3, so somehow each separate output got merged into one 
element.
> so the best you could get from
> this is characters, words, and lines -- but even for words you need to
> explain whether you mean "shell words" (separated by $IFS characters)
> or something else, including whether quotes matter.
It is a bit confusing.

>    Further, you seem
> to be starting from scalar text sometimes, and text that's already
> split into an array other times -- in the latter case you have to
> explain whether and how you want the array re-joined into a block of
> text before re-splitting.
I've got a whole bunch of that figured out today.  What I thought were 
arrays were scalars that just happened to print nicely on separate lines 
where wanted but not due to '\n''s.  And what I thought line splitting 
-- (f) -- did was enter '\n's into the body of the variable -- a guy 
might be forgiven for thinking that -- but no it's dollar signs.  And 
efforts to force '\n's' were disastrous. Some quality time with typedef 
-p really helped.  Sorta funny, everything was working fine, but there 
were hidden disasters lurking that surfaced for that most trivial of 
reasons -- but forced me to redo quite a bit of stuff where things 
really are arrays and nevermind the '\n's.  And I get my line counts 
honestly now :-)  One thing: it sure is hard to hang on to blank lines.  
I wish there was some option to default to preserving them.
> The shell is not a word processor and doesn't understand your
> conceptualization of text formatting.
Very true.  But I focus on what I can see and if it looks right it's 
easy to think it is right.  Anyway, thanks to Lawrence much as been 
learned. BTW $# is a very convenient way of detecting how things are 
split, now that I know that scalars always return character counts and 
arrays, element counts.  Easy!

[-- Attachment #2: Type: text/html, Size: 3604 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-13  1:13       ` Ray Andrews
@ 2024-04-13  1:33         ` Mark J. Reed
  2024-04-13  2:28           ` Ray Andrews
  2024-04-13  1:35         ` Bart Schaefer
  1 sibling, 1 reply; 40+ messages in thread
From: Mark J. Reed @ 2024-04-13  1:33 UTC (permalink / raw)
  To: Zsh Users

[-- Attachment #1: Type: text/plain, Size: 2942 bytes --]

More context would clarify what you're trying to do and how best to do it.
Without that context, the approach you're currently taking feels deeply
weird. Can you not provide sample input and desired output? Maybe with all
of your code rather than a few snippets from "so deep they need eval",
whatever that means...

On Fri, Apr 12, 2024 at 9:13 PM Ray Andrews <rayandrews@eastlink.ca> wrote:

>
> On 2024-04-12 12:09, Bart Schaefer wrote:
>
> None of that is about $#. $# just counts either characters in a
>
> string or elements in an array, full stop.
>
> Right, it's a question of getting the splitting correct.
>
> What you're asking for is a dissertation on how to split text into
> arrays.  I have no idea what you mean by "without spaces" and there's
> no inherent definition of a "paragraph"
>
> I know it, thus the air-quotes, In one of my tests I had three consecutive
> outputs from aptitude written to the array and at some point the count was
> 3, so somehow each separate output got merged into one element.
>
> so the best you could get from
> this is characters, words, and lines -- but even for words you need to
> explain whether you mean "shell words" (separated by $IFS characters)
> or something else, including whether quotes matter.
>
> It is a bit confusing.
>
>   Further, you seem
> to be starting from scalar text sometimes, and text that's already
> split into an array other times -- in the latter case you have to
> explain whether and how you want the array re-joined into a block of
> text before re-splitting.
>
> I've got a whole bunch of that figured out today.  What I thought were
> arrays were scalars that just happened to print nicely on separate lines
> where wanted but not due to '\n''s.  And what I thought line splitting --
> (f) -- did was enter '\n's into the body of the variable -- a guy might be
> forgiven for thinking that -- but no it's dollar signs.  And efforts to
> force '\n's' were disastrous.  Some quality time with typedef -p really
> helped.  Sorta funny, everything was working fine, but there were hidden
> disasters lurking that surfaced for that most trivial of reasons -- but
> forced me to redo quite a bit of stuff where things really are arrays and
> nevermind the '\n's.  And I get my line counts honestly now :-)  One thing:
> it sure is hard to hang on to blank lines.  I wish there was some option to
> default to preserving them.
>
> The shell is not a word processor and doesn't understand your
> conceptualization of text formatting.
>
> Very true.  But I focus on what I can see and if it looks right it's easy
> to think it is right.  Anyway, thanks to Lawrence much as been learned. BTW
> $# is a very convenient way of detecting how things are split, now that I
> know that scalars always return character counts and arrays, element
> counts.  Easy!
>
>

-- 
Mark J. Reed <markjreed@gmail.com>

[-- Attachment #2: Type: text/html, Size: 4020 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-13  1:13       ` Ray Andrews
  2024-04-13  1:33         ` Mark J. Reed
@ 2024-04-13  1:35         ` Bart Schaefer
  1 sibling, 0 replies; 40+ messages in thread
From: Bart Schaefer @ 2024-04-13  1:35 UTC (permalink / raw)
  To: zsh-users

On Fri, Apr 12, 2024 at 6:13 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> I've got a whole bunch of that figured out today.  What I thought were arrays were scalars that just happened to print nicely on separate lines where wanted but not due to '\n''s.  And what I thought line splitting -- (f) -- did was enter '\n's into the body of the variable -- a guy might be forgiven for thinking that -- but no it's dollar signs.

You're definitely confusing yourself again there somehow.  (f) does
not "enter" anything into the "body" of a variable -- it splits a
string into an array, converting newlines into the breaks between
array elements.  I have no idea where you think dollar signs are
coming from ... unless possibly because "typeset -p" will output array
elements using $'...' quoting if there are certain non-printable
characters in the element?

>  One thing: it sure is hard to hang on to blank lines.  I wish there was some option to default to preserving them.

Again this is not making much sense.  There are only two cases:
Strings with newline characters in them, and array elements where a
blank line might become an empty element if you got there by splitting
a string.  Empty elements generally get removed from argument lists if
you reference the array without proper quoting, especially if you're
forcing an additional layer of interpretation by using "eval", but
they won't be removed from the array itself.


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

* Re: triviality regarding $# counts
  2024-04-13  1:33         ` Mark J. Reed
@ 2024-04-13  2:28           ` Ray Andrews
  2024-04-13  3:25             ` Lawrence Velázquez
  0 siblings, 1 reply; 40+ messages in thread
From: Ray Andrews @ 2024-04-13  2:28 UTC (permalink / raw)
  To: zsh-users



On 2024-04-12 18:33, Mark J. Reed wrote:
> More context would clarify what you're trying to do and how best to do 
> it. Without that context, the approach you're currently taking feels 
> deeply weird. Can you not provide sample input and desired output? 
> Maybe with all of your code rather than a few snippets from "so deep 
> they need eval", whatever that means...
Context would be very difficult, trust me.  You'd hafta run the thing.  
But yes, it could all be deeply weird, I have nothing to build from but 
my own notions of how things should work.



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

* Re: triviality regarding $# counts
  2024-04-13  2:28           ` Ray Andrews
@ 2024-04-13  3:25             ` Lawrence Velázquez
  2024-04-13 14:37               ` Ray Andrews
  0 siblings, 1 reply; 40+ messages in thread
From: Lawrence Velázquez @ 2024-04-13  3:25 UTC (permalink / raw)
  To: zsh-users

On Fri, Apr 12, 2024, at 10:28 PM, Ray Andrews wrote:
> On 2024-04-12 18:33, Mark J. Reed wrote:
>> More context would clarify what you're trying to do and how best to do 
>> it. Without that context, the approach you're currently taking feels 
>> deeply weird. Can you not provide sample input and desired output? 
>> Maybe with all of your code rather than a few snippets from "so deep 
>> they need eval", whatever that means...
> Context would be very difficult, trust me.  You'd hafta run the thing.  
> But yes, it could all be deeply weird, I have nothing to build from but 
> my own notions of how things should work.

We all understand that it can be difficult to boil a problem down
to a tractable, self-contained example.  But the alternative you've
chosen -- presenting baffling examples without necessary context,
describing your debugging attempts in vague terms without concrete
details, and inventing deeply bogus theories instead of consulting
the documentation first -- is making it difficult for us to help.

-- 
vq


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

* Re: triviality regarding $# counts
  2024-04-13  3:25             ` Lawrence Velázquez
@ 2024-04-13 14:37               ` Ray Andrews
  2024-04-13 15:14                 ` Ray Andrews
  0 siblings, 1 reply; 40+ messages in thread
From: Ray Andrews @ 2024-04-13 14:37 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1376 bytes --]



On 2024-04-12 20:25, Lawrence Velázquez wrote:
> We all understand that it can be difficult to boil a problem down
> to a tractable, self-contained example.  But the alternative you've
> chosen -- presenting baffling examples without necessary context,
> describing your debugging attempts in vague terms without concrete
> details, and inventing deeply bogus theories instead of consulting
> the documentation first -- is making it difficult for us to help.
On the contrary, your help has been most effective.  I wouldn't know how 
to expand the context without expanding it 'all the way out' and that's 
more context than you want, trust me.  And sorry about the deeply bogus 
theories, I know they're deeply bogus but I'm a pattern seeking animal 
and I'll attempt to model what I think is going on knowing full well 
that I'm usually wrong.

Bart:

>  I have no idea where you think dollar signs are
coming from ... unless possibly because "typeset -p" will output array
elements using $'...' quoting if there are certain non-printable
characters in the element?



I dunno.  I've lost the example that I saved. Never mind, I'll keep an eye on it, and figure out next time. Red herring for now.  It's a bit confusing looking into typeset -p output. All this 'splitting' stuff is not simple. For now everything works and I'm quite sure it's a bit more orthodox.

    

[-- Attachment #2: Type: text/html, Size: 1924 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-13 14:37               ` Ray Andrews
@ 2024-04-13 15:14                 ` Ray Andrews
  2024-04-13 17:19                   ` Mark J. Reed
  2024-04-13 20:53                   ` Bart Schaefer
  0 siblings, 2 replies; 40+ messages in thread
From: Ray Andrews @ 2024-04-13 15:14 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 2719 bytes --]

> I dunno.  I've lost the example that I saved. Never mind, I'll keep an eye on it, and figure out next time. Red herring for now.  It's a bit confusing looking into typeset -p output. All this 'splitting' stuff is not simple. For now everything works and I'm quite sure it's a bit more orthodox.
>
>     
A script:
---------------------------------------------------------------------------------

redline () { echo -e "$red$@$nrm" }

typeset -ga aaa=("
abc

     def ghi
     jkl mno

     pqr
")

redline "\naaa:"
print -l $aaa
redline "\naaa[1]:"
print -l $aaa[1]
redline "linecount of aaa is: $#aaa ... Single element!"

ccc=( ${(@f)aaa} )

redline '\nccc=( ${(@f)aaa} )'
print -l $ccc
redline "linecount of ccc is: $#ccc ... split, but blank lines gone."

ddd=( "${(@f)aaa}" )

redline '\nddd=( "${(@f)aaa}" ) ... it seems like a lot of trouble to 
copy the array as it is.'
print -l "$ddd[@]"  #... don't forget the quotes, idiot!"
redline "linecount of ddd is: $#ddd ... split, but blanks preserved and 
counted. NB EIGHT NOT SIX!"

redline "\nddd[1]: That's right it's blank, just as it should be."
print -l $ddd[1]
redline "\nddd[2]:"
print -l $ddd[2]

redline "And now the typesets\n"
typeset -p aaa
typeset -p ccc
typeset -p ddd

# Verbatim:

# typeset -a aaa=( $'\nabc\n\n\tdef ghi\n\tjkl mno\n\n\tpqr\n' )
# typeset -a ccc=( abc $'\tdef ghi' $'\tjkl mno' $'\tpqr' )
# typeset -a ddd=( '' abc '' $'\tdef ghi' $'\tjkl mno' '' $'\tpqr' '' )

# Aligned: Note the steeenking dollars ;-) ... and how they seem to 
replace the newlines. No?

# typeset -a aaa=( $'\nabc  \n\n\tdef ghi  \n\tjkl mno \n\n\tpqr\n' 
)     #Original with blanks
# typeset -a ccc=(     abc    $'\tdef ghi' $'\tjkl mno   ' $'\tpqr' )  
          #No blanks.
# typeset -a ddd=(  '' abc '' $'\tdef ghi' $'\tjkl mno' '' $'\tpqr' '' 
)    #Blanks retained BUT not the same structure!

-----------------------------------------------------------------------------------

... so what about the dollars?

Anyway, it comes clear: '${(@f)....}' doesn't ADD (or retain) newlines 
it removes them!  (Tho splitting the array where they used to be.) 
Doesn't need them cuz elements aren't separated by newlines (like I 
thought) but by ... however it's done.  Single quotes indicate 
elements.  And, best of all, copying an array, blanks and all, (not 
shown above) turns out to be simple:

eee=( $aaa ) and:

eee=( "{$(@f)aaa}" )

... turns out to be a false equivalence where newlines are REMOVED. 
Don't be fooled by 'printf' -- it might not show you the genuine state 
of the array.  Scalars show their blank lines automatically but we need:

print -l -- "$eee[@]"

... with arrays.  Trust typedef -p.


[-- Attachment #2: Type: text/html, Size: 3679 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-13 15:14                 ` Ray Andrews
@ 2024-04-13 17:19                   ` Mark J. Reed
  2024-04-13 17:27                     ` Mark J. Reed
  2024-04-13 20:53                   ` Bart Schaefer
  1 sibling, 1 reply; 40+ messages in thread
From: Mark J. Reed @ 2024-04-13 17:19 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 7123 bytes --]

Hm.

*typeset* -ga aaa=(*"*

*abc*


*    def ghi*

*    jkl mno*


*    pqr*

*"*)

This makes *aaa* an array with a grand total of 1 element. Then you do this:

redline *"linecount of aaa is: *$#aaa* ... Single element!"*


Your prefix text is wrong; calling  *$# *a "linecount" is a gross
mischaracterization. It never ever ever counts lines.  Never. It counts
characters on a scalar variable, elements of an array.  Lines have nothing
to do with it.

There are various transformations you can do that will map between lines on
the one hand and array elements on the other, but that's always some
command or special expansion flag doing an explicit transformation of the
data - which is to say, changing it. Inside an array there is no concept of
"lines" anywhere. By the same token, a piece of text containing newlines is
not inherently any sort of array at all. (Well, zsh lets you treat a
non-array variable as an array of individual characters, so in that sense
it is an array, but each character is its own element in that case, and
newlines are not in any way special.)

After your above declaration, the variable *aaa* is an array. The
parentheses in the assignment would make it one even if you hadn't
done *typeset
-a*. Unless you un-array-ify the varaible, *$#aaa* will always be *the
number of elements in the array*. It doesn't matter whether any of those
elements contain newlines or not.  Your initialization has exactly one
element, so *$#aaa* is 1. End of story.

You display things with *print -l* *$array* a lot; that's one of those
transformations I mentioned above. When you do that to an array (and *printf
'%\n' "${array[@]}"* does much the same thing in a POSIX-standard way), you
will get output that *starts *each element of the array on a separate line.
But that's all it does. Any newlines inside any of the array elements still
show up as newlines in the output. So there is no guarantee that e.g. *print
-l $ary | wc -l * will produce the same number as *$#ary*.  In your
*aaa* example,
*print -l $aaa *gets you 8 lines. But it's still a single-element array.
There is no *$aaa[put anything in here]* expression that will isolate any
of the lines of text; your only option is the whole thing, because it's all
one element.  (You can use the "a string is an array of characters" trick
to get substrings of that one element, e.g. *${aaa[1][2,4]}* is "abc".  But
again, the inner array is of *characters**, *not lines.)

Then you do this, using another transformation: the *f* expansion flag:

ccc=( ${(@f)aaa} )


By not putting double quotes around the expansion of aaa, you are throwing
away all the blank lines in its expansion. Since this is followed by a
version using the quotes, I assume that's intentional. But as far as I can
tell, the lack of quotation marks also removes any point for including the
*@* flag, since that flag's job is to maintain the identity of the separate
elements of an array when the expansion is quoted.  If it does anything at
all when not quoted, I'm unaware of it, but I admit that I could just be
ignorant of some subtlety.

ddd=( *"*${(@f)aaa}*"* )


Now you're keeping the blank lines, so the (f) gives you a separate array
element for every line that you get from the expansion - 8 of them, the
same as the output of *print -l $aaa | wc -l*.


redline *'\nddd=( "${(@f)aaa}" ) ... it seems like a lot of trouble to copy
the array as it is.'*


That comment confuses me; you aren't copying the array as it is at all!
You've gone from *aaa, *which has one element, to *ddd *having 8 elements.
That's a far cry from "copying as it is".

Your next comment says "8 not 6". I assume the expected 6 would be the
middle lines, without the leading and trailing blank ones, but I know of no
expansion that will produce that. You can get 6 elements out of *aaa*, like
this:

*eee=( $=aaa )*


But it gets there by throwing away all space, including newlines.  So the
six elements will be simply "abc", "def", "ghi", "jkl", "mno", and "pqr"


On Sat, Apr 13, 2024 at 11:14 AM Ray Andrews <rayandrews@eastlink.ca> wrote:

> I dunno.  I've lost the example that I saved. Never mind, I'll keep an eye on it, and figure out next time. Red herring for now.  It's a bit confusing looking into typeset -p output. All this 'splitting' stuff is not simple. For now everything works and I'm quite sure it's a bit more orthodox.
>
>
>
> A script:
>
> ---------------------------------------------------------------------------------
>
> redline () { echo -e "$red$@$nrm" }
>
> typeset -ga aaa=("
> abc
>
>     def ghi
>     jkl mno
>
>     pqr
> ")
>
> redline "\naaa:"
> print -l $aaa
> redline "\naaa[1]:"
> print -l $aaa[1]
> redline "linecount of aaa is: $#aaa ... Single element!"
>
> ccc=( ${(@f)aaa} )
>
> redline '\nccc=( ${(@f)aaa} )'
> print -l $ccc
> redline "linecount of ccc is: $#ccc ... split, but blank lines gone."
>
> ddd=( "${(@f)aaa}" )
>
> redline '\nddd=( "${(@f)aaa}" ) ... it seems like a lot of trouble to copy
> the array as it is.'
> print -l "$ddd[@]"  #... don't forget the quotes, idiot!"
> redline "linecount of ddd is: $#ddd ... split, but blanks preserved and
> counted. NB EIGHT NOT SIX!"
>
> redline "\nddd[1]: That's right it's blank, just as it should be."
> print -l $ddd[1]
> redline "\nddd[2]:"
> print -l $ddd[2]
>
> redline "And now the typesets\n"
> typeset -p aaa
> typeset -p ccc
> typeset -p ddd
>
> # Verbatim:
>
> # typeset -a aaa=( $'\nabc\n\n\tdef ghi\n\tjkl mno\n\n\tpqr\n' )
> # typeset -a ccc=( abc $'\tdef ghi' $'\tjkl mno' $'\tpqr' )
> # typeset -a ddd=( '' abc '' $'\tdef ghi' $'\tjkl mno' '' $'\tpqr' '' )
>
> # Aligned: Note the steeenking dollars ;-) ... and how they seem to
> replace the newlines. No?
>
> # typeset -a aaa=( $'\nabc  \n\n\tdef ghi  \n\tjkl mno   \n\n\tpqr\n'
> )     #Original with blanks
> # typeset -a ccc=(     abc    $'\tdef ghi' $'\tjkl mno   ' $'\tpqr' )
>          #No blanks.
> # typeset -a ddd=(  '' abc '' $'\tdef ghi' $'\tjkl mno' '' $'\tpqr' ''
> )    #Blanks retained BUT not the same structure!
>
>
> -----------------------------------------------------------------------------------
>
> ... so what about the dollars?
>
> Anyway, it comes clear: '${(@f)....}' doesn't ADD (or retain) newlines it
> removes them!  (Tho splitting the array where they used to be.) Doesn't
> need them cuz elements aren't separated by newlines (like I thought) but by
> ... however it's done.  Single quotes indicate elements.  And, best of all,
> copying an array, blanks and all, (not shown above) turns out to be simple:
>
> eee=( $aaa ) and:
>
> eee=( "{$(@f)aaa}" )
>
> ... turns out to be a false equivalence where newlines are REMOVED.  Don't
> be fooled by 'printf' -- it might not show you the genuine state of the
> array.  Scalars show their blank lines automatically but we need:
>
> print -l -- "$eee[@]"
>
> ... with arrays.  Trust typedef -p.
>
>
>

-- 
Mark J. Reed <markjreed@gmail.com>

[-- Attachment #2: Type: text/html, Size: 17714 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-13 17:19                   ` Mark J. Reed
@ 2024-04-13 17:27                     ` Mark J. Reed
  2024-04-13 18:08                       ` Ray Andrews
  0 siblings, 1 reply; 40+ messages in thread
From: Mark J. Reed @ 2024-04-13 17:27 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 847 bytes --]

Small followup I meant to type but didn't:

On Sat, Apr 13, 2024 at 1:19 PM Mark J. Reed <markjreed@gmail.com> wrote:

> redline *'\nddd=( "${(@f)aaa}" ) ... it seems like a lot of trouble to
> copy the array as it is.'*
>
>
> That comment confuses me; you aren't copying the array as it is at all!
> You've gone from *aaa, *which has one element, to *ddd *having 8
> elements. That's a far cry from "copying as it is".
>

If you want to copy an array as it is, this is all you need:

*fff=("${(@)aaa}")*


Or, if you prefer the POSIX syntax:

*fff=("${aaa[@]}")*


After either of the above assignments, *fff* is an exact copy of *aaa*,
including any empty elements.

(If there aren't any empty elements or you want to strip them, you can use
the even simpler *fff=($aaa)*.)
-- 
Mark J. Reed <markjreed@gmail.com>

[-- Attachment #2: Type: text/html, Size: 2477 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-13 17:27                     ` Mark J. Reed
@ 2024-04-13 18:08                       ` Ray Andrews
  2024-04-13 19:45                         ` Bart Schaefer
  2024-04-13 20:11                         ` Mark J. Reed
  0 siblings, 2 replies; 40+ messages in thread
From: Ray Andrews @ 2024-04-13 18:08 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1188 bytes --]



On 2024-04-13 10:27, Mark J. Reed wrote:
> Small followup I meant to type but didn't:
>
> On Sat, Apr 13, 2024 at 1:19 PM Mark J. Reed <markjreed@gmail.com> wrote:
>
>         redline *'\nddd=( "${(@f)aaa}" ) ... it seems like a lot of
>         trouble to copy the array as it is.'*
>
>
>     That comment confuses me; you aren't copying the array as it is at
>     all! You've gone from *aaa, *which has one element, to *ddd
>     *having 8 elements. That's a far cry from "copying as it is".
>
Ah, but Mark, I figured all that out by the bottom of the post.  At that 
point I was still laboring under 'visual thinking' .  I dare say I'm 
straightened out.  I had thought that 'split on newlines' meant 'add 
\n's where needed to demarcate element boundaries'.  It's actually sorta 
the opposite -- there is no demarcation character and \n's will in fact 
be removed.  But I'm still not happy with the dollars.  I had thought 
that "  $'...'  "  was grammatical but we have " ' ' "  -- meaning an 
empty line -- without the leading dollar, so the closest thing I could 
pattern was that they replaced the newlines.   If anyone on the planet 
can get it wrong, it's me.


[-- Attachment #2: Type: text/html, Size: 3114 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-13 18:08                       ` Ray Andrews
@ 2024-04-13 19:45                         ` Bart Schaefer
  2024-04-13 20:36                           ` Ray Andrews
  2024-04-13 20:11                         ` Mark J. Reed
  1 sibling, 1 reply; 40+ messages in thread
From: Bart Schaefer @ 2024-04-13 19:45 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Sat, Apr 13, 2024 at 11:08 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> But I'm still not happy with the dollars.  I had thought that "  $'...'  "  was grammatical but we have " ' ' "  -- meaning an empty line

There are three* forms of quoting:

1) "X" -- expand variable references and other substitutions in X, but
do not split on $IFS **
2) 'X' -- do not do any expansions, X is literal
3) $'X' -- interpret \n \t \e etc., but everything else is literal, as
is the final result

This is all explained in the manual section "Quoting".  "typeset -p"
will output either no quoting at all, or #2, or #3, depending on which
is most appropriate to the value of the parameter, such that the
entire output is printable without the possibility of events like
terminals interpreting escape sequences.  If the parameter is an
array, "typeset -p" may output some elements in #2 form and others in
#3 form depending on the value of each element.

Note that because #3 is quoting, not substitution, it does not expand
inside #1.  Conversely, backticks `X` only look like quoting, they are
actually substitution equivalent to $(X) except without nesting, so
they do execute a command when appearing inside double quotes (#1).

* Four if you count using a backslash to protect a single following character.
** $@ and $ary[@] and ${(@)ary} get special handling, their array-ness
is preserved with each element quoted separately.

Let's look at your "redline" function:

redline () { echo -e "$red$@$nrm" }

The special handling of $@ means that for example:

redline a b c

is interpreted as

echo -e "$red$1" "$2" "$3$nrm"

So you probably should have written

redline () { echo -e "$red$*$nrm" }

because $* is the same as $@ except without that special
interpretation inside double quotes.


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

* Re: triviality regarding $# counts
  2024-04-13 18:08                       ` Ray Andrews
  2024-04-13 19:45                         ` Bart Schaefer
@ 2024-04-13 20:11                         ` Mark J. Reed
  1 sibling, 0 replies; 40+ messages in thread
From: Mark J. Reed @ 2024-04-13 20:11 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 5144 bytes --]

There still seems to be some confusion, so I'm going to back up a bit.
Apologies in advance if I tell you something you already know.

Quotes are part of the shell syntax. They aren't part of the quoted value.
If you do this:

name='Ray'


then the value stored into the variable *name* is just 3 characters: *R*,
*a*, and *y*.  There aren't any quotes anymore; they were just there long
enough to tell the shell that you want the characters in between them to be
taken literally. In this simple case, they aren't even needed; this has
exactly the same result:

name=Ray


It's important to keep the distinction in mind between the *values* you're
working with and the particular way you represent those values in the
*syntax* of the language.

Here's an example where the quotes are actually required:

multiline='hello,
there'


The above command is two physical lines of text, but only one shell
command, and that command is assigning one string value. The result is not
an array; it's a single, scalar parameter containing 12 characters, one of
which happens to be a newline:  *h*, *e*, *l*, another* l*, *o*, a comma, a
newline, *t*, *h*, *e*, *r*, and finally another *e*. You can access all of
them with subscripts; *$multiline[1]* is *h*, *$multiline[2]* is *e*, etc.
The quotes, despite being required, are still not part of the value.

The ability to do this also highlights the fact that newline is just
another character. Just like a letter of the alphabet or a digit or a
punctuation mark, it's just a number, but in the context of text that
number is interpreted as a character. The number 65 means *A*, 44 means
comma, 48 means *0*, and 10 means newline.  After the above assignment, the
newline may be found at *$multiline[7]*.

Here's another way of assigning exactly the same value to the same variable:

multiline=$'hello,\nthere'

Here we have a single-line command assigning a multiline value. The ANSI
quotes *$'*...*' *let us use the ANSI C escape sequence *\n* to mean a
newline. The result is the same: the value of *multline* is 12 characters
long, and *$multiline[7] *is a newline.

This assignment gets you something completely different:

oneline='hello,\nthere'


Now there is no newline character anywhere in the string. It's 13
characters long, not 12; *$oneline[7] *is not a newline but a backslash,
and *$oneline[8]* is an *n*.

After the above pair of assignments, you might be confused by the fact
that *echo
$multiline *and *echo $oneline* produce the same result, but that's because
*echo* is doing the same kind of translation of ANSI C escapes that the
shell does when you use *$'*...*'* quotes. If you turn that off by using *echo
-E*, then you'll get two different answers:

$ echo -E "$multiline"

hello,

there

$ echo -E "$oneline"

hello,\nthere


(I used double quotes above out of long habit; they're not strictly
necessary, especially not in zsh.)

A pair of quotes – of any variety, single, double, or ANSI – with nothing
between them represents the empty string. The empty string is nothing at
all; if you print it out by itself, it's the same as not even executing the
print command. Despite this, it is sometimes a useful thing to store in a
variable:

empty=''


After the above assignment, *$#empty* is 0. It literally contains nothing.

Again, you don't actually need the quotes; this also works:

empty=


Which reinforces the role of the quotes as syntax rather than value.

And again, an empty string is not an empty *line. *If, when you print out
the empty string, you do so with a command that adds a newline at the end,
the *output* will be an empty line, but it's the printing that makes it a
line. The value inside the variable has no line-ness.

On Sat, Apr 13, 2024 at 2:08 PM Ray Andrews <rayandrews@eastlink.ca> wrote:

> On 2024-04-13 10:27, Mark J. Reed wrote:
>
> Small followup I meant to type but didn't:
>
> On Sat, Apr 13, 2024 at 1:19 PM Mark J. Reed <markjreed@gmail.com> wrote:
>
>> redline *'\nddd=( "${(@f)aaa}" ) ... it seems like a lot of trouble to
>> copy the array as it is.'*
>>
>>
>> That comment confuses me; you aren't copying the array as it is at all!
>> You've gone from *aaa, *which has one element, to *ddd *having 8
>> elements. That's a far cry from "copying as it is".
>>
> Ah, but Mark, I figured all that out by the bottom of the post.  At that
> point I was still laboring under 'visual thinking' .  I dare say I'm
> straightened out.  I had thought that 'split on newlines' meant 'add \n's
> where needed to demarcate element boundaries'.  It's actually sorta the
> opposite -- there is no demarcation character and \n's will in fact be
> removed.  But I'm still not happy with the dollars.  I had thought that "
> $'...'  "  was grammatical but we have " ' ' "  -- meaning an empty line --
> without the leading dollar, so the closest thing I could pattern was that
> they replaced the newlines.   If anyone on the planet can get it wrong,
> it's me.
>
>
>

-- 
Mark J. Reed <markjreed@gmail.com>

[-- Attachment #2: Type: text/html, Size: 11239 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-13 19:45                         ` Bart Schaefer
@ 2024-04-13 20:36                           ` Ray Andrews
  2024-04-13 21:01                             ` Bart Schaefer
  0 siblings, 1 reply; 40+ messages in thread
From: Ray Andrews @ 2024-04-13 20:36 UTC (permalink / raw)
  To: zsh-users


On 2024-04-13 12:45, Bart Schaefer wrote:
> On Sat, Apr 13, 2024 at 11:08 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>> But I'm still not happy with the dollars.  I had thought that "  $'...'  "  was grammatical but we have " ' ' "  -- meaning an empty line
> There are three* forms of quoting:
Many thanks, it's a brief page of explanation like this that would 
feature in my imaginary 'Idiot's Guide to Shells'.  It's not the sort of 
information you can go looking for  when you don't know it because you 
don't even know what you're looking for.  It must be brought to your 
attention.
> 1) "X" -- expand variable references and other substitutions in X, but
> do not split on $IFS **
> 2) 'X' -- do not do any expansions, X is literal
Those two I pretty much understand -- except IFS which I've learned not 
to touch.

> 3) $'X' -- interpret \n \t \e etc., but everything else is literal, as
> is the final result
This is new to me.  Never used it.  Looks useful for strings.
> This is all explained in the manual section "Quoting".  "typeset -p"
> will output either no quoting at all, or #2, or #3,
I remember chafing over that some years back.
> Note that because #3 is quoting, not substitution, it does not expand
> inside #1.  Conversely, backticks `X` only look like quoting, they are
> actually substitution equivalent to $(X) except without nesting, so
> they do execute a command when appearing inside double quotes (#1).
Heavy.
> * Four if you count using a backslash to protect a single following character.
Right.
> ** $@ and $ary[@] and ${(@)ary} get special handling, their array-ness
> is preserved with each element quoted separately.
That needs pondering.
> Let's look at your "redline" function:
> ...
> So you probably should have written
>
> redline () { echo -e "$red$*$nrm" }
>
> because $* is the same as $@ except without that special
> interpretation inside double quotes.
So, compared to the previous expansion, how would '$*' expand there?  
I'm unclear as to the practical  difference.

Anyway .... when my typedef -p line showed those "   ' '    " with no 
dollar -- which seemed to me to forbid that "   $'...'  " grammar -- 
what I should read is that that element has nothing quoted ergo no 
'controller' -- no expansion flag -- is needed.  Yes?  IOW the dollar 
might have been put there, but it has no work to do so is simply 
omitted.  Logical.  Do I have that right, for once?






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

* Re: triviality regarding $# counts
  2024-04-13 15:14                 ` Ray Andrews
  2024-04-13 17:19                   ` Mark J. Reed
@ 2024-04-13 20:53                   ` Bart Schaefer
  2024-04-14  0:19                     ` Ray Andrews
  1 sibling, 1 reply; 40+ messages in thread
From: Bart Schaefer @ 2024-04-13 20:53 UTC (permalink / raw)
  To: zsh-users

On Sat, Apr 13, 2024 at 8:14 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> Anyway, it comes clear: '${(@f)....}' doesn't ADD (or retain) newlines it removes them!  (Tho splitting the array where they used to be.) Doesn't need them cuz elements aren't separated by newlines (like I thought) but by ... however it's done.

(Liberties taken with historical accuracy below, do not feel compelled
to leap in with sequencing corrections, etc.)

In the beginning, there were only environment strings ($SHELL, $PATH,
etc.) and positional parameters ($1, $2, etc.).  When a command was
run, it got its arguments as an "array" of positional parameters.
This is how "variables" came to be called "parameters" in shell
jargon.  This mapped directly onto C main() argc ($#) and argv[] ($@)
with the phantom $0 as the name of the command.

Referencing an environment string or an individual positional
parameter without quoting in a command argument caused the value to be
split on whitespace (as defined by the value of $IFS) to convert it
into an argv array.  Putting it in double quotes protected it from
that splitting but still permitted it to be replaced by its value.
Single quotes were for literal strings.  To reference an entire argv
without further splitting but also without losing its array property,
"$@" got the special meaning to quote each element individually.  $*
would give the entire argv but also split it further on whitespace,
and "$*" gave the entire argv joined back together with with spaces to
make it a single string.

It follows from this that it's useful to be able to assign names to
strings other than environment strings and to arrays other than the
positional parameters.  Thus we get scalar parameters and array
parameters, but they still follow the rules corresponding to
environment strings and positional parameters including the $* and $@
references to the full arrays, except now the name is added as in
${ary[3]} and ${ary[*]} and ${ary[@]}.  From this point forward shells
began to vary on details like whether named arrays begin with index 0
or 1 and whether it was necessary to wrap the reference in braces and
(in zsh's case) whether splitting on whitespace happens by default.

The salient point here is that regardless of the internal
representation of an array, you can think of it like an argv[] in C.
The elements are separated by conceptually being different string
pointers, and anything you "see" from e.g. "typeset -p" is language
syntax, not representation.

When you use (f) and other syntax to split something, you're creating
(temporarily) that same kind of array.  It might collapse to a string
again almost immediately based on context, which is why you might need
e.g. (@f) to specifically preserve it, but it exists however briefly
in that form.

>  Single quotes indicate elements.

Thus, that's an effect of "typeset -p" rather than anything about the
internal representation.


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

* Re: triviality regarding $# counts
  2024-04-13 20:36                           ` Ray Andrews
@ 2024-04-13 21:01                             ` Bart Schaefer
  2024-04-14  0:28                               ` Ray Andrews
  2024-04-14  0:30                               ` Lawrence Velázquez
  0 siblings, 2 replies; 40+ messages in thread
From: Bart Schaefer @ 2024-04-13 21:01 UTC (permalink / raw)
  To: zsh-users

On Sat, Apr 13, 2024 at 1:36 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> On 2024-04-13 12:45, Bart Schaefer wrote:
> > redline () { echo -e "$red$*$nrm" }
> >
> So, compared to the previous expansion, how would '$*' expand there?

redline a b c

would mean

echo -e "$red$1 $2 $3$nrm"

One word, with two quoted spaces, instead of three words.

> I'm unclear as to the practical  difference.

For "echo" it doesn't matter because echo is also going to paste its
arguments together, but it might matter to some other command.

> Anyway .... when my typedef -p line showed those "   ' '    " with no
> dollar -- which seemed to me to forbid that "   $'...'  " grammar --
> what I should read is that that element has nothing quoted ergo no
> 'controller' -- no expansion flag -- is needed.  Yes?  IOW the dollar
> might have been put there, but it has no work to do so is simply
> omitted.  Logical.  Do I have that right, for once?

You do, though I would caution not to think of the $ as an "expansion
flag" -- it's just part of the quoting syntax.


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

* Re: triviality regarding $# counts
  2024-04-13 20:53                   ` Bart Schaefer
@ 2024-04-14  0:19                     ` Ray Andrews
  0 siblings, 0 replies; 40+ messages in thread
From: Ray Andrews @ 2024-04-14  0:19 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 711 bytes --]



On 2024-04-13 13:53, Bart Schaefer wrote:
> On Sat, Apr 13, 2024 at 8:14 AM Ray Andrews<rayandrews@eastlink.ca>  wrote:
> In the beginning, there were only environment strings ($SHELL, $PATH,
> etc.) and positional parameters ($1, $2, etc.).  When a command was
> run, it got its arguments as an "array" of positional parameters.
> This is how "variables" came to be called "parameters" in shell
> jargon.  This mapped directly onto C main() argc ($#) and argv[] ($@)
> with the phantom $0 as the name of the command.
>
Some might say it's esoteric trivia but I disagree.  When you elucidate 
the history, and the mapping onto C, things make more sense.  The shells 
had to grow organically, didn't they?

[-- Attachment #2: Type: text/html, Size: 1282 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-13 21:01                             ` Bart Schaefer
@ 2024-04-14  0:28                               ` Ray Andrews
  2024-04-14  0:30                               ` Lawrence Velázquez
  1 sibling, 0 replies; 40+ messages in thread
From: Ray Andrews @ 2024-04-14  0:28 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 534 bytes --]



On 2024-04-13 14:01, Bart Schaefer wrote:
> redline a b c
> would mean
>
> echo -e "$red$1 $2 $3$nrm"
>
> One word, with two quoted spaces, instead of three words.
That simple example makes it trivially easy to understand.  I remember 
trying to figure that out previously via the manual and I just got more 
confused.  There's no merit to obfuscation tho you'd not know that 
reading some Linux/Unix man pages.  It's a critical lesson: what you see 
is not what you get, you hafta understand the hidden structure of your 
data.

[-- Attachment #2: Type: text/html, Size: 991 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-13 21:01                             ` Bart Schaefer
  2024-04-14  0:28                               ` Ray Andrews
@ 2024-04-14  0:30                               ` Lawrence Velázquez
  2024-04-14  3:26                                 ` Ray Andrews
  1 sibling, 1 reply; 40+ messages in thread
From: Lawrence Velázquez @ 2024-04-14  0:30 UTC (permalink / raw)
  To: zsh-users

On Sat, Apr 13, 2024, at 5:01 PM, Bart Schaefer wrote:
> On Sat, Apr 13, 2024 at 1:36 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>>
>> On 2024-04-13 12:45, Bart Schaefer wrote:
>> > redline () { echo -e "$red$*$nrm" }
>> >
>> So, compared to the previous expansion, how would '$*' expand there?
>
> redline a b c
>
> would mean
>
> echo -e "$red$1 $2 $3$nrm"
>
> One word, with two quoted spaces, instead of three words.
>
>> I'm unclear as to the practical  difference.
>
> For "echo" it doesn't matter because echo is also going to paste its
> arguments together, but it might matter to some other command.

A different output method should make this clearer:

	% f1() { printf '<%s>' "x$@x"; echo; }
	% f2() { printf '<%s>' "x$*x"; echo; }
	% f1 a b c
	<xa><b><cx>
	% f2 a b c
	<xa b cx>

The command "printf '<%s>' ..." outputs each argument enclosed in
"<...>" (other than the format string itself).  Observe that
double-quoted $@ can expand to multiple words, while double-quoted
$* always expands to one.

This actually makes a difference to nearly every command you might
think of, with "echo" being a rare exception (and even then, only
when the first character of IFS is a space).

	% arr=(.zshenv .zprofile .zshrc)
	% set -x
	% wc -c "$arr[@]"
	+zsh:44> wc -c .zshenv .zprofile .zshrc
	    1063 .zshenv
	    1023 .zprofile
	    3807 .zshrc
	    5893 total
	% wc -c "$arr[*]"
	+zsh:45> wc -c '.zshenv .zprofile .zshrc'
	wc: .zshenv .zprofile .zshrc: open: No such file or directory


-- 
vq


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

* Re: triviality regarding $# counts
  2024-04-14  0:30                               ` Lawrence Velázquez
@ 2024-04-14  3:26                                 ` Ray Andrews
  2024-04-14  3:49                                   ` Lawrence Velázquez
  0 siblings, 1 reply; 40+ messages in thread
From: Ray Andrews @ 2024-04-14  3:26 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 299 bytes --]



On 2024-04-13 17:30, Lawrence Velázquez wrote:
> A different output method should make this clearer:

Yes, thanks.  Up till now I've basically ignored $* completely. Gotta 
give it another look.  Man, the things I don't know I don't know ... not 
to mention the things I do know ... wrongly.



[-- Attachment #2: Type: text/html, Size: 718 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-14  3:26                                 ` Ray Andrews
@ 2024-04-14  3:49                                   ` Lawrence Velázquez
  2024-04-14  4:57                                     ` Bart Schaefer
  0 siblings, 1 reply; 40+ messages in thread
From: Lawrence Velázquez @ 2024-04-14  3:49 UTC (permalink / raw)
  To: zsh-users

On Sat, Apr 13, 2024, at 11:26 PM, Ray Andrews wrote:
> On 2024-04-13 17:30, Lawrence Velázquez wrote:
>> A different output method should make this clearer: 
> Yes, thanks.  Up till now I've basically ignored $* completely.

In a sense, you've been using it all along.  Given an array "arr",
$arr is the same as $arr[*] (by default), which is why double-quoting
it produces a single word.

	% arr=(a '' b 'c   d' '' e)
	% printf '<%s>' $arr; echo
	<a><b><c   d><e>
	% printf '<%s>' $arr[*]; echo
	<a><b><c   d><e>
	% printf '<%s>' $arr[@]; echo
	<a><b><c   d><e>
	% printf '<%s>' ${(@)arr}; echo
	<a><b><c   d><e>
	% printf '<%s>' "$arr"; echo
	<a  b c   d  e>
	% printf '<%s>' "$arr[*]"; echo
	<a  b c   d  e>
	% printf '<%s>' "$arr[@]"; echo
	<a><><b><c   d><><e>
	% printf '<%s>' "${(@)arr}"; echo
	<a><><b><c   d><><e>

-- 
vq


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

* Re: triviality regarding $# counts
  2024-04-14  3:49                                   ` Lawrence Velázquez
@ 2024-04-14  4:57                                     ` Bart Schaefer
  2024-04-14 13:24                                       ` Ray Andrews
  0 siblings, 1 reply; 40+ messages in thread
From: Bart Schaefer @ 2024-04-14  4:57 UTC (permalink / raw)
  To: zsh-users

On Sat, Apr 13, 2024 at 8:49 PM Lawrence Velázquez <larryv@zsh.org> wrote:
>
> In a sense, you've been using it all along.  Given an array "arr",
> $arr is the same as $arr[*] (by default), which is why double-quoting
> it produces a single word.

This puts me in mind of a couple of other details.

Because zsh does not split parameter expansions by default, $ary and
$ary[*] and $ary[@] are equivalent when not quoted, as Lawrence
demonstrated.

However, in all three of those cases, empty elements are typically
discarded, as they would be in a shell that defaults to splitting.
That's why "$ary[@]" is still useful:  It quotes each element
individually, so empty elements are preserved.

(Aside, in bash and ksh, $ary is equivalent to ${ary[0]}, not to
${ary[*]}.  A little oddly, this is also true for their associative
arrays, that is, the value for key 0 is used.)


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

* Re: triviality regarding $# counts
  2024-04-14  4:57                                     ` Bart Schaefer
@ 2024-04-14 13:24                                       ` Ray Andrews
  2024-04-14 13:35                                         ` Roman Perepelitsa
                                                           ` (2 more replies)
  0 siblings, 3 replies; 40+ messages in thread
From: Ray Andrews @ 2024-04-14 13:24 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 2967 bytes --]



On 2024-04-13 21:57, Bart Schaefer wrote:
> Because zsh does not split parameter expansions by default, $ary and
> $ary[*] and $ary[@] are equivalent when not quoted, as Lawrence
> demonstrated.
>
> However, in all three of those cases, empty elements are typically
> discarded, as they would be in a shell that defaults to splitting.
> That's why "$ary[@]" is still useful:  It quotes each element
> individually, so empty elements are preserved.
>
> (Aside, in bash and ksh, $ary is equivalent to ${ary[0]}, not to
> ${ary[*]}.  A little oddly, this is also true for their associative
> arrays, that is, the value for key 0 is used.)
I know it's far too late to fret this stuff, still it's interesting to 
contemplate these design level issues.  P.F. did the right thing not 
splitting by default but he should have left the empties in by default 
too, IMHO.  Options should be positive not negative as a fundamental 
principle.  Don't do helpful things automatically, and force me to stop 
you from doing them.  Much better to leave things alone, and if I want, 
say, empty elements removed, I'll ask for them to be removed.  A=B 
should mean that A is identical to B, not B with blanks removed, nor 
sorted, nor capitalized, nor duplicates removed, nor checked for 
spelling, nor ... nothing.

"$ary[@]" should be the default with some ${(?)...} flag to indicate 
that I'd like blanks removed or  duplicates or ... whatever massaging 
I'd want.  Cool that all those manipulations are available of course, 
but as Raymond Sensei  (E. S. Raymond) explains so well, the 'doctrine 
of least surprise' should prevail.  Equals equals equals, not 'equals 
minus blanks'.  So we have:

aaa=( "${(@f)bbb}" )

... which is code fighting itself.  The quotes normally mean 'join 
together' but they also mean 'preserve spaces' and so then '(@f)' 
contradicts the joining so we retain multiple elements.  IMHO it should 
look like this:

aaa=( $bbb )

Equals equals equals.

But as we have  it:

----------------------------------------------------------------------------------

% print $ddd
abc     def ghi     jkl mno     pqr

% fff=( $ddd )

% print $fff
abc     def ghi     jkl mno     pqr

# Looks ok, donit? But don't be a chump:

% typeset -p ddd; typeset -p fff
typeset -a ddd=( '' abc '' $'\tdef ghi' $'\tjkl mno' '' $'\tpqr' '' )
typeset -a fff=( abc $'\tdef ghi' $'\tjkl mno' $'\tpqr' )

# It's not a zebra, it's a horse with painted stripes!
# If you want a COPY ... yes, a Xerox copy:

% fff=( "${(@f)ddd}" )

% typeset -p ddd; typeset -p fff
typeset -a ddd=( '' abc '' $'\tdef ghi' $'\tjkl mno' '' $'\tpqr' '' )
typeset -a fff=( '' abc '' $'\tdef ghi' $'\tjkl mno' '' $'\tpqr' '' )

# That's a COPY ... and don't even think about a simpler way, we are on 
this earth to suffer.

------------------------------------------------------------------------------------

Just sayin', I know there's nothing to be done about it now.



[-- Attachment #2: Type: text/html, Size: 4000 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-14 13:24                                       ` Ray Andrews
@ 2024-04-14 13:35                                         ` Roman Perepelitsa
  2024-04-14 14:06                                           ` Ray Andrews
  2024-04-14 14:06                                         ` Mark J. Reed
  2024-04-14 15:51                                         ` Bart Schaefer
  2 siblings, 1 reply; 40+ messages in thread
From: Roman Perepelitsa @ 2024-04-14 13:35 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Sun, Apr 14, 2024 at 3:25 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> # If you want a COPY ... yes, a Xerox copy:
>
> % fff=( "${(@f)ddd}" )
>
> # That's a COPY ... and don't even think about a simpler way, we are on this earth to suffer.

That won't make a copy if any of the ddd elements have a newline in
them. Recall what (f) does.

Roman.


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

* Re: triviality regarding $# counts
  2024-04-14 13:35                                         ` Roman Perepelitsa
@ 2024-04-14 14:06                                           ` Ray Andrews
  2024-04-14 14:15                                             ` Roman Perepelitsa
  0 siblings, 1 reply; 40+ messages in thread
From: Ray Andrews @ 2024-04-14 14:06 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: zsh-users



On 2024-04-14 06:35, Roman Perepelitsa wrote:
> On Sun, Apr 14, 2024 at 3:25 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>> # If you want a COPY ... yes, a Xerox copy:
>>
>> % fff=( "${(@f)ddd}" )
>>
>> # That's a COPY ... and don't even think about a simpler way, we are on this earth to suffer.
> That won't make a copy if any of the ddd elements have a newline in
> them. Recall what (f) does.
But:

% ggg=( 'abc\n' '\n' 'def\n' '\n' 'ghi\n' )

% hhh=( "${(@f)ggg}" )

% typeset -p hhh; typeset -p ggg
typeset -a hhh=( 'abc\n' '\n' 'def\n' '\n' 'ghi\n' )
typeset -a ggg=( 'abc\n' '\n' 'def\n' '\n' 'ghi\n' )

... nuts yesterday I thought I had it figured out that the newlines 
would be removed but look at the above.





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

* Re: triviality regarding $# counts
  2024-04-14 13:24                                       ` Ray Andrews
  2024-04-14 13:35                                         ` Roman Perepelitsa
@ 2024-04-14 14:06                                         ` Mark J. Reed
  2024-04-14 14:47                                           ` Ray Andrews
  2024-04-14 15:51                                         ` Bart Schaefer
  2 siblings, 1 reply; 40+ messages in thread
From: Mark J. Reed @ 2024-04-14 14:06 UTC (permalink / raw)
  To: Zsh Users

[-- Attachment #1: Type: text/plain, Size: 4110 bytes --]

>
> # It's not a zebra, it's a horse with painted stripes!
> # If you want a COPY ... yes, a Xerox copy:
> % fff=( "${(@f)ddd}" )


What? No.  Why do you keep bringing (f) into this? That flag has nothing to
do with copying; in fact it intentionally changes things: anywhere there
used to be a single string containing a newline,you get two strings
instead.

But if you drop the f, you do get your Xerox copy:

% fff=( "${(@)ddd}" )

Would it be nicer if you could just do *fff=$ddd* and not have to include
the parens and quotes and @? Sure. You could even make a case that it *should
*work that way, since we're in Zshland where *$ddd* expands to the whole
array instead of a single element. But that's not the way assignment works.
Though, as I said, if the array has no empty elements, you can get away
with just *fff=($ddd)*.






On Sun, Apr 14, 2024 at 9:24 AM Ray Andrews <rayandrews@eastlink.ca> wrote:

>
>
> On 2024-04-13 21:57, Bart Schaefer wrote:
>
> Because zsh does not split parameter expansions by default, $ary and
> $ary[*] and $ary[@] are equivalent when not quoted, as Lawrence
> demonstrated.
>
> However, in all three of those cases, empty elements are typically
> discarded, as they would be in a shell that defaults to splitting.
> That's why "$ary[@]" is still useful:  It quotes each element
> individually, so empty elements are preserved.
>
> (Aside, in bash and ksh, $ary is equivalent to ${ary[0]}, not to
> ${ary[*]}.  A little oddly, this is also true for their associative
> arrays, that is, the value for key 0 is used.)
>
> I know it's far too late to fret this stuff, still it's interesting to
> contemplate these design level issues.  P.F. did the right thing not
> splitting by default but he should have left the empties in by default too,
> IMHO.  Options should be positive not negative as a fundamental principle.
> Don't do helpful things automatically, and force me to stop you from doing
> them.  Much better to leave things alone, and if I want, say, empty
> elements removed, I'll ask for them to be removed.  A=B should mean that A
> is identical to B, not B with blanks removed, nor sorted, nor capitalized,
> nor duplicates removed, nor checked for spelling, nor ... nothing.
>
> "$ary[@]" should be the default with some ${(?)...} flag to indicate that
> I'd like blanks removed or  duplicates or ... whatever massaging I'd want.
> Cool that all those manipulations are available of course, but as Raymond
> Sensei  (E. S. Raymond) explains so well, the 'doctrine of least surprise'
> should prevail.  Equals equals equals, not 'equals minus blanks'.  So we
> have:
>
> aaa=( "${(@f)bbb}" )
>
> ... which is code fighting itself.  The quotes normally mean 'join
> together' but they also mean 'preserve spaces' and so then '(@f)'
> contradicts the joining so we retain multiple elements.  IMHO it should
> look like this:
>
> aaa=( $bbb )
>
> Equals equals equals.
>
> But as we have  it:
>
>
> ----------------------------------------------------------------------------------
>
> % print $ddd
> abc     def ghi     jkl mno     pqr
>
> % fff=( $ddd )
>
> % print $fff
> abc     def ghi     jkl mno     pqr
>
> # Looks ok, donit? But don't be a chump:
>
> % typeset -p ddd; typeset -p fff
> typeset -a ddd=( '' abc '' $'\tdef ghi' $'\tjkl mno' '' $'\tpqr' '' )
> typeset -a fff=( abc $'\tdef ghi' $'\tjkl mno' $'\tpqr' )
>
> # It's not a zebra, it's a horse with painted stripes!
> # If you want a COPY ... yes, a Xerox copy:
>
> % fff=( "${(@f)ddd}" )
>
> % typeset -p ddd; typeset -p fff
> typeset -a ddd=( '' abc '' $'\tdef ghi' $'\tjkl mno' '' $'\tpqr' '' )
> typeset -a fff=( '' abc '' $'\tdef ghi' $'\tjkl mno' '' $'\tpqr' '' )
>
> # That's a COPY ... and don't even think about a simpler way, we are on
> this earth to suffer.
>
>
> ------------------------------------------------------------------------------------
>
> Just sayin', I know there's nothing to be done about it now.
>
>
>
>

-- 
Mark J. Reed <markjreed@gmail.com>

[-- Attachment #2: Type: text/html, Size: 6285 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-14 14:06                                           ` Ray Andrews
@ 2024-04-14 14:15                                             ` Roman Perepelitsa
  2024-04-14 14:53                                               ` Ray Andrews
  0 siblings, 1 reply; 40+ messages in thread
From: Roman Perepelitsa @ 2024-04-14 14:15 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Sun, Apr 14, 2024 at 4:06 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> % ggg=( 'abc\n' '\n' 'def\n' '\n' 'ghi\n' )

There are no newlines in there. If this isn't clear, check the post by
Mark J. Reed in this thread where he elaborated on this topic in great
detail.

Roman.


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

* Re: triviality regarding $# counts
  2024-04-14 14:06                                         ` Mark J. Reed
@ 2024-04-14 14:47                                           ` Ray Andrews
  2024-04-14 14:59                                             ` Mark J. Reed
  0 siblings, 1 reply; 40+ messages in thread
From: Ray Andrews @ 2024-04-14 14:47 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1773 bytes --]



On 2024-04-14 07:06, Mark J. Reed wrote:
>
> What? No.  Why do you keep bringing (f) into this? That flag has 
> nothing to do with copying; in fact it intentionally changes things: 
> anywhere there used to be a single string containing a newline,you get 
> two strings instead.
% hhh=( "${(@f)iii}" )
% typeset -p hhh; typeset -p iii
typeset -a hhh=( 'abc\ndef\nghi' )
typeset iii='abc\ndef\nghi'

... newlines still there.  One element.


Besides it worked as I showed.
>
> But if you drop the f, you do get your Xerox copy:
>
>     % fff=( "${(@)ddd}" )
>
... so far so good with tests.  The (f) seems not to have removed 
anything -- I was sure it did, yesterday :( -- but that was then. But 
yours seems to work and it's simpler, more intuitive.  The (f) does not 
seem to be missed, either.  And to think that just yesterday I thought I 
had this all sorted.

> Would it be nicer if you could just do *fff=$ddd* and not have to 
> include the parens and quotes and @? Sure. You could even make a case 
> that it /should /work that way, since we're in Zshland where *$ddd* 
> expands to the whole array instead of a single element. But that's not 
> the way assignment works. Though, as I said, if the array has no empty 
> elements, you can get away with just *fff=($ddd)*.
'IF' ... what I'm wanting is some universal copy that has no gotchas.

BTW, just philosophically speaking, the parens are an interesting 
question.  Whereas I'd say that a copy is a copy is a copy:

aaa=$bbb

... so whatever bbb may happen to be, aaa will become the same.  But if 
aaa is a scalar, should it be promoted 'silently' ?  Seems to me the 
parens are explicit that aaa will become an array so I like them.  One 
can never be too clear as to what's happening.

cut


[-- Attachment #2: Type: text/html, Size: 3212 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-14 14:15                                             ` Roman Perepelitsa
@ 2024-04-14 14:53                                               ` Ray Andrews
  2024-04-14 15:11                                                 ` Mark J. Reed
  0 siblings, 1 reply; 40+ messages in thread
From: Ray Andrews @ 2024-04-14 14:53 UTC (permalink / raw)
  To: zsh-users



On 2024-04-14 07:15, Roman Perepelitsa wrote:
> On Sun, Apr 14, 2024 at 4:06 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>> % ggg=( 'abc\n' '\n' 'def\n' '\n' 'ghi\n' )
> There are no newlines in there.
% ggg=( ' abc\n' '\n' 'def\n' '\n' 'ghi\n' )

% print $ggg
  abc

  def

  ghi


% typeset -p ggg
typeset -a ggg=( ' abc\n' '\n' 'def\n' '\n' 'ghi\n' )




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

* Re: triviality regarding $# counts
  2024-04-14 14:47                                           ` Ray Andrews
@ 2024-04-14 14:59                                             ` Mark J. Reed
  0 siblings, 0 replies; 40+ messages in thread
From: Mark J. Reed @ 2024-04-14 14:59 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1328 bytes --]

On Sun, Apr 14, 2024 at 10:48 Ray Andrews <rayandrews@eastlink.ca> wrote:

>
>
>
>
> % hhh=( "${(@f)iii}" )
> % typeset -p hhh; typeset -p iii
> typeset -a hhh=( 'abc\ndef\nghi' )
> typeset iii='abc\ndef\nghi'
>
> ... newlines still there.  One element.
>

No newlines nowhere! You've got backslashes and n's, but nary a newline to
be found. Which is the only reason (f) isn't completely mucking things up.
See my last message.

BTW, just philosophically speaking, the parens are an interesting
> question.  Whereas I'd say that a copy is a copy is a copy:
>
> aaa=$bbb
>
> ... so whatever bbb may happen to be, aaa will become the same.  But if
> aaa is a scalar, should it be promoted 'silently' ?  Seems to me the parens
> are explicit that aaa will become an array so I like them.  One can never
> be too clear as to what's happening.
>

The parens are needed because of the way assignment works. At least
conceptually (though the implementation may optimize), the right hand side
is first expanded, and then the result of that expansion, treated as a
literal value, is what gets assigned. The shell doesn't just copy the
innards of the variable value from one spot in its symbol table to another;
it takes a detour through first  expanding the value and then doing some
subset of its normal parsing on that expanded value.

[-- Attachment #2: Type: text/html, Size: 2296 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-14 14:53                                               ` Ray Andrews
@ 2024-04-14 15:11                                                 ` Mark J. Reed
  2024-04-14 16:23                                                   ` Ray Andrews
  0 siblings, 1 reply; 40+ messages in thread
From: Mark J. Reed @ 2024-04-14 15:11 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1807 bytes --]

As I said about *echo* way back in my first response: the *print* command
is what is turning the backslash-n sequences into newlines. If you use *-r* to
turn off that behavior, you can see the strings unmangled:

% print -r $ggg

 abc\n \n def\n \n ghi\n


The -r is telling print not to do something it normally does. The result is
the raw string (which I think is what *-r* stands for).

To restate: if your goal is to print out a newline, you have options. If
you do this:

print $'\n'

Then you are creating in the shell's memory a string containing a literal
newline character (one byte with value 10), which the shell then passes to
*print*, which just echoes it verbatim, doing no translation on it
whatsoever.  Job done. The translation from \n to newline was done by the
shell before *print* ever ran.

If you instead do this:

print '\n'

Then the string you create and pass to *print* has no newline in it. It is
not one byte of value 10, but two bytes, one with value 92 (backslash) and
the second with value 110 (lowercase *n*).  The code implementing the
*print* command recognizes this sequence as code for "print a newline", so
it does. But that's the command doing that. The string itself has no
newline in it.



Mark J. Reed <markjreed@gmail.com>


On Sun, Apr 14, 2024 at 10:53 Ray Andrews <rayandrews@eastlink.ca> wrote:

>
>
> On 2024-04-14 07:15, Roman Perepelitsa wrote:
> > On Sun, Apr 14, 2024 at 4:06 PM Ray Andrews <rayandrews@eastlink.ca>
> wrote:
> >> % ggg=( 'abc\n' '\n' 'def\n' '\n' 'ghi\n' )
> > There are no newlines in there.
> % ggg=( ' abc\n' '\n' 'def\n' '\n' 'ghi\n' )
>
> % print $ggg
>   abc
>
>   def
>
>   ghi
>
>
> % typeset -p ggg
> typeset -a ggg=( ' abc\n' '\n' 'def\n' '\n' 'ghi\n' )
>
>
>
>

[-- Attachment #2: Type: text/html, Size: 4423 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-14 13:24                                       ` Ray Andrews
  2024-04-14 13:35                                         ` Roman Perepelitsa
  2024-04-14 14:06                                         ` Mark J. Reed
@ 2024-04-14 15:51                                         ` Bart Schaefer
  2024-04-14 17:22                                           ` Ray Andrews
  2 siblings, 1 reply; 40+ messages in thread
From: Bart Schaefer @ 2024-04-14 15:51 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Sun, Apr 14, 2024 at 6:24 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> I know it's far too late to fret this stuff, still it's interesting to contemplate these design level issues.  P.F. did the right thing not splitting by default but he should have left the empties in by default too, IMHO.
> [...]
> the 'doctrine of least surprise' should prevail.

The trouble with that "doctrine" is that what is surprising is
subjective and context-dependent both in usage and in time.  When
these decisions were made, the largest number of zsh adoptees would
have been more surprised by having empty elements kept than removed.
Mysteriously receiving error messages like

ls: : No such file or directory

would have been the surprising thing.  Further, many commands neither
understand nor do anything useful with empty string arguments, and zsh
was intended first to be an interactive command shell and only second
a programming language (just a better one than BSD csh).


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

* Re: triviality regarding $# counts
  2024-04-14 15:11                                                 ` Mark J. Reed
@ 2024-04-14 16:23                                                   ` Ray Andrews
  0 siblings, 0 replies; 40+ messages in thread
From: Ray Andrews @ 2024-04-14 16:23 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1441 bytes --]



On 2024-04-14 08:11, Mark J. Reed wrote:
> As I said about *echo* way back in my first response: the 
> *print* command is what is turning the backslash-n sequences into 
> newlines. If you use *-r* to turn off that behavior, you can see the 
> strings unmangled:
>
>     % print -r $ggg
>
>     abc\n \n def\n \n ghi\n
>
>
> The -r is telling print not to do something it normally does. The 
> result is the raw string (which I think is what *-r* stands for).

Ah!  Threw me off the scent there.  So print is ... yes I get it. Ok, so 
that's what had me fooled.  So, one more thing and then I think I'll get 
back to straight and level:  How do we separate the elements?  I've 
always seen it with ticks.  Or ... now that I think ... with
$'...'
Yes?

If you instead do this:
>
>     print '\n'
>
> Then the string you create and pass to *print* has no newline in it. 
> It is not one byte of value 10, but two bytes, one with value 92 
> (backslash) and the second with value 110 (lowercase *n*).  The code 
> implementing the *print* command recognizes this sequence as code for 
> "print a newline", so it does. But that's the command doing that. The 
> string itself has no newline in it.

Ok, that blows the fog away.  We have the 'real' newline, we have the 
string '\n' ... which print helpfully translates into the former.  Yes, 
if in doubt 'print -r'.

Sheesh, I fall into every pothole there could possibly be.



[-- Attachment #2: Type: text/html, Size: 4115 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-14 15:51                                         ` Bart Schaefer
@ 2024-04-14 17:22                                           ` Ray Andrews
  2024-04-14 17:42                                             ` Mark J. Reed
  0 siblings, 1 reply; 40+ messages in thread
From: Ray Andrews @ 2024-04-14 17:22 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1962 bytes --]



On 2024-04-14 08:51, Bart Schaefer wrote:
> On Sun, Apr 14, 2024 at 6:24 AM Ray Andrews<rayandrews@eastlink.ca>  wrote:
> The trouble with that "doctrine" is that what is surprising is
> subjective and context-dependent both in usage and in time.  When
> these decisions were made, the largest number of zsh adoptees would
> have been more surprised by having empty elements kept than removed.
> Mysteriously receiving error messages like
Absolutely.  It is subjective therefore a design decision, not anything 
like right or wrong.  I think the 'no negative options' rule is more 
objective tho.  Still, even recognizing the rule, there will be 
exceptions and maybe this is one of them.
> ls: : No such file or directory
>
> would have been the surprising thing.  Further, many commands neither
> understand nor do anything useful with empty string arguments, and zsh
> was intended first to be an interactive command shell and only second
> a programming language (just a better one than BSD csh).
That might be enough to close the case.  When I think of my data arrays 
it doesn't occur to me that 'ls' is going to receive it's arguments 
using the same rules.  Yeah, I've run into that -- piping array contents 
to 'ls' and having it barf at a blank.  So even as a theoretical 
discussion, what I'm suggesting would have to be unique to personal 
data, not arguments sent to ls ... but that might not be possible so ... 
I loose.  Or ... the speculative: 'no empty elements' flag would have to 
be applied to all utilities.  Anyway it's just philosophy.

But this morning's mixup is cured.  print might take "  \n  " and give 
me a new line but as far as "  ${(f)....}  " ... is concerned they are 
not the same thing and "  '\n'  " will not be removed but "   $'\n'   " 
will be removed.  I get it.  And in an assignment, it's spaces that 
delimit elements. Hard spaces will be inside ticks or $'' .

Thanks for everyone's patience.

[-- Attachment #2: Type: text/html, Size: 2786 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-14 17:22                                           ` Ray Andrews
@ 2024-04-14 17:42                                             ` Mark J. Reed
  2024-04-14 18:24                                               ` Bart Schaefer
  2024-04-14 22:00                                               ` Ray Andrews
  0 siblings, 2 replies; 40+ messages in thread
From: Mark J. Reed @ 2024-04-14 17:42 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1425 bytes --]

On Sun, Apr 14, 2024 at 1:22 PM Ray Andrews <rayandrews@eastlink.ca> wrote:

> Hard spaces will be inside ticks or $'' .
>

.. or double-quotes; don't forget about them.   *" "*, *' '*, and *$' '* are
all literal spaces. It's other characters where the difference shows up. In
*"*...*"*, *$*-expansions still happen; in the others, they don't.  In *$'*
...*'*, ANSI C backslash escapes work; in the others, they don't.  Inside
*'*...*'*, absolutely everything is literal; there's not even a way to
include a literal *'* in the string.

One thing about the shell that makes it different from other programming
languages, however, is that the quotation marks themselves are not word
delimiters.  So you can switch between types of quoted string... including
entirely unquoted... without introducing a new shell "word".  That means
all of these assignments store exactly the same thing in the variable *x*:

*x=this\ is\ all\ one\ word*
*x="this is all one word"*
*x='this is all one word'*
*x=$'this is all one word'*
*x=this\ is' 'all" "one$' 'word*

The ability to mix and match gives us the old way to get an apostrophe into
an otherwise-single-quoted string: to close the quotes, add a
backslashed apostrophe, and then go back into quotes:

*x='That'\''s all, folks!'*


But it's easier to just use ANSI quotes:

*x=$'That\'s all, folks!'*



-- 
Mark J. Reed <markjreed@gmail.com>

[-- Attachment #2: Type: text/html, Size: 3030 bytes --]

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

* Re: triviality regarding $# counts
  2024-04-14 17:42                                             ` Mark J. Reed
@ 2024-04-14 18:24                                               ` Bart Schaefer
  2024-04-14 22:00                                               ` Ray Andrews
  1 sibling, 0 replies; 40+ messages in thread
From: Bart Schaefer @ 2024-04-14 18:24 UTC (permalink / raw)
  To: zsh-users

On Sun, Apr 14, 2024 at 10:42 AM Mark J. Reed <markjreed@gmail.com> wrote:
>
> On Sun, Apr 14, 2024 at 1:22 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>>
>> Hard spaces will be inside ticks or $'' .
>
> .. or double-quotes; don't forget about them.

However, "typeset -p" never outputs double-quotes for this purpose.

> But it's easier to just use ANSI quotes:
>
> x=$'That\'s all, folks!'

Which typeset will output "the old way"

'That'\''s all, folks!'


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

* Re: triviality regarding $# counts
  2024-04-14 17:42                                             ` Mark J. Reed
  2024-04-14 18:24                                               ` Bart Schaefer
@ 2024-04-14 22:00                                               ` Ray Andrews
  1 sibling, 0 replies; 40+ messages in thread
From: Ray Andrews @ 2024-04-14 22:00 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1184 bytes --]



On 2024-04-14 10:42, Mark J. Reed wrote:
> ...  That means all of these assignments store exactly the same thing 
> in the variable *x*:
>
>     *x=this\ is\ all\ one\ word*
>
That one is new to me.  So a quoted or escaped space is no longer a word 
delimiter.  Yeah ... that's why in typeset, any naked space is a 
delimiter, even a dozen of them make no difference, they are 'just' 
delimiters.  Yup, this kind of thing won't catch me again.

>     *x="this is all one word"*
>     *x='this is all one word'*
>     *x=$'this is all one word'*
>     *x=this\ is' 'all" "one$' 'word*
>     *
>     *
>
> The ability to mix and match gives us the old way to get an apostrophe 
> into an otherwise-single-quoted string: to close the quotes, add a 
> backslashed apostrophe, and then go back into quotes:
>
>     *x='That'\''s all, folks!'*
>

Geez ... that's dicing with the law. I'm seeing:
'That'
then an escaped apostrophe, so literal,  then
's all, folks!"
... three ... dunno how to say it ... three words joined into one.
>
>
> But it's easier to just use ANSI quotes:
>
>     *x=$'That\'s all, folks!'*
>
>
Yes, that's clear.
>
> -- 
> Mark J. Reed <markjreed@gmail.com>

[-- Attachment #2: Type: text/html, Size: 4038 bytes --]

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

end of thread, other threads:[~2024-04-14 22:01 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-11  0:56 triviality regarding $# counts Ray Andrews
2024-04-12  4:55 ` Lawrence Velázquez
2024-04-12 14:48   ` Ray Andrews
2024-04-12 19:09     ` Bart Schaefer
2024-04-13  1:13       ` Ray Andrews
2024-04-13  1:33         ` Mark J. Reed
2024-04-13  2:28           ` Ray Andrews
2024-04-13  3:25             ` Lawrence Velázquez
2024-04-13 14:37               ` Ray Andrews
2024-04-13 15:14                 ` Ray Andrews
2024-04-13 17:19                   ` Mark J. Reed
2024-04-13 17:27                     ` Mark J. Reed
2024-04-13 18:08                       ` Ray Andrews
2024-04-13 19:45                         ` Bart Schaefer
2024-04-13 20:36                           ` Ray Andrews
2024-04-13 21:01                             ` Bart Schaefer
2024-04-14  0:28                               ` Ray Andrews
2024-04-14  0:30                               ` Lawrence Velázquez
2024-04-14  3:26                                 ` Ray Andrews
2024-04-14  3:49                                   ` Lawrence Velázquez
2024-04-14  4:57                                     ` Bart Schaefer
2024-04-14 13:24                                       ` Ray Andrews
2024-04-14 13:35                                         ` Roman Perepelitsa
2024-04-14 14:06                                           ` Ray Andrews
2024-04-14 14:15                                             ` Roman Perepelitsa
2024-04-14 14:53                                               ` Ray Andrews
2024-04-14 15:11                                                 ` Mark J. Reed
2024-04-14 16:23                                                   ` Ray Andrews
2024-04-14 14:06                                         ` Mark J. Reed
2024-04-14 14:47                                           ` Ray Andrews
2024-04-14 14:59                                             ` Mark J. Reed
2024-04-14 15:51                                         ` Bart Schaefer
2024-04-14 17:22                                           ` Ray Andrews
2024-04-14 17:42                                             ` Mark J. Reed
2024-04-14 18:24                                               ` Bart Schaefer
2024-04-14 22:00                                               ` Ray Andrews
2024-04-13 20:11                         ` Mark J. Reed
2024-04-13 20:53                   ` Bart Schaefer
2024-04-14  0:19                     ` Ray Andrews
2024-04-13  1:35         ` Bart Schaefer

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