Re: more splitting

"Mark J. Reed" <[email protected]> Wed, 15 Apr 2026 18:10:26 -0400
Newsgroups gmane.comp.shells.zsh.devel,gmane.comp.shells.zsh.user
Message-ID <CAA=-s3yF6SmDDpH6LCNPvkFZcyjwYvDXGKJaMseisHhOb5qsVQ@mail.gmail.com>
On Wed, Apr 15, 2026 at 5:18 PM Ray Andrews <[email protected]> wrote:

> I mean that arrays might have been designed to carry a separator character
> between elements.  ASCII FF maybe.  So when piped, reconstructing an array
> would be easier.
>

Arrays having a built-in separator character is an intriguing notion, but I
don't know of any programming language that has such a construct. It's just
easier to specify the separator when you request the operation that needs
it (usually called *join*). When you do use *$array* somewhere that wants a
string, you're effectively joining the elements together with spaces. When
you do *print -l $array* you're joining them elements together with
newlines and printing the result. But you can turn an array into a string
with any delimiter you like between elements using the *j* expansion flag -
short for *join*.

Pipes in PowerShell may carry structured data, but pipes in Zsh are
undecorated bog-standard UNIX pipes as presented by the OS, and those just
carry bytes. They have no idea of arrays or variables in general. And that
goes not just for shell pipes but network sockets, which is why so much
modern software tends to spend (arguably waste) a lot of time serializing
and deserializing data (turning it into streams of bytes and back, often in
the form of JSON). Your goal when writing software should be to avoid
serialization as much as possible - deserialize your input if needed,
serialize your output if needed, but in between you should try to keep
everything in its natural unserialized state.


> % print -n $var
> a b c
> d e f g h ij#   # What's the hash for?
>

I'm guessing you have PROMPT_EOL_MARK set to "#"? When the output of a
command doesn't end with a newline, Zsh adds one anyway before printing the
next prompt, but prints a special character first to signal the fact that
the newline wasn't actually part of the output. By default it's  an
inverse-video percent sign, but you can customize that . . .

2 /aWorking/Zsh/Source/Wk 6 % var2=( $=var ); hex var2
>
> a
> b
> c
> d
> e
> f
> g
> h
> ij
>
> ... as expected, except that the newline disappeared.
>

An unquoted newline is treated the same as a space or a tab - or a vertical
tab, probably. Space is space.

% var2=( ${(f)var} ); hex var2
>
> 'a b c'
> 'd e f g h ij'
>
> ... love it.  Split on newline.  All spaces preserved. One thing tho: when
> $var is created, would not the splitting spaces vanish? But we see the
> space between 'b' and 'c' remains in var2.  Likewise the space between 'h'
> and 'i' -- how are they retained? Or are they put back for display?
>

You used ${(f)var}. (f) means "split the contents of this variable on
newlines". Since the variable is an array in this case, the only way to get
something splittable is to first turn it into a string.  And any time
you're treating an array as if it were a single string - even as an
intermediate step in an operation like the (f) expansion - the default
translation puts a space between elements.

... so typeset output very close to original variable creation keystrokes.
> Better! Running output of typeset -p to create a new array, it's identical
> to the original.  :-)  Typeset edits my input string while retaining the
> product exactly.  Love it.  IOW, typeset returns what I should have typed
> in the first place.  That explains the movement of the dollar too, which
> has always baffled me.


Quotation marks in the shell are not word delimiters, so you can change
between quotation mark types in the middle of a word.  "Li"'ke'$' 'this. That's
what you were doing - switching to ANSI quotes long enough to include the
newline. But it's usually clearer to pick a type and stick with it. I like
to use the "least powerful" form I can get away with - single quotes if I
don't need any expansion, ANSI quotes (that's the $'...') if I need control
characters (which I can enter as backslash escapes) or a literal apostrophe
in the string, double quotes if I need any variable expansion.

So a mad scientist could take the output from typeset -p, pipe that string
> and use it to create a new var downstream of the pipe!


Yes, but you should avoid trying to parse shell code in shell. Use *eval* if
you have to, but it's better to avoid doing anything like that in the first
place.

-- 
Mark J. Reed <[email protected]>