Why Sponsor Oils? | source | all docs for version 0.19.0 | all versions | oilshell.org
Warning: Work in progress! Leave feedback on Zulip or Github if you'd like this doc to be updated.
Recall that Oil is composed of three interleaved languages: words, commands, and expressions.
This doc describes words, but only the things that are not in:
#word-lang
section of OSH Help
Topics#word-lang
section of Oil Help
TopicsA word is an expression like $x
, "hello $name"
, or {build,test}/*.py
. It
evaluates to a string or an array of strings.
Generally speaking, Oil behaves like a simpler version of POSIX shell / bash. Sophisticated users can read Simple Word Evaluation for a comparison.
Part of an expression:
var x = ${y:-'default'}
Part of a command:
echo ${y:-'default'}
The three contexts where splitting and globbing apply are the ones where a
sequence of words is evaluated (EvalWordSequence
):
echo $x foo
for i in $x foo; do ...
a=($x foo)
and var a = :| $x foo |
(oil-array)Oil has a new array syntax, but it also supports the bash-compatible syntax:
local myarray=(one two *.py) # bash
var myarray = :| one two *.py | # Oil style
Shell also has contexts where it evaluates words to a single string, rather than a sequence, like:
# RHS of Assignment
x="${not_array[@]}"
x=*.py # not a glob
# Redirect Arg
echo foo > "${not_array[@]}"
echo foo > *.py # not a glob
# Case variables and patterns
case "${not_array1[@]}" in
"${not_array2[@]}")
echo oops
;;
esac
case *.sh in # not a glob
*.py) # a string pattern, not a file system glob
echo oops
;;
esac
The behavior of these snippets diverges a lot in existing shells. That is, shells are buggy and poorly-specified.
Oil disallows most of them. Arrays are considered separate from strings and don't randomly "decay".
Related: the RHS of an Oil assignment is an expression, which can be of any type, including an array:
var parts = split(x) # returns an array
var python = glob('*.py') # ditto
var s = join(parts) # returns a string
This is a recap of A Feel for Oil's Syntax.
$
Means "Returns One String"Examples:
All substitutions: var, command, arith
$[a[x+1]]
as an expression substitution?$[ /pat+ /]
?Inline function calls, a YSH extension: $[join(myarray)]
(C-style strings like $'\n'
use $
, but that's more of a bash anachronism.
In Oil, c'\n'
is preferred.
@
Means "Returns An Array of Strings"Enabled with shopt -s parse_at
.
Examples:
@myarray
@[arrayfunc(x, y)]
These are both Oil extensions.
The array literal syntax also uses a @
:
var myarray = :| 1 2 3 |
Uses POSIX behavior for unquoted substitutions like $x
.
$IFS
.Shell has odd "joining" semantics, which are supported in Oil but generally discouraged:
set -- 'a b' 'c d'
argv.py X"$@"X # => ['Xa', 'b', 'c', 'dX']
In Oil, the RHS of an assignment is an expression, and joining only occurs within double quotes:
# Oil
var joined = $x$y # parse error
var joined = "$x$y" # OK
# Shell
joined=$x$y # OK
joined="$x$y" # OK
Extended globs in OSH are a "legacy syntax" modelled after the behavior of
bash
and mksh
. This features adds alternation, repetition, and negation to
globs, giving the power of regexes.
You can use them to match strings:
$ [[ foo.cc == *.(cc|h) ]] && echo 'matches' # => matches
Or produce lists of filename arguments:
$ touch foo.cc foo.h
$ echo *.@(cc|h) # => foo.cc foo.h
There are some limitations and differences:
FNM_EXTMATCH
extension to fnmatch()
. Unlike bash and
mksh, Oil doesn't implement its own extended glob matcher.mksh
. When an extended glob appears in a
word, we evaluate the word, match filenames, and skip the rest of the
word evaluation pipeline. This means:
$unquoted/@(*.cc|h)
."$@"
and extended globs in the same word, e.g.
"$@"_*.@(cc|h)
. This is usually nonsensical anyway.echo foo > @(cc|h)
is a runtime error in OSH, but other
shells will write a file literally named @(cc|h)
.${undef:-@(cc)}
. But it does accept ${x%@(cc)}
,
since string strip operators like %
accept a glob.shopt -s extglob
.
bash
can't parse some extended globs unless extglob
is on. But
it parses others when it's off.PATTERN
in ${x//PATTERN/replace}
.
This is because we only translate normal (non-extended) globs to regexes (in
order to get the position information necessary for string replacement).shopt --set simple_word_eval
(Oil word
evaluation).