source | all docs for version 0.8.7 | all versions | oilshell.org
Warning: Work in progress! Leave feedback on Zulip or Github if you'd like this doc to be updated.
This doc describes every aspect of Oil briefly. It underlies the help
builtin, and is indexed by keywords.
Navigate it with the index of Oil help topics.
This section describes how to use the Oil binary.
bin/oil
UsageUsage: oil [OPTION]... SCRIPT [ARG]...
oil [OPTION]... -c COMMAND [ARG]...
bin/oil
is the same as bin/osh
with a the oil:all
option group set. So
bin/oil
also accepts shell flags.
oil -c 'echo hi'
oil myscript.oil
echo 'echo hi' | oil
Usage: oil.ovm MAIN_NAME [ARG]...
MAIN_NAME [ARG]...
oil.ovm behaves like busybox. If it's invoked through a symlink, e.g. 'osh', then it behaves like that binary. Otherwise, the binary name can be passed as the first argument, e.g.:
oil.ovm osh -c 'echo hi'
The %%% prefix Starts a Single Command Over Multiple Lines (?)
This special lexer mode has several use cases:
Long command lines without trailing \
%%% chromium-browser
--no-proxy-server
# comments allowed
--incognito
Long pipelines or and-or chains without trailing \
%%% find .
# exclude tests
| grep -v '_test.py'
| xargs wc -l
| sort -n
%%% ls /
&& ls /bin
&& ls /lib
|| error "oops"
TODO
Procs are shell-like functions, but with named parameters, and without dynamic scope (TODO):
proc copy(src, dest) {
cp --verbose --verbose $src $dest
}
Compare with sh-func.
The =
keyword evaluates an expression and shows the result:
oil$ = 1 + 2*3
(Int) 7
It's meant to be used interactively. Think of it as an assignment with no variable on the left.
The _
keyword evaluates an expression and throws away the result:
var x = %(one two)
_ push(x, 'three')
Think of it as a shortcut for _ = expr
(throwaway assignment).
Blocks can be passed to builtins (and procs eventually):
cd /tmp {
echo $PWD # prints /tmp
}
echo $PWD
Compare with sh-block.
Initializes a constant name to the Oil expression on the right.
const c = 'mystr' # equivalent to readonly c=mystr
const pat = / digit+ / # an eggex, with no shell equivalent
It's either a global constant or scoped to the current function.
Initializes a name to the Oil expression on the right.
var s = 'mystr' # equivalent to declare s=mystr
var pat = / digit+ / # an eggex, with no shell equivalent
It's either global or scoped to the current function.
Like shell's x=1
, setvar x = 1
either:
var
)It's meant for interactive use and to easily convert existing shell scripts.
New Oil programs should use set
, setglobal
, or setref
instead of
setvar
.
Mutates a global variable. If it doesn't exist, the shell exits with a fatal error.
Mutates a variable through a named reference. TODO: Show an example.
Mutates an existing variable in the current scope. If it doesn't exist, the shell exits with a fatal error.
set
is an alias for setlocal
in the Oil language. Requires shopt -s parse_set
, because otherwise, it would conflict with the set
builtin. Use
builtin set -- 1 2 3
to get the builtin, or shopt -o
to change options.
var myint = 42
var myfloat = 3.14
var float2 = 1e100
Oil strings appear in expression contexts, and look like shell strings:
var s = 'foo'
var double = "hello $world and $(hostname)"
However, strings with backslashes are forced to specify whether they're raw strings or C-style strings:
var s = 'line\n' # parse error: ambiguous
var s = c'line\n' # C-style string
var s = $'line\n' # also accepted for compatibility
var s = r'[a-z]\n' # raw strings are useful for regexes (not eggexes)
var unicode = 'mu = \u{3bc}'
#'a' #'_' \n \\ \u{3bc}
Capital letters like Python, which avoids confusion with the builtin
commands true
and false
:
True False
And the value that's unequal to any other:
None null # JSON style also accepted
It's preferable to use the empty string in many cases. The None
value can't
be interpolated into words.
Lists have a Python-like syntax:
var mylist = ['one', 'two', 3]
And a shell-like syntax:
var list2 = %(one two)
The shell-like syntax accepts the same syntax that a command can:
ls $mystr @ARGV *.py {foo,bar}@example.com
# Rather than executing ls, evaluate and store words
var cmd = %(ls $mystr @ARGV *.py {foo,bar}@example.com)
{name: 'value'}
var s = 's'
var concat1 = s ++ '_suffix'
var concat2 = "${s}_suffix" # similar
var c = %(one two)
var concat3 = c ++ %(three 4)
var concat4 = %( @c three 4 )
var mydict = {a: 1, b: 2}
var otherdict = {a: 10, c: 20}
var concat5 = mydict ++ otherdict
a == b # Python-like equality, no type conversion
3 ~== 3.0 # True, type conversion
3 ~== '3' # True, type conversion
3 ~== '3.0' # True, type conversion
not and or
+ - * / // % **
~ & | ^
Like Python:
display = 'yes' if len(s) else 'empty'
Like Python:
myarray[3]
mystr[3]
TODO: Does string indexing give you an integer back?
Like Python:
myarray[1 : -1]
mystr[1 : -1]
Like Python:
f(x, y)
var myblock = &(echo $PWD)
Not implemented.
Not implemented.
~~ !~~
It takes a block:
cd / {
echo $PWD
}
It takes a block:
shopt --unset errexit {
false
echo 'ok'
}
The preferred alternative to shell's &
.
fork { sleep 1 }
wait -n
The preferred alternative to shell's ()
. Prefer cd
with a block if possible.
forkwait {
not_mutated=zzz
}
echo $not_mutated
Pretty prints interpreter state. Some of these are implementation details, subject to change.
Examples:
pp proc # print all procs and their doc comments
var x = %(one two)
pp .cell x # print a cell, which is a location for a value
The .cell
action starts with .
to indicate that its format is unstable.
write -- @strs
read --line # default var is $_line
read --line --with-eol # keep the \n
read --line --qsn # decode QSN too
read --all # whole file including newline; var is $_all
read -0 # read until NUL, synonym for read -r -d ''
When --qsn is passed, the line is check for an opening single quote. If so, it's decoded as QSN. The line must have a closing single quote, and there can't be any non-whitespace characters after it.
Re-enable errexit, and provide fine-grained control over exit codes.
if run --allow-status-01 -- grep pat file.txt {
}
run --assign-status :st -- mycmd
echo $st
run --status-ok SIGPIPE yes | head
Option in this group disallow problematic or confusing shell constructs. The resulting script will still run in another shell.
shopt --set strict:all # turn on all options
shopt -p strict:all # print their current state
Options in this group enable Oil features that are less likely to break existing shell scripts.
For example, parse_at
means that @myarray
is now the operation to splice
an array. This will break scripts that expect @
to be literal, but you can
simply quote it like '@literal'
to fix the problem.
shopt --set oil:basic # turn on all options
shopt -p oil:basic # print their current state
Enable the full Oil language. This includes everything in the oil:basic
group.
shopt --set oil:all # turn on all options
shopt -p oil:all # print their current state
Failed tilde expansions cause hard errors (like zsh) rather than silently
evaluating to ~
or ~bad
.
TODO
When strict_nameref
is set, undefined references produce fatal errors:
declare -n ref
echo $ref # fatal error, not empty string
ref=x # fatal error instead of decaying to non-reference
References that don't contain variables also produce hard errors:
declare -n ref='not a var'
echo $ref # fatal
ref=x # fatal
For compatibility, Oil will parse some constructs it doesn't execute, like:
return 0 2>&1 # redirect on control flow
When this option is disabled, that statement is a syntax error.
TODO:
Replacement for "$@"
TODO: Do we need this in expression mode?
if ($? == 0) {
}
if (STATUS == 0) {
}
TODO: The match
The version of Oil that is being run, e.g. 0.9.0
.
TODO: comparison algorithm.
len(mystr)
is its length in byteslen(myarray)
is the number of elementslen(assocarray)
is the number of pairscopy()
:
var d = {name: value}
var alias = d # illegal, because it can create ownership problems
# reference cycles
var new = copy(d) # valid
_match() _start() _end()
These functions give better syntax to existing shell constructs.
shquote()
for printf %q
and ${x@Q}
lstrip()
for ${x#prefix}
and ${x##prefix}
rstrip()
for ${x%suffix}
and ${x%%suffix}
lstripglob()
and rstripglob()
for slow, legacy globupper()
for ${x^^}
lower()
for ${x,,}
strftime()
: hidden in printf
index(A, item)
is like the awk function@names()
values()
. Problem: these aren't all strings?Useful for logging callbacks. NOTE: bash has this with the obscure printf '%(...)' syntax.
TODO