Expand

Commands

this is a command curl -s https://syshell.org/
use "" to pass arguments with spaces or other special characters mkdir "New Folder"
commands can span multiple lines, if indented. No need for backslashes. Comment with #
find /usr/lib64
    -type f      # ignore links
    -maxdepth 1  # skip subdirectories
    -name "lib*"

Commands vs. Expressions Syntax

To determine whether it is a call or an expression, parser checks the leftmost symbols:

This rules are consistent for standalone calls, calls done inside the assign operator, or calls done inside parens:

standalone call call in assign inline call
put 1 $one := put 1 print (put 1)
/bin/echo 1 $one := /bin/echo 1 print (/bin/echo 1)
~/bin/go version $vsn := ~/bin/go version print (~/bin/go version)
./script.sy $res := ./script.sy print (./script.sy)
standalone expr expr in assign inline expr
N/A $two := 1 + 1 print (1 + 1)
N/A $map := {a: 1} + {b: 2} print ({a: 1} + {b: 2})
N/A $list := [1] + [2, 3] print ([1] + [2, 3])
N/A $two := (put 10)/5 print ((put 10)/5)
N/A $msg := "Hi " + "there" print ("hi " + "there")
N/A $msg := 'Hi ' + 'there' print ('hi ' + 'there')
N/A $three := $one + $two print ($one + $two)

A few command start with a digit (e.g. 7z or 9p), in this case use run syntax with quoted command name:

extract a 7z archive
run "7z" e archive.7z
run a command, stored in a variable
$python := "/usr/bin/python"
run $python --version
execute a command based on extension
fn exec-script $script $args... {
    $interp := {
        py: "python",
        sh: "bash",
        sy: "sy",
    }
    $ext := $script:dots[-1]
    if $ext not in $interp {
        panic "unknown extension $ext"
    }
    run $interp[$ext] $script $args...
}

Argument Syntax

There are two types of arguments:

Similarly to commands vs. expressions, to distinguish barewords vs. primary parser checks the left most symbols:

time Modifier

time executes a provided command and reports execution statistics:

time outputs a map with this fields to the output stream:

>> time sleep 1
{ real: 1.008347:s, userCPU: 2.724:ms, systemCPU: 3.652:ms, execs: 1 }

This output can be captured in a standard assignment:

>> $a, $b, $time := time put 1 2
>> print A=$a B=$b time=$time
A=1 B=2 time={ real: 21.32:µs, userCPU: 0:s, systemCPU: 0:s, execs: 0 }
>> put $time.real
21.32:µs

ignore Modifier

ignore executes a provided command, while redirecting error stream to /dev/null and silencing all errors.

$lines... := ignore cat maybe-exists.txt

$lines will be [], if file doesn't exist, otherwise it will contain a list of its lines.

mute Modifier

mute executes a provided command, while redirecting both output and error streams to /dev/null:

mute apt update

It does not, however, silence errors: in the example above, if apt update exits with non-zero exit code, it will cause a panic.

try Modifier

try executes a provided command, captures its error or exit code, and appends to the output stream after the command output:

$lines..., $err := try cat counter.txt
if $err != null {
    print 0 > counter.txt
    $lines = ["0"]
}

It's guaranteed that, if no error occurred or if an external program exited with 0 exit code, the captured error will be null. try is experimental and most likely will be revised.

wrap and defer

Instead of running a command immediately, it's possible to 'box' or 'wrap' and run this command later when necessary or when the current function exits. Check out wrap and defer for that.

Grammar

<commandMode>
    = <command> # first symbols must comply with rules above
    | run   <command>
    | defer <command>
    | wrap  <command>

<command>
    = <commandName> <args>*
    | time   <command>
    | ignore <command>
    | mute   <command>
    | try    <command>

See Also