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

1377 lines, 895 significant
1---
2in_progress: yes
3body_css_class: width40 help-body
4default_highlighter: oils-sh
5preserve_anchor_case: yes
6---
7
8Builtin Commands
9===
10
11This chapter in the [Oils Reference](index.html) describes builtin commands for OSH and YSH.
12
13<div id="toc">
14</div>
15
16## Memory
17
18### append
19
20Append word arguments to a list:
21
22 var mylist = :| hello |
23
24 append *.py (mylist) # append all Python files
25
26 var myflags = []
27 append -- -c 'echo hi' (myflags) # -- to avoid ambiguity
28
29It's a shortcut for:
30
31 call myflags->append('-c')
32 call myflags->append('echo hi')
33
34### pp
35
36Pretty prints interpreter state. Some of these are implementation details,
37subject to change.
38
39Examples:
40
41 pp proc # print all procs and their doc comments
42
43 var x = :| one two |
44 pp cell x # dump the "guts" of a cell, which is a location for a value
45
46 pp asdl (x) # dump the ASDL "guts"
47
48 pp line (x) # single-line stable format, for spec tests
49
50## Handle Errors
51
52### try
53
54Run a block of code, stopping at the first error. In other words, shopt
55`errexit` is enabled.
56
57Set the `_status` variable to the exit status of the block, and return 0.
58
59 try {
60 ls /nonexistent
61 }
62 if (_status !== 0) {
63 echo 'ls failed'
64 }
65
66Handle expression errors:
67
68 try {
69 var x = 42 / 0
70 }
71
72And errors from compound commands:
73
74 try {
75 ls | wc -l
76 diff <(sort left.txt) <(sort right.txt)
77 }
78
79The case statement can be useful:
80
81 try {
82 grep PATTERN FILE.txt
83 }
84 case (_status) {
85 (0) { echo 'found' }
86 (1) { echo 'not found' }
87 (else) { echo "grep returned status $_status" }
88 }
89
90The `try` builtin may also set the `_error` register.
91
92### boolstatus
93
94Runs a command and requires the exit code to be 0 or 1.
95
96 if boolstatus egrep '[0-9]+' myfile { # may abort
97 echo 'found' # status 0 means found
98 } else {
99 echo 'not found' # status 1 means not found
100 }
101
102### error
103
104The `error` builtin interrupts the shell program.
105
106 error 'Missing /tmp' # program fails with status 10
107
108Override the default status of `10` with a named argument:
109
110 error 'Missing /tmp' (status=99)
111
112In YSH, it's customary to use `error` instead of `return 1`, since it provides
113more information:
114
115 proc p {
116 if ! test -d /tmp {
117 error 'Missing /tmp' # more descriptive than return
118 }
119 echo hi
120 }
121
122Handle the error with the `try` builtin:
123
124 try {
125 p
126 }
127 if (_status !== 0) {
128 echo $[_error.message] # => Missing /tmp
129 }
130
131The integer `_status` is always set, and the Dict `_error` is set for all
132"structured" errors, which includes errors raised by the `try` builtin.
133
134Special properties of `_error`:
135
136- `_error.message` - the positional string arg
137- `_error.status` - the named `status` arg, or the default 10
138
139You can attach other, arbitrary properties to the error:
140
141 error 'Oops' (path='foo.json')
142
143They are attached to `_error`:
144
145 try {
146 error 'Oops' (path='foo.json')
147 }
148 if (_status !== 0) {
149 echo $[_error.path] # => foo.json
150 }
151
152## Shell State
153
154### ysh-cd
155
156It takes a block:
157
158 cd / {
159 echo $PWD
160 }
161
162### ysh-shopt
163
164It takes a block:
165
166 shopt --unset errexit {
167 false
168 echo 'ok'
169 }
170
171### shvar
172
173Execute a block with a global variable set.
174
175 shvar IFS=/ {
176 echo "ifs is $IFS"
177 }
178 echo "ifs restored to $IFS"
179
180### ctx
181
182Execute a block with a shared "context" that can be updated using the `ctx`
183built-in.
184
185 var mydict = {}
186 ctx push (mydict) {
187 # = mydict => {}
188 ctx set (mykey='myval')
189 }
190 # = mydict => { mykey: 'myval' }
191
192The context can be modified with `ctx set (key=val)`, which updates or inserts
193the value at the given key.
194
195The context can also be updated with `ctx emit field (value)`.
196
197 ctx push (mydict) {
198 # = mydict => {}
199 ctx emit mylist (0)
200 # = mydict => { mylist: [0] }
201 ctx emit mylist (1)
202 }
203 # = mydict => { mylist: [0, 1] }
204
205Contexts can be nested, resulting in a stack of contexts.
206
207 ctx push (mydict1) {
208 ctx set (dict=1)
209 ctx push (mydict2) {
210 ctx set (dict=2)
211 }
212 }
213 # = mydict1 => { dict: 1 }
214 # = mydict2 => { dict: 2 }
215
216`ctx` is useful for creating DSLs, such as a mini-parseArgs.
217
218 proc parser (; place ; ; block_def) {
219 var p = {}
220 ctx push (p, block_def)
221 call place->setValue(p)
222 }
223
224 proc flag (short_name, long_name; type; help) {
225 ctx emit flag ({short_name, long_name, type, help})
226 }
227
228 proc arg (name) {
229 ctx emit arg ({name})
230 }
231
232 parser (&spec) {
233 flag -t --tsv (Bool, help='Output as TSV')
234 flag -r --recursive (Bool, help='Recurse into the given directory')
235 flag -N --count (Int, help='Process no more than N files')
236 arg path
237 }
238
239### push-registers
240
241Save global registers like $? on a stack. It's useful for preventing plugins
242from interfering with user code. Example:
243
244 status_42 # returns 42 and sets $?
245 push-registers { # push a new frame
246 status_43 # top of stack changed here
247 echo done
248 } # stack popped
249 echo $? # 42, read from new top-of-stack
250
251Current list of registers:
252
253 Regex data underlying BASH_REMATCH, _group(), _start(), _end()
254 $?
255 _status # set by the try builtin
256 PIPESTATUS # aka _pipeline_status
257 _process_sub_status
258
259
260## Modules
261
262### runproc
263
264Runs a named proc with the given arguments. It's often useful as the only top
265level statement in a "task file":
266
267 proc p {
268 echo hi
269 }
270 runproc @ARGV
271
272Like 'builtin' and 'command', it affects the lookup of the first word.
273
274### module
275
276Registers a name in the global module dict. Returns 0 if it doesn't exist, or
2771 if it does.
278
279Use it like this in executable files:
280
281 module main || return 0
282
283And like this in libraries:
284
285 module myfile.ysh || return 0
286
287### is-main
288
289The `is-main` builtin returns 1 (false) if the current file was executed with
290the `source` builtin.
291
292In the "main" file, including `-c` or `stdin` input, it returns 0 (true).
293
294Use it like this:
295
296 if is-main {
297 runproc @ARGV
298 }
299
300### use
301
302TODO
303
304Reuse code from other files, respecting namespaces.
305
306 use lib/foo.ysh # relative import, i.ie implicit $_this_dir?
307 # makes name 'foo' available
308
309Bind a specific name:
310
311 use lib/foo.ysh (&myvar) # makes 'myvar' available
312
313Bind multiple names:
314
315 use lib/foo.ysh (&myvar) {
316 var log, die
317 }
318
319Maybe:
320
321 use lib/foo.ysh (&myvar) {
322 var mylog = myvar.log
323 }
324
325Also a declaration
326
327 use --extern grep sed
328
329## I/O
330
331### ysh-read
332
333YSH adds long flags to shell's `read`:
334
335 read --all # whole file including newline, fills $_reply
336 read --all (&x) # fills $x
337
338 read --num-bytes 3 # read N bytes, fills _reply
339 read --num-bytes 3 (&x) # fills $x
340
341And a convenience:
342
343 read -0 # read until NUL, synonym for read -r -d ''
344
345TODO: We used to have `read --line`, but buffered I/O doesn't mix with shell
346I/O, which is reads directly from file descriptors.
347
348<!--
349
350buffered, line-oriented I/O
351
352 read --line # fills $_reply var with line
353 read --line (&x) # fills $x (&x is a place)
354
355 read --line --with-eol # keep the \n
356
357You may want to use `fromJ8()` or `fromJson()` after reading a line.
358
359TODO: read --netstr
360-->
361
362<!--
363
364Problem with read --json -- there's also https://jsonlines.org, which allows
365
366 {"my": "line"}
367
368That can be done with
369
370 while read --line {
371 var record = fromJson(_reply)
372 }
373
374This is distinct from:
375
376 while read --line --j8 {
377 echo $_reply
378 }
379
380This allows unquoted. Maybe it should be read --j8-line
381
382What about write? These would be the same:
383
384 write --json -- $s
385 write --j8 -- $s
386
387 write -- $[toJson(s)]
388 write -- $[toJson8(s)]
389
390 write --json -- @strs
391 write --j8 -- @strs
392
393 write -- @[toJson(s) for s in strs]
394 write -- @[toJson8(s) for s in strs]
395
396It's an argument for getting rid --json and --j8? I already implemented them,
397but it makes the API smaller.
398
399I guess the main thing would be to AVOID quoting sometimes?
400
401 $ write --j8 -- unquoted
402 unquoted
403
404 $ write --j8 -- $'\'' '"'
405 "'"
406 "\""
407
408I think this could be the shell style?
409
410 $ write --shell-str -- foo bar baz
411
412Or it could be
413
414 $ write -- @[toShellString(s) for s in strs]
415
416I want this to be "J8 Lines", but it can be done in pure YSH. It's not built
417into the interpreter.
418
419 foo/bar
420 "hi"
421b'hi'
422u'hi'
423
424But what about
425
426 Fool's Gold
427a'hi' # This feels like an error?
428a"hi" # what about this?
429
430Technically we CAN read those as literal strings
431-->
432
433### write
434
435write fixes problems with shell's `echo` builtin.
436
437The default separator is a newline, and the default terminator is a
438newline.
439
440Examples:
441
442 write -- ale bean # write two lines
443
444 write -n -- ale bean # synonym for --end '', like echo -n
445 write --sep '' --end '' -- a b # write 2 bytes
446 write --sep $'\t' --end $'\n' -- a b # TSV line
447
448You may want to use `toJson8()` or `toJson()` before writing:
449
450 write -- $[toJson8(mystr)]
451 write -- $[toJson(mystr)]
452
453
454<!--
455 write --json -- ale bean # JSON encode, guarantees two lines
456 write --j8 -- ale bean # J8 encode, guarantees two lines
457-->
458
459
460### fork
461
462The preferred alternative to shell's `&`.
463
464 fork { sleep 1 }
465 wait -n
466
467### forkwait
468
469The preferred alternative to shell's `()`. Prefer `cd` with a block if possible.
470
471 forkwait {
472 not_mutated=zzz
473 }
474 echo $not_mutated
475
476
477
478## Data Formats
479
480### json
481
482Write JSON:
483
484 var d = {name: 'bob', age: 42}
485 json write (d) # default indentation of 2
486 json write (d, space=0) # no indentation
487
488Read JSON:
489
490 echo hi | json read # fills $_reply by default
491
492Or use an explicit place:
493
494 var x = ''
495 json read (&x) < myfile.txt
496
497Related: [json-encode-err]() and [json-decode-error]()
498
499### json8
500
501Like `json`, but on the encoding side:
502
503- Falls back to `b'\yff'` instead of lossy Unicode replacement char
504
505On decoding side:
506
507- Understands `b'' u''` strings
508
509Related: [json8-encode-err]() and [json8-decode-error]()
510
511## Testing
512
513TODO: describe
514
515## External Lang
516
517TODO: when
518
519
520## I/O
521
522These builtins take input and output. They're often used with redirects.
523
524### read
525
526 read FLAG* VAR*
527
528Read a line from stdin, split it into tokens with the `$IFS` algorithm,
529and assign the tokens to the given variables. When no VARs are given,
530assign to `$REPLY`.
531
532Note: When writing ySH, prefer the extensions documented in
533[ysh-read](#ysh-read). The `read` builtin is confusing because `-r` needs to
534be explicitly enabled.
535
536Flags:
537
538 -a ARRAY assign the tokens to elements of this array
539 -d CHAR use DELIM as delimiter, instead of newline
540 -n NUM read up to NUM characters, respecting delimiters
541 -p STR print the string PROMPT before reading input
542 -r raw mode: don't let backslashes escape characters
543 -s silent: do not echo input coming from a terminal
544 -t NUM time out and fail after TIME seconds
545 -t 0 returns whether any input is available
546 -u FD read from file descriptor FD instead of 0 (stdin)
547
548 <!-- -N NUM read up to NUM characters, ignoring delimiters -->
549 <!-- -e use readline to obtain the line
550 -i STR use STR as the initial text for readline -->
551
552### echo
553
554 echo FLAG* ARG*
555
556Prints ARGs to stdout, separated by a space, and terminated by a newline.
557
558Flags:
559
560 -e enable interpretation of backslash escapes
561 -n omit the trailing newline
562<!-- -E -->
563
564See [char-escapes]($osh-help).
565
566### printf
567
568 printf FLAG* FMT ARG*
569
570Formats values and prints them. The FMT string contain three types of objects:
571
5721. Literal Characters
5732. Character escapes like `\t`. See [char-escapes]($osh-help).
5743. Percent codes like `%s` that specify how to format each each ARG.
575
576If not enough ARGS are passed, the empty string is used. If too many are
577passed, the FMT string will be "recycled".
578
579Flags:
580
581 -v VAR Write output in variable VAR instead of standard output.
582
583Format specifiers:
584
585 %% Prints a single "%".
586 %b Interprets backslash escapes while printing.
587 %q Prints the argument escaping the characters needed to make it reusable
588 as shell input.
589 %d Print as signed decimal number.
590 %i Same as %d.
591 %o Print as unsigned octal number.
592 %u Print as unsigned decimal number.
593 %x Print as unsigned hexadecimal number with lower-case hex-digits (a-f).
594 %X Same as %x, but with upper-case hex-digits (A-F).
595 %f Print as floating point number.
596 %e Print as a double number, in "±e" format (lower-case e).
597 %E Same as %e, but with an upper-case E.
598 %g Interprets the argument as double, but prints it like %f or %e.
599 %G Same as %g, but print it like %E.
600 %c Print as a single char, only the first character is printed.
601 %s Print as string
602 %n The number of characters printed so far is stored in the variable named
603 in the argument.
604 %a Interprets the argument as double, and prints it like a C99 hexadecimal
605 floating-point literal.
606 %A Same as %a, but print it like %E.
607 %(FORMAT)T Prints date and time, according to FORMAT as a format string
608 for strftime(3). The argument is the number of seconds since
609 epoch. It can also be -1 (current time, also the default value
610 if there is no argument) or -2 (shell startup time).
611
612### readarray
613
614Alias for `mapfile`.
615
616### mapfile
617
618 mapfile FLAG* ARRAY?
619
620Reads lines from stdin into the variable named ARRAY (default
621`${MAPFILE[@]}`).
622
623Flags:
624
625 -t Remove the trailing newline from every line
626<!--
627 -d CHAR use CHAR as delimiter, instead of the default newline
628 -n NUM copy up to NUM lines
629 -O NUM begins copying lines at the NUM element of the array
630 -s NUM discard the first NUM lines
631 -u FD read from FD file descriptor instead of the standard input
632 -C CMD run CMD every NUM lines specified in -c
633 -c NUM every NUM lines, the CMD command in C will be run
634-->
635
636## Run Code
637
638These builtins accept shell code and run it.
639
640### source
641
642 source SCRIPT ARG*
643
644Executes SCRIPT with given ARGs in the context of the current shell. It will
645modify existing variables.
646
647### eval
648
649 eval ARG+
650
651Creates a string by joining ARGs with a space, then runs it as a shell command.
652
653Example:
654
655 # Create the string echo "hello $name" and run it.
656 a='echo'
657 b='"hello $name"'
658 eval $a $b
659
660Tips:
661
662- Using `eval` can confuse code and user-supplied data, leading to [security
663issues][].
664- Prefer passing single string ARG to `eval`.
665
666[security issues]: https://mywiki.wooledge.org/BashFAQ/048
667
668YSH eval:
669
670 var myblock = ^(echo hi)
671 eval (myblock) # => hi
672
673
674### trap
675
676 trap FLAG* CMD SIGNAL*
677
678Registers the shell string CMD to be run after the SIGNALs are received. If
679the CMD is empty, then the signal is ignored.
680
681Flags:
682
683 -l Lists all signals and their signal number
684 -p Prints a list of the installed signal handlers
685
686Tip:
687
688Prefer passing the name of a shell function to `trap`.
689
690## Set Options
691
692The `set` and `shopt` builtins set global shell options. YSH code should use
693the more natural `shopt`.
694
695### set
696
697 set FLAG* ARG*
698
699Sets global shell options. Short style:
700
701 set -e
702
703Long style:
704
705 set -o errexit
706
707Set the arguments array:
708
709 set -- 1 2 3
710
711### shopt
712
713 shopt FLAG* OPTION* BLOCK?
714
715Sets global shell options.
716
717Flags:
718
719 -s --set Turn the named options on
720 -u --unset Turn the named options off
721 -p Print option values
722 -q Return 0 if the option is true, else 1
723
724Examples:
725
726 shopt --set errexit
727
728You can set or unset multiple options with the groups `strict:all`,
729`ysh:upgrade`, and `ysh:all`.
730
731If a block is passed, then the mutated options are pushed onto a stack, the
732block is executed, and then options are restored to their original state.
733
734## Working Dir
735
736These 5 builtins deal with the working directory of the shell.
737
738### cd
739
740 cd FLAG* DIR
741
742Changes the working directory of the current shell process to DIR.
743
744If DIR isn't specified, change to `$HOME`. If DIR is `-`, change to `$OLDPWD`
745(a variable that the sets to the previous working directory.)
746
747Flags:
748
749 -L Follow symbolic links, i.e. change to the TARGET of the symlink.
750 (default).
751 -P Don't follow symbolic links.
752
753### pwd
754
755 pwd FLAG*
756
757Prints the current working directory.
758
759Flags:
760
761 -L Follow symbolic links if present (default)
762 -P Don't follow symbolic links. Print the link instead of the target.
763
764### pushd
765
766<!--pushd FLAGS DIR-->
767 pushd DIR
768<!--pushd +/-NUM-->
769
770Add DIR to the directory stack, then change the working directory to DIR.
771Typically used with `popd` and `dirs`.
772
773<!--FLAGS:
774 -n Don't change the working directory, just manipulate the stack
775NUM:
776 Rotates the stack the number of places specified. Eg, given the stack
777 '/foo /bar /baz', where '/foo' is the top of the stack, pushd +1 will move
778 it to the bottom, '/bar /baz /foo'-->
779
780### popd
781
782 popd
783
784Removes a directory from the directory stack, and changes the working directory
785to it. Typically used with `pushd` and `dirs`.
786
787### dirs
788
789 dirs FLAG*
790
791Shows the contents of the directory stack. Typically used with `pushd` and
792`popd`.
793
794Flags:
795
796 -c Clear the dir stack.
797 -l Show the dir stack, but with the real path instead of ~.
798 -p Show the dir stack, but formatted as one line per entry.
799 -v Like -p, but numbering each line.
800
801## Completion
802
803These builtins implement our bash-compatible autocompletion system.
804
805### complete
806
807Registers completion policies for different commands.
808
809### compgen
810
811Generates completion candidates inside a user-defined completion function.
812
813It can also be used in scripts, i.e. outside a completion function.
814
815### compopt
816
817Changes completion options inside a user-defined completion function.
818
819### compadjust
820
821Adjusts `COMP_ARGV` according to specified delimiters, and optionally set
822variables cur, prev, words (an array), and cword. May also set 'split'.
823
824This is an OSH extension that makes it easier to run the bash-completion
825project.
826
827### compexport
828
829Complete an entire shell command string. For example,
830
831 compexport -c 'echo $H'
832
833will complete variables like `$HOME`. And
834
835 compexport -c 'ha'
836
837will complete builtins like `hay`, as well as external commands.
838
839
840## Shell Process
841
842These builtins mutate the state of the shell process.
843
844### exec
845
846 exec BIN_PATH ARG*
847
848Replaces the running shell with the binary specified, which is passed ARGs.
849BIN_PATH must exist on the file system; i.e. it can't be a shell builtin or
850function.
851
852### umask
853
854 umask MODE?
855
856Sets the bit mask that determines the permissions for new files and
857directories. The mask is subtracted from 666 for files and 777 for
858directories.
859
860Oils currently supports writing masks in octal.
861
862If no MODE, show the current mask.
863
864### times
865
866 times
867
868Shows the user and system time used by the shell and its child processes.
869
870## Child Process
871
872### jobs
873
874 jobs
875
876Shows all jobs running in the shell and their status.
877
878### wait
879
880 wait FLAG* ARG
881
882Wait for processes to exit.
883
884If the ARG is a PID, wait only for that job, and return its status.
885
886If there's no ARG, wait for all child processes.
887
888<!--
889The ARG can be a PID (tracked by the kernel), or a job number (tracked by the
890shell). Specify jobs with the syntax `%jobnumber`.
891-->
892
893Flags:
894
895 -n Wait for the next process to exit, rather than a specific process.
896
897Wait can be interrupted by a signal, in which case the exit code indicates the
898signal number.
899
900### fg
901
902 fg JOB?
903
904Returns a job running in the background to the foreground. If no JOB is
905specified, use the latest job.
906
907<!--<h4 id="bg">bg</h4>
908
909The bg builtin resumes suspend job, while keeping it in the background.
910
911bg JOB?
912
913JOB:
914 Job ID to be resumed in the background. If none is specified, the latest job
915 is chosen. -->
916
917## External
918
919### test
920
921 test OP ARG
922 test ARG OP ARG
923 [ OP ARG ] # [ is an alias for test that requires closing ]
924 [ ARG OP ARG ]
925
926Evaluates a conditional expression and returns 0 (true) or 1 (false).
927
928Note that [ is the name of a builtin, not an operator in the language. Use
929'test' to avoid this confusion.
930
931String expressions:
932
933 -n STR True if STR is not empty.
934 'test STR' is usually equivalent, but discouraged.
935 -z STR True if STR is empty.
936 STR1 = STR2 True if the strings are equal.
937 STR1 != STR2 True if the strings are not equal.
938 STR1 < STR2 True if STR1 sorts before STR2 lexicographically.
939 STR1 > STR2 True if STR1 sorts after STR2 lexicographically.
940 Note: < and > should be quoted like \< and \>
941
942File expressions:
943
944 -a FILE Synonym for -e.
945 -b FILE True if FILE is a block special file.
946 -c FILE True if FILE is a character special file.
947 -d FILE True if FILE is a directory.
948 -e FILE True if FILE exists.
949 -f FILE True if FILE is a regular file.
950 -g FILE True if FILE has the sgid bit set.
951 -G FILE True if current user's group is also FILE's group.
952 -h FILE True if FILE is a symbolic link.
953 -L FILE True if FILE is a symbolic link.
954 -k FILE True if FILE has the sticky bit set.
955 -O FILE True if current user is the file owner.
956 -p FILE True if FILE is a named pipe (FIFO).
957 -r FILE True if FILE is readable.
958 -s FILE True if FILE has size bigger than 0.
959 -S FILE True if FILE is a socket file.
960 -t FD True if file descriptor FD is open and refers to a terminal.
961 -u FILE True if FILE has suid bit set.
962 -w FILE True if FILE is writable.
963 -x FILE True if FILE is executable.
964 FILE1 -nt FILE2 True if FILE1 is newer than FILE2 (mtime).
965 FILE1 -ot FILE2 True if FILE1 is older than FILE2 (mtime).
966 FILE1 -ef FILE2 True if FILE1 is a hard link to FILE2.
967<!-- -N FILE True if FILE was modified since last read (mtime newer than atime).-->
968
969Arithmetic expressions coerce arguments to integers, then compare:
970
971 INT1 -eq INT2 True if they're equal.
972 INT1 -ne INT2 True if they're not equal.
973 INT1 -lt INT2 True if INT1 is less than INT2.
974 INT1 -le INT2 True if INT1 is less or equal than INT2.
975 INT1 -gt INT2 True if INT1 is greater than INT2.
976 INT1 -ge INT2 True if INT1 is greater or equal than INT2.
977
978Other expressions:
979
980 -o OPTION True if the shell option OPTION is set.
981 -v VAR True if the variable VAR is set.
982
983The test builtin also supports POSIX conditionals like -a, -o, !, and ( ), but
984these are discouraged.
985
986<!-- -R VAR True if the variable VAR has been set and is a nameref variable. -->
987
988Oils supports these long flags:
989
990 --dir same as -d
991 --exists same as -e
992 --file same as -f
993 --symlink same as -L
994
995### getopts
996
997 getopts SPEC VAR ARG*
998
999A single iteration of flag parsing. The SPEC is a sequence of flag characters,
1000with a trailing `:` to indicate that the flag takes an argument:
1001
1002 ab # accept -a and -b
1003 xy:z # accept -x, -y arg, and -z
1004
1005The input is `"$@"` by default, unless ARGs are passed.
1006
1007On each iteration, the flag character is stored in VAR. If the flag has an
1008argument, it's stored in `$OPTARG`. When an error occurs, VAR is set to `?`
1009and `$OPTARG` is unset.
1010
1011Returns 0 if a flag is parsed, or 1 on end of input or another error.
1012
1013Example:
1014
1015 while getopts "ab:" flag; do
1016 case $flag in
1017 a) flag_a=1 ;;
1018 b) flag_b=$OPTARG" ;;
1019 '?') echo 'Invalid Syntax'; break ;;
1020 esac
1021 done
1022
1023Notes:
1024- `$OPTIND` is initialized to 1 every time a shell starts, and is used to
1025 maintain state between invocations of `getopts`.
1026- The characters `:` and `?` can't be flags.
1027
1028### kill
1029
1030Unimplemented.
1031
1032<!-- Note: 'kill' accepts job control syntax -->
1033
1034## Introspection
1035
1036<h3 id="help" class="osh-topic ysh-topic" oils-embed="1">
1037 help
1038</h3>
1039
1040<!-- pre-formatted for help builtin -->
1041
1042```
1043Usage: help TOPIC?
1044
1045Examples:
1046
1047 help # this help
1048 help echo # help on the 'echo' builtin
1049 help command-sub # help on command sub $(date)
1050
1051 help oils-usage # identical to oils-for-unix --help
1052 help osh-usage # osh --help
1053 help ysh-usage # ysh --help
1054```
1055
1056### hash
1057
1058 hash
1059
1060Display information about remembered commands.
1061
1062 hash FLAG* CMD+
1063
1064Determine the locations of commands using `$PATH`, and remember them.
1065
1066Flag:
1067
1068 -r Discard all remembered locations.
1069<!-- -d Discard the remembered location of each NAME.
1070 -l Display output in a format reusable as input.
1071 -p PATH Inhibit path search, PATH is used as location for NAME.
1072 -t Print the full path of one or more NAME.-->
1073
1074### type
1075
1076 type FLAG* NAME+
1077
1078Print the type of each NAME, if it were the first word of a command. Is it a
1079shell keyword, builtin command, shell function, alias, or executable file on
1080$PATH?
1081
1082Flags:
1083
1084 -a Show all possible candidates, not just the first one
1085 -f Don't search for shell functions
1086 -P Only search for executable files
1087 -t Print a single word: alias, builtin, file, function, or keyword
1088
1089<!-- TODO:
1090- procs are counted as shell functions, should be their own thing
1091- Hay nodes ('hay define x') also live in the first word namespace, and should
1092 be recognized
1093-->
1094
1095Modeled after the [bash `type`
1096builtin](https://www.gnu.org/software/bash/manual/bash.html#index-type).
1097
1098## Word Lookup
1099
1100### command
1101
1102 command FLAG* CMD ARG*
1103
1104Look up CMD as a shell builtin or executable file, and execute it with the
1105given ARGs. That is, the lookup ignores shell functions named CMD.
1106
1107Flags:
1108
1109 -v Instead of executing CMD, print a description of it.
1110 Similar to the 'type' builtin.
1111<!-- -p Use a default value for PATH that is guaranteed to find all of the
1112 standard utilities.
1113 -V Print a more verbose description of CMD.-->
1114
1115### builtin
1116
1117 builtin CMD ARG*
1118
1119Look up CMD as a shell builtin, and execute it with the given ARGs. That is,
1120the lookup ignores shell functions and executables named CMD.
1121
1122## Interactive
1123
1124### alias
1125
1126 alias NAME=CODE
1127
1128Make NAME a shortcut for executing CODE, e.g. `alias hi='echo hello'`.
1129
1130 alias NAME
1131
1132Show the value of this alias.
1133
1134 alias
1135
1136Show a list of all aliases.
1137
1138Tips:
1139
1140Prefer shell functions like:
1141
1142 ls() {
1143 command ls --color "$@"
1144 }
1145
1146to aliases like:
1147
1148 alias ls='ls --color'
1149
1150Functions are less likely to cause parsing problems.
1151
1152- Quoting like `\ls` or `'ls'` disables alias expansion
1153- To remove an existing alias, use [unalias]($osh-help).
1154
1155### unalias
1156
1157 unalias NAME
1158
1159Remove the alias NAME.
1160
1161<!--Flag:
1162
1163 -a Removes all existing aliases.-->
1164
1165### history
1166
1167 history FLAG*
1168
1169Display and manipulate the shell's history entries.
1170
1171 history NUM
1172
1173Show the last NUM history entries.
1174
1175Flags:
1176
1177 -c Clears the history.
1178 -d POS Deletes the history entry at position POS.
1179<!-- -a
1180 -n
1181 -r
1182 -w
1183 -p
1184 -s -->
1185
1186
1187## Unsupported
1188
1189### enable
1190
1191Bash has this, but OSH won't implement it.
1192
1193
1194## Args Parser
1195
1196YSH includes a command-line argument parsing utility called `parseArgs`. This
1197is intended to be used for command-line interfaces to YSH programs.
1198
1199To use it, first import `args.ysh`:
1200
1201 source --builtin args.ysh
1202
1203Then, create an argument parser **spec**ification:
1204
1205 parser (&spec) {
1206 flag -v --verbose (help="Verbosely") # default is Bool, false
1207
1208 flag -P --max-procs ('int', default=-1, help='''
1209 Run at most P processes at a time
1210 ''')
1211
1212 flag -i --invert ('bool', default=true, help='''
1213 Long multiline
1214 Description
1215 ''')
1216
1217 arg src (help='Source')
1218 arg dest (help='Dest')
1219
1220 rest files
1221 }
1222
1223Finally, parse `ARGV` (or any other array of strings) with:
1224
1225 var args = parseArgs(spec, ARGV)
1226
1227The returned `args` is a `Dict` containing key-value pairs with the parsed
1228values (or defaults) for each flag and argument. For example, given
1229`ARGV = :| mysrc -P 12 mydest a b c |`, `args` would be:
1230
1231 {
1232 "verbose": false,
1233 "max-procs": 12,
1234 "invert": true,
1235 "src": "mysrc",
1236 "dest": "mydest",
1237 "files": ["a", "b", "c"]
1238 }
1239
1240### parser
1241
1242`parseArgs()` requires a parser specification to indicate how to parse the
1243`ARGV` array. This specification should be constructed using the `parser` proc.
1244
1245 parser (&spec) {
1246 flag -f --my-flag
1247 arg myarg
1248 rest otherArgs
1249 }
1250
1251In the above example, `parser` takes in a place `&spec`, which will store the
1252resulting specification and a block which is evaluated to build that
1253specification.
1254
1255Inside of a `parser` block, you should call the following procs:
1256
1257- `flag` to add `--flag` options
1258- `arg` to add positional arguments
1259- `rest` to capture remaining positional arguments into a list
1260
1261`parser` will validate the parser specification for errors such as duplicate
1262flag or argument names.
1263
1264 parser (&spec) {
1265 flag -n --name
1266 flag -n --name # Duplicate!
1267 }
1268
1269 # => raises "Duplicate flag/arg name 'name' in spec" (status = 3)
1270
1271### flag
1272
1273`flag` should be called within a `parser` block.
1274
1275 parser (&spec) {
1276 flag -v --verbose
1277 }
1278
1279The above example declares a flag "--verbose" and a short alias "-v".
1280`parseArgs()` will then store a boolean value under `args.verbose`:
1281- `true` if the flag was passed at least once
1282- `false` otherwise
1283
1284Flags can also accept values. For example, if you wanted to accept an integer count:
1285
1286 parser (&spec) {
1287 flag -N --count ('int')
1288 }
1289
1290Calling `parseArgs` with `ARGV = :| -n 5 |` or `ARGV = :| --count 5 |` will
1291store the integer `5` under `args.count`. If the user passes in a non-integer
1292value like `ARGV = :| --count abc |`, `parseArgs` will raise an error.
1293
1294Default values for an argument can be set with the `default` named argument.
1295
1296 parser (&spec) {
1297 flag -N --count ('int', default=2)
1298
1299 # Boolean flags can be given default values too
1300 flag -O --optimize ('bool', default=true)
1301 }
1302
1303 var args = parseArgs(spec, :| -n 3 |)
1304 # => args.count = 2
1305 # => args.optimize = true
1306
1307Each name passed to `flag` must be unique to that specific `parser`. Calling
1308`flag` with the same name twice will raise an error inside of `parser`.
1309
1310<!-- TODO: how can we explicitly pass false to a boolean flag? -->
1311<!-- TODO: how about --no-XXXX variants of flags? -->
1312
1313### arg
1314
1315`arg` should be called within a `parser` block.
1316
1317 parser (&spec) {
1318 arg query
1319 arg path
1320 }
1321
1322The above example declares two positional arguments called "query" and "path".
1323`parseArgs()` will then store strings under `args.query` and `args.path`. Order
1324matters, so the first positional argument will be stored to `query` and the
1325second to `path`. If not enough positional arguments are passed, then
1326`parseArgs` will raise an error.
1327
1328Similar to `flag`, each `arg` name must be unique. Calling `arg` with the same
1329name twice will cause `parser` to raise an error.
1330
1331### rest
1332
1333`rest` should be called within a `parser` block.
1334
1335 parser (&spec) {
1336 arg query
1337 rest files
1338 }
1339
1340Capture zero or more positional arguments not already captured by `arg`. So,
1341for `ARGV = :| hello file.txt message.txt README.md |`, we would have
1342`args.query = "file.txt"` and `args.files = ["file.txt", "message.txt",
1343"README.md"]`.
1344
1345Without rest, passing extraneous arguments will raise an error in
1346`parseArgs()`.
1347
1348`rest` can only be called _once_ within a `parser`. Calling it multiple times
1349will raise an error in `parser`.
1350
1351### parseArgs()
1352
1353Given a parser specification `spec` produced by `parser`, parse a list of
1354strings (usually `ARGV`.)
1355
1356 var args = parseArgs(spec, ARGV)
1357
1358The returned `args` is a dictionary mapping the names of each `arg`, `flag` and
1359`rest` to their captured values. (See the example at the [start of this
1360topic](#Args-Parser).)
1361
1362`parseArgs` will raise an error if the `ARGV` is invalid per the parser
1363specification. For example, if it's missing a required positional argument:
1364
1365 parser (&spec) {
1366 arg path
1367 }
1368
1369 var args = parseArgs(spec, [])
1370 # => raises an error about the missing 'path' (status = 2)
1371
1372<!--
1373TODO: Document chaining parsers / sub-commands
1374 - Either will allow parser nesting
1375 - Or can use `rest rest` and `parseArgs` again on `rest`
1376TODO: Document the help named argument. Punting while we do not generate help messages
1377-->