mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-22 23:48:30 +00:00
270 lines
7.5 KiB
Markdown
270 lines
7.5 KiB
Markdown
# The REPL
|
|
|
|
The Miller REPL (read-evaluate-print loop) is an interactive counterpart to record-processing using the `put`/`filter` language. (A REPL is anything that evaluates what you type into it -- like `python` with no arguments, or Ruby's `irb`, or `node` with no arguments, etc.)
|
|
|
|
Miller's REPL isn't a source-level debugger which lets you execute one source-code *statement* at a time -- however, it does let you operate on one *record* at a time. Further, it lets you use "immediate expressions", namely, you can interact with the [Miller programming language](miller-programming-language.md) without having to provide data from an input file.
|
|
|
|
GENMD-CARDIFY-HIGHLIGHT-ONE
|
|
mlr repl
|
|
|
|
[mlr] 1 + 2
|
|
3
|
|
|
|
[mlr] apply([1,2,3,4,5], func(e) {return e ** 3})
|
|
[1, 8, 27, 64, 125]
|
|
|
|
[mlr] :open example.csv
|
|
|
|
[mlr] :read
|
|
|
|
[mlr] $*
|
|
{
|
|
"color": "yellow",
|
|
"shape": "triangle",
|
|
"flag": "true",
|
|
"k": 1,
|
|
"index": 11,
|
|
"quantity": 43.6498,
|
|
"rate": 9.8870
|
|
}
|
|
|
|
[mlr] :context
|
|
FILENAME="example.csv",FILENUM=1,NR=1,FNR=1
|
|
GENMD-EOF
|
|
|
|
## Using Miller without the REPL
|
|
|
|
Using `put` and `filter`, you can do the following as we've seen above:
|
|
|
|
* Specify input format (e.g. `--icsv`), output format (e.g. `--ojson`), etc. using command-line flags.
|
|
* Specify filenames on the command line.
|
|
* Define `begin {...}` blocks which are executed before the first record is read.
|
|
* Define `end {...}` blocks which are executed after the last record is read.
|
|
* Define user-defined functions/subroutines using `func` and `subr`.
|
|
* Specify statements to be executed on each record -- which are anything outside of `begin`/`end`/`func`/`subr`.
|
|
* Example:
|
|
|
|
GENMD-RUN-COMMAND
|
|
mlr --icsv --ojson --from example.csv head -n 2 \
|
|
then put 'begin {print "HELLO"} $qr = $quantity / $rate; end {print "GOODBYE"}'
|
|
GENMD-EOF
|
|
|
|
## Using Miller with the REPL
|
|
|
|
Using the REPL, by contrast, you get interactive control over those same steps:
|
|
|
|
* Specify input format (e.g. `--icsv`), output format (e.g. `--ojson`), etc. using command-line flags.
|
|
* REPL-only statements (non-DSL statements) start with `:`, such as `:help` or `:quit`
|
|
or `:open`.
|
|
* Specify filenames either on the command line or via `:open` at the Miller REPL.
|
|
* Read records one at a time using `:read`.
|
|
* Write the current record (maybe after you've modified it with things like `$z = $x + $y`)
|
|
using `:write`. This goes to the terminal; you can use `:> {filename}` to make writes
|
|
go to a file, or `:>> {filename}` to append.
|
|
* You can type `:reopen` to go back to the start of the same file(s) you specified
|
|
with `:open`.
|
|
* Skip ahead using statements `:skip 10` or `:skip until NR == 100` or
|
|
`:skip until $status_code != 200`.
|
|
* Similarly, but processing records rather than skipping past them, using
|
|
`:process` rather than `:skip`. Like `:write`, these go to the screen;
|
|
use `:> {filename}` or `:>> {filename}` to log to a file instead.
|
|
* Define `begin {...}` blocks; invoke them at will using `:begin`.
|
|
* Define `end {...}` blocks; invoke them at will using `:end`.
|
|
* Define user-defined functions/subroutines using `func`/`subr`; call them from other statements.
|
|
* Interactively specify statements to be executed immediately on the current record.
|
|
* Load any of the above from Miller-script files using `:load`.
|
|
|
|
The input "record" by default is the empty map but you can do things like
|
|
`$x=3`, or `unset $y`, or `$* = {"x": 3, "y": 4}` to populate it. Or, `:open
|
|
foo.dat` followed by `:read` to populate it from a data file.
|
|
|
|
Non-assignment expressions, such as `7` or `true`, operate as filter conditions
|
|
in the `put` DSL: they can be used to specify whether a record will or won't be
|
|
included in the output-record stream. But here in the REPL, they are simply
|
|
printed to the terminal, e.g. if you type `1+2`, you will see `3`.
|
|
|
|
## Entering multi-line statements
|
|
|
|
* To enter multi-line statements, enter `<` on a line by itself, then the code (taking care
|
|
for semicolons), then `>` on a line by itself. These will be executed immediately.
|
|
* If you enter `<<` on a line by itself, then the code, then `>>` on a line by
|
|
itself, the statements will be remembered for executing on records with
|
|
`:main`, as if you had done `:load` to load statements from a file.
|
|
|
|
## Examples
|
|
|
|
Use the REPL to look at arithmetic:
|
|
|
|
GENMD-CARDIFY-HIGHLIGHT-ONE
|
|
mlr repl
|
|
|
|
[mlr] 6/3
|
|
2
|
|
|
|
[mlr] 6/5
|
|
1.2
|
|
|
|
[mlr] typeof(6/3)
|
|
int
|
|
|
|
[mlr] typeof(6/5)
|
|
float
|
|
GENMD-EOF
|
|
|
|
Read the first record from a small file:
|
|
|
|
GENMD-CARDIFY-HIGHLIGHT-ONE
|
|
mlr repl
|
|
|
|
[mlr] :open foo.dat
|
|
|
|
[mlr] :read
|
|
|
|
[mlr] :context
|
|
FILENAME="foo.dat",FILENUM=1,NR=1,FNR=1
|
|
|
|
[mlr] $*
|
|
{
|
|
"a": "eks",
|
|
"b": "wye",
|
|
"i": 4,
|
|
"x": 0.38139939387114097,
|
|
"y": 0.13418874328430463
|
|
}
|
|
|
|
[mlr] $z = $x + $i
|
|
|
|
[mlr] :write
|
|
a=eks,b=wye,i=4,x=0.38139939387114097,y=0.13418874328430463,z=4.381399393871141
|
|
GENMD-EOF
|
|
|
|
Skip until deep into a larger file, then inspect a record:
|
|
|
|
GENMD-CARDIFY-HIGHLIGHT-ONE
|
|
mlr repl --csv
|
|
|
|
[mlr] :open data/colored-shapes.csv
|
|
[mlr] :skip until NR == 10000
|
|
[mlr] :r
|
|
[mlr] $*
|
|
{
|
|
"color": "yellow",
|
|
"shape": "circle",
|
|
"flag": 1,
|
|
"i": 496422,
|
|
"u": 0.6530503199545348,
|
|
"v": 0.23908588907834516,
|
|
"w": 0.4799125551304738,
|
|
"x": 6.379888206335166
|
|
}
|
|
GENMD-EOF
|
|
|
|
## Parsing and operator precedence
|
|
|
|
You can invoke `mlr repl` with the `-v` or `-d` flags to show parse trees for expressions you enter.
|
|
(The `-v` and `-d` flags differ only in the format they use to present the parse trees.)
|
|
For example, if you have any questions about operator precedence, you can check the
|
|
[operator-precedence section](reference-dsl-operators.md#operator-precedence) -- or, you can
|
|
try it out and see for yourself:
|
|
|
|
GENMD-CARDIFY-HIGHLIGHT-ONE
|
|
mlr repl -v
|
|
Miller 6.0.0-rc1 REPL for darwin/amd64/go1.16.5
|
|
Docs: https://miller.readthedocs.io
|
|
Type ':h' or ':help' for online help; ':q' or ':quit' to quit.
|
|
[mlr] x = 1 * 2 + 3
|
|
* statement block
|
|
* assignment "="
|
|
* local variable "x"
|
|
* operator "+"
|
|
* operator "*"
|
|
* int literal "1"
|
|
* int literal "2"
|
|
* int literal "3"
|
|
[mlr] x = 1 + 2 * 3
|
|
* statement block
|
|
* assignment "="
|
|
* local variable "x"
|
|
* operator "+"
|
|
* int literal "1"
|
|
* operator "*"
|
|
* int literal "2"
|
|
* int literal "3"
|
|
GENMD-EOF
|
|
|
|
GENMD-CARDIFY-HIGHLIGHT-ONE
|
|
mlr repl -d
|
|
$ mrpl -d
|
|
Miller 6.0.0-rc1 REPL for darwin/amd64/go1.16.5
|
|
Docs: https://miller.readthedocs.io
|
|
Type ':h' or ':help' for online help; ':q' or ':quit' to quit.
|
|
[mlr] x = 1 * 2 + 3
|
|
(statement-block
|
|
(=
|
|
x
|
|
(+
|
|
(* 1 2)
|
|
3
|
|
)
|
|
)
|
|
)
|
|
[mlr] x = 1 + 2 * 3
|
|
(statement-block
|
|
(=
|
|
x
|
|
(+
|
|
1
|
|
(* 2 3)
|
|
)
|
|
)
|
|
)
|
|
GENMD-EOF
|
|
|
|
## History-editing
|
|
|
|
No command-line-history-editing feature is built in but **rlwrap mlr repl** is a
|
|
delight. You may need `brew install rlwrap`, `sudo apt-get install rlwrap`,
|
|
etc. depending on your platform.
|
|
|
|
Suggestion: `alias mrpl='rlwrap mlr repl'` in your shell's startup file.
|
|
|
|
## Customization
|
|
|
|
In your shell environment you can set the `MLR_REPL_PS1` and `MLR_REPL_PS2` environment variables if you like:
|
|
|
|
GENMD-CARDIFY
|
|
$ mlr repl -q
|
|
> 1+2
|
|
3
|
|
> <
|
|
... func f(x) {
|
|
... return x**2
|
|
... }
|
|
... >
|
|
> f(99)
|
|
9801
|
|
GENMD-EOF
|
|
|
|
GENMD-CARDIFY
|
|
$ export MLR_REPL_PS1='\nMLR REPL> '
|
|
$ export MLR_REPL_PS2=' '
|
|
$ mlr repl -q
|
|
|
|
MLR REPL> 1+2
|
|
3
|
|
|
|
MLR REPL> <
|
|
func f(x) {
|
|
return x**2
|
|
}
|
|
>
|
|
|
|
MLR REPL> f(99)
|
|
9801
|
|
GENMD-EOF
|
|
|
|
See also `MLR_REPL_PS1_COLOR` on the [output-colorization page](output-colorization.md).
|
|
|
|
## Online help
|
|
|
|
After `mlr repl`, type `:help` to see more about your options. In particular, `:help examples`.
|