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

417 lines, 268 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
203Note that the `repeat()` function is modeled after these Python expressions:
204
205 >>> 'a' * 3
206 'aaa'
207 >>> ['a'] * 3
208 ['a', 'a', 'a']
209
210## yblocks
211
212Helpers to assert the status and output of commands.
213
214### yb-capture
215
216Capture the status and stdout of a command block:
217
218 yb-capture (&r) {
219 echo hi
220 }
221 assert [0 === r.status]
222 assert [u'hi\n' === r.stdout]
223
224### yb-capture-2
225
226Capture the status and stderr of a command block:
227
228 yb-capture-2 (&r) {
229 echo hi >& 2
230 }
231 assert [0 === r.status]
232 assert [u'hi\n' === r.stderr]
233
234## args
235
236YSH includes a command-line argument parsing utility called `parseArgs`. This
237is intended to be used for command-line interfaces to YSH programs.
238
239To use it, first import `args.ysh`:
240
241 source $LIB_YSH/args.ysh
242
243Then, create an argument parser **spec**ification:
244
245 parser (&spec) {
246 flag -v --verbose (help="Verbosely") # default is Bool, false
247
248 flag -P --max-procs ('int', default=-1, help='''
249 Run at most P processes at a time
250 ''')
251
252 flag -i --invert ('bool', default=true, help='''
253 Long multiline
254 Description
255 ''')
256
257 arg src (help='Source')
258 arg dest (help='Dest')
259
260 rest files
261 }
262
263Finally, parse `ARGV` (or any other array of strings) with:
264
265 var args = parseArgs(spec, ARGV)
266
267The returned `args` is a `Dict` containing key-value pairs with the parsed
268values (or defaults) for each flag and argument. For example, given
269`ARGV = :| mysrc -P 12 mydest a b c |`, `args` would be:
270
271 {
272 "verbose": false,
273 "max-procs": 12,
274 "invert": true,
275 "src": "mysrc",
276 "dest": "mydest",
277 "files": ["a", "b", "c"]
278 }
279
280### parser
281
282`parseArgs()` requires a parser specification to indicate how to parse the
283`ARGV` array. This specification should be constructed using the `parser` proc.
284
285 parser (&spec) {
286 flag -f --my-flag
287 arg myarg
288 rest otherArgs
289 }
290
291In the above example, `parser` takes in a place `&spec`, which will store the
292resulting specification and a block which is evaluated to build that
293specification.
294
295Inside of a `parser` block, you should call the following procs:
296
297- `flag` to add `--flag` options
298- `arg` to add positional arguments
299- `rest` to capture remaining positional arguments into a list
300
301`parser` will validate the parser specification for errors such as duplicate
302flag or argument names.
303
304 parser (&spec) {
305 flag -n --name
306 flag -n --name # Duplicate!
307 }
308
309 # => raises "Duplicate flag/arg name 'name' in spec" (status = 3)
310
311### flag
312
313`flag` should be called within a `parser` block.
314
315 parser (&spec) {
316 flag -v --verbose
317 }
318
319The above example declares a flag "--verbose" and a short alias "-v".
320`parseArgs()` will then store a boolean value under `args.verbose`:
321- `true` if the flag was passed at least once
322- `false` otherwise
323
324Flags can also accept values. For example, if you wanted to accept an integer count:
325
326 parser (&spec) {
327 flag -N --count ('int')
328 }
329
330Calling `parseArgs` with `ARGV = :| -n 5 |` or `ARGV = :| --count 5 |` will
331store the integer `5` under `args.count`. If the user passes in a non-integer
332value like `ARGV = :| --count abc |`, `parseArgs` will raise an error.
333
334Default values for an argument can be set with the `default` named argument.
335
336 parser (&spec) {
337 flag -N --count ('int', default=2)
338
339 # Boolean flags can be given default values too
340 flag -O --optimize ('bool', default=true)
341 }
342
343 var args = parseArgs(spec, :| -n 3 |)
344 # => args.count = 2
345 # => args.optimize = true
346
347Each name passed to `flag` must be unique to that specific `parser`. Calling
348`flag` with the same name twice will raise an error inside of `parser`.
349
350<!-- TODO: how can we explicitly pass false to a boolean flag? -->
351<!-- TODO: how about --no-XXXX variants of flags? -->
352
353### arg
354
355`arg` should be called within a `parser` block.
356
357 parser (&spec) {
358 arg query
359 arg path
360 }
361
362The above example declares two positional arguments called "query" and "path".
363`parseArgs()` will then store strings under `args.query` and `args.path`. Order
364matters, so the first positional argument will be stored to `query` and the
365second to `path`. If not enough positional arguments are passed, then
366`parseArgs` will raise an error.
367
368Similar to `flag`, each `arg` name must be unique. Calling `arg` with the same
369name twice will cause `parser` to raise an error.
370
371### rest
372
373`rest` should be called within a `parser` block.
374
375 parser (&spec) {
376 arg query
377 rest files
378 }
379
380Capture zero or more positional arguments not already captured by `arg`. So,
381for `ARGV = :| hello file.txt message.txt README.md |`, we would have
382`args.query = "file.txt"` and `args.files = ["file.txt", "message.txt",
383"README.md"]`.
384
385Without rest, passing extraneous arguments will raise an error in
386`parseArgs()`.
387
388`rest` can only be called _once_ within a `parser`. Calling it multiple times
389will raise an error in `parser`.
390
391### parseArgs()
392
393Given a parser specification `spec` produced by `parser`, parse a list of
394strings (usually `ARGV`.)
395
396 var args = parseArgs(spec, ARGV)
397
398The returned `args` is a dictionary mapping the names of each `arg`, `flag` and
399`rest` to their captured values. (See the example at the [start of this
400topic](#Args-Parser).)
401
402`parseArgs` will raise an error if the `ARGV` is invalid per the parser
403specification. For example, if it's missing a required positional argument:
404
405 parser (&spec) {
406 arg path
407 }
408
409 var args = parseArgs(spec, [])
410 # => raises an error about the missing 'path' (status = 2)
411
412<!--
413TODO: Document chaining parsers / sub-commands
414 - Either will allow parser nesting
415 - Or can use `rest rest` and `parseArgs` again on `rest`
416TODO: Document the help named argument. Punting while we do not generate help messages
417-->