mirror of
https://github.com/foo-dogsquared/wiki.git
synced 2025-01-31 04:58:21 +00:00
158 lines
46 KiB
HTML
158 lines
46 KiB
HTML
|
<!DOCTYPE html><html><head><meta name="viewport" content="width=device-width"/><meta charSet="utf-8"/><title>Oil shell language</title><script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script><script id="MathJax-script" async="" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script><script type="text/x-mathjax-config">
|
||
|
MathJax = {
|
||
|
tex: {
|
||
|
inlineMath: [ ['$','$'], ['\(','\)'] ],
|
||
|
displayMath: [ ['$$','$$'], ['[',']'] ]
|
||
|
},
|
||
|
options = {
|
||
|
processHtmlClass = "math"
|
||
|
}
|
||
|
}
|
||
|
</script><meta name="next-head-count" content="6"/><link rel="preload" href="/wiki/_next/static/css/52fc2ba29703df73922c.css" as="style"/><link rel="stylesheet" href="/wiki/_next/static/css/52fc2ba29703df73922c.css" data-n-g=""/><noscript data-n-css=""></noscript><link rel="preload" href="/wiki/_next/static/chunks/main-ae4733327bd95c4ac325.js" as="script"/><link rel="preload" href="/wiki/_next/static/chunks/webpack-50bee04d1dc61f8adf5b.js" as="script"/><link rel="preload" href="/wiki/_next/static/chunks/framework.9d524150d48315f49e80.js" as="script"/><link rel="preload" href="/wiki/_next/static/chunks/commons.0e1c3f9aa780c2dfe9f0.js" as="script"/><link rel="preload" href="/wiki/_next/static/chunks/pages/_app-8e3d0c58a60ec788aa69.js" as="script"/><link rel="preload" href="/wiki/_next/static/chunks/940643274e605e7596ecea1f2ff8d83317a3fb76.4841a16762f602a59f00.js" as="script"/><link rel="preload" href="/wiki/_next/static/chunks/pages/%5B%5B...slug%5D%5D-1aa198f87ede1cd0e1dc.js" as="script"/></head><body><div id="__next"><main><h1>Oil shell language</h1><section class="post-metadata"><span>Date: <!-- -->2021-05-09 16:40:50 +08:00</span><span>Date modified: <!-- -->2022-04-16 20:18:16 +08:00</span></section><nav class="toc"><ol class="toc-level toc-level-1"><li class="toc-item toc-item-h1"><a href="/wiki/lang.oil#what-is-oil-shell" class="toc-link toc-link-h1">What is Oil shell?</a></li><li class="toc-item toc-item-h1"><a href="/wiki/lang.oil#overview-of-the-oil-language" class="toc-link toc-link-h1">Overview of the Oil language</a><ol class="toc-level toc-level-2"><li class="toc-item toc-item-h2"><a href="/wiki/lang.oil#strings" class="toc-link toc-link-h2">Strings</a></li><li class="toc-item toc-item-h2"><a href="/wiki/lang.oil#arrays" class="toc-link toc-link-h2">Arrays</a></li><li class="toc-item toc-item-h2"><a href="/wiki/lang.oil#conditions" class="toc-link toc-link-h2">Conditions</a></li><li class="toc-item toc-item-h2"><a href="/wiki/lang.oil#associative-arrays" class="toc-link toc-link-h2">Associative arrays</a></li></ol></li><li class="toc-item toc-item-h1"><a href="/wiki/lang.oil#expression-and-command-mode" class="toc-link toc-link-h1">Expression and command mode</a></li><li class="toc-item toc-item-h1"><a href="/wiki/lang.oil#quoted-string-notation-qsn" class="toc-link toc-link-h1">Quoted string notation (QSN)</a></li><li class="toc-item toc-item-h1"><a href="/wiki/lang.oil#structured-data" class="toc-link toc-link-h1">Structured data</a></li><li class="toc-item toc-item-h1"><a href="/wiki/lang.oil#tips-and-tricks" class="toc-link toc-link-h1">Tips and tricks</a></li></ol></nav><p>For future references, this note mainly notes Oil v0.8.11 and later versions.
|
||
|
Also, we'll be comparing to Bash shell (src<sub>bash</sub>[:eval yes :results output]{bash --version | head -n 1} {{{results(<code class="inline-verbatim">GNU bash\, version 4.4.23(1)-release (x86_64-unknown-linux-gnu)</code>)}}}) as it is the most popular shell on the Unix world.
|
||
|
</p><h1 id="what-is-oil-shell">What is Oil shell?</h1><p>Ripping off from the <a href="https://www.oilshell.org/blog/2020/01/simplest-explanation.html">explanation page</a>:
|
||
|
</p><blockquote><p>Oil is also aimed at people who know say Python or JavaScript, but purposely avoid shell.
|
||
|
</p></blockquote><p>A modern shell attempting the replace <a href="id:dd9d3ffa-03ff-42a1-8c5d-55dc9fcc70fe">GNU Bash</a> slowly.
|
||
|
The project has an ambitious goal with a wide scope.
|
||
|
It is known for its <a href="https://oilshell.org/blog">shell-oriented blog</a> and the developer is very responsive and active with shell-related posts.
|
||
|
</p><p>While there are multiple components in this project, we're focusing on two: <strong>OSH and Oil shell</strong>.
|
||
|
</p><ul><li><p><strong>OSH is the bridge between Bash and Oil.</strong>
|
||
|
It aims to be the most Bash-compatible shell that you can run most Bash scripts just fine.
|
||
|
The point of this component is improving what's under the hood, imposing sensible defaults on them, and getting a wide reach since Bash is the most popular shell.
|
||
|
While it may not run every Bash script in existence, the other point is to require minimal rewrites to run it with OSH or eventually rewrite it in Oil.
|
||
|
</p></li><li><p><strong>Oil shell is the modern replacement of Bash</strong> from its syntax and behavior.
|
||
|
It aims to be the shell for people familiar to Python, Ruby, JavaScript, and the like.
|
||
|
This is the other side of the bridge that OSH aims to reach.
|
||
|
</p></li></ul><p>Both OSH and Oil are referring to the same interpreter but configured differently.
|
||
|
</p><h1 id="overview-of-the-oil-language">Overview of the Oil language</h1><p>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.
|
||
|
</p><p>The following block should be sufficient for jogging your memory and a quick glance of what Oil is all about.
|
||
|
</p><pre class="src-block"><code class="language-oil">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" }
|
||
|
</code></pre><h2 id="strings">Strings</h2><p>While strings are similar to Bash strings<!-- -->, there are subtle differences.
|
||
|
Most notably, Bash splits the string when trying to do something.
|
||
|
</p><pre class="src-block"><code class="language-bash">d='echo 3'
|
||
|
e='echo "The quick brown fox jumps over the lazy dog."'
|
||
|
|
||
|
parallel -- $d $e
|
||
|
</code></pre><p>It should throw an error because <code class="inline-verbatim">parallel</code> interprets it as if it has 4 arguments due to the splitting — i.e., <code class="inline-code">parallel -- echo 3 echo "The quick brown fox jumps over the lazy dog."</code>.
|
||
|
The solution here is to quote the variables in evaluation (e.g., <code class="inline-code">parallel -- "$d" "$e"</code>).
|
||
|
</p><p>Compare that to Oil...
|
||
|
</p><pre class="src-block"><code class="language-oil">var d = 'echo 3'
|
||
|
var e = 'echo "The quick brown fox jumps over the lazy dog."'
|
||
|
|
||
|
parallel -- $d $e
|
||
|
</code></pre><p>If you want splitting, you could use <code class="inline-verbatim">split</code> Oil function — e.g., <code class="inline-code">@split(array_var)</code>.
|
||
|
</p><h2 id="arrays">Arrays</h2><p>Arrays are mostly similar to Bash arrays except you have more options.
|
||
|
</p><ul><li><p>You can create a heterogenous list containing different types of data — e.g., <code class="inline-code">var a = ['Dogs', 24, true ]</code>.
|
||
|
Useful for JSON compatibility.
|
||
|
</p></li><li><p>A homogenous array is useful for data consistency.
|
||
|
It can accept a list of data of the same type — e.g., <code class="inline-code">var b = %("foo" "bar" "baz")</code>.
|
||
|
</p></li></ul><p>You can iterate through an array with a loop.
|
||
|
</p><pre class="src-block"><code class="language-oil">for i in @a { echo "word: $i" }
|
||
|
</code></pre><p>You can also add an item to the array with <code class="inline-verbatim">append</code> keyword.
|
||
|
</p><pre class="src-block"><code class="language-oil">append :a "biz"
|
||
|
|
||
|
# The expression mode equivalent
|
||
|
# You can also append associative arrays due to the expressiveness of the mode
|
||
|
_ a.append("biz")
|
||
|
</code></pre><h2 id="conditions">Conditions</h2><p>Conditions in Oil look like this...
|
||
|
Note that the parenthesis is a part of it.
|
||
|
</p><pre class="src-block"><code class="language-oil">if (4 == 5) {
|
||
|
echo "Alright, this is true."
|
||
|
} elif (1 > 5) {
|
||
|
echo "Another condition?"
|
||
|
} else {
|
||
|
echo "It seems you got me."
|
||
|
}
|
||
|
</code></pre><p>You can also make ternary conditionals.
|
||
|
</p><pre class="src-block"><code class="language-oil">echo $['dogs' if dogs == 'cute' else 'cats']
|
||
|
</code></pre><p>While Oil expressions are usually used for conditions, you can also use command mode lines (see <a href="/wiki/Expression%20and%20command%20mode">Expression and command mode</a>).
|
||
|
Similar to Bash conditions, it will pass when the exit code is zero.
|
||
|
</p><pre class="src-block"><code class="language-oil">if test -d /usr/home {
|
||
|
echo "OK, you have an unusual home."
|
||
|
} elif test -d /home {
|
||
|
echo "Alrighty, home does exist."
|
||
|
} else {
|
||
|
echo "Homeless."
|
||
|
}
|
||
|
</code></pre><h2 id="associative-arrays">Associative arrays</h2><ul><li><p>similar to Bash associative arrays or Python dictionaries (practically like Python dictionaries)
|
||
|
</p></li><li><p>when interacting with Oil, an associative array is exactly that, an array
|
||
|
</p></li></ul><pre class="src-block"><code class="language-oil">const conditions = {}
|
||
|
setvar conditions['sunny'] = 80
|
||
|
setvar conditions['cloudy'] = 30
|
||
|
setvar conditions['rainy'] = -20
|
||
|
|
||
|
for key in @conditions {
|
||
|
write -- $key $[conditions[key]]
|
||
|
}
|
||
|
</code></pre><p>You can check for a member in an associative with <code class="inline-verbatim">in</code> keyword.
|
||
|
</p><pre class="src-block"><code class="language-oil">if ('rainy' in conditions) {
|
||
|
write -- "We have rainy days over here."
|
||
|
}
|
||
|
</code></pre><h1 id="expression-and-command-mode">Expression and command mode</h1><ul><li><p>There are different ways <a href="https://www.oilshell.org/release/latest/doc/syntactic-concepts.html">how Oil can create an expressive language with the shell</a>.
|
||
|
It can parse different sublanguages with different lexer modes.
|
||
|
But there are dominantly two modes to keep in mind: expression and command mode.
|
||
|
</p></li><li><p>simply put:
|
||
|
</p><ul><li><p><strong>command mode is similar to Bash expressions</strong></p></li><li><p><strong>expression mode is akin to Python expressions</strong></p></li></ul></li><li><p>Expression mode even has Python familiarisms — e.g., <code class="inline-code">if ("item" in array)</code>, <code class="inline-code">if ("key" in object)</code>.
|
||
|
</p></li><li><p>The addition of a Python-like expressiveness is how Oil can make a rich scripting exprience.
|
||
|
</p></li><li><p>command mode is what you see most of the time
|
||
|
</p></li><li><p>expression mode is activated when:
|
||
|
</p><ul><li><p>right-hand side of <code class="inline-verbatim">=</code> — e.g., <code class="inline-code">var a = 234</code></p></li><li><p>the <code class="inline-verbatim">_</code> keyword where output will be ignored — e.g., <code class="inline-code">_ a.append(b)</code></p></li><li><p>the <code class="inline-verbatim">=</code> command where it will print the results — e.g., <code class="inline-code">= 53</code></p></li><li><p>you can interpolate expression mode expressions with <code class="inline-verbatim">$[]</code> — e.g., <code class="inline-code">echo $[4 + 43 + a]</code>, <code class="inline-code">echo $[len(ARGV)]</code></p></li><li><p>in <code class="inline-verbatim">if</code> statements — e.g., <code class="inline-code">if (true) { echo "WHOA" }</code></p></li></ul></li></ul><h1 id="quoted-string-notation-qsn">Quoted string notation (QSN)</h1><ul><li><p>a data format that can represent any byte sequence
|
||
|
</p></li><li><p>adapted from Rust's string syntax
|
||
|
</p></li><li><p>Oil can print non-ASCII stuff through <a href="https://www.oilshell.org/release/latest/doc/qsn.html">QSN</a></p></li></ul><pre class="src-block"><code class="language-oil">write -- $'\u044f\u043c\u0443' $'\u3bc'
|
||
|
</code></pre><h1 id="structured-data">Structured data</h1><p>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 <a href="https://github.com/oilshell/oil/issues/741">the developer is also interested in solving that</a>.
|
||
|
</p><p>Though, you can still declare and assign variables with nested data structures.
|
||
|
</p><pre class="src-block"><code class="language-oil">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']]
|
||
|
</code></pre><p>Oil has a built-in JSON support with the <code class="inline-verbatim">json</code> keyword.
|
||
|
</p><pre class="src-block"><code class="language-oil">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
|
||
|
</code></pre><p>This is handy as most tools has an option to print JSON data — e.g., <code class="inline-verbatim">systemctl</code>, Ripgrep, <code class="inline-verbatim">buku</code>, <a href="/wiki/cli.borg">BorgBackup</a>.
|
||
|
</p><h1 id="tips-and-tricks">Tips and tricks</h1><ul><li><p>Oil seems to evaluate in normal order, evaluating only when the conditions passed — e.g., <code class="inline-code">echo $['' + null if null else 'EEEEHHH']</code> should print <code class="inline-verbatim">EEEEHHH</code>.
|
||
|
</p><ul><li><p>Just like most modern mainstream languages... nice.
|
||
|
</p></li></ul></li><li><p>Two operands of different types are considered unequal — e.g., <code class="inline-code">'4' == 4</code>.
|
||
|
</p><ul><li><p>You can use Python-like type conversions like <code class="inline-verbatim">Int</code>, <code class="inline-verbatim">Bool</code>, and <code class="inline-verbatim">Str</code> — e.g., <code class="inline-code">Int('4') == 4</code>.
|
||
|
</p></li></ul></li><li><p>By default, errexit is disabled (e.g., the script will not exit on error).
|
||
|
You can have fine control over it with <code class="inline-verbatim">run</code>.
|
||
|
</p></li></ul></main></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"metadata":{"date":"\"2021-05-09 16:40:50 +08:00\"","date_modified":"\"2022-04-16 20:18:16 +08:00\"","language":"en","source":""},"title":"Oil shell language","hast":{"type":"root","children":[{"type":"element","tagName":"nav","properties":{"className":"toc"},"children":[{"type":"element","tagName":"ol","properties":{"className":"toc-level toc-level-1"},"children":[{"type":"element","tagName":"li","data":{"hookArgs":[{"type":"element","tagName":"h1","properties":{"id":"what-is-oil-shell"},"children":[{"type":"text","value":"What is Oil shell?"}]}]},"properties":{"className":"toc-item toc-item-h1"},"children":[{"type":"element","tagName":"a","properties":{"className":"toc-link toc-link-h1","href":"/lang.oil#what-is-oil-shell"},"children":[{"type":"text","value":"What is Oil shell?"}]}]},{"type":"element","tagName":"li","data":{"hookArgs":[{"type":"element","tagName":"h1","properties":{"id":"overview-of-the-oil-language"},"children":[{"type":"text","value":"Overview of the Oil language"}]}]},"properties":{"className":"toc-item toc-item-h1"},"children":[{"type":"element","tagName":"a","properties":{"className":"toc-link toc-link-h1","href":"/lang.oil#overview-of-the-oil-language"},"children":[{"type":"text","value":"Overview of the Oil language"}]},{"type":"element","tagName":"ol","properties":{"className":"toc-level toc-level-2"},"children":[{"type":"element","tagName":"li","data":{"hookArgs":[{"type":"element","tagName":"h2","properties":{"id":"strings"},"children":[{"type":"text","value":"Strings"}]}]},"properties":{"className":"toc-item toc-item-h2"},"children":[{"type":"element","tagName":"a","properties":{"className":"toc-link toc-link-h2","href":"/lang.oil#strings"},"children":[{"type":"text","value":"Strings"}]}]},{"type":"element","tagName":"li","data":{"hookArgs":[{"type":"element","tagName":"h2","properties":{"id":"arrays"},"children":[{"type":"text","value":"Arrays"}]}]},"properties":{"className":"toc-item toc-item-h2"},"children":[{"type":"element","tagName":"a","properties":{"className":"toc-link toc-link-h2","href":"/lang.oil#arrays"},"children":[{"type":"text","value":"Arrays"}]}]},{"type":"element","tagName":"li","data":{"hookArgs":[{"type":"element","tagName":"h2","properties":{"id":"conditions"},"children":[{"type":"text","value":"Conditions"}]}]},"properties":{"className":"toc-item toc-item-h2"},"children":[{"type":"element","tagName":"a","properties":{"className":"toc-link toc-link-h2","href":"/lang.oil#conditions"},"children":[{"type":"text","value":"Conditions"}]}]},{"type":"element","tagName":"li","data":{"hookArgs":[{"type":"element","tagName":"h2","properties":{"id":"associative-arrays"},"children":[{"type":"text","value":"Associative arrays"}]}]},"properties":{"className":"toc-item toc-item-h2"},"children":[{"type":"element","tagName":"a","properties":{"className":"toc-link toc-link-h2","href":"/lang.oil#associative-arrays"},"children":[{"type":"text","value":"Associative arrays"}]}]}]}]},{"type":"element","tagName":"li","data":{"hookArgs":[{"type":"element","tagName":"h1","properties":{"id":"expression-and-command-mode"},"children":[{"type":"text","value":"Expression and command mode"}]}]},"properties":{"className":"toc-item toc-item-h1"},"children":[{"type":"element","tagName":"a","properties":{"className":"toc-link toc-link-h1","href":"/lang.oil#expression-and-command-mode"},"children":[{"type":"text","value":"Expression and command mode"}]}]},{"type":"element","tagName":"li","data":{"hookArgs":[{"type":"element","tagName":"h1","properties":{"id":"quoted-string-notation-qsn"},"children":[{"type":"text","value":"Quoted string notation (QSN)"}]}]},"properties":{"className":"toc-item toc-item-h1"},"children":[{"type":"element","tagName":"a","properties":{"className":"toc-link toc-link-h1","href":"/lang.oil#quoted-string-notation-qsn"},"children":[{"type":"text","value":"Quoted string notation (QSN)"}]}]},{"type":"element","tagName":"li","data":{"hookArgs":[{"type":"element","tagName":"h1","propert
|