Why Sponsor Oils? | source | all docs for version 0.26.0 | all versions | oils.pub
Oils Reference — Chapter Word Language
This chapter describes the word language for OSH and YSH. Words evaluate to strings, or arrays of strings.
(in progress)
Try to turn an expression into a string. Examples:
$ echo $[3 * 2]
6
$ var s = 'foo'
$ echo $[s[1:]]
oo
Some types can't be stringified, like Dict and List:
$ var d = {k: 42}
$ echo $[d]
fatal: expected Null, Bool, Int, Float, Eggex
You can explicitly use toJson8
or toJson()
:
$ echo $[toJson8(d)]
{"k":42}
(This is similar to json write (d)
)
Splicing puts the elements of a List
into a string array context:
$ var foods = ['ale', 'bean', 'corn']
$ echo pizza @[foods[1:]] worm
pizza bean corn worm
This syntax is enabled by shopt --set
parse_at, which is part of YSH.
$ var foods = ['ale', 'bean', 'corn']
echo @foods
This syntax is enabled by shopt --set
parse_at, which is part of YSH.
Not done.
echo ${x %.3f}
Not done.
echo ${x|html}
$'\n'
TODO: elaborate
YSH strings in the word language are the same as in the expression language.
See ysh-string in chap-expr-lang.
Triple-quoted in the word language are the same as in the expression language.
See triple-quoted in chap-expr-lang.
Not done.
Executes a command and captures its stdout.
OSH has shell-compatible command sub like $(echo hi)
. If a trailing newline
is returned, it's removed:
$ hostname
example.com
$ echo "/tmp/$(hostname)"
/tmp/example.com
YSH has spliced command subs, enabled by shopt --set parse_at
. The result is
a List of strings, rather than a single string.
$ write -- @(echo foo; echo 'with spaces')
foo
with-spaces
The command's stdout parsed as the "J8 Lines" format, where each line is either:
""
or J8-style b'' u'' ''
)See J8 Notation for more details.
Evaluates to the value of a variable:
$ x=X
$ echo $x ${x}
X X
Shell has C-style arithmetic:
$ echo $(( 1 + 2*3 ))
7
Used as a shortcut for a user's home directory:
~/src # my home dir
~bob/src # user bob's home dir
Open stdout as a named file in /dev/fd
, which can be passed to a command:
diff <(sort L.txt) <(sort R.txt)
Open stdin as a named file in /dev/fd
:
seq 3 | tee >(sleep 1; tac)
There are three types of braced variable expansions:
${!name*} or ${!name@}
${!name[@]} or ${!name[*]}
${ops var ops}
name
needs to be a valid identifier. If the expansion matches the first
form, the variable names starting with name
are generated. Otherwise, if the
expansion matches the second form, the keys of the indexed or associative array
named name
are generated. When the expansion does not much either the first
or second forms, it is interpreted as the third form of the variable name
surrounded by operators.
The value within brackets is called an "index", and retrieves a value from an array:
${A[i+1]}
${A['key']}
If A
is an indexed array, the index is interpreted as an arithmetic
expression. Arithmetic evaluation is performed, and the value at that numeric
offset is retrieved.
If A
is an associative array, the index is interpreted as a string. The
value associated with that string is retrieved.
If A
is a string, it's treated as an indexed array with a single element,
i.e. so that ${A[0]}
is ${A}
.
${A[*]}
${A[@]}
The index expressions [*]
and [@]
are special cases. Both generate a word
list of all elements in a
.
When the variable substitution is unquoted, there's no difference between
[*]
and [@]
:
$ A=(1 2 3)
$ printf '<%s>\n' ${A[*]}
<1>
<2>
<3>
$ printf '<%s>\n' ${A[@]}
<1>
<2>
<3>
When double-quoted, the [*]
form joins the elements by the first character of
IFS
:
$ IFS=x
$ printf '<%s>\n' "${A[*]}"
<1x2x3>
When double-quoted, the [@]
form generates a word list by splitting the word
at the boundary of every element in A
:
$ printf '<%s>\n' "-${A[@]}-"
<-1>
<2>
<3->
If the container A
has no elements, and the variable substitution has no
other parts, [@]
evaluates to an empty word list:
$ empty=()
$ set -- "${empty[@]}"
$ echo $#
0
These rules for [*]
and [@]
also apply to:
$*
and $@
${!name*}
and ${!name@}
${!name[*]}
and ${!name[@]}
, etc.The indirection operator !
is a prefix operator, and it interprets the
received string as a variable name name
, an array element name[key]
, or an
arrat list name[@]
/ name[*]
and reads its values.
$ a=1234
$ v=a
$ echo $v
a
$ echo ${!v}
1234
Shell has boolean operations within ${}
. I use :-
most frequently:
x=${1:-default}
osh=${OSH:-default}
This idiom is also useful:
: ${LIB_OSH=stdlib/osh}
There are test operators with colons, and without:
${x-default}
${x:-default}
${x=default}
${x:=default}
${x+other}
${x:+other}
${x?error}
${x:?error}
Without the colon, the shell checks whether a value is defined. In the
case of a word list, e.g. generated by $*
or $@
, it tests whether there is
at least one element.
With the colon, the shell checks whether the value is non-empty (is not the empty string). In the case of a word list, the test is performed after joining the elements by a space.
Elements are joined by the first character of IFS
only with double-quoted
"${*:-}"
.
In contrast, ${*:-}
, ${@:-}
, and "${@:-}"
are joined by a space. This is
because the joining of "$*"
by IFS
is performed earlier than the joining by
space for the test.
Remove prefixes or suffixes from strings:
echo ${y#prefix}
echo ${y##'prefix'}
echo ${y%suffix}
echo ${y%%'suffix'}
The prefix and suffix can be glob patterns, but this usage is discouraged because it may be slow.
Replace a substring or pattern.
The character after the first /
can be /
to replace all occurrences:
$ x=food
$ echo ${x//o/--} # replace 1 o with 2 --
f----d
It can be #
or %
for an anchored replacement:
$ echo ${x/#f/--} # left anchored f
--ood
$ echo ${x/%d/--} # right anchored d
foo--
The pattern can also be a glob:
$ echo ${x//[a-z]/o} # replace 1 char with o
oooo
$ echo ${x//[a-z]+/o} # replace multiple chars
o
echo ${a[@]:1:2}
echo ${@:1:2}
${x@P} evaluates x as a prompt string, i.e. the string that would be printed if PS1=$x.
${x@Q}
quotes the value of x
, if necessary, so that it can be evaluated as
a shell word.
$ x='<'
$ echo "value = $x, quoted = ${x@Q}."
value = <, quoted = '<'.
$ x=a
$ echo "value = $x, quoted = ${x@Q}."
value = a, quoted = a.
In the second case, the string a
doesn't need to be quoted.
Format operations like @Q
generally treat empty variables differently
than unset variables.
That is, ${empty@Q}
is the string ''
, while ${unset@Q}
is an empty
string:
$ x=''
$ echo "value = $x, quoted = ${x@Q}."
value = , quoted = ''.
$ unset -v x
$ echo "value = $x, quoted = ${x@Q}."
value = , quoted = .
${x@a}
returns characters that represent the attributes of the ${x}
, or
more precisely, the h-value of ${x}
.
Definitions:
${x}
would originally come.${x}
For example, with arr=(1 2 3)
:
Reference | Expression | H-value | R-value | Flags returned | |
---|---|---|---|---|---|
${arr[0]@a} or ${arr@a} |
array(1 2 3) |
string1 |
a |
||
${arr[@]@a} |
array(1 2 3) |
array(1 2 3) |
a a a |
||
ref=arr or ref=arr[0] |
${!ref@a} |
array(1 2 3) |
string1 |
a |
|
ref=arr[@] |
${!ref@a} |
array(1 2 3) |
array(1 2 3) |
a a a |
When ${x}
would result in a word list, ${x@a}
returns a word list
containing the attributes of the h-value of each word.
These characters may be returned:
Character | Where ${x} would be obtained |
---|---|
a |
indexed array |
A |
associative array |
r |
readonly container |
x |
exported variable |
n |
name reference (OSH extension) |