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 | ## Args Parser
|
45 |
|
46 | YSH includes a command-line argument parsing utility called `parseArgs`. This
|
47 | is intended to be used for command-line interfaces to YSH programs.
|
48 |
|
49 | To use it, first import `args.ysh`:
|
50 |
|
51 | source --builtin args.ysh
|
52 |
|
53 | Then, 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 |
|
73 | Finally, parse `ARGV` (or any other array of strings) with:
|
74 |
|
75 | var args = parseArgs(spec, ARGV)
|
76 |
|
77 | The returned `args` is a `Dict` containing key-value pairs with the parsed
|
78 | values (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 |
|
101 | In the above example, `parser` takes in a place `&spec`, which will store the
|
102 | resulting specification and a block which is evaluated to build that
|
103 | specification.
|
104 |
|
105 | Inside 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
|
112 | flag 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 |
|
129 | The 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 |
|
134 | Flags 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 |
|
140 | Calling `parseArgs` with `ARGV = :| -n 5 |` or `ARGV = :| --count 5 |` will
|
141 | store the integer `5` under `args.count`. If the user passes in a non-integer
|
142 | value like `ARGV = :| --count abc |`, `parseArgs` will raise an error.
|
143 |
|
144 | Default 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 |
|
157 | Each 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 |
|
172 | The above example declares two positional arguments called "query" and "path".
|
173 | `parseArgs()` will then store strings under `args.query` and `args.path`. Order
|
174 | matters, so the first positional argument will be stored to `query` and the
|
175 | second to `path`. If not enough positional arguments are passed, then
|
176 | `parseArgs` will raise an error.
|
177 |
|
178 | Similar to `flag`, each `arg` name must be unique. Calling `arg` with the same
|
179 | name 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 |
|
190 | Capture zero or more positional arguments not already captured by `arg`. So,
|
191 | for `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 |
|
195 | Without 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
|
199 | will raise an error in `parser`.
|
200 |
|
201 | ### parseArgs()
|
202 |
|
203 | Given a parser specification `spec` produced by `parser`, parse a list of
|
204 | strings (usually `ARGV`.)
|
205 |
|
206 | var args = parseArgs(spec, ARGV)
|
207 |
|
208 | The 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
|
210 | topic](#Args-Parser).)
|
211 |
|
212 | `parseArgs` will raise an error if the `ARGV` is invalid per the parser
|
213 | specification. 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 | <!--
|
223 | TODO: Document chaining parsers / sub-commands
|
224 | - Either will allow parser nesting
|
225 | - Or can use `rest rest` and `parseArgs` again on `rest`
|
226 | TODO: Document the help named argument. Punting while we do not generate help messages
|
227 | -->
|