1 | ---
|
2 | in_progress: yes
|
3 | default_highlighter: oils-sh
|
4 | ---
|
5 |
|
6 | Global Shell Options: Turning OSH into YSH
|
7 | ==========================================
|
8 |
|
9 |
|
10 | This document describes global shell options, which look like this:
|
11 |
|
12 | shopt --set strict_backslash # YSH style
|
13 | shopt --set ysh:upgrade # A whole group of options
|
14 | set -o errexit # Bourne shell style
|
15 |
|
16 | They can affect parsing or execution, and are used to gradually turn the
|
17 | [OSH]($xref:OSH) into the [YSH]($xref:YSH).
|
18 |
|
19 | For example, YSH doesn't have word splitting on whitespace. Instead, it use
|
20 | [Simple Word Evaluation](simple-word-eval.html). (Blog: [Oil Doesn't Require
|
21 | Quoting
|
22 | Everywhere](https://www.oilshell.org/blog/2021/04/simple-word-eval.html)). (Until 2023, YSH was called the "Oil language".)
|
23 |
|
24 | This isn't the **only** use for options, but it's an important one.
|
25 |
|
26 | <div id="toc">
|
27 | </div>
|
28 |
|
29 | ## What Every User Should Know (2 minutes)
|
30 |
|
31 | When you run `bin/osh`, the **option groups** `strict:all` and `ysh:upgrade` are
|
32 | "canned settings" that relieve you of having to know about dozens of shell
|
33 | options.
|
34 |
|
35 | Running `bin/ysh` is equivalent to using `shopt --set ysh:all` in `bin/osh`.
|
36 |
|
37 | Let's look at three examples.
|
38 |
|
39 | ### Strict
|
40 |
|
41 | If you put this line at the top of your shell script, it will still **run under
|
42 | other shells**, but OSH will act as sort of a "runtime linter":
|
43 |
|
44 | # Abort on more errors, but fixes will still be compatible
|
45 | shopt -s strict:all 2>/dev/null || true
|
46 |
|
47 | ### Upgrade
|
48 |
|
49 | If you want to upgrade a script, and don't care about running under other
|
50 | shells, use this:
|
51 |
|
52 | # Start enabling YSH syntax and semantics
|
53 | shopt --set ysh:upgrade
|
54 |
|
55 | This second line may break a few things, but is designed to be an easy upgrade.
|
56 | See [What Breaks When You Upgrade to YSH](upgrade-breakage.html).
|
57 |
|
58 | ### YSH
|
59 |
|
60 | If you're writing a new script, you can use `bin/ysh` to get **all**
|
61 | enhancements. Typically you use a shebang line like this:
|
62 |
|
63 | #!/usr/bin/env ysh
|
64 |
|
65 | That's all most users need to know. For more details, see the wiki page:
|
66 | [Gradually Upgrading Shell to Oil]($wiki).
|
67 |
|
68 | ## Using Shell Options
|
69 |
|
70 | There are several different ways of using shell options.
|
71 |
|
72 | ### Preferred Style
|
73 |
|
74 | YSH has **long flags** for readability, which are preferred:
|
75 |
|
76 | shopt --set errexit
|
77 | shopt --unset errexit
|
78 |
|
79 | It also allows **scoped** options:
|
80 |
|
81 | shopt --unset errexit {
|
82 | false # non-zero status ignored
|
83 | ls /bad
|
84 | }
|
85 | false # original setting restored
|
86 |
|
87 | ### Bourne Shell Style
|
88 |
|
89 | For compatibility, these styles works in YSH:
|
90 |
|
91 | set -e # abort script on non-zero exit exit code
|
92 | set +e # turn it off
|
93 |
|
94 | set -o errexit # a more readable version of the above
|
95 | set +o errexit
|
96 |
|
97 | [Bash]($xref:bash)-style option with `shopt`:
|
98 |
|
99 | shopt -s nullglob # turn it on
|
100 | shopt -u nullglob # turn it off
|
101 |
|
102 | ### Setting Options Via Command Line Flags
|
103 |
|
104 | You typically invoke the `shopt` builtin at the top of a script, but you
|
105 | can also set options at the command line:
|
106 |
|
107 | osh -O errexit -c 'shopt -p -o' # turn on Bourne option
|
108 | osh +O errexit -c 'shopt -p -o' # turn off Bourne option
|
109 |
|
110 | osh -O strict_tilde -c 'shopt -p' # turn on YSH option
|
111 | osh +O strict_tilde -c 'shopt -p' # turn off YSH option
|
112 |
|
113 | ### Inspecting Option State
|
114 |
|
115 | Shell has many ways to do this, like:
|
116 |
|
117 | set -o # print all Bourne shell options
|
118 | shopt -p # print all bash options
|
119 | shopt -p nullglob failglob # print selected options
|
120 | shopt -p ysh:upgrade # print options in the given group
|
121 |
|
122 | TODO: YSH should enable `shopt --print` for all options. It should have a flat
|
123 | list.
|
124 |
|
125 | ## Kinds of Options, With Examples
|
126 |
|
127 | *Option groups* like `ysh:upgrade` are baked into the interpreter. What follows
|
128 | is an informal list of *kinds* of options, which are different categorization:
|
129 |
|
130 | - Groups: How much of YSH do you want to use?
|
131 | - Kinds: Does this option affect parsing behavior, runtime behavior, or
|
132 | something else?
|
133 |
|
134 | ### Naming Conventions
|
135 |
|
136 | - `parse_*`: Change parsing.
|
137 | - enable new features: `parse_at`, `parse_equals`.
|
138 | - turn off to reject bad or old code: `parse_backticks`, `parse_backslash`,
|
139 | `parse_dollar`.
|
140 | - `strict_*`: Fail at runtime instead of ignoring the bug like bash.
|
141 | - `${#s}` on invalid unicode is a runtime error.
|
142 | - `~typo` is a runtime error.
|
143 | - `simple_*`: Break things to improve style.
|
144 | - `simple_eval_builtin`, `simple_echo`.
|
145 | - `simple_word_eval` is the most aggressive
|
146 |
|
147 | ### Strict Options Produce More Errors
|
148 |
|
149 | These options produce more **programming errors**. Importantly, the resulting
|
150 | program is still compatible with other shells.
|
151 |
|
152 | For example, `shopt -s strict_array` produces runtime errors when you confuse
|
153 | strings and arrays. After you fix these problems, your program will still run
|
154 | correctly under `bash`.
|
155 |
|
156 | In contrast, if you set `shopt -s simple_word_eval` (an option that doesn't
|
157 | start with `strict_`), the semantics of your program have changed, and you can
|
158 | **no longer** run it under other shells. It's considered an "YSH option": by
|
159 | setting it, you're using parts of YSH.
|
160 |
|
161 | ### Parse Options Change Syntax
|
162 |
|
163 | Options that affect parsing start with `parse_`. For example, `shopt -s
|
164 | parse_at` enables **splicing** with the `@` character:
|
165 |
|
166 | var words = :| ale bean |
|
167 | write -- @words
|
168 | # =>
|
169 | # ale
|
170 | # bean
|
171 |
|
172 | and inline function calls:
|
173 |
|
174 | write -- @[split('ale bean')]
|
175 | # =>
|
176 | # ale
|
177 | # bean
|
178 |
|
179 | As another example, `shopt --set parse_brace` takes over the `{ }` characters.
|
180 | Specifically, it does three things:
|
181 |
|
182 | 1. Allow builtins like `cd` to take a block (discussed in a [Zulip
|
183 | thread](https://oilshell.zulipchat.com/#narrow/stream/121540-oil-discuss/topic/cd.20now.20takes.20a.20Ruby-like.20block))
|
184 | 2. Control flow like `if`, `case`, `for`, and `while/until`, use curly brace
|
185 | delimiters instead of `then/fi`, `do/done`, etc. See below.
|
186 | 3. To remove confusion, braces must be balanced inside a word. echo `foo{` is
|
187 | an error. It has to be `echo foo\{` or `echo 'foo{'`.
|
188 | - In a correct brace expansion, they're always balanced: `{pea,coco}nut`
|
189 | - This is so that the syntax errors are better when you forget a space.
|
190 |
|
191 | <!--
|
192 | Test cases start here: <https://github.com/oilshell/oil/blob/master/spec/oil-options.test.sh#L257>
|
193 | -->
|
194 |
|
195 | Here's idiomatic YSH syntax after `parse_brace`:
|
196 |
|
197 | cd /tmp {
|
198 | echo $PWD
|
199 | }
|
200 |
|
201 | if test -d foo {
|
202 | echo 'dir'
|
203 | } elif test -f foo {
|
204 | echo 'file'
|
205 | } else {
|
206 | echo 'neither'
|
207 | }
|
208 |
|
209 | # Single line statements are supported:
|
210 | if test -d / { echo 'dir' } else { echo 'nope' }
|
211 |
|
212 | while true {
|
213 | echo hi
|
214 | break
|
215 | }
|
216 |
|
217 | # Loop over words
|
218 | for x in ale bean *.sh {
|
219 | echo $x
|
220 | }
|
221 |
|
222 | # Replace 'in' with {, and 'esac' with }
|
223 | case $x {
|
224 | *.py)
|
225 | echo python
|
226 | ;;
|
227 | *.sh)
|
228 | echo shell
|
229 | ;;
|
230 | }
|
231 |
|
232 | What's the motivation for this? Mainly familiarity: I hear a lot of feedback
|
233 | that nobody can remember how to write if statements in shell. See [The
|
234 | Simplest Explanation of
|
235 | Oil](//www.oilshell.org/blog/2020/01/simplest-explanation.html).
|
236 |
|
237 | <!--
|
238 |
|
239 | There are also **expression** variants of these constructs:
|
240 |
|
241 | if (x > 0) {
|
242 | echo hi
|
243 | }
|
244 |
|
245 | while (x > 0) {
|
246 | echo hi
|
247 | }
|
248 |
|
249 | (`for` and `case` to come later.)
|
250 |
|
251 | -->
|
252 |
|
253 |
|
254 | ### Runtime Options Change Behavior
|
255 |
|
256 | - `simple_echo`. Changes the flags accepted by the `echo` builtin, and style of flag parsing.
|
257 | See the `Builtins > echo` below.
|
258 | - `simple_word_eval`. Word evaluation consists of one stage rather than three:
|
259 | - No word splitting or empty elision. (In other words, arity isn't data-dependent.)
|
260 | - Static globbing, but no dynamic globbing. (In other words, data isn't re-parsed as code.)
|
261 | - This option is intended to be implemented by other shells.
|
262 |
|
263 | TODO: copy examples from spec tests
|
264 |
|
265 | echo $dir/*.py
|
266 |
|
267 | - `command_sub_errexit`. A error in a command sub can cause the **parent
|
268 | shell** to exit fatally. Also see `inherit_errexit` and `strict_errexit`.
|
269 |
|
270 | ## List of Options
|
271 |
|
272 | ### Selected Options
|
273 |
|
274 | `strict_arith`. Strings that don't look like integers cause a fatal error in
|
275 | arithmetic expressions.
|
276 |
|
277 | `strict_argv`. Empty `argv` arrays are disallowed (because there's no
|
278 | practical use for them). For example, the second statement in `x=''; $x`
|
279 | results in a fatal error.
|
280 |
|
281 | `strict_array`. No implicit conversions between string an array. In other
|
282 | words, turning this on gives you a "real" array type.
|
283 |
|
284 | `strict_control_flow`. `break` and `continue` outside of a loop are fatal
|
285 | errors.
|
286 |
|
287 | `simple_eval_builtin`. The `eval` builtin takes exactly **one** argument. It
|
288 | doesn't concatenate its arguments with spaces, or accept zero arguments.
|
289 |
|
290 | `strict_word_eval`. More word evaluation errors are fatal.
|
291 |
|
292 | - String slices with negative arguments like `${s: -1}` and `${s: 1 : -1}`
|
293 | result in a fatal error. (NOTE: In array slices, negative start indices are
|
294 | allowed, but negative lengths are always fatal, regardless of
|
295 | `strict_word_eval`.)
|
296 | - UTF-8 decoding errors are fatal when computing lengths (`${#s}`) and slices.
|
297 |
|
298 | For options affecting exit codes, see the [error handling
|
299 | doc](error-handling.html).
|
300 |
|
301 | ### Complete List
|
302 |
|
303 | See the [Chapter on Global Shell Options](ref/chap-option.html) in the
|
304 | reference.
|
305 |
|
306 | ## FAQ: Aren't Global Variables Bad?
|
307 |
|
308 | Options are technically globals, but YSH controls them in 2 ways:
|
309 |
|
310 | 1. It has scoped mutation with Ruby-like [blocks](proc-block-func.html).
|
311 | - Example: `shopt --unset errexit { false }`
|
312 | 2. Like all Bourne shells, YSH uses process-based concurrency. It doesn't have
|
313 | shared memory.
|
314 |
|
315 | ## Related Documents
|
316 |
|
317 | - Up: [Interpreter State](interpreter-state.html), which is under construction
|
318 |
|