OILS / doc / ref / chap-word-lang.md View on Github | oils.pub

496 lines, 334 significant
1---
2title: Word Language (Oils Reference)
3all_docs_url: ..
4body_css_class: width40
5default_highlighter: oils-sh
6preserve_anchor_case: yes
7---
8
9<div class="doc-ref-header">
10
11[Oils Reference](index.html) &mdash;
12Chapter **Word Language**
13
14</div>
15
16This chapter describes the word language for OSH and YSH. Words evaluate to
17strings, or arrays of strings.
18
19<span class="in-progress">(in progress)</span>
20
21<div id="dense-toc">
22</div>
23
24<h2 id="expression">Expressions to Words</h2>
25
26### expr-sub
27
28Try to turn an expression into a string. Examples:
29
30 $ echo $[3 * 2]
31 6
32
33 $ var s = 'foo'
34 $ echo $[s[1:]]
35 oo
36
37Some types can't be stringified, like Dict and List:
38
39 $ var d = {k: 42}
40
41 $ echo $[d]
42 fatal: expected Null, Bool, Int, Float, Eggex
43
44You can explicitly use `toJson8` or `toJson()`:
45
46 $ echo $[toJson8(d)]
47 {"k":42}
48
49(This is similar to `json write (d)`)
50
51### expr-splice
52
53Splicing puts the elements of a `List` into a string array context:
54
55 $ var foods = ['ale', 'bean', 'corn']
56 $ echo pizza @[foods[1:]] worm
57 pizza bean corn worm
58
59This syntax is enabled by `shopt --set` [parse_at][], which is part of YSH.
60
61[parse_at]: chap-option.html#ysh:upgrade
62
63### var-splice
64
65 $ var foods = ['ale', 'bean', 'corn']
66 echo @foods
67
68This syntax is enabled by `shopt --set` [parse_at][], which is part of YSH.
69
70
71<h2 id="formatting">Formatting Typed Data as Strings</h2>
72
73### ysh-printf
74
75Not done.
76
77 echo ${x %.3f}
78
79### ysh-format
80
81Not done.
82
83 echo ${x|html}
84
85## Quotes
86
87### osh-string
88
89- Single quotes
90- Double Quotes
91- C-style strings: `$'\n'`
92
93TODO: elaborate
94
95### ysh-string
96
97YSH strings in the word language are the same as in the expression language.
98
99See [ysh-string in chap-expr-lang](chap-expr-lang.html#ysh-string).
100
101### triple-quoted
102
103Triple-quoted in the word language are the same as in the expression language.
104
105See [triple-quoted in chap-expr-lang](chap-expr-lang.html#triple-quoted).
106
107### tagged-str
108
109Not done.
110
111## Substitutions
112
113### command-sub
114
115Executes a command and captures its stdout.
116
117OSH has shell-compatible command sub like `$(echo hi)`. If a trailing newline
118is returned, it's removed:
119
120 $ hostname
121 example.com
122
123 $ echo "/tmp/$(hostname)"
124 /tmp/example.com
125
126YSH has spliced command subs, enabled by `shopt --set parse_at`. The result is
127a **List** of strings, rather than a single string.
128
129 $ write -- @(echo foo; echo 'with spaces')
130 foo
131 with-spaces
132
133The command's stdout parsed as the "J8 Lines" format, where each line is
134either:
135
1361. An unquoted string, which must be valid UTF-8. Whitespace is allowed, but
137 not other ASCII control chars.
1382. A quoted J8 string (JSON style `""` or J8-style `b'' u'' ''`)
1393. An **ignored** empty line
140
141See [J8 Notation](../j8-notation.html) for more details.
142
143### var-sub
144
145Evaluates to the value of a variable:
146
147 $ x=X
148 $ echo $x ${x}
149 X X
150
151### arith-sub
152
153Shell has C-style arithmetic:
154
155 $ echo $(( 1 + 2*3 ))
156 7
157
158### tilde-sub
159
160Used as a shortcut for a user's home directory:
161
162 ~/src # my home dir
163 ~bob/src # user bob's home dir
164
165### proc-sub
166
167Open stdout as a named file in `/dev/fd`, which can be passed to a command:
168
169 diff <(sort L.txt) <(sort R.txt)
170
171Open stdin as a named file in `/dev/fd`:
172
173 seq 3 | tee >(sleep 1; tac)
174
175
176## Var Ops
177
178There are three types of braced variable expansions:
179
180 ${!name*} or ${!name@}
181 ${!name[@]} or ${!name[*]}
182 ${ops var ops}
183
184`name` needs to be a valid identifier. If the expansion matches the first
185form, the variable names starting with `name` are generated. Otherwise, if the
186expansion matches the second form, the keys of the indexed or associative array
187named `name` are generated. When the expansion does not much either the first
188or second forms, it is interpreted as the third form of the variable name
189surrounded by operators.
190
191
192### op-bracket
193
194The value within brackets is called an "index", and retrieves a value from an
195array:
196
197 ${A[i+1]}
198 ${A['key']}
199
200If `A` is an indexed array, the index is interpreted as an arithmetic
201expression. Arithmetic evaluation is performed, and the value at that numeric
202offset is retrieved.
203
204If `A` is an associative array, the index is interpreted as a string. The
205value associated with that string is retrieved.
206
207If `A` is a string, it's treated as an indexed array with a single element,
208i.e. so that `${A[0]}` is `${A}`.
209
210---
211
212 ${A[*]}
213 ${A[@]}
214
215The index expressions `[*]` and `[@]` are special cases. Both generate a word
216list of all elements in `a`.
217
218When the variable substitution is **unquoted**, there's no difference between
219`[*]` and `[@]`:
220
221 $ A=(1 2 3)
222 $ printf '<%s>\n' ${A[*]}
223 <1>
224 <2>
225 <3>
226
227 $ printf '<%s>\n' ${A[@]}
228 <1>
229 <2>
230 <3>
231
232When double-quoted, the `[*]` form joins the elements by the first character of
233`IFS`:
234
235 $ IFS=x
236 $ printf '<%s>\n' "${A[*]}"
237 <1x2x3>
238
239When double-quoted, the `[@]` form generates a word list by splitting the word
240at the boundary of every element in `A`:
241
242 $ printf '<%s>\n' "-${A[@]}-"
243 <-1>
244 <2>
245 <3->
246
247If the container `A` has no elements, and the variable substitution has no
248other parts, `[@]` evaluates to an empty word list:
249
250 $ empty=()
251 $ set -- "${empty[@]}"
252 $ echo $#
253 0
254
255---
256
257These rules for `[*]` and `[@]` also apply to:
258
259- `$*` and `$@`
260- `${!name*}` and `${!name@}`
261- `${!name[*]}` and `${!name[@]}`, etc.
262
263<!--
264Note: OSH currently joins the values by `IFS` even for unquoted `$*` and
265performs word splitting afterward. This is different from the POSIX standard.
266-->
267
268### op-indirect
269
270The indirection operator `!` is a prefix operator, and it interprets the
271received string as a variable name `name`, an array element `name[key]`, or an
272arrat list `name[@]` / `name[*]` and reads its values.
273
274 $ a=1234
275 $ v=a
276 $ echo $v
277 a
278 $ echo ${!v}
279 1234
280
281### op-test
282
283Shell has boolean operations within `${}`. I use `:-` most frequently:
284
285 x=${1:-default}
286 osh=${OSH:-default}
287
288This idiom is also useful:
289
290 : ${LIB_OSH=stdlib/osh}
291
292---
293
294There are test operators with colons, and without:
295
296 ${x-default}
297 ${x:-default}
298
299 ${x=default}
300 ${x:=default}
301
302 ${x+other}
303 ${x:+other}
304
305 ${x?error}
306 ${x:?error}
307
308**Without** the colon, the shell checks whether a value is **defined**. In the
309case of a word list, e.g. generated by `$*` or `$@`, it tests whether there is
310at least one element.
311
312**With** the colon, the shell checks whether the value is **non-empty** (is not
313the empty string). In the case of a word list, the test is performed after
314joining the elements by a space.
315
316Elements are joined by the first character of `IFS` only with double-quoted
317`"${*:-}"`.
318
319In contrast, `${*:-}`, `${@:-}`, and `"${@:-}"` are joined by a space. This is
320because the joining of `"$*"` by `IFS` is performed earlier than the joining by
321space for the test.
322
323<!--
324Note: OSH currently joins the values by `IFS` even for unquoted `$*`. This is
325different from Bash.
326-->
327
328### op-strip
329
330Remove prefixes or suffixes from strings:
331
332 echo ${y#prefix}
333 echo ${y##'prefix'}
334
335 echo ${y%suffix}
336 echo ${y%%'suffix'}
337
338The prefix and suffix can be glob patterns, but this usage is discouraged
339because it may be slow.
340
341### op-patsub
342
343Replace a substring or pattern.
344
345The character after the first `/` can be `/` to replace all occurrences:
346
347 $ x=food
348
349 $ echo ${x//o/--} # replace 1 o with 2 --
350 f----d
351
352It can be `#` or `%` for an anchored replacement:
353
354 $ echo ${x/#f/--} # left anchored f
355 --ood
356
357 $ echo ${x/%d/--} # right anchored d
358 foo--
359
360The pattern can also be a glob:
361
362 $ echo ${x//[a-z]/o} # replace 1 char with o
363 oooo
364
365 $ echo ${x//[a-z]+/o} # replace multiple chars
366 o
367
368### op-slice
369
370 echo ${a[@]:1:2}
371 echo ${@:1:2}
372
373### op-format
374
375${x@P} evaluates x as a prompt string, i.e. the string that would be printed if
376PS1=$x.
377
378---
379
380`${x@Q}` quotes the value of `x`, if necessary, so that it can be evaluated as
381a shell word.
382
383 $ x='<'
384 $ echo "value = $x, quoted = ${x@Q}."
385 value = <, quoted = '<'.
386
387 $ x=a
388 $ echo "value = $x, quoted = ${x@Q}."
389 value = a, quoted = a.
390
391In the second case, the string `a` doesn't need to be quoted.
392
393---
394
395Format operations like `@Q` generally treat **empty** variables differently
396than **unset** variables.
397
398That is, `${empty@Q}` is the string `''`, while `${unset@Q}` is an empty
399string:
400
401 $ x=''
402 $ echo "value = $x, quoted = ${x@Q}."
403 value = , quoted = ''.
404
405 $ unset -v x
406 $ echo "value = $x, quoted = ${x@Q}."
407 value = , quoted = .
408
409---
410
411`${x@a}` returns characters that represent the attributes of the `${x}`, or
412more precisely, the *h-value* of `${x}`.
413
414Definitions:
415
416- *h-value* is the variable (or the object that the variable directly points)
417 from which the result of `${x}` would originally come.
418- *r-value* is the value of the expansion of `${x}`
419
420For example, with `arr=(1 2 3)`:
421
422<style>
423table {
424 width: 100%;
425 margin-left: 2em; /* matches p text in manual.css */
426}
427thead {
428 text-align: left;
429}
430</style>
431
432<table>
433
434- thead
435 - Reference
436 - Expression
437 - H-value
438 - R-value
439 - Flags returned
440- tr
441 - <!-- empty -->
442 - `${arr[0]@a}` or <br/> `${arr@a}`
443 - array<br/> `(1 2 3)`
444 - string<br/> `1`
445 - `a`
446- tr
447 - <!-- empty -->
448 - `${arr[@]@a}`
449 - array<br/> `(1 2 3)`
450 - array<br/> `(1 2 3)`
451 - `a a a`
452- tr
453 - `ref=arr` or `ref=arr[0]`
454 - `${!ref@a}`
455 - array<br/> `(1 2 3)`
456 - string<br/> `1`
457 - `a`
458 - <!-- empty -->
459- tr
460 - `ref=arr[@]`
461 - `${!ref@a}`
462 - array<br/> `(1 2 3)`
463 - array<br/> `(1 2 3)`
464 - `a a a`
465
466</table>
467
468When `${x}` would result in a word list, `${x@a}` returns a word list
469containing the attributes of the *h-value* of each word.
470
471---
472
473These characters may be returned:
474
475<table>
476
477- thead
478 - Character
479 - Where `${x}` would be obtained
480- tr
481 - `a`
482 - indexed array
483- tr
484 - `A`
485 - associative array
486- tr
487 - `r`
488 - readonly container
489- tr
490 - `x`
491 - exported variable
492- tr
493 - `n`
494 - name reference (OSH extension)
495
496</table>