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

Re: more splitting



On Wed, Apr 15, 2026 at 5:18 PM Ray Andrews <rayandrews@xxxxxxxxxxx> 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 <markjreed@xxxxxxxxx>


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