3 ms·
I think many people are even more surprised by this: x=$a # not split! It means the same thing as x="$a" They were taught that you have to quote everythi
by chubot 2y ago
I think many people are even more surprised by this:
x=$a # not split! It means the same thing as x="$a"
They were taught that you have to quote everything, which is a reasonable rule to follow, but it's not true.
---
I never wrote about this on the Oils blog (https://www.oilshell.org/ https://www.oilshell.org/ ), but the post would be titled:
Shell Has Context Sensitive Evaluation
Basically the two contexts you should think of are:
(1) EVAL WORD SEQUENCE
This occurs in 2 places in POSIX shell:
ls $x$y # simple command is a sequence of words
for i in $x$y; do echo $i; done # for loop
And 1 place in bash:
a=( $x$y ) # array literal
In these cases, the shell "wants" a sequence of strings, not a single one. So it does splitting.
---
(2) EVAL WORD TO STRING
But there are many other contexts where the shell does not "want" a sequence of strings.
It wants a SINGLE string. And conversely, it actually JOINS arrays of strings, rather than splitting.
Usually "$@" is an array / sequence of strings, while $@ or $* is a string, roughly speaking.
But the shell doesn't want sequences of strings in MANY cases, e.g.
a=$@ # I only want 1 string here, so I JOIN rather than splitting
echo hi > "$@" # redirect arg (not all shells agree though!)
case "$@" in ... esac # as you point out
So the bottom line is that variables aren't really strings OR arrays of strings. Whatever the shell wants, it converts it to.
And shells also DISAGREE on the specifics of those rules. POSIX shell has the array "$@", but arrays in general are not in POSIX.
---
And even worse, think about this case:
local x=$a
Does it behave like an assignment, which wants a single string?
Or does it behave like a simple command, which wants a sequence?
You can look at it both ways. The bottom line is that assignment builtins are special and they don't follow the normal rules of simple commands. Shells have differed, but POSIX decided on this awhile ago.
---
This is all of course mind numbing trivia that has no real reason for existing ... YSH fixes it, and it's now pure native C++, no more Python.
YSH Doesn't Require Quoting Everywhere - https://www.oilshell.org/blog/2021/04/simple-word-eval.html https://www.oilshell.org/blog/2021/04/simple-word-eval.html (Oil was renamed to YSH since this blog post was written)
Simple Word Evaluation in Unix Shell - https://www.oilshell.org/release/latest/doc/simple-word-eval.html https://www.oilshell.org/release/latest/doc/simple-word-eval...
In YSH you can tell just by looking it's a single string or an array.
ls $a # identical to ls "$a"
ls @myarray # splice an array
It never "molests" your variables. There's no auto-conversion, and you can upgrade to those rules with
shopt --set ysh:upgrade
- parasense 2y agoSometimes when I'm being lazy, say for example I have a variable with some folder/file absolute path... I'll convert the slashes to spaces, and word split there, sending the results into the stack. $ readarray -d '/' <<<${PWD:1:-1} $ echo ${MAPFILE[@]} and you get a nice list of folders you can push/pop as you wish...
- unnah 2y agoThat's also one of the more notable incompatibilities of zsh - by default it treats $a the same as "$a", and you're supposed to use arrays if you want multiple words. Although I'm not an expert - maybe ysh and zsh differ in the details here?
- chubot 2y agoYup, in terms of ls $a -- YSH happens to be like zsh. OSH is compatible with bash and does the POSIX word splitting, but YSH is not. In general YSH is pretty different than zsh though -- it's more of a Python- JS-like language with structured data, e.g. ysh$ var a = ['list', 'of' strings'] ysh$ write -- @a list of strings In zsh I still think that's the pretty obscure "${a[@]}" rather than @a. Arrays are also "flat" in zsh -- you can't have an array of arrays, because there's no garbage collector. But YSH has arbitrarily nested JSON-like data structures, and JSON serialization built in. I need to put some code examples on the home page, but for now - https://www.oilshell.org/release/latest/doc/ysh-tour.html https://www.oilshell.org/release/latest/doc/ysh-tour.html
- arp242 2y agoYou can use $=a to get word splitting in zsh. While incompatible, the zsh behaviour makes a lot more sense. You can use "setopt sh_word_split" to get the POSIX behaviour. Or split explicitly with ${(s: :)a}, ${(s:SPLIT-ON-THIS:)a}, etc. (not compatible with anything but zsh).
- kazinator 2y agoThis is old hat though; I think it was already specified that way in 1990 POSIX.
- 2y ago