1 | ---
|
2 | title: Builtin Commands (Oils Reference)
|
3 | all_docs_url: ..
|
4 | body_css_class: width40
|
5 | default_highlighter: oils-sh
|
6 | preserve_anchor_case: yes
|
7 | ---
|
8 |
|
9 | <div class="doc-ref-header">
|
10 |
|
11 | [Oils Reference](index.html) — Chapter **Standard Library**
|
12 |
|
13 | </div>
|
14 |
|
15 | This chapter in the [Oils Reference](index.html) describes the standard library
|
16 | for 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 |
|
27 | These functions are in `two.sh`
|
28 |
|
29 | source $OSH_LIB/two.sh
|
30 |
|
31 | ### log
|
32 |
|
33 | Write a message to stderr:
|
34 |
|
35 | log "hi $x"
|
36 | log '---'
|
37 |
|
38 | ### die
|
39 |
|
40 | Write 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 |
|
48 | Use 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 |
|
58 | Run 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 |
|
70 | Run a command and return its status and stdout.
|
71 |
|
72 | ### nq-capture-2
|
73 |
|
74 | Run a command and return its status and stderr.
|
75 |
|
76 | ### nq-redir
|
77 |
|
78 | Run a command and return its status and a file with its stdout, so you can diff
|
79 | it.
|
80 |
|
81 | ### nq-redir-2
|
82 |
|
83 | Run a command and return its status and a file with its stderr, so you can diff
|
84 | it.
|
85 |
|
86 | ## task-five
|
87 |
|
88 | ### task-five
|
89 |
|
90 | Dispatch to shell functions, and provide BYO test enumeration.
|
91 |
|
92 | OSH:
|
93 |
|
94 | task-five "$@"
|
95 |
|
96 | YSH:
|
97 |
|
98 | task-five @ARGV
|
99 |
|
100 | ## math
|
101 |
|
102 | ### abs()
|
103 |
|
104 | Compute the absolute (positive) value of a number (float or int).
|
105 |
|
106 | = abs(-1) # => 1
|
107 | = abs(0) # => 0
|
108 | = abs(1) # => 1
|
109 |
|
110 | Note, you will need to `source $LIB_YSH/math.ysh` to use this function.
|
111 |
|
112 | ### max()
|
113 |
|
114 | Compute 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 |
|
121 | For example:
|
122 |
|
123 | = max(1, 2) # => 2
|
124 | = max([1, 2, 3]) # => 3
|
125 |
|
126 | Note, you will need to `source $LIB_YSH/math.ysh` to use this function.
|
127 |
|
128 | ### min()
|
129 |
|
130 | Compute 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 |
|
137 | For example:
|
138 |
|
139 | = min(2, 3) # => 2
|
140 | = max([1, 2, 3]) # => 1
|
141 |
|
142 | Note, you will need to `source $LIB_YSH/math.ysh` to use this function.
|
143 |
|
144 | ### round()
|
145 |
|
146 | TODO
|
147 |
|
148 | ### sum()
|
149 |
|
150 | Computes the sum of all elements in the list.
|
151 |
|
152 | Returns 0 for an empty list.
|
153 |
|
154 | = sum([]) # => 0
|
155 | = sum([0]) # => 0
|
156 | = sum([1, 2, 3]) # => 6
|
157 |
|
158 | Note, you will need to `source $LIB_YSH/list.ysh` to use this function.
|
159 |
|
160 |
|
161 | ## list
|
162 |
|
163 | ### all()
|
164 |
|
165 | Returns true if all values in the list are truthy (`x` is truthy if `Bool(x)`
|
166 | returns true).
|
167 |
|
168 | If 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 |
|
175 | Note, you will need to `source $LIB_YSH/list.ysh` to use this function.
|
176 |
|
177 | ### any()
|
178 |
|
179 | Returns true if any value in the list is truthy (`x` is truthy if `Bool(x)`
|
180 | returns true).
|
181 |
|
182 | If 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 |
|
189 | Note, you will need to `source $LIB_YSH/list.ysh` to use this function.
|
190 |
|
191 | ### repeat()
|
192 |
|
193 | Repeat a string or a list:
|
194 |
|
195 | = repeat('foo', 3) # => 'foofoofoo'
|
196 | = repeat(['foo', 'bar'], 2) # => ['foo', 'bar', 'foo', 'bar']
|
197 |
|
198 | Negative repetitions are equivalent to zero:
|
199 |
|
200 | = repeat('foo', -5) # => ''
|
201 | = repeat(['foo', 'bar'], -5) # => []
|
202 |
|
203 | Note 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 |
|
212 | Helpers to assert the status and output of commands.
|
213 |
|
214 | ### yb-capture
|
215 |
|
216 | Capture 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 |
|
226 | Capture 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 |
|
236 | YSH includes a command-line argument parsing utility called `parseArgs`. This
|
237 | is intended to be used for command-line interfaces to YSH programs.
|
238 |
|
239 | To use it, first import `args.ysh`:
|
240 |
|
241 | source $LIB_YSH/args.ysh
|
242 |
|
243 | Then, 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 |
|
263 | Finally, parse `ARGV` (or any other array of strings) with:
|
264 |
|
265 | var args = parseArgs(spec, ARGV)
|
266 |
|
267 | The returned `args` is a `Dict` containing key-value pairs with the parsed
|
268 | values (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 |
|
291 | In the above example, `parser` takes in a place `&spec`, which will store the
|
292 | resulting specification and a block which is evaluated to build that
|
293 | specification.
|
294 |
|
295 | Inside 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
|
302 | flag 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 |
|
319 | The 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 |
|
324 | Flags 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 |
|
330 | Calling `parseArgs` with `ARGV = :| -n 5 |` or `ARGV = :| --count 5 |` will
|
331 | store the integer `5` under `args.count`. If the user passes in a non-integer
|
332 | value like `ARGV = :| --count abc |`, `parseArgs` will raise an error.
|
333 |
|
334 | Default 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 |
|
347 | Each 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 |
|
362 | The above example declares two positional arguments called "query" and "path".
|
363 | `parseArgs()` will then store strings under `args.query` and `args.path`. Order
|
364 | matters, so the first positional argument will be stored to `query` and the
|
365 | second to `path`. If not enough positional arguments are passed, then
|
366 | `parseArgs` will raise an error.
|
367 |
|
368 | Similar to `flag`, each `arg` name must be unique. Calling `arg` with the same
|
369 | name 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 |
|
380 | Capture zero or more positional arguments not already captured by `arg`. So,
|
381 | for `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 |
|
385 | Without 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
|
389 | will raise an error in `parser`.
|
390 |
|
391 | ### parseArgs()
|
392 |
|
393 | Given a parser specification `spec` produced by `parser`, parse a list of
|
394 | strings (usually `ARGV`.)
|
395 |
|
396 | var args = parseArgs(spec, ARGV)
|
397 |
|
398 | The 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
|
400 | topic](#Args-Parser).)
|
401 |
|
402 | `parseArgs` will raise an error if the `ARGV` is invalid per the parser
|
403 | specification. 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 | <!--
|
413 | TODO: Document chaining parsers / sub-commands
|
414 | - Either will allow parser nesting
|
415 | - Or can use `rest rest` and `parseArgs` again on `rest`
|
416 | TODO: Document the help named argument. Punting while we do not generate help messages
|
417 | -->
|