Oil shell language

For future references, this note mainly notes Oil v0.8.11 and later versions. Also, we'll be comparing to Bash shell (srcbash[:eval yes :results output]{bash --version | head -n 1} {{{results(GNU bash\, version 4.4.23(1)-release (x86_64-unknown-linux-gnu))}}}) as it is the most popular shell on the Unix world.

What is Oil shell?

Ripping off from the explanation page:

Oil is also aimed at people who know say Python or JavaScript, but purposely avoid shell.

A modern shell attempting the replace GNU Bash slowly. The project has an ambitious goal with a wide scope. It is known for its shell-oriented blog and the developer is very responsive and active with shell-related posts.

While there are multiple components in this project, we're focusing on two: OSH and Oil shell.

Both OSH and Oil are referring to the same interpreter but configured differently.

Overview of the Oil language

Oil is an entirely new programming language built from scratch. It adds a hint of familiarity with Bash and takes a big queue of Python.

The following block should be sufficient for jogging your memory and a quick glance of what Oil is all about.

var title = "Catenbury's Tale"
setvar title = "MS Fnd in a Lbry"

var keywords = %("metadata" "information overload" "information retrieval")
append :keywords "information organization"

var metadata = {}
setvar metadata['author'] = "Hal Draper"
setvar metadata['year'] = 1961

# Practically, it's a function.
# Not necessarily a function since it doesn't return an output.
proc kebab_case(word) {
  write -- $word | sed -E -e 's/./\L&/g' -e 's/s+/-/g' -e 's/[^.a-z0-9-]//g' -e 's/-+/-/g'
}

var title_slug = $(kebab_case $title)

{
  var keywords = %("alternate universes" "aliens" "spaceships")
  for i in @keywords { echo "keyword: $i" }
}
for i in @keywords { echo "keyword: $i" }

Strings

While strings are similar to Bash strings, there are subtle differences. Most notably, Bash splits the string when trying to do something.

d='echo 3'
e='echo "The quick brown fox jumps over the lazy dog."'

parallel -- $d $e

It should throw an error because parallel interprets it as if it has 4 arguments due to the splitting — i.e., parallel -- echo 3 echo "The quick brown fox jumps over the lazy dog.". The solution here is to quote the variables in evaluation (e.g., parallel -- "$d" "$e").

Compare that to Oil...

var d = 'echo 3'
var e = 'echo "The quick brown fox jumps over the lazy dog."'

parallel -- $d $e

If you want splitting, you could use split Oil function — e.g., @split(array_var).

Arrays

Arrays are mostly similar to Bash arrays except you have more options.

You can iterate through an array with a loop.

for i in @a { echo "word: $i" }

You can also add an item to the array with append keyword.

append :a "biz"

# The expression mode equivalent
# You can also append associative arrays due to the expressiveness of the mode
_ a.append("biz")

Conditions

Conditions in Oil look like this... Note that the parenthesis is a part of it.

if (4 == 5) {
  echo "Alright, this is true."
} elif (1 > 5) {
  echo "Another condition?"
} else {
  echo "It seems you got me."
}

You can also make ternary conditionals.

echo $['dogs' if dogs == 'cute' else 'cats']

While Oil expressions are usually used for conditions, you can also use command mode lines (see Expression and command mode). Similar to Bash conditions, it will pass when the exit code is zero.

if test -d /usr/home {
  echo "OK, you have an unusual home."
} elif test -d /home {
  echo "Alrighty, home does exist."
} else {
  echo "Homeless."
}

Associative arrays

const conditions = {}
setvar conditions['sunny'] = 80
setvar conditions['cloudy'] = 30
setvar conditions['rainy'] = -20

for key in @conditions {
  write -- $key $[conditions[key]]
}

You can check for a member in an associative with in keyword.

if ('rainy' in conditions) {
  write -- "We have rainy days over here."
}

Expression and command mode

Quoted string notation (QSN)

write -- $'\u044f\u043c\u0443' $'\u3bc'

Structured data

While Bash have support for structured data such as arrays and associative arrays, it does not go any further such as not letting you assign arrays in an item. As of v0.8.9, Oil also comes with the same problem but it seems the developer is also interested in solving that.

Though, you can still declare and assign variables with nested data structures.

const author = {
  "name": "John Doe",
  "birthdate": "1992-04-04",
  "portfolio": [
    { "title": "Philistine: A Jon Doe story", "isbn": "392-423-2113-123" },
    { "title": "Whoa there!", "isbn": "241-123-35241-123" }
  ]
  "has_criminal_record": false
}

write -- $[author['name']] $[author['portfolio'][0]['title']]

Oil has a built-in JSON support with the json keyword.

const author = {
  "name": "John Doe",
  "birthdate": "1992-04-04",
  "portfolio": [
    { "title": "Philistine: A Jon Doe story", "isbn": "392-423-2113-123" },
    { "title": "Whoa there!", "isbn": "241-123-35241-123" }
  ]
  "has_criminal_record": false
}

json write :author

This is handy as most tools has an option to print JSON data — e.g., systemctl, Ripgrep, buku, BorgBackup.

Tips and tricks