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

Re: triviality regarding $# counts



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@xxxxxxxxxxx> 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@xxxxxxxxx> 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@xxxxxxxxx>


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