Latest commit

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

BETter SHell

Better Shell - or betsh for short - is a new kind of scripting language, which aims to be a replacement for sh/bash scripting. While using it as a REPL makes sense, using it as your login shell is probably not the best idea.

The basic syntax

Variables

a=b

Sets the variable a to the value b. If a doesn't exist, it is created in the current scope.

c=$a

Sets the variable c to the value of the variable a.

When variables go out of scope, they are automatically deleted.

Functions

f=[a b c] {
+ a b c
}

Defines the function f with the parameters a, b and c.

f 1 2 3

Calls the function f with the parameters 1, 2 and 3.

Function calls are run through either microprocesses or processes, microprocesses being low-overhead, non-forking emulations of processes, which means that they each have their own stdin, stdout, stderr and exit code.

Pipes work exactly like in sh, with the addition that they can also be used with microprocesses.

The exit code of the last (micro)process that was ran is stored in the pseudovariable ?, like in sh.

Function calls search for the function in the current file, imported libraries, betsh standard library and PATH, in that order.

(f 1 2 3)

Reads the stdout of f when called with the parameters 1, 2 and 3.

There is also a special case for a variable number of arguments:

g=[@]{ print $@ }

Defines the variable g as a function that takes any number of arguments and prints all of them.

If

a=(if 0 1 ; else 2)

Sets the variable a to 1, because 0 evaluates to true, just like in sh.

if false print lol
elif 1 print lel
else print kek

Prints "kek", because false and non-zero numbers evaluate to false.

make
else print compilation failed

Shows how to use else with other (micro)processes, by calling print when make fails.

if make print compiled successfully

For

for 1 2 3 [i]{
print $i
}

Prints:

1
2
3

Can also be η-reduced (shortened) to:

for 1 2 3 print

because print is a unary (one argument) function.

While

while true {
print lulw
}

Prints "lulw" in an infinite loop.

Streams

Like in sh, there are streams. But betsh streams are massively improved. The standard C streams are pre-defined, just like in sh:

idname
0stdin
1stdout
2stderr

sh redirections

Like in sh, you can redirect to and from streams, as well as files:

print hello >&2
print omg it works > /tmp/file
echo second line >> /tmp/file
echo < /tmp/file
echo lel <&1

betsh streams

s=(mkstream)

Assigns s to the id of a new stream, like 3. It can now be written to and read from, like a normal sh stream:

print hi >&$s

Now s is closed. But to allow for IPC through streams, we don't want this, so you can also use the append operators here:

s=(mkstream)
print <&$s &
print 1 >>&$s
print 2 >>&$s
print 3 >&$s
# output:
# 1
# 2
# 3

Libraries

Using shell functions defined somewhere else is a mess in every sh implementation around, betsh tries to fix this:

import mylibrary
mylibrary.some-function arg1 arg2 arg3

Imports a library and calls a function defined in it.

import mylibrary/*
some-function arg1 arg2 arg3

Imports everything defined in a library and calls a function from there.

import mylibrary/some-function
some-function arg1 arg2 arg3

Imports only a specific function from a library and calls it.

import mylibrary/????-function

Imports everything defined in a library that matches a wildcard.

Restrictions on naming

You can use basically any non-whitespace Unicode character for your names, but you may not ever define or use anything with two leading underbars (__), as that is reserved for internals of the implementation and standard library.

stdlib functions

functionargumentsdescriptionec
ifcondblockruns block if cond's ec is 0
elifcondblockruns block if the previous command's ec is not 0 and cond's ec is 0
elseblockruns block if the previous command's ec is not 0block
whilecondblockruns block while cond returns 0block
for@fcalls f with every argument before itf
mkstreamcreates a new stream and prints the id (fd)0 if everything worked
=@probes if all parameters are equal (sets ec)$1 == ... == $n
!=@probes if any of the parameters are not equal (sets ec)! "= $@"
&@probes if all of the parameters evaluate to true (sets ec)$1 && ... && $n
|@probes if any of the parameters evaluate to true (sets ec)$1 || ... || $n
!binverts bb ? false : true

About

What Unix Shell should have been for scripting.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

BETter SHell

Better Shell - or betsh for short - is a new kind of scripting language, which aims to be a replacement for sh/bash scripting. While using it as a REPL makes sense, using it as your login shell is probably not the best idea.

The basic syntax

Variables

a=b

Sets the variable a to the value b. If a doesn't exist, it is created in the current scope.

c=$a

Sets the variable c to the value of the variable a.

When variables go out of scope, they are automatically deleted.

Functions

f=[a b c] {
+ a b c
}

Defines the function f with the parameters a, b and c.

f 1 2 3

Calls the function f with the parameters 1, 2 and 3.

Function calls are run through either microprocesses or processes, microprocesses being low-overhead, non-forking emulations of processes, which means that they each have their own stdin, stdout, stderr and exit code.

Pipes work exactly like in sh, with the addition that they can also be used with microprocesses.

The exit code of the last (micro)process that was ran is stored in the pseudovariable ?, like in sh.

Function calls search for the function in the current file, imported libraries, betsh standard library and PATH, in that order.

(f 1 2 3)

Reads the stdout of f when called with the parameters 1, 2 and 3.

There is also a special case for a variable number of arguments:

g=[@]{ print $@ }

Defines the variable g as a function that takes any number of arguments and prints all of them.

If

a=(if 0 1 ; else 2)

Sets the variable a to 1, because 0 evaluates to true, just like in sh.

if false print lol
elif 1 print lel
else print kek

Prints "kek", because false and non-zero numbers evaluate to false.

make
else print compilation failed

Shows how to use else with other (micro)processes, by calling print when make fails.

if make print compiled successfully

For

for 1 2 3 [i]{
print $i
}

Prints:

1
2
3

Can also be η-reduced (shortened) to:

for 1 2 3 print

because print is a unary (one argument) function.

While

while true {
print lulw
}

Prints "lulw" in an infinite loop.

Streams

Like in sh, there are streams. But betsh streams are massively improved. The standard C streams are pre-defined, just like in sh:

idname
0stdin
1stdout
2stderr

sh redirections

Like in sh, you can redirect to and from streams, as well as files:

print hello >&2
print omg it works > /tmp/file
echo second line >> /tmp/file
echo < /tmp/file
echo lel <&1

betsh streams

s=(mkstream)

Assigns s to the id of a new stream, like 3. It can now be written to and read from, like a normal sh stream:

print hi >&$s

Now s is closed. But to allow for IPC through streams, we don't want this, so you can also use the append operators here:

s=(mkstream)
print <&$s &
print 1 >>&$s
print 2 >>&$s
print 3 >&$s
# output:
# 1
# 2
# 3

Libraries

Using shell functions defined somewhere else is a mess in every sh implementation around, betsh tries to fix this:

import mylibrary
mylibrary.some-function arg1 arg2 arg3

Imports a library and calls a function defined in it.

import mylibrary/*
some-function arg1 arg2 arg3

Imports everything defined in a library and calls a function from there.

import mylibrary/some-function
some-function arg1 arg2 arg3

Imports only a specific function from a library and calls it.

import mylibrary/????-function

Imports everything defined in a library that matches a wildcard.

Restrictions on naming

You can use basically any non-whitespace Unicode character for your names, but you may not ever define or use anything with two leading underbars (__), as that is reserved for internals of the implementation and standard library.

stdlib functions

functionargumentsdescriptionec
ifcondblockruns block if cond's ec is 0
elifcondblockruns block if the previous command's ec is not 0 and cond's ec is 0
elseblockruns block if the previous command's ec is not 0block
whilecondblockruns block while cond returns 0block
for@fcalls f with every argument before itf
mkstreamcreates a new stream and prints the id (fd)0 if everything worked
=@probes if all parameters are equal (sets ec)$1 == ... == $n
!=@probes if any of the parameters are not equal (sets ec)! "= $@"
&@probes if all of the parameters evaluate to true (sets ec)$1 && ... && $n
|@probes if any of the parameters evaluate to true (sets ec)$1 || ... || $n
!binverts bb ? false : true

About

What Unix Shell should have been for scripting.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

BETter SHell

Better Shell - or betsh for short - is a new kind of scripting language, which aims to be a replacement for sh/bash scripting. While using it as a REPL makes sense, using it as your login shell is probably not the best idea.

The basic syntax

Variables

a=b

Sets the variable a to the value b. If a doesn't exist, it is created in the current scope.

c=$a

Sets the variable c to the value of the variable a.

When variables go out of scope, they are automatically deleted.

Functions

f=[a b c] {
+ a b c
}

Defines the function f with the parameters a, b and c.

f 1 2 3

Calls the function f with the parameters 1, 2 and 3.

Function calls are run through either microprocesses or processes, microprocesses being low-overhead, non-forking emulations of processes, which means that they each have their own stdin, stdout, stderr and exit code.

Pipes work exactly like in sh, with the addition that they can also be used with microprocesses.

The exit code of the last (micro)process that was ran is stored in the pseudovariable ?, like in sh.

Function calls search for the function in the current file, imported libraries, betsh standard library and PATH, in that order.

(f 1 2 3)

Reads the stdout of f when called with the parameters 1, 2 and 3.

There is also a special case for a variable number of arguments:

g=[@]{ print $@ }

Defines the variable g as a function that takes any number of arguments and prints all of them.

If

a=(if 0 1 ; else 2)

Sets the variable a to 1, because 0 evaluates to true, just like in sh.

if false print lol
elif 1 print lel
else print kek

Prints "kek", because false and non-zero numbers evaluate to false.

make
else print compilation failed

Shows how to use else with other (micro)processes, by calling print when make fails.

if make print compiled successfully

For

for 1 2 3 [i]{
print $i
}

Prints:

1
2
3

Can also be η-reduced (shortened) to:

for 1 2 3 print

because print is a unary (one argument) function.

While

while true {
print lulw
}

Prints "lulw" in an infinite loop.

Streams

Like in sh, there are streams. But betsh streams are massively improved. The standard C streams are pre-defined, just like in sh:

idname
0stdin
1stdout
2stderr

sh redirections

Like in sh, you can redirect to and from streams, as well as files:

print hello >&2
print omg it works > /tmp/file
echo second line >> /tmp/file
echo < /tmp/file
echo lel <&1

betsh streams

s=(mkstream)

Assigns s to the id of a new stream, like 3. It can now be written to and read from, like a normal sh stream:

print hi >&$s

Now s is closed. But to allow for IPC through streams, we don't want this, so you can also use the append operators here:

s=(mkstream)
print <&$s &
print 1 >>&$s
print 2 >>&$s
print 3 >&$s
# output:
# 1
# 2
# 3

Libraries

Using shell functions defined somewhere else is a mess in every sh implementation around, betsh tries to fix this:

import mylibrary
mylibrary.some-function arg1 arg2 arg3

Imports a library and calls a function defined in it.

import mylibrary/*
some-function arg1 arg2 arg3

Imports everything defined in a library and calls a function from there.

import mylibrary/some-function
some-function arg1 arg2 arg3

Imports only a specific function from a library and calls it.

import mylibrary/????-function

Imports everything defined in a library that matches a wildcard.

Restrictions on naming

You can use basically any non-whitespace Unicode character for your names, but you may not ever define or use anything with two leading underbars (__), as that is reserved for internals of the implementation and standard library.

stdlib functions

functionargumentsdescriptionec
ifcondblockruns block if cond's ec is 0
elifcondblockruns block if the previous command's ec is not 0 and cond's ec is 0
elseblockruns block if the previous command's ec is not 0block
whilecondblockruns block while cond returns 0block
for@fcalls f with every argument before itf
mkstreamcreates a new stream and prints the id (fd)0 if everything worked
=@probes if all parameters are equal (sets ec)$1 == ... == $n
!=@probes if any of the parameters are not equal (sets ec)! "= $@"
&@probes if all of the parameters evaluate to true (sets ec)$1 && ... && $n
|@probes if any of the parameters evaluate to true (sets ec)$1 || ... || $n
!binverts bb ? false : true

About

What Unix Shell should have been for scripting.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

BETter SHell

Better Shell - or betsh for short - is a new kind of scripting language, which aims to be a replacement for sh/bash scripting. While using it as a REPL makes sense, using it as your login shell is probably not the best idea.

The basic syntax

Variables

a=b

Sets the variable a to the value b. If a doesn't exist, it is created in the current scope.

c=$a

Sets the variable c to the value of the variable a.

When variables go out of scope, they are automatically deleted.

Functions

f=[a b c] {
+ a b c
}

Defines the function f with the parameters a, b and c.

f 1 2 3

Calls the function f with the parameters 1, 2 and 3.

Function calls are run through either microprocesses or processes, microprocesses being low-overhead, non-forking emulations of processes, which means that they each have their own stdin, stdout, stderr and exit code.

Pipes work exactly like in sh, with the addition that they can also be used with microprocesses.

The exit code of the last (micro)process that was ran is stored in the pseudovariable ?, like in sh.

Function calls search for the function in the current file, imported libraries, betsh standard library and PATH, in that order.

(f 1 2 3)

Reads the stdout of f when called with the parameters 1, 2 and 3.

There is also a special case for a variable number of arguments:

g=[@]{ print $@ }

Defines the variable g as a function that takes any number of arguments and prints all of them.

If

a=(if 0 1 ; else 2)

Sets the variable a to 1, because 0 evaluates to true, just like in sh.

if false print lol
elif 1 print lel
else print kek

Prints "kek", because false and non-zero numbers evaluate to false.

make
else print compilation failed

Shows how to use else with other (micro)processes, by calling print when make fails.

if make print compiled successfully

For

for 1 2 3 [i]{
print $i
}

Prints:

1
2
3

Can also be η-reduced (shortened) to:

for 1 2 3 print

because print is a unary (one argument) function.

While

while true {
print lulw
}

Prints "lulw" in an infinite loop.

Streams

Like in sh, there are streams. But betsh streams are massively improved. The standard C streams are pre-defined, just like in sh:

idname
0stdin
1stdout
2stderr

sh redirections

Like in sh, you can redirect to and from streams, as well as files:

print hello >&2
print omg it works > /tmp/file
echo second line >> /tmp/file
echo < /tmp/file
echo lel <&1

betsh streams

s=(mkstream)

Assigns s to the id of a new stream, like 3. It can now be written to and read from, like a normal sh stream:

print hi >&$s

Now s is closed. But to allow for IPC through streams, we don't want this, so you can also use the append operators here:

s=(mkstream)
print <&$s &
print 1 >>&$s
print 2 >>&$s
print 3 >&$s
# output:
# 1
# 2
# 3

Libraries

Using shell functions defined somewhere else is a mess in every sh implementation around, betsh tries to fix this:

import mylibrary
mylibrary.some-function arg1 arg2 arg3

Imports a library and calls a function defined in it.

import mylibrary/*
some-function arg1 arg2 arg3

Imports everything defined in a library and calls a function from there.

import mylibrary/some-function
some-function arg1 arg2 arg3

Imports only a specific function from a library and calls it.

import mylibrary/????-function

Imports everything defined in a library that matches a wildcard.

Restrictions on naming

You can use basically any non-whitespace Unicode character for your names, but you may not ever define or use anything with two leading underbars (__), as that is reserved for internals of the implementation and standard library.

stdlib functions

functionargumentsdescriptionec
ifcondblockruns block if cond's ec is 0
elifcondblockruns block if the previous command's ec is not 0 and cond's ec is 0
elseblockruns block if the previous command's ec is not 0block
whilecondblockruns block while cond returns 0block
for@fcalls f with every argument before itf
mkstreamcreates a new stream and prints the id (fd)0 if everything worked
=@probes if all parameters are equal (sets ec)$1 == ... == $n
!=@probes if any of the parameters are not equal (sets ec)! "= $@"
&@probes if all of the parameters evaluate to true (sets ec)$1 && ... && $n
|@probes if any of the parameters evaluate to true (sets ec)$1 || ... || $n
!binverts bb ? false : true

About

What Unix Shell should have been for scripting.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

BETter SHell

Better Shell - or betsh for short - is a new kind of scripting language, which aims to be a replacement for sh/bash scripting. While using it as a REPL makes sense, using it as your login shell is probably not the best idea.

The basic syntax

Variables

a=b

Sets the variable a to the value b. If a doesn't exist, it is created in the current scope.

c=$a

Sets the variable c to the value of the variable a.

When variables go out of scope, they are automatically deleted.

Functions

f=[a b c] {
+ a b c
}

Defines the function f with the parameters a, b and c.

f 1 2 3

Calls the function f with the parameters 1, 2 and 3.

Function calls are run through either microprocesses or processes, microprocesses being low-overhead, non-forking emulations of processes, which means that they each have their own stdin, stdout, stderr and exit code.

Pipes work exactly like in sh, with the addition that they can also be used with microprocesses.

The exit code of the last (micro)process that was ran is stored in the pseudovariable ?, like in sh.

Function calls search for the function in the current file, imported libraries, betsh standard library and PATH, in that order.

(f 1 2 3)

Reads the stdout of f when called with the parameters 1, 2 and 3.

There is also a special case for a variable number of arguments:

g=[@]{ print $@ }

Defines the variable g as a function that takes any number of arguments and prints all of them.

If

a=(if 0 1 ; else 2)

Sets the variable a to 1, because 0 evaluates to true, just like in sh.

if false print lol
elif 1 print lel
else print kek

Prints "kek", because false and non-zero numbers evaluate to false.

make
else print compilation failed

Shows how to use else with other (micro)processes, by calling print when make fails.

if make print compiled successfully

For

for 1 2 3 [i]{
print $i
}

Prints:

1
2
3

Can also be η-reduced (shortened) to:

for 1 2 3 print

because print is a unary (one argument) function.

While

while true {
print lulw
}

Prints "lulw" in an infinite loop.

Streams

Like in sh, there are streams. But betsh streams are massively improved. The standard C streams are pre-defined, just like in sh:

idname
0stdin
1stdout
2stderr

sh redirections

Like in sh, you can redirect to and from streams, as well as files:

print hello >&2
print omg it works > /tmp/file
echo second line >> /tmp/file
echo < /tmp/file
echo lel <&1

betsh streams

s=(mkstream)

Assigns s to the id of a new stream, like 3. It can now be written to and read from, like a normal sh stream:

print hi >&$s

Now s is closed. But to allow for IPC through streams, we don't want this, so you can also use the append operators here:

s=(mkstream)
print <&$s &
print 1 >>&$s
print 2 >>&$s
print 3 >&$s
# output:
# 1
# 2
# 3

Libraries

Using shell functions defined somewhere else is a mess in every sh implementation around, betsh tries to fix this:

import mylibrary
mylibrary.some-function arg1 arg2 arg3

Imports a library and calls a function defined in it.

import mylibrary/*
some-function arg1 arg2 arg3

Imports everything defined in a library and calls a function from there.

import mylibrary/some-function
some-function arg1 arg2 arg3

Imports only a specific function from a library and calls it.

import mylibrary/????-function

Imports everything defined in a library that matches a wildcard.

Restrictions on naming

You can use basically any non-whitespace Unicode character for your names, but you may not ever define or use anything with two leading underbars (__), as that is reserved for internals of the implementation and standard library.

stdlib functions

functionargumentsdescriptionec
ifcondblockruns block if cond's ec is 0
elifcondblockruns block if the previous command's ec is not 0 and cond's ec is 0
elseblockruns block if the previous command's ec is not 0block
whilecondblockruns block while cond returns 0block
for@fcalls f with every argument before itf
mkstreamcreates a new stream and prints the id (fd)0 if everything worked
=@probes if all parameters are equal (sets ec)$1 == ... == $n
!=@probes if any of the parameters are not equal (sets ec)! "= $@"
&@probes if all of the parameters evaluate to true (sets ec)$1 && ... && $n
|@probes if any of the parameters evaluate to true (sets ec)$1 || ... || $n
!binverts bb ? false : true

About

What Unix Shell should have been for scripting.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

BETter SHell

Better Shell - or betsh for short - is a new kind of scripting language, which aims to be a replacement for sh/bash scripting. While using it as a REPL makes sense, using it as your login shell is probably not the best idea.

The basic syntax

Variables

a=b

Sets the variable a to the value b. If a doesn't exist, it is created in the current scope.

c=$a

Sets the variable c to the value of the variable a.

When variables go out of scope, they are automatically deleted.

Functions

f=[a b c] {
+ a b c
}

Defines the function f with the parameters a, b and c.

f 1 2 3

Calls the function f with the parameters 1, 2 and 3.

Function calls are run through either microprocesses or processes, microprocesses being low-overhead, non-forking emulations of processes, which means that they each have their own stdin, stdout, stderr and exit code.

Pipes work exactly like in sh, with the addition that they can also be used with microprocesses.

The exit code of the last (micro)process that was ran is stored in the pseudovariable ?, like in sh.

Function calls search for the function in the current file, imported libraries, betsh standard library and PATH, in that order.

(f 1 2 3)

Reads the stdout of f when called with the parameters 1, 2 and 3.

There is also a special case for a variable number of arguments:

g=[@]{ print $@ }

Defines the variable g as a function that takes any number of arguments and prints all of them.

If

a=(if 0 1 ; else 2)

Sets the variable a to 1, because 0 evaluates to true, just like in sh.

if false print lol
elif 1 print lel
else print kek

Prints "kek", because false and non-zero numbers evaluate to false.

make
else print compilation failed

Shows how to use else with other (micro)processes, by calling print when make fails.

if make print compiled successfully

For

for 1 2 3 [i]{
print $i
}

Prints:

1
2
3

Can also be η-reduced (shortened) to:

for 1 2 3 print

because print is a unary (one argument) function.

While

while true {
print lulw
}

Prints "lulw" in an infinite loop.

Streams

Like in sh, there are streams. But betsh streams are massively improved. The standard C streams are pre-defined, just like in sh:

idname
0stdin
1stdout
2stderr

sh redirections

Like in sh, you can redirect to and from streams, as well as files:

print hello >&2
print omg it works > /tmp/file
echo second line >> /tmp/file
echo < /tmp/file
echo lel <&1

betsh streams

s=(mkstream)

Assigns s to the id of a new stream, like 3. It can now be written to and read from, like a normal sh stream:

print hi >&$s

Now s is closed. But to allow for IPC through streams, we don't want this, so you can also use the append operators here:

s=(mkstream)
print <&$s &
print 1 >>&$s
print 2 >>&$s
print 3 >&$s
# output:
# 1
# 2
# 3

Libraries

Using shell functions defined somewhere else is a mess in every sh implementation around, betsh tries to fix this:

import mylibrary
mylibrary.some-function arg1 arg2 arg3

Imports a library and calls a function defined in it.

import mylibrary/*
some-function arg1 arg2 arg3

Imports everything defined in a library and calls a function from there.

import mylibrary/some-function
some-function arg1 arg2 arg3

Imports only a specific function from a library and calls it.

import mylibrary/????-function

Imports everything defined in a library that matches a wildcard.

Restrictions on naming

You can use basically any non-whitespace Unicode character for your names, but you may not ever define or use anything with two leading underbars (__), as that is reserved for internals of the implementation and standard library.

stdlib functions

functionargumentsdescriptionec
ifcondblockruns block if cond's ec is 0
elifcondblockruns block if the previous command's ec is not 0 and cond's ec is 0
elseblockruns block if the previous command's ec is not 0block
whilecondblockruns block while cond returns 0block
for@fcalls f with every argument before itf
mkstreamcreates a new stream and prints the id (fd)0 if everything worked
=@probes if all parameters are equal (sets ec)$1 == ... == $n
!=@probes if any of the parameters are not equal (sets ec)! "= $@"
&@probes if all of the parameters evaluate to true (sets ec)$1 && ... && $n
|@probes if any of the parameters evaluate to true (sets ec)$1 || ... || $n
!binverts bb ? false : true

About

What Unix Shell should have been for scripting.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

BETter SHell

Better Shell - or betsh for short - is a new kind of scripting language, which aims to be a replacement for sh/bash scripting. While using it as a REPL makes sense, using it as your login shell is probably not the best idea.

The basic syntax

Variables

a=b

Sets the variable a to the value b. If a doesn't exist, it is created in the current scope.

c=$a

Sets the variable c to the value of the variable a.

When variables go out of scope, they are automatically deleted.

Functions

f=[a b c] {
+ a b c
}

Defines the function f with the parameters a, b and c.

f 1 2 3

Calls the function f with the parameters 1, 2 and 3.

Function calls are run through either microprocesses or processes, microprocesses being low-overhead, non-forking emulations of processes, which means that they each have their own stdin, stdout, stderr and exit code.

Pipes work exactly like in sh, with the addition that they can also be used with microprocesses.

The exit code of the last (micro)process that was ran is stored in the pseudovariable ?, like in sh.

Function calls search for the function in the current file, imported libraries, betsh standard library and PATH, in that order.

(f 1 2 3)

Reads the stdout of f when called with the parameters 1, 2 and 3.

There is also a special case for a variable number of arguments:

g=[@]{ print $@ }

Defines the variable g as a function that takes any number of arguments and prints all of them.

If

a=(if 0 1 ; else 2)

Sets the variable a to 1, because 0 evaluates to true, just like in sh.

if false print lol
elif 1 print lel
else print kek

Prints "kek", because false and non-zero numbers evaluate to false.

make
else print compilation failed

Shows how to use else with other (micro)processes, by calling print when make fails.

if make print compiled successfully

For

for 1 2 3 [i]{
print $i
}

Prints:

1
2
3

Can also be η-reduced (shortened) to:

for 1 2 3 print

because print is a unary (one argument) function.

While

while true {
print lulw
}

Prints "lulw" in an infinite loop.

Streams

Like in sh, there are streams. But betsh streams are massively improved. The standard C streams are pre-defined, just like in sh:

idname
0stdin
1stdout
2stderr

sh redirections

Like in sh, you can redirect to and from streams, as well as files:

print hello >&2
print omg it works > /tmp/file
echo second line >> /tmp/file
echo < /tmp/file
echo lel <&1

betsh streams

s=(mkstream)

Assigns s to the id of a new stream, like 3. It can now be written to and read from, like a normal sh stream:

print hi >&$s

Now s is closed. But to allow for IPC through streams, we don't want this, so you can also use the append operators here:

s=(mkstream)
print <&$s &
print 1 >>&$s
print 2 >>&$s
print 3 >&$s
# output:
# 1
# 2
# 3

Libraries

Using shell functions defined somewhere else is a mess in every sh implementation around, betsh tries to fix this:

import mylibrary
mylibrary.some-function arg1 arg2 arg3

Imports a library and calls a function defined in it.

import mylibrary/*
some-function arg1 arg2 arg3

Imports everything defined in a library and calls a function from there.

import mylibrary/some-function
some-function arg1 arg2 arg3

Imports only a specific function from a library and calls it.

import mylibrary/????-function

Imports everything defined in a library that matches a wildcard.

Restrictions on naming

You can use basically any non-whitespace Unicode character for your names, but you may not ever define or use anything with two leading underbars (__), as that is reserved for internals of the implementation and standard library.

stdlib functions

functionargumentsdescriptionec
ifcondblockruns block if cond's ec is 0
elifcondblockruns block if the previous command's ec is not 0 and cond's ec is 0
elseblockruns block if the previous command's ec is not 0block
whilecondblockruns block while cond returns 0block
for@fcalls f with every argument before itf
mkstreamcreates a new stream and prints the id (fd)0 if everything worked
=@probes if all parameters are equal (sets ec)$1 == ... == $n
!=@probes if any of the parameters are not equal (sets ec)! "= $@"
&@probes if all of the parameters evaluate to true (sets ec)$1 && ... && $n
|@probes if any of the parameters evaluate to true (sets ec)$1 || ... || $n
!binverts bb ? false : true

About

What Unix Shell should have been for scripting.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

BETter SHell

Better Shell - or betsh for short - is a new kind of scripting language, which aims to be a replacement for sh/bash scripting. While using it as a REPL makes sense, using it as your login shell is probably not the best idea.

The basic syntax

Variables

a=b

Sets the variable a to the value b. If a doesn't exist, it is created in the current scope.

c=$a

Sets the variable c to the value of the variable a.

When variables go out of scope, they are automatically deleted.

Functions

f=[a b c] {
+ a b c
}

Defines the function f with the parameters a, b and c.

f 1 2 3

Calls the function f with the parameters 1, 2 and 3.

Function calls are run through either microprocesses or processes, microprocesses being low-overhead, non-forking emulations of processes, which means that they each have their own stdin, stdout, stderr and exit code.

Pipes work exactly like in sh, with the addition that they can also be used with microprocesses.

The exit code of the last (micro)process that was ran is stored in the pseudovariable ?, like in sh.

Function calls search for the function in the current file, imported libraries, betsh standard library and PATH, in that order.

(f 1 2 3)

Reads the stdout of f when called with the parameters 1, 2 and 3.

There is also a special case for a variable number of arguments:

g=[@]{ print $@ }

Defines the variable g as a function that takes any number of arguments and prints all of them.

If

a=(if 0 1 ; else 2)

Sets the variable a to 1, because 0 evaluates to true, just like in sh.

if false print lol
elif 1 print lel
else print kek

Prints "kek", because false and non-zero numbers evaluate to false.

make
else print compilation failed

Shows how to use else with other (micro)processes, by calling print when make fails.

if make print compiled successfully

For

for 1 2 3 [i]{
print $i
}

Prints:

1
2
3

Can also be η-reduced (shortened) to:

for 1 2 3 print

because print is a unary (one argument) function.

While

while true {
print lulw
}

Prints "lulw" in an infinite loop.

Streams

Like in sh, there are streams. But betsh streams are massively improved. The standard C streams are pre-defined, just like in sh:

idname
0stdin
1stdout
2stderr

sh redirections

Like in sh, you can redirect to and from streams, as well as files:

print hello >&2
print omg it works > /tmp/file
echo second line >> /tmp/file
echo < /tmp/file
echo lel <&1

betsh streams

s=(mkstream)

Assigns s to the id of a new stream, like 3. It can now be written to and read from, like a normal sh stream:

print hi >&$s

Now s is closed. But to allow for IPC through streams, we don't want this, so you can also use the append operators here:

s=(mkstream)
print <&$s &
print 1 >>&$s
print 2 >>&$s
print 3 >&$s
# output:
# 1
# 2
# 3

Libraries

Using shell functions defined somewhere else is a mess in every sh implementation around, betsh tries to fix this:

import mylibrary
mylibrary.some-function arg1 arg2 arg3

Imports a library and calls a function defined in it.

import mylibrary/*
some-function arg1 arg2 arg3

Imports everything defined in a library and calls a function from there.

import mylibrary/some-function
some-function arg1 arg2 arg3

Imports only a specific function from a library and calls it.

import mylibrary/????-function

Imports everything defined in a library that matches a wildcard.

Restrictions on naming

You can use basically any non-whitespace Unicode character for your names, but you may not ever define or use anything with two leading underbars (__), as that is reserved for internals of the implementation and standard library.

stdlib functions

functionargumentsdescriptionec
ifcondblockruns block if cond's ec is 0
elifcondblockruns block if the previous command's ec is not 0 and cond's ec is 0
elseblockruns block if the previous command's ec is not 0block
whilecondblockruns block while cond returns 0block
for@fcalls f with every argument before itf
mkstreamcreates a new stream and prints the id (fd)0 if everything worked
=@probes if all parameters are equal (sets ec)$1 == ... == $n
!=@probes if any of the parameters are not equal (sets ec)! "= $@"
&@probes if all of the parameters evaluate to true (sets ec)$1 && ... && $n
|@probes if any of the parameters evaluate to true (sets ec)$1 || ... || $n
!binverts bb ? false : true

About

What Unix Shell should have been for scripting.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages