OILS / doc / ysh-faq.md View on Github | oilshell.org

212 lines, 131 significant
1---
2default_highlighter: oils-sh
3---
4
5YSH FAQ
6=======
7
8Here are some common questions about [YSH]($xref). Many of the answers boil
9down to the fact that YSH is a **smooth upgrade** from [bash]($xref).
10
11Old and new constructs exist side-by-side. New constructs have fewer
12"gotchas".
13
14<!-- cmark.py expands this -->
15<div id="toc">
16</div>
17
18## What's the difference `myvar`, `$myvar`, and `"$myvar"` ?
19
20YSH is more like Python/JavaScript rather than PHP/Perl, so it doesn't use the
21`$` sigil as much.
22
23Never use `$` on the left-hand side:
24
25 var mystr = "foo" # not var $mystr
26
27Use `$` to **substitute** vars into commands:
28
29 echo $mystr
30 echo $mystr/subdir # no quotes in commands
31
32or quoted strings:
33
34 echo "$mystr/subdir"
35 var x = "$mystr/subdir"
36
37Rarely use `$` on the right-hand side:
38
39 var x = mystr # preferred
40 var x = $mystr # ILLEGAL -- use remove $
41 var x = ${mystr:-} # occasionally useful
42
43 var x = $? # allowed
44
45See [Command vs. Expression Mode](command-vs-expression-mode.html) for more
46details.
47
48## How do I write `~/src` or `~bob/git` in a YSH assignment?
49
50This should cover 80% of cases:
51
52 var path = "$HOME/src" # equivalent to ~/src
53
54The old shell style will cover the remaining cases:
55
56 declare path=~/src
57 readonly other=~bob/git
58
59---
60
61This is only in issue in *expressions*. The traditional shell idioms work in
62*command* mode:
63
64 echo ~/src ~bob/git
65 # => /home/alice/src /home/bob/git
66
67The underlying design issue is that the YSH expression `~bob` looks like a
68unary operator and a variable, not some kind of string substitution.
69
70Also, quoted `"~"` is a literal tilde, and shells disagree on what `~""` means.
71The rules are subtle, so we avoid inventing new ones.
72
73## How do I write the equivalent of `echo -e` or `echo -n`?
74
75To echo special characters denoted by backslash escapes, use a
76statically-parsed string literal, not `echo -e`:
77
78 echo u'tab \t newline \n' # YES: J8 style string is recommended in YSH
79 echo $'tab \t newline \n' # bash-style string is also accepted
80
81These styles don't work in YSH:
82
83 echo -e "tab \\t newline \\n" # NO: -e is printed literally
84 echo -e "tab \t newline \n" # Error: Invalid char escape
85
86To omit the trailing newline, use the `write` builtin:
87
88 write -n -- $prefix # YES
89 write --end '' -- $prefix # synonym
90
91 echo -n $prefix # NO: -n is printed literally
92
93### Why Were `-e` and `-n` Removed?
94
95The idioms with `u''` and `write` are more powerful and consistent.
96
97Moreover, shell's `echo` is the *only* builtin that doesn't accept `--` to stop
98flag processing.
99
100That is, `echo "$flag"` always has a few bugs: when `$flag` is `-e`, `-n`,
101`-en`, or `-ne`. There's **no** way to fix this bug in POSIX shell.
102
103So portable shell scripts use:
104
105 printf '%s\n' "$x" # print $x "unmolested" in POSIX shell
106
107We could have chosen to respect `echo -- $x`, but YSH already has:
108
109 write -- $x # print $x "unmolested" in YSH
110
111That means YSH has:
112
113 echo $x # an even shorter way
114
115So `echo` is technically superfluous in YSH, but it's also short, familiar, and
116correct.
117
118YSH isn't intended to be compatible with POSIX shell; only OSH is.
119
120### How do I write a string literal with both `$myvar` and `\n`?
121
122In YSH, either use `$[ \n ]` inside a double-quoted string:
123
124 $ echo "$myvar $[ \n ] two" # expression sub wraps \n
125 value_of_myvar
126 two
127
128Or use the concatenation operator `++` with two styles of string literal:
129
130 echo $[u'newline \n' ++ " $year/$month/$day"]
131
132This POSIX shell behavior is probably not what you want:
133
134 $ echo "\n"
135 \n # not a newline!
136
137### How do I find all the `echo` invocations I need to change when using YSH?
138
139A search like this can statically find most usages:
140
141 $ egrep -n 'echo (-e|-n|-en|-ne)' *.sh
142 test/syscall.sh:58: echo -n hi
143 test/syscall.sh:76: echo -e '\t'
144
145## What's the difference between `$(dirname $x)` and `$[len(x)]` ?
146
147Superficially, both of these syntaxes take an argument `x` and return a
148string. But they are different:
149
150- `$(dirname $x)` is a shell command substitution that returns a string, and
151 **starts another process**.
152- `$[len(x)]` is an expression sub containing a function call expression.
153 - It doesn't need to start a process.
154 - Note that `len(x)` evaluates to an integer, and `$[len(x)]` converts it to
155 a string.
156
157<!--
158(Note: builtin subs like `${.myproc $x}` are meant to eliminate process
159overhead, but they're not yet implemented.)
160-->
161
162## Why doesn't a raw string work here: `${array[r'\']}` ?
163
164This boils down to the difference between OSH and YSH, and not being able to
165mix the two. Though they look similar, `${array[i]}` syntax (with braces) is
166fundamentally different than `$[array[i]]` syntax (with brackets).
167
168- OSH supports `${array[i]}`.
169 - The index is legacy/deprecated shell arithmetic like `${array[i++]}` or
170 `${assoc["$key"]}`.
171 - The index **cannot** be a raw string like `r'\'`.
172- YSH supports both, but [expression substitution][expr-sub] syntax
173 `$[array[i]]` is preferred.
174 - It accepts YSH expressions like `$[array[i + 1]` or `$[mydict[key]]`.
175 - A raw string like `r'\'` is a valid key, e.g. `$[mydict[r'\']]`.
176
177[expr-sub]: ref/chap-expr-lang.html#expr-sub
178
179Of course, YSH style is preferred when compatibility isn't an issue.
180
181No:
182
183 echo ${array[r'\']}
184
185Yes:
186
187 echo $[array[r'\']]
188
189A similar issue exists with arithmetic.
190
191Old:
192
193 echo $((1 + 2)) # shell arithmetic
194
195New:
196
197 echo $[1 + 2] # YSH expression
198
199<!--
200
201## Why doesn't the ternary operator work here: `${array[0 if cond else 5]}`?
202
203The issue is the same as above. YSH expression are allowed within `$[]` but
204not `${}`.
205
206-->
207
208## Related
209
210- [Oil Language FAQ]($wiki) on the wiki has more answers. They may be migrated
211 here at some point.
212