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

227 lines, 156 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## Args Parser
45
46YSH includes a command-line argument parsing utility called `parseArgs`. This
47is intended to be used for command-line interfaces to YSH programs.
48
49To use it, first import `args.ysh`:
50
51 source --builtin args.ysh
52
53Then, create an argument parser **spec**ification:
54
55 parser (&spec) {
56 flag -v --verbose (help="Verbosely") # default is Bool, false
57
58 flag -P --max-procs ('int', default=-1, help='''
59 Run at most P processes at a time
60 ''')
61
62 flag -i --invert ('bool', default=true, help='''
63 Long multiline
64 Description
65 ''')
66
67 arg src (help='Source')
68 arg dest (help='Dest')
69
70 rest files
71 }
72
73Finally, parse `ARGV` (or any other array of strings) with:
74
75 var args = parseArgs(spec, ARGV)
76
77The returned `args` is a `Dict` containing key-value pairs with the parsed
78values (or defaults) for each flag and argument. For example, given
79`ARGV = :| mysrc -P 12 mydest a b c |`, `args` would be:
80
81 {
82 "verbose": false,
83 "max-procs": 12,
84 "invert": true,
85 "src": "mysrc",
86 "dest": "mydest",
87 "files": ["a", "b", "c"]
88 }
89
90### parser
91
92`parseArgs()` requires a parser specification to indicate how to parse the
93`ARGV` array. This specification should be constructed using the `parser` proc.
94
95 parser (&spec) {
96 flag -f --my-flag
97 arg myarg
98 rest otherArgs
99 }
100
101In the above example, `parser` takes in a place `&spec`, which will store the
102resulting specification and a block which is evaluated to build that
103specification.
104
105Inside of a `parser` block, you should call the following procs:
106
107- `flag` to add `--flag` options
108- `arg` to add positional arguments
109- `rest` to capture remaining positional arguments into a list
110
111`parser` will validate the parser specification for errors such as duplicate
112flag or argument names.
113
114 parser (&spec) {
115 flag -n --name
116 flag -n --name # Duplicate!
117 }
118
119 # => raises "Duplicate flag/arg name 'name' in spec" (status = 3)
120
121### flag
122
123`flag` should be called within a `parser` block.
124
125 parser (&spec) {
126 flag -v --verbose
127 }
128
129The above example declares a flag "--verbose" and a short alias "-v".
130`parseArgs()` will then store a boolean value under `args.verbose`:
131- `true` if the flag was passed at least once
132- `false` otherwise
133
134Flags can also accept values. For example, if you wanted to accept an integer count:
135
136 parser (&spec) {
137 flag -N --count ('int')
138 }
139
140Calling `parseArgs` with `ARGV = :| -n 5 |` or `ARGV = :| --count 5 |` will
141store the integer `5` under `args.count`. If the user passes in a non-integer
142value like `ARGV = :| --count abc |`, `parseArgs` will raise an error.
143
144Default values for an argument can be set with the `default` named argument.
145
146 parser (&spec) {
147 flag -N --count ('int', default=2)
148
149 # Boolean flags can be given default values too
150 flag -O --optimize ('bool', default=true)
151 }
152
153 var args = parseArgs(spec, :| -n 3 |)
154 # => args.count = 2
155 # => args.optimize = true
156
157Each name passed to `flag` must be unique to that specific `parser`. Calling
158`flag` with the same name twice will raise an error inside of `parser`.
159
160<!-- TODO: how can we explicitly pass false to a boolean flag? -->
161<!-- TODO: how about --no-XXXX variants of flags? -->
162
163### arg
164
165`arg` should be called within a `parser` block.
166
167 parser (&spec) {
168 arg query
169 arg path
170 }
171
172The above example declares two positional arguments called "query" and "path".
173`parseArgs()` will then store strings under `args.query` and `args.path`. Order
174matters, so the first positional argument will be stored to `query` and the
175second to `path`. If not enough positional arguments are passed, then
176`parseArgs` will raise an error.
177
178Similar to `flag`, each `arg` name must be unique. Calling `arg` with the same
179name twice will cause `parser` to raise an error.
180
181### rest
182
183`rest` should be called within a `parser` block.
184
185 parser (&spec) {
186 arg query
187 rest files
188 }
189
190Capture zero or more positional arguments not already captured by `arg`. So,
191for `ARGV = :| hello file.txt message.txt README.md |`, we would have
192`args.query = "file.txt"` and `args.files = ["file.txt", "message.txt",
193"README.md"]`.
194
195Without rest, passing extraneous arguments will raise an error in
196`parseArgs()`.
197
198`rest` can only be called _once_ within a `parser`. Calling it multiple times
199will raise an error in `parser`.
200
201### parseArgs()
202
203Given a parser specification `spec` produced by `parser`, parse a list of
204strings (usually `ARGV`.)
205
206 var args = parseArgs(spec, ARGV)
207
208The returned `args` is a dictionary mapping the names of each `arg`, `flag` and
209`rest` to their captured values. (See the example at the [start of this
210topic](#Args-Parser).)
211
212`parseArgs` will raise an error if the `ARGV` is invalid per the parser
213specification. For example, if it's missing a required positional argument:
214
215 parser (&spec) {
216 arg path
217 }
218
219 var args = parseArgs(spec, [])
220 # => raises an error about the missing 'path' (status = 2)
221
222<!--
223TODO: Document chaining parsers / sub-commands
224 - Either will allow parser nesting
225 - Or can use `rest rest` and `parseArgs` again on `rest`
226TODO: Document the help named argument. Punting while we do not generate help messages
227-->