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

594 lines, 393 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## Glob
25
26### osh-glob
27
28Expand a [glob pattern][glob-pat] into arguments.
29
30 echo *_test.py # => foo_test.py bar_test.py
31
32Expansion respects these global settings:
33
34- [Globbing options][globbing-options] like `dotglob nullglob no_dash_glob`
35- [GLOBIGNORE][]
36- The `libc` `LC_COLLATE` var (like bash and zsh)
37 - Related: [osh-locale][]
38
39Example of collation:
40
41 $ touch foo-bar foo_bar
42 $ echo foo* # foo_bar MAY come first
43
44[glob-pat]: chap-mini-lang.html#glob-pat
45[GLOBIGNORE]: chap-special-var.html#GLOBIGNORE
46[globbing-options]: chap-option.html#Globbing
47[osh-locale]: chap-special-var.html#osh-locale
48
49### ysh-glob
50
51Expand a [glob pattern][glob-pat] into arguments.
52
53 echo *_test.py # => foo_test.py bar_test.py
54
55In YSH, glob expansion is always done with the default `libc` collation:
56
57 ysh$ touch foo-bar foo_bar
58 ysh$ echo foo* # foo-bar always comes first
59
60Related: [ysh-locale][], the [glob()][glob] function
61
62[ysh-locale]: chap-special-var.html#ysh-locale
63[glob]: chap-builtin-func.html#glob
64
65<h2 id="expression">Expressions to Words</h2>
66
67### expr-sub
68
69Turn an expression into a string. Examples:
70
71 $ echo $[3 * 2]
72 6
73
74 $ var s = 'foo'
75 $ echo $[s[1:]]
76 oo
77
78Some types can't be stringified, like Dict and List:
79
80 $ var d = {k: 42}
81
82 $ echo $[d]
83 fatal: expected Null, Bool, Int, Float, Eggex
84
85You can explicitly use `toJson8` or `toJson()`:
86
87 $ echo $[toJson8(d)]
88 {"k":42}
89
90(This is similar to `json write (d)`)
91
92### expr-splice
93
94Splicing turns each element of a `List` into a string, and puts those strings
95into an array:
96
97 $ var foods = ['ale', 'bean', 42]
98 $ echo pizza @[foods[1:]] worm
99 pizza bean 42 worm
100
101It also works in arays:
102
103 $ var myarray = :| prefix @[foods]] |
104 $ echo @myarray
105 prefix ale bean 42
106
107This syntax is enabled by `shopt --set` [parse_at][], which is part of YSH.
108
109[parse_at]: chap-option.html#ysh:upgrade
110
111### var-splice
112
113 $ var foods = ['ale', 'bean', 'corn']
114 echo @foods
115
116This syntax is enabled by `shopt --set` [parse_at][], which is part of YSH.
117
118
119<h2 id="formatting">Formatting Typed Data as Strings</h2>
120
121### ysh-printf
122
123Not done.
124
125 echo ${x %.3f}
126
127### ysh-format
128
129Not done.
130
131 echo ${x|html}
132
133## Joining
134
135### osh-word-join
136
137OSH joins arbitrary word parts:
138
139 $ myvar=/
140 $ echo 'single'\'$myvar"double $myvar"
141 single'/double /
142
143That is, the argument to `echo` is a word that has 4 word parts:
144
145 'single'
146 \'
147 $myvar
148 "double $myvar"
149
150When the word is evaluated, the result of each part is evaluated and
151concatenated.
152
153### ysh-word-join
154
155In general, YSH doesn't allow single- and double-quoted parts to be joined.
156They most often form an entire word:
157
158 echo 'single-quoted word'
159 echo "double-quoted word"
160
161YSH allows word joining in these special cases:
162
163 echo --flag='value'
164 echo NAME="value"
165
166 echo ~/'dir with spaces'
167 echo ~root/src/"dir with spaces"
168
169The purpose of this rule is to eliminate ambiguous words like:
170
171 --flag=u'value\n' # does u indicate a J8 string, or is it a literal?
172
173See [OILS-ERR-17][] for details.
174
175[OILS-ERR-17]: ../error-catalog.html#oils-err-17
176
177## Quotes
178
179
180### osh-string
181
182- Single quotes
183- Double Quotes
184- C-style strings: `$'\n'`
185
186TODO: elaborate
187
188### ysh-string
189
190YSH strings in the word language are the same as in the expression language.
191
192See [ysh-string in chap-expr-lang](chap-expr-lang.html#ysh-string).
193
194### triple-quoted
195
196Triple-quoted in the word language are the same as in the expression language.
197
198See [triple-quoted in chap-expr-lang](chap-expr-lang.html#triple-quoted).
199
200### tagged-str
201
202Not done.
203
204## Substitutions
205
206### command-sub
207
208Executes a command and captures its stdout.
209
210If stdout has a trailing newline, it's removed:
211
212 $ hostname
213 example.com
214
215 $ echo "/tmp/$(hostname)"
216 /tmp/example.com
217
218If stdout has any NUL bytes, they are removed (regardless of position).
219
220Related: [captureStdout()](chap-type-method.html#captureStdout)
221
222### command-splice
223
224YSH also has spliced command subs, enabled by `shopt --set parse_at`. The
225result is a **List** of strings, rather than a single string.
226
227 $ write -- @(echo foo; echo 'with spaces')
228 foo
229 with-spaces
230
231The command's stdout parsed as the "J8 Lines" format, where each line is
232either:
233
2341. An unquoted string, which must be valid UTF-8. Whitespace is allowed, but
235 not other ASCII control chars.
2362. A quoted J8 string (JSON style `""` or J8-style `b'' u'' ''`)
2373. An **ignored** empty line
238
239See [J8 Notation](../j8-notation.html) for more details.
240
241### var-sub
242
243Evaluates to the value of a variable:
244
245 $ x=X
246 $ echo $x ${x}
247 X X
248
249### arith-sub
250
251Shell has C-style arithmetic:
252
253 $ echo $(( 1 + 2*3 ))
254 7
255
256### tilde-sub
257
258Used as a shortcut for a user's home directory:
259
260 ~/src # my home dir
261 ~bob/src # user bob's home dir
262
263### proc-sub
264
265Open stdout as a named file in `/dev/fd`, which can be passed to a command:
266
267 diff <(sort L.txt) <(sort R.txt)
268
269Open stdin as a named file in `/dev/fd`:
270
271 seq 3 | tee >(sleep 1; tac)
272
273
274## Var Ops
275
276There are three types of braced variable expansions:
277
278 ${!name*} or ${!name@}
279 ${!name[@]} or ${!name[*]}
280 ${ops var ops}
281
282`name` needs to be a valid identifier. If the expansion matches the first
283form, the variable names starting with `name` are generated. Otherwise, if the
284expansion matches the second form, the keys of the indexed or associative array
285named `name` are generated. When the expansion does not much either the first
286or second forms, it is interpreted as the third form of the variable name
287surrounded by operators.
288
289
290### op-bracket
291
292The value within brackets is called an "index", and retrieves a value from an
293array:
294
295 ${A[i+1]}
296 ${A['key']}
297
298If `A` is an indexed array, the index is interpreted as an arithmetic
299expression. Arithmetic evaluation is performed, and the value at that numeric
300offset is retrieved.
301
302If `A` is an associative array, the index is interpreted as a string. The
303value associated with that string is retrieved.
304
305If `A` is a string, it's treated as an indexed array with a single element,
306i.e. so that `${A[0]}` is `${A}`.
307
308---
309
310 ${A[*]}
311 ${A[@]}
312
313The index expressions `[*]` and `[@]` are special cases. Both generate a word
314list of all elements in `a`.
315
316When the variable substitution is **unquoted**, there's no difference between
317`[*]` and `[@]`:
318
319 $ A=(1 2 3)
320 $ printf '<%s>\n' ${A[*]}
321 <1>
322 <2>
323 <3>
324
325 $ printf '<%s>\n' ${A[@]}
326 <1>
327 <2>
328 <3>
329
330When double-quoted, the `[*]` form joins the elements by the first character of
331`IFS`:
332
333 $ IFS=x
334 $ printf '<%s>\n' "${A[*]}"
335 <1x2x3>
336
337When double-quoted, the `[@]` form generates a word list by splitting the word
338at the boundary of every element in `A`:
339
340 $ printf '<%s>\n' "-${A[@]}-"
341 <-1>
342 <2>
343 <3->
344
345If the container `A` has no elements, and the variable substitution has no
346other parts, `[@]` evaluates to an empty word list:
347
348 $ empty=()
349 $ set -- "${empty[@]}"
350 $ echo $#
351 0
352
353---
354
355These rules for `[*]` and `[@]` also apply to:
356
357- `$*` and `$@`
358- `${!name*}` and `${!name@}`
359- `${!name[*]}` and `${!name[@]}`, etc.
360
361<!--
362Note: OSH currently joins the values by `IFS` even for unquoted `$*` and
363performs word splitting afterward. This is different from the POSIX standard.
364-->
365
366### op-indirect
367
368The indirection operator `!` is a prefix operator, and it interprets the
369received string as a variable name `name`, an array element `name[key]`, or an
370arrat list `name[@]` / `name[*]` and reads its values.
371
372 $ a=1234
373 $ v=a
374 $ echo $v
375 a
376 $ echo ${!v}
377 1234
378
379### op-test
380
381Shell has boolean operations within `${}`. I use `:-` most frequently:
382
383 x=${1:-default}
384 osh=${OSH:-default}
385
386This idiom is also useful:
387
388 : ${LIB_OSH=stdlib/osh}
389
390---
391
392There are test operators with colons, and without:
393
394 ${x-default}
395 ${x:-default}
396
397 ${x=default}
398 ${x:=default}
399
400 ${x+other}
401 ${x:+other}
402
403 ${x?error}
404 ${x:?error}
405
406**Without** the colon, the shell checks whether a value is **defined**. In the
407case of a word list, e.g. generated by `$*` or `$@`, it tests whether there is
408at least one element.
409
410**With** the colon, the shell checks whether the value is **non-empty** (is not
411the empty string). In the case of a word list, the test is performed after
412joining the elements by a space.
413
414Elements are joined by the first character of `IFS` only with double-quoted
415`"${*:-}"`.
416
417In contrast, `${*:-}`, `${@:-}`, and `"${@:-}"` are joined by a space. This is
418because the joining of `"$*"` by `IFS` is performed earlier than the joining by
419space for the test.
420
421<!--
422Note: OSH currently joins the values by `IFS` even for unquoted `$*`. This is
423different from Bash.
424-->
425
426### op-strip
427
428Remove prefixes or suffixes from strings:
429
430 echo ${y#prefix}
431 echo ${y##'prefix'}
432
433 echo ${y%suffix}
434 echo ${y%%'suffix'}
435
436The prefix and suffix can be glob patterns, but this usage is discouraged
437because it may be slow.
438
439### op-patsub
440
441Replace a substring or pattern.
442
443The character after the first `/` can be `/` to replace all occurrences:
444
445 $ x=food
446
447 $ echo ${x//o/--} # replace 1 o with 2 --
448 f----d
449
450It can be `#` or `%` for an anchored replacement:
451
452 $ echo ${x/#f/--} # left anchored f
453 --ood
454
455 $ echo ${x/%d/--} # right anchored d
456 foo--
457
458The pattern can also be a glob:
459
460 $ echo ${x//[a-z]/o} # replace 1 char with o
461 oooo
462
463 $ echo ${x//[a-z]+/o} # replace multiple chars
464 o
465
466### op-slice
467
468 echo ${a[@]:1:2}
469 echo ${@:1:2}
470
471### op-format
472
473${x@P} evaluates x as a prompt string, i.e. the string that would be printed if
474PS1=$x.
475
476---
477
478`${x@Q}` quotes the value of `x`, if necessary, so that it can be evaluated as
479a shell word.
480
481 $ x='<'
482 $ echo "value = $x, quoted = ${x@Q}."
483 value = <, quoted = '<'.
484
485 $ x=a
486 $ echo "value = $x, quoted = ${x@Q}."
487 value = a, quoted = a.
488
489In the second case, the string `a` doesn't need to be quoted.
490
491---
492
493Format operations like `@Q` generally treat **empty** variables differently
494than **unset** variables.
495
496That is, `${empty@Q}` is the string `''`, while `${unset@Q}` is an empty
497string:
498
499 $ x=''
500 $ echo "value = $x, quoted = ${x@Q}."
501 value = , quoted = ''.
502
503 $ unset -v x
504 $ echo "value = $x, quoted = ${x@Q}."
505 value = , quoted = .
506
507---
508
509`${x@a}` returns characters that represent the attributes of the `${x}`, or
510more precisely, the *h-value* of `${x}`.
511
512Definitions:
513
514- *h-value* is the variable (or the object that the variable directly points)
515 from which the result of `${x}` would originally come.
516- *r-value* is the value of the expansion of `${x}`
517
518For example, with `arr=(1 2 3)`:
519
520<style>
521table {
522 width: 100%;
523 margin-left: 2em; /* matches p text in manual.css */
524}
525thead {
526 text-align: left;
527}
528</style>
529
530<table>
531
532- thead
533 - Reference
534 - Expression
535 - H-value
536 - R-value
537 - Flags returned
538- tr
539 - <!-- empty -->
540 - `${arr[0]@a}` or <br/> `${arr@a}`
541 - array<br/> `(1 2 3)`
542 - string<br/> `1`
543 - `a`
544- tr
545 - <!-- empty -->
546 - `${arr[@]@a}`
547 - array<br/> `(1 2 3)`
548 - array<br/> `(1 2 3)`
549 - `a a a`
550- tr
551 - `ref=arr` or `ref=arr[0]`
552 - `${!ref@a}`
553 - array<br/> `(1 2 3)`
554 - string<br/> `1`
555 - `a`
556 - <!-- empty -->
557- tr
558 - `ref=arr[@]`
559 - `${!ref@a}`
560 - array<br/> `(1 2 3)`
561 - array<br/> `(1 2 3)`
562 - `a a a`
563
564</table>
565
566When `${x}` would result in a word list, `${x@a}` returns a word list
567containing the attributes of the *h-value* of each word.
568
569---
570
571These characters may be returned:
572
573<table>
574
575- thead
576 - Character
577 - Where `${x}` would be obtained
578- tr
579 - `a`
580 - indexed array
581- tr
582 - `A`
583 - associative array
584- tr
585 - `r`
586 - readonly container
587- tr
588 - `x`
589 - exported variable
590- tr
591 - `n`
592 - name reference (OSH extension)
593
594</table>