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)

In This Chapter

Expressions to Words

expr-sub

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))

expr-splice

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-splice

$ var foods = ['ale', 'bean', 'corn']
echo @foods

This syntax is enabled by shopt --set parse_at, which is part of YSH.

Formatting Typed Data as Strings

ysh-printf

Not done.

echo ${x %.3f}

ysh-format

Not done.

echo ${x|html}

Quotes

osh-string

TODO: elaborate

ysh-string

YSH strings in the word language are the same as in the expression language.

See ysh-string in chap-expr-lang.

triple-quoted

Triple-quoted in the word language are the same as in the expression language.

See triple-quoted in chap-expr-lang.

tagged-str

Not done.

Substitutions

command-sub

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:

  1. An unquoted string, which must be valid UTF-8. Whitespace is allowed, but not other ASCII control chars.
  2. A quoted J8 string (JSON style "" or J8-style b'' u'' '')
  3. An ignored empty line

See J8 Notation for more details.

var-sub

Evaluates to the value of a variable:

$ x=X
$ echo $x ${x}
X X

arith-sub

Shell has C-style arithmetic:

$ echo $(( 1 + 2*3 ))
7

tilde-sub

Used as a shortcut for a user's home directory:

~/src     # my home dir
~bob/src  # user bob's home dir

proc-sub

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)

Var Ops

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.

op-indirect

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

op-test

Shell has boolean operations within ${}. I use :- most frequently:

x=${1:-default}
osh=${OSH:-default}

This idiom is also useful:

: ${LIB_OSH=stdlib/osh}

op-strip

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.

op-patsub

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

op-index

echo ${a[i+1]}

op-slice

echo ${a[@]:1:2}
echo ${@:1:2}

op-format

${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 the set of characters that represent the attributes of the variable in which each resulting string is stored.

It should be noted that ${x@a} does not return the attributes of the obtained value. For example, ${a[0]@a} returns a because the string ${a[0]} would be obtained from an array although the resulting value of ${a[0]} is a scalar string.

$ echo ${a[0]@a}
a

When $x would result in a word list (such as ${a[@]} and ${!ref} with ref="a[@]"), ${x@a} returns a word list containing the attributes for each word.

$ a=(1 2 3)
$ echo "${a[@]@a}"
a a a
Generated on Tue, 31 Dec 2024 15:32:20 +0000