🐚
sensishell is a simple way to turn shell commands into a sensor that is compared to defined thresholds, e.g. to periodically check if the system is idle and suspend it - it is a single-file app, written in pure Go and without any third-party dependencies. Originally built to replace all the overcomplicated auto-suspend solutions for my home servers, it can be used for a wide range of scenarios.
Getting started • Configuration • Development
Copy the compiled executable as to your target computer, create a config file (which is simply read from STDIN
, see the example in the config
folder or the section below) and run it using the command line:
cat config/is-idle.conf | ./sensishell
The above example will output the sensor values using structured logging - if you want to easily use the values to actually do something, you can provide a command that should be executed after n
cycles where the sensor was active (i.e. the threshold was exceeded):
cat config/is-idle.conf | ./sensishell -n 5 -c "echo system is idle"
Of course you can also specify the interval between the cycles or whether sensishell should exit after a cycle limit was reached:
$ ./sensishell -h
Usage of ./sensishell:
-c string
command to run after cycle limit is reached
-n int
number of maximum consecutive active cycles (default 3)
-r restart the cycles after cycle limit is reached (default true)
-s int
number of seconds to sleep between each cycle (default 5)
All sensor configuration is provided to sensishell as input to STDIN
in the following format where each line is an individual sensor and each field is separated by a single space character as in the following, annotated, example:
active-users "who | wc -l" == 0 ──> threshold
| | |
└──> name └──> command └──> comparator
Lines starting with a #
are treated as comments. Technically, the configuration format is a valid CSV-dialect that uses the space character as the delimiter, so make sure to properly quote your commands and to use single spaces.
An example configuration that defines different sensors to see if a system is idle would therefore look like this:
# active users?
no-users "who | wc -l" == 0
# active connections on port :22?
no-ssh "lsof -Pi :22 -sTCP:ESTABLISHED -t | wc -l" == 0
# active samba sessions?
no-samba "smbstatus -j | jq '.sessions | length'" <= 0
# active processes for snapraid or restic?
no-snapraid "pgrep -lc snapraid" == 0
no-restic "pgrep -lc restic" == 0
# audio playing?
no-alsa "cat /proc/asound/card*/*p/*/status | grep RUNNING | wc -l" == 0
# five minute load average?
low-load5 "cat /proc/loadavg | cut -d ' ' -f 3" <= 2.5
# minimum uptime in seconds?
minimum-uptime "cat /proc/uptime | cut -d ' ' -f 1" >= 300
Command outputs are parsed to floating point numbers to compute the sensor values and sensors are treated as active when the expression comparing the value to the thresholds with the defined comparator evaluates to true.
Valid comparators are ==
, !=
, <
, >
, <=
and >=
.
The following sections will help you to get started if you want to help with the development of sensishell or just want to modify or compile it for yourself. No dependencies are required, but the easiest way to get started is still to just spin up a dev container from the included config.
This project is structured into multiple folders with different purposes:
As the configuration is read from STDIN
, sensishell makes zero assumptions about its runtime environment.
The complete source code is contained in sensishell.go
.
.github
,.devcontainer
,.vscode
: Contain configurations for the development infrastructure/bin
: Target folder for the compiled binaries, if the suppliedVS Code
build tasks are used, the resulting binaries will be ordered into subfolders of the format<os>/<architecture>
(These are only required if you want to contribute to the development of sensishell)
/config
: Exemplary application configuration files
All sensishell commands (executables) can be build using the default go toolchain:
go build ./...
Additionally, a GoReleaser
configuration is provided to automate the building of production ready releases for all target platforms using:
goreleaser release --clean
🐚 /ˈsen.sə.ʃel/ 🐚