PicoLisp Explored: Piping from the Command Line

Search for a command to run...

No comments yet. Be the first to comment.
In this series, some more advanced features of PicoLisp will be explained that have not been covered in the beginner's tutorial.
In this series, we will further explore functions and concepts of PicoLisp that have not been covered in the beginner's tutorial. Today we will talk about the set function. Although its purpose is simple (setting values to variables), the usage can ...
In our previous post, we introduced how to utilize Discrete Event Simulation (DES) in PicoLisp. Now, let's explore another application: a railroad model simulation that includes tracks and trains. The visualization is ASCII-based, so feel free to unl...

The Dining Philosophers

In this post, we will introduce the concept of co-routines and how they are handled in PicoLisp. This will be the foundation for the subsequent posts on Discrete Event Simulation and finally a couple of examples, including an ASCII model railway simu...

One of the many nice things of PicoLisp is that it comes with a built-in database. This makes it easy to collect and store our own data, for example via a mobile app. But not all data is best represented in tables and lists: sometimes a colorful litt...

In the last two posts, we have built a little app that shows the current location and displays the nearest ice cream shops: https://picolisp-explored.com/an-openstreetmap-app-written-in-picolisp-pt-1 https://picolisp-explored.com/an-openstreetmap-ap...

Today we will explore further input/output options in PicoLisp, specifically how to pipe input from the command line to a PicoLisp script. For the example, we will try to read the battery status of our laptop, but of course the principles apply to any kind of command line output.
This article builds up on the Input-Output functions post from the Beginner's Guide.
In Debian systems we can get the status of your system with the upower command. First, we need to find the path of your power source by enumerating our system with upower -e:
$ upower -e
/org/freedesktop/UPower/devices/line_power_ACAD
/org/freedesktop/UPower/devices/battery_BAT1
/org/freedesktop/UPower/devices/mouse_hidpp_battery_0
/org/freedesktop/UPower/devices/DisplayDevice
$ stands for commands which are executed in the terminal.
We can see a number of battery powered devices. The main one which powers my laptop is battery_BAT1.
Now we let's check the status of "battery_BAT1" by typing upower -i <path> which gives a lot of information such as vendor, path, model...:
$ upower -i /org/freedesktop/UPower/devices/battery_BAT1
native-path: BAT1
[...]
battery
[...]
state: discharging
warning-level: none
energy: 23,1186 Wh
energy-empty: 0 Wh
energy-full: 49,7364 Wh
energy-full-design: 55,2372 Wh
energy-rate: 13,3242 W
voltage: 15,018 V
time to empty: 1,7 hours
percentage: 46%
capacity: 90,0415%
technology: lithium-ion
[...]
Let's try to pipe this output to a simple PicoLisp script.
As we learned in the "Input-Output"-functions blog, we have two main options to read in from an input source:
read stops at specific delimitors such as whitespace or new-line,line reads in the full line. But what is our input source? Let's check the documentation of the in-function:
(in 'any . prg) -> anyOpens any as input channel during the execution of prg. The current input channel will be saved and restored appropriately. If the argument is NIL, standard input is used. If the argument is a symbol, it is used as a file name (opened for reading and writing if the first character is "+"). [...] Otherwise (if it is a list), it is taken as a command with arguments, and a pipe is opened for input. [...]
According to the docs, we have three main options:
in NILin <filename>in <list>.Let's try the third option and see if we can get the output to PicoLisp. It seems we need to transform the command to a list. What does that mean?
It's much easier than you might expect - it simply means we split up the words of the command like this: ("upower" "-i" "/org/freedesktop/UPower/devices/battery_BAT1").
Let's type pil + to open the PicoLisp REPL and try to get the first line:
: (in '("upower" "-i" "/org/freedesktop/UPower/devices/battery_BAT1") (line T))
-> " native-path: BAT1"
Note: the quote ' before the list is needed to escape evaluation. (line T) returns the list as single string instead of a list of single characters.
We get the first line of the command line printed as expected.
Now let's do the same using piping. In this case, we use input option 1) NIL to get the input from "the current input channel". We define a script called battery.l and try:
# <battery.l>
(in NIL
(prinl (line)) )
(bye)
Now we query the battery status from the command line and pipe it to the PicoLisp script.
$ upower -i /org/freedesktop/UPower/devices/battery_BAT1 | pil battery.l
native-path: BAT1
Again, we receive the first line as output.
upower gives us a lot of information, but probably we will not need all of it. Of course we could pre-format output using tools like grep, but let's try to do it in PicoLisp now.
Some helpful functions:
(from 'any): Skips the current input channel until one of the strings any is found, and starts subsequent reading from that point.(till 'any): Reads from the current input channel till a character contained in any is found (or until end of file if any is NIL).
-skip ['any]: Skips all whitespace (and comments if any is given) in the input stream.As an example, let's say we want to read out the battery status and percentage. As a reminder, the command line output has this format:
state: discharging
percentage: 46%
Let's add (from "percentage:") to our previous script.
: (in '("upower" "-i" "/org/freedesktop/UPower/devices/battery_BAT1") (from "percentage:") (line T]
-> " 70%"
] is a short form which closes all open parentheses.
The output is correct, but we have a lot of whitespace before the output. In order to prettify it a little bit, let's (skip) the whitespace:
: (in '("upower" "-i" "/org/freedesktop/UPower/devices/battery_BAT1") (from "percentage:") (skip) (line T]
-> "70%"
Looks good!
We are almost done, but let's make three small improvements:
"percentage:" string exists in our piped output before we try reading it. "state"A possible solution could look like this:
(in NIL
(when (from "state:")
(skip)
(prinl "Battery status: " (line))
(when (from "percentage:")
(skip)
(prinl (line) " remaining") ) ) )
(bye)
Calling the script returns:
$ upower -i /org/freedesktop/UPower/devices/battery_BAT1 | pil batt.l
Battery status: charging
49% remaining
The final script can be downloaded here.
http://manpages.ubuntu.com/manpages/trusty/man1/upower.1.html
https://askubuntu.com/questions/69556/how-do-i-check-the-batterys-status-via-the-terminal
https://software-lab.de/doc/index.html