Expand

Examples

Release Script

:= declares a new variable
$tag := git describe --tags --abbrev=0
the end of the tar command is determined by indent
tar -czv
    -f "release-$tag.tar.gz"
    --exclude "*.o"
    --exclude "*.so"
    src/

Disk Space Check

$threshold   := 0.8
$targetMount := "/"
discard the first line of the df output, set the second line to $line _, $line := df -k $targetMount
split the line using :columns formatter, which splits by spaces awk-style $stat := $line:columns
:int converts a string to an integer
$used, $total := $stat[2]:int, $stat[1]:int
use any expressions inside {} in strings
if $used/$total > $threshold {
    $toFree := $used - $total*$threshold

    print "$targetMount usage is too high"
    print "Target is {$threshold * 100}%"
    print "Please free $toFree KB"
    exit 1
} else {
    print OK
}

:columns, :int and :json are called formatters, they parse a string from a specified format to a syshell type. There are lots of built-in formatters that cover many scripting needs.

Send a Slack Message

$token := "xx-secret-token-yy"
$channelID := "C123"
$msg := "test message"

$payload := {
    channel: $channelID,
    text:    $msg,
}
@json is also a formatter, but it's doing reverse of :json. $payload@json convert a syshell object (a map in this case) to a JSON string.
$response := curl -s -X POST
    -H "Authorization: Bearer $token"
    -H "Content-Type: application/json"
    -d $payload@json
    https://slack.com/api/chat.postMessage
  | from json
panic stops current function and starts propagating an error. If no one handles this error, syshell will print it along with a stack trace.
if !$response.ok {
    # when "ok" is false, slack response
    # must contain an "error" field
    panic "slack error:" $response.error
}

@json are @csv are also formatters, @json converts from a syshell type to a string in a specified format, @json is a reverse of :json. Formatters always come in pairs.

Indent a File

for processess input line-by-line
cat a-file.txt
    | for $line { print "  $line" }

syshell works with external program's output as if they were a stream of lines.

Wait for an Event

Same as cat, just interactive. tail -f access.log
in works like in python.
| for $req {
    if "/honeypot" in $req {
      break
    }
}

for consumes items or lines as they come, once there's a line with "/honeypot" inside, break will stop to the loop, and tail -f will quit.

Countries Stats

Given a CSV file with cities stats like below, compute how many 1M+ population cities each country has:

>> head -4 cities.csv
"city","lat","lng","country","iso2","population"
"Tokyo","35.6897","139.6922","Japan","JP","37732000"
"Jakarta","-6.1750","106.8275","Indonesia","ID","33756000"
"Delhi","28.6100","77.2300","India","IN","32226000"
$countries := {}
For each CSV record, create a map and send it over a pipe to a for loop.
from csv < cities.csv
  | for $city { 
      if $city.population:float > 1000000 { 
        $countries[$city.country] += 1
      }
  }
put $countries

Pipes in syshell can transport typed values without serialization overhead.

Disk Space Check Function

Function check-space must have exactly one argument, which will be assigned to $mount.
fn check-space $mount {
    _, $line := df -k $mount
    $stat := $line:columns
    $used, $total := $stat[2]:int, $stat[1]:int
put adds typed value to the output stream.
put ($used / $total > 0.8)
put ($total - $used)
}
$rootOK is a boolean, $left is an integer. $rootOK, $left := check-space /

put adds its arguments to the output stream as is, while print converts arguments to strings and may output multiple lines, if arguments have \n in them.

Build Function

# build source files into executables and
# shared libraries
fn build
List function options and they will be set to specified variables
-C           $directory
-t|--target  $arch
-o|--output  $destination
Validate that supplied parameters have a correct type
-j|--jobs    (int)$jobs
-v|--verbose (bool)$verbose
-f|--force   (bool)$forceRebuild
$name
{
    # implementation
}