yash-cli 3.3.3

Extended POSIX shell
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
# Changelog

All notable changes to the shell are documented in this file.

This file lists changes to the shell executable as a whole. Changes to the
implementing library crate are not documented since it is not intended to be
used by other programs.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.3.3] - 2026-07-22

### Changed

- With `portable` enabled:
    - At startup, ignore environment variables with non-portable names.
    - Reject attempts to:
        - Make `PWD`, `OLDPWD`, `OPTIND`, `OPTARG`, or `LINENO` read-only via `readonly` or `typeset -r`.
        - Create or update variables with non-portable names via `export`, `readonly`, `typeset`, `read`, or `getopts`.

A portable variable name is non-empty, does not start with a digit, and contains only ASCII letters, digits, and underscores.

### Fixed

- The error message the `read` built-in prints for an invalid variable name
  now annotates the operand with just the variable name instead of the
  internal debug representation of the whole operand field.

## [3.3.2] - 2026-07-16

### Changed

- With the `portable` shell option enabled, arithmetic expansions now reject
  the increment and decrement operators (`++` and `--`).

## [3.3.1] - 2026-07-12

### Changed

- With the `portable` shell option enabled, the `alias` built-in now reports
  an error, instead of defining the alias, when an operand's alias name
  contains a character other than ASCII letters, digits, `!`, `%`, `,`, `-`,
  `@`, or `_`.
- With the `portable` shell option enabled, the shell now rejects array
  assignments (`name=(...)`) as a syntax error.

## [3.3.0] - 2026-07-09

### Added

- The `portable` shell option, which restricts the shell to portable constructs
  so that scripts can be checked for portability. See
  [Writing portable scripts]https://magicant.github.io/yash-rs/posix.html#writing-portable-scripts
  in the manual for the constructs it rejects. Currently, non-portable syntax is
  flagged. More checks will be added in future releases.

### Changed

- The shell now recognizes `]]` as a reserved word and reports a syntax error
  when it is used as a command name, instead of running it as an ordinary
  command.
- The shell now recognizes `namespace` and `select` as reserved words and
  reports a syntax error for them (they are reserved for future use but not yet
  implemented), instead of running them as ordinary commands.

## [3.2.2] - 2026-07-05

### Fixed

- A here-document whose delimiter is quoted with double quotes or
  `$'...'` (e.g. `<<"EOF"`) is now correctly treated as quoted. Previously,
  such a delimiter consisting only of literal characters was misdetected as
  unquoted, so the here-document body was incorrectly subject to parameter,
  command, and arithmetic expansion.

## [3.2.1] - 2026-06-21

### Changed

- The protection against exiting an interactive shell with suspended jobs, which
  was introduced in 3.2.0, can now be disabled by setting the `posixlycorrect`
  option.

## [3.2.0] - 2026-06-15

### Added

- The interactive shell now warns and refuses to exit when Ctrl+D (EOF) is
  received while suspended jobs exist, similar to other major shells.
- The `exit` built-in now refuses to exit with the same warning when there are
  suspended jobs in an interactive shell.
- The `exit` built-in has a new `-f`/`--force` option that forces the shell to
  exit even when there are suspended jobs.

## [3.1.0] - 2026-06-11

### Added

- The interactive shell now allows interrupting command execution with the
  `SIGINT` signal.

### Fixed

- Previously, the `fg` built-in always returned an interrupt when invoked in an
  interactive shell (unless there was an error). This was undesirable because
  any commands that followed `fg` would unconditionally be ignored. Now, `fg`
  only returns an interrupt in the following cases:
    - The job was suspended, or
    - The job was terminated by `SIGINT` and the `SIGINT` trap is not set.

## [3.0.8] - 2026-05-23

### Fixed

- Fixed a bug where subshells may not respond to signals correctly.

## [3.0.7] - 2026-04-30

### Changed

- Internal fixes only. No user-visible changes.

## [3.0.5] - 2026-02-04

### Changed

- The `kill` built-in no longer filters out invalid signals when they are
  specified by number. Instead, it now attempts to send the specified signal
  number as is, and lets the operating system handle invalid signal numbers.
  This change allows sending custom signals that are not recognized by the
  shell, if the operating system supports them.

### Fixed

- The `kill` built-in now correctly formats error messages for invalid options
  and signal specifications.

## [3.0.4] - 2025-11-07

### Changed

- Revised some error messages related to executing external utilities.

## [3.0.3] - 2025-10-18

### Changed

- The `times` built-in now uses the `getrusage` system call instead of `times`
  to get CPU times. This provides better resolution on many systems.

## [3.0.2] - 2025-10-16

### Fixed

- The shell no longer crashes when the `xtrace` option is enabled and the `PS4`
  variable contains a command substitution, which previously caused infinitely
  recursive expansion of `PS4`.

## [3.0.1] - 2025-10-13

### Changed

- Slightly refined the format of error messages.

## [3.0.0] - 2025-09-23

This is the first stable release of yash-rs.

### Added

- The `pipefail` shell option is now supported.
    - When this option is enabled, the exit status of a pipeline reflects the
      failure of any command in the pipeline, not just the last command.

### Changed

- The special parameter `!` is now considered unset if no asynchronous command
  has been executed.
- The shell now displays a more informative error message when the `function`
  or `[[` reserved word is used, indicating that these syntaxes are not yet
  supported.
- The shell now displays a more informative error message when process
  redirections (`>(...)` or `<(...)`), pipe redirections (`>>|`), or
  here-strings (`<<<`) are used, indicating that these redirections are not yet
  supported.

## [0.4.5] - 2025-09-20

### Added

- The `return` built-in now supports the `--no-return` option as a synonym of
  `-n`, which returns the specified exit status without actually returning from
  the current function or script.

### Fixed

- The `eval`, `exit`, `return`, `shift`, and `typeset` built-ins now correctly
  handle the `--` separator between options and operands.
- The `export`, `readonly`, and `typeset` built-ins now correctly print the `--`
  separator when the name of a variable or function starts with `-`.
- The `jobs` built-in no longer crashes when reporting the same finished job more
  than once in a single invocation.

## [0.4.4] - 2025-09-20

### Fixed

- The execution of a simple command now searches for the external utility in the
  `PATH` after performing variable assignments, as specified in POSIX-1.2024.
  Previously, it would search for the utility before performing the redirections
  and assignments, which could lead to incorrect behavior if the assignments
  modified the `PATH` variable.

## [0.4.3] - 2025-09-14

**Update:** This version was accidentally published without updating the
necessary dependencies for the advertised behavior. Please use version 0.4.5 or
later.

### Added

- ~~The `return` built-in now supports the `--no-return` option as a synonym of
  `-n`, which returns the specified exit status without actually returning from
  the current function or script.~~

### Fixed

- Error messages now accurately highlight the relevant source code fragment.
  Previously, the shell could highlight the wrong section or crash when the
  source contained multi-byte characters.
- ~~The `eval`, `exit`, `return`, `shift`, and `typeset` built-ins now correctly
  handle the `--` separator between options and operands.~~
- ~~The `export`, `readonly`, and `typeset` built-ins now correctly print the `--`
  separator when the name of a variable or function starts with `-`.~~
- ~~The `jobs` built-in no longer crashes when reporting the same finished job more
  than once in a single invocation.~~

## [0.4.2] - 2025-05-11

### Changed

- The shell now recognizes the I/O location notation attached to a redirection
  operator as in `{n}<file`. Currently, the shell does not support this
  notation, but it is reserved for future use.

### Fixed

- When a tilde expansion produces a directory name that ends with a slash and
  the expansion is followed by a slash, the trailing slash in the directory name
  is now removed to maintain the correct number of slashes.
- The `cd` built-in now returns exit status 1 if updating `$PWD` or `$OLDPWD`
  fails because the variable is read-only. Previously, it returned status 0,
  which did not conform to POSIX.1-2024 XBD 8.1.

## [0.4.1] - 2025-05-03

### Fixed

- The shell now correctly handles traps for signals that are caught while
  reading a command. Previously, the shell would ignore such signals.
- The `getopts` and `read` built-ins now fail when a specified variable name
  contains an `=` character.
- The `set` built-in without arguments no longer prints variables that have an
  invalid name.
- When a field is made up of a single tilde expansion that expands to an empty
  string, the expanded field is no longer removed from the command line, as
  required by POSIX.1-2024.

## [0.4.0] - 2025-04-26

### Changed

- In pathname expansion, pathname component patterns no longer expand to the
  filename `.` or `..`. For example, the pattern `.*` may match `.config` and
  `.git`, but not `.` or `..`.
- When a value is assigned to a variable in an expansion of the form
  `${name=word}` or `${name:=word}`, the resulting expansion is now the value of
  the variable after the assignment, rather than the expansion of `word`.
  This is the behavior specified in POSIX.1-2024.
- The `true`, `false`, and `pwd` built-ins are now substitutive, as specified in
  POSIX.1-2024.
- The `exec` built-in now accepts the `--` separator between options and
  operands, as required by POSIX.1-2024.
- When an asynchronous command is executed in an interactive shell, the job
  number and the process ID are now printed to the standard error, as required
  by POSIX.1-2024.
- The shell now returns an exit status of 128 on an I/O error reading command
  input, except when reading a script in the `.` built-in, as required by
  POSIX.1-2024.
- When a command is terminated by a signal and its exit status is used as the
  exit status of the shell, the shell now terminates itself with the same
  signal, as required by POSIX.1-2024.
- As specified in POSIX.1-2024, the shell now becomes interactive if the `+i`
  option is not set, the `-s` option is set, and the standard input and error are
  connected to a terminal, regardless of positional parameters. Previously, the
  shell would become interactive only if there were no positional parameters.

## [0.3.0] - 2025-03-23

### Added

- The shell now supports declaration utilities as defined in POSIX.
- The `cd` built-in now supports the `-e` option as defined in POSIX.
- The `read` built-in now supports the `-d` (`--delimiter`) option, which allows
  specifying a delimiter character to terminate the input.
- The `trap` built-in now implements the POSIX.1-2024 behavior of showing
  signal dispositions that are not explicitly set by the user. It also supports
  the `-p` (`--print`) option.
- The `-p` option for the `command` built-in now works on Linux.

### Changed

- When a foreground job is suspended in an interactive shell, the shell now
  discards any remaining commands in the current command line and prompts for
  the next command line. This behavior basically conforms to POSIX.1-2024, but
  differs in that the shell does not resume with the remaining commands
  following the next asynchronous and-or list.
- When the shell starts job control, if it is in the background, the shell now
  suspends itself until it is resumed in the foreground. Previously, the shell
  would continue running in the background, interfering with the foreground
  process group.
- If job control is enabled and the shell does not have a controlling terminal,
  the shell now proceeds without managing foreground-ness of process groups.
  Jobs are still assigned to their own process groups. Previously, the shell
  would abort command execution in this case.
- The `cd` built-in now errors out when a given operand is an empty string.
- The `cd` built-in now returns different exit statuses for different errors.
- The `fg` and `bg` built-ins now error out if job control is not enabled.
- The command `kill -l` now shows signals in the ascending order of their
  numbers.
- The `read` built-in now returns a more specific exit status depending on the
  cause of the error. It also rejects an input containing a null byte.
- The output of the `trap` built-in now includes not only user-defined traps but
  also signal dispositions that are not explicitly set by the user.
- The `wait` built-in no longer treats suspended jobs as terminated jobs. When
  waiting for a suspended job, the built-in now waits indefinitely until the job
  is resumed and finished.

## [0.2.0] - 2024-12-14

### Added

- A case branch now can be terminated with `;&` or `;|` instead of `;;` to fall
  through to the next branch or to resume pattern matching from the next branch,
  respectively. `;&` is a POSIX.1-2024 feature, and `;|` is an extension. For
  compatibility with other shells, `;;&` is also accepted as an alias for `;|`.
- Dollar-single-quotes are now supported as a form of quoting where backslash
  escapes are recognized.
    - Currently, octal and hexadecimal escapes that expand to a value greater
      than 127 are translated to a UTF-8 sequence for the corresponding Unicode
      scalar value. This behavior does not conform to POSIX.1-2024 and is
      subject to change.
    - As an extension to POSIX.1-2024, the shell also recognizes the `\u` and
      `\U` escapes for Unicode scalar values, and the `\E` escape as a synonym
      for `\e`.

### Changed

- The shell's syntax now allows `esac` as the first pattern of a case branch
  as in `case esac in (esac|case) echo ok; esac`. Previously, it was a syntax
  error, but POSIX.1-2024 allows it.
- The `bg` built-in now updates the `!` special parameter to the process ID of
  the background job, as required by POSIX.1-2024.
- The `exec` built-in no longer exits the shell when the specified command is
  not found in an interactive shell, as required by POSIX.1-2024.

### Fixed

- The interactive shell now discards the entire line when a syntax error occurs
  in the middle of a command line. Previously, it would continue parsing the
  rest of the line, which could lead to confusing behavior.

## [0.1.0] - 2024-09-29

### Added

- The shell now runs the initialization file specified by the `ENV` environment
  variable if it is set and the shell is interactive.

### Changed

- The shell now rejects an invalid parameter as a syntax error. Specifically,
  if a parameter starts with a digit but is not a valid number, the shell now
  reports a syntax error instead of treating it as a variable. For example,
  `${1abc}` and `${0_1}` are now syntax errors.
- Improved error messages for some parameter expansion errors.
- Interactive shells now report updates to job status before showing the prompt.
- Interactive shells no longer exit on shell errors such as syntax errors.
- Interactive shells now ignore the `noexec` option.
- Interactive shells now support the `ignoreeof` option.
- Interactive shells now allow modifying the trap for signals that were ignored
  on the shell startup.

### Fixed

- When the shell cannot open a script specified by the command-line argument,
  it now returns the exit status of 126 or 127 as required by POSIX. Previously,
  it returned the exit status of 2.

## [0.1.0-beta.2] - 2024-07-13

### Changed

- The shell now shows the prompt before reading the input in the interactive mode.

### Fixed

- The break and continue built-ins no longer allow exiting a trap.
- The read built-in now shows a prompt when reading a continued line.
- The source built-in now echoes the input when the verbose shell option is set.
- The set built-in no longer sets the `SIGTTIN`, `SIGTTOU`, and `SIGTSTP` signals
  to be ignored when invoked with the `-m` option in a subshell of an
  interactive shell.

## [0.1.0-beta.1] - 2024-06-09

### Changed

- The shell now enables blocking reads on the standard input if it is a terminal
  or a pipe as [required by POSIX]https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/sh.html#tag_20_117_06.

## [0.1.0-alpha.1] - 2024-04-13

### Added

- Initial release of the shell

[3.3.3]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.3.3
[3.3.2]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.3.2
[3.3.1]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.3.1
[3.3.0]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.3.0
[3.2.2]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.2.2
[3.2.1]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.2.1
[3.2.0]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.2.0
[3.1.0]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.1.0
[3.0.8]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.0.8
[3.0.7]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.0.7
[3.0.5]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.0.5
[3.0.4]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.0.4
[3.0.3]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.0.3
[3.0.2]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.0.2
[3.0.1]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.0.1
[3.0.0]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-3.0.0
[0.4.5]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.4.5
[0.4.4]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.4.4
[0.4.3]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.4.3
[0.4.2]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.4.2
[0.4.1]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.4.1
[0.4.0]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.4.0
[0.3.0]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.3.0
[0.2.0]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.2.0
[0.1.0]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.1.0
[0.1.0-beta.2]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.1.0-beta.2
[0.1.0-beta.1]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.1.0-beta.1
[0.1.0-alpha.1]: https://github.com/magicant/yash-rs/releases/tag/yash-cli-0.1.0-alpha.1