OILS / doc / ref / chap-stdlib.md View on Github | oilshell.org

410 lines, 263 significant
1---
2title: Builtin Commands (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; Chapter **Standard Library**
12
13</div>
14
15This chapter in the [Oils Reference](index.html) describes the standard library
16for OSH and YSH.
17
18(These functions are implemented in OSH or YSH, not C++ or Python.)
19
20<span class="in-progress">(in progress)</span>
21
22<div id="dense-toc">
23</div>
24
25## two
26
27These functions are in `two.sh`
28
29 source $OSH_LIB/two.sh
30
31### log
32
33Write a message to stderr:
34
35 log "hi $x"
36 log '---'
37
38### die
39
40Write an error message with the script name, and exit with status 1.
41
42 die 'Expected a number'
43
44## no-quotes
45
46### nq-assert
47
48Use the syntax of the [test][] builtin to assert a condition is true.
49
50 nq-assert 99 = "$status"
51 nq-assert "$status" -lt 2
52
53
54[test]: chap-builtin-cmd.html#test
55
56### nq-run
57
58Run a command and "return" its status with nameref variables.
59
60 test-foo() {
61 local status
62
63 nq-run status \
64 false
65 nq-assert 1 = "$status"
66 }
67
68### nq-capture
69
70Run a command and return its status and stdout.
71
72### nq-capture-2
73
74Run a command and return its status and stderr.
75
76### nq-redir
77
78Run a command and return its status and a file with its stdout, so you can diff
79it.
80
81### nq-redir-2
82
83Run a command and return its status and a file with its stderr, so you can diff
84it.
85
86## task-five
87
88### task-five
89
90Dispatch to shell functions, and provide BYO test enumeration.
91
92OSH:
93
94 task-five "$@"
95
96YSH:
97
98 task-five @ARGV
99
100## math
101
102### abs()
103
104Compute the absolute (positive) value of a number (float or int).
105
106 = abs(-1) # => 1
107 = abs(0) # => 0
108 = abs(1) # => 1
109
110Note, you will need to `source $LIB_YSH/math.ysh` to use this function.
111
112### max()
113
114Compute the maximum of 2 or more values.
115
116`max` takes two different signatures:
117
118 1. `max(a, b)` to return the maximum of `a`, `b`
119 2. `max(list)` to return the greatest item in the `list`
120
121For example:
122
123 = max(1, 2) # => 2
124 = max([1, 2, 3]) # => 3
125
126Note, you will need to `source $LIB_YSH/math.ysh` to use this function.
127
128### min()
129
130Compute the minimum of 2 or more values.
131
132`min` takes two different signatures:
133
134 1. `min(a, b)` to return the minimum of `a`, `b`
135 2. `min(list)` to return the least item in the `list`
136
137For example:
138
139 = min(2, 3) # => 2
140 = max([1, 2, 3]) # => 1
141
142Note, you will need to `source $LIB_YSH/math.ysh` to use this function.
143
144### round()
145
146TODO
147
148### sum()
149
150Computes the sum of all elements in the list.
151
152Returns 0 for an empty list.
153
154 = sum([]) # => 0
155 = sum([0]) # => 0
156 = sum([1, 2, 3]) # => 6
157
158Note, you will need to `source $LIB_YSH/list.ysh` to use this function.
159
160
161## list
162
163### all()
164
165Returns true if all values in the list are truthy (`x` is truthy if `Bool(x)`
166returns true).
167
168If the list is empty, return true.
169
170 = any([]) # => true
171 = any([true, true]) # => true
172 = any([false, true]) # => false
173 = any(["foo", true, true]) # => true
174
175Note, you will need to `source $LIB_YSH/list.ysh` to use this function.
176
177### any()
178
179Returns true if any value in the list is truthy (`x` is truthy if `Bool(x)`
180returns true).
181
182If the list is empty, return false.
183
184 = any([]) # => false
185 = any([true, false]) # => true
186 = any([false, false]) # => false
187 = any([false, "foo", false]) # => true
188
189Note, you will need to `source $LIB_YSH/list.ysh` to use this function.
190
191### repeat()
192
193Repeat a string or a list:
194
195 = repeat('foo', 3) # => 'foofoofoo'
196 = repeat(['foo', 'bar'], 2) # => ['foo', 'bar', 'foo', 'bar']
197
198Negative repetitions are equivalent to zero:
199
200 = repeat('foo', -5) # => ''
201 = repeat(['foo', 'bar'], -5) # => []
202
203## yblocks
204
205Helpers to assert the status and output of commands.
206
207### yb-capture
208
209Capture the status and stdout of a command block:
210
211 yb-capture (&r) {
212 echo hi
213 }
214 assert [0 === r.status]
215 assert [u'hi\n' === r.stdout]
216
217### yb-capture-2
218
219Capture the status and stderr of a command block:
220
221 yb-capture-2 (&r) {
222 echo hi >& 2
223 }
224 assert [0 === r.status]
225 assert [u'hi\n' === r.stderr]
226
227## args
228
229YSH includes a command-line argument parsing utility called `parseArgs`. This
230is intended to be used for command-line interfaces to YSH programs.
231
232To use it, first import `args.ysh`:
233
234 source $LIB_YSH/args.ysh
235
236Then, create an argument parser **spec**ification:
237
238 parser (&spec) {
239 flag -v --verbose (help="Verbosely") # default is Bool, false
240
241 flag -P --max-procs ('int', default=-1, help='''
242 Run at most P processes at a time
243 ''')
244
245 flag -i --invert ('bool', default=true, help='''
246 Long multiline
247 Description
248 ''')
249
250 arg src (help='Source')
251 arg dest (help='Dest')
252
253 rest files
254 }
255
256Finally, parse `ARGV` (or any other array of strings) with:
257
258 var args = parseArgs(spec, ARGV)
259
260The returned `args` is a `Dict` containing key-value pairs with the parsed
261values (or defaults) for each flag and argument. For example, given
262`ARGV = :| mysrc -P 12 mydest a b c |`, `args` would be:
263
264 {
265 "verbose": false,
266 "max-procs": 12,
267 "invert": true,
268 "src": "mysrc",
269 "dest": "mydest",
270 "files": ["a", "b", "c"]
271 }
272
273### parser
274
275`parseArgs()` requires a parser specification to indicate how to parse the
276`ARGV` array. This specification should be constructed using the `parser` proc.
277
278 parser (&spec) {
279 flag -f --my-flag
280 arg myarg
281 rest otherArgs
282 }
283
284In the above example, `parser` takes in a place `&spec`, which will store the
285resulting specification and a block which is evaluated to build that
286specification.
287
288Inside of a `parser` block, you should call the following procs:
289
290- `flag` to add `--flag` options
291- `arg` to add positional arguments
292- `rest` to capture remaining positional arguments into a list
293
294`parser` will validate the parser specification for errors such as duplicate
295flag or argument names.
296
297 parser (&spec) {
298 flag -n --name
299 flag -n --name # Duplicate!
300 }
301
302 # => raises "Duplicate flag/arg name 'name' in spec" (status = 3)
303
304### flag
305
306`flag` should be called within a `parser` block.
307
308 parser (&spec) {
309 flag -v --verbose
310 }
311
312The above example declares a flag "--verbose" and a short alias "-v".
313`parseArgs()` will then store a boolean value under `args.verbose`:
314- `true` if the flag was passed at least once
315- `false` otherwise
316
317Flags can also accept values. For example, if you wanted to accept an integer count:
318
319 parser (&spec) {
320 flag -N --count ('int')
321 }
322
323Calling `parseArgs` with `ARGV = :| -n 5 |` or `ARGV = :| --count 5 |` will
324store the integer `5` under `args.count`. If the user passes in a non-integer
325value like `ARGV = :| --count abc |`, `parseArgs` will raise an error.
326
327Default values for an argument can be set with the `default` named argument.
328
329 parser (&spec) {
330 flag -N --count ('int', default=2)
331
332 # Boolean flags can be given default values too
333 flag -O --optimize ('bool', default=true)
334 }
335
336 var args = parseArgs(spec, :| -n 3 |)
337 # => args.count = 2
338 # => args.optimize = true
339
340Each name passed to `flag` must be unique to that specific `parser`. Calling
341`flag` with the same name twice will raise an error inside of `parser`.
342
343<!-- TODO: how can we explicitly pass false to a boolean flag? -->
344<!-- TODO: how about --no-XXXX variants of flags? -->
345
346### arg
347
348`arg` should be called within a `parser` block.
349
350 parser (&spec) {
351 arg query
352 arg path
353 }
354
355The above example declares two positional arguments called "query" and "path".
356`parseArgs()` will then store strings under `args.query` and `args.path`. Order
357matters, so the first positional argument will be stored to `query` and the
358second to `path`. If not enough positional arguments are passed, then
359`parseArgs` will raise an error.
360
361Similar to `flag`, each `arg` name must be unique. Calling `arg` with the same
362name twice will cause `parser` to raise an error.
363
364### rest
365
366`rest` should be called within a `parser` block.
367
368 parser (&spec) {
369 arg query
370 rest files
371 }
372
373Capture zero or more positional arguments not already captured by `arg`. So,
374for `ARGV = :| hello file.txt message.txt README.md |`, we would have
375`args.query = "file.txt"` and `args.files = ["file.txt", "message.txt",
376"README.md"]`.
377
378Without rest, passing extraneous arguments will raise an error in
379`parseArgs()`.
380
381`rest` can only be called _once_ within a `parser`. Calling it multiple times
382will raise an error in `parser`.
383
384### parseArgs()
385
386Given a parser specification `spec` produced by `parser`, parse a list of
387strings (usually `ARGV`.)
388
389 var args = parseArgs(spec, ARGV)
390
391The returned `args` is a dictionary mapping the names of each `arg`, `flag` and
392`rest` to their captured values. (See the example at the [start of this
393topic](#Args-Parser).)
394
395`parseArgs` will raise an error if the `ARGV` is invalid per the parser
396specification. For example, if it's missing a required positional argument:
397
398 parser (&spec) {
399 arg path
400 }
401
402 var args = parseArgs(spec, [])
403 # => raises an error about the missing 'path' (status = 2)
404
405<!--
406TODO: Document chaining parsers / sub-commands
407 - Either will allow parser nesting
408 - Or can use `rest rest` and `parseArgs` again on `rest`
409TODO: Document the help named argument. Punting while we do not generate help messages
410-->