mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-22 15:37:59 +00:00
172 lines
7.2 KiB
HTML
172 lines
7.2 KiB
HTML
POKI_PUT_TOC_HERE
|
|
|
|
<h1>Number one FAQ</h1>
|
|
|
|
<b>
|
|
Please use <tt>mlr --csv --rs lf</tt> for native Un*x (linefeed-terminated) CSV files.
|
|
</b>
|
|
|
|
<h1>No output at all</h1>
|
|
|
|
<p/>Check the line-terminators of the data, e.g. with the command-line
|
|
<tt>file</tt> program. Example: for CSV, Miller’s default line terminator
|
|
is CR/LF (carriage return followed by linefeed, following
|
|
<a href="https://tools.ietf.org/html/rfc4180">RFC4180</a>). Yet if your CSV has
|
|
*nix-standard LF line endings, Miller will keep reading the file looking for a
|
|
CR/LF which never appears. Solution in this case: tell Miller the input has LF line-terminator, e.g. <b>mlr --csv --rs
|
|
lf {remaining arguments ...}</b>.
|
|
|
|
<p/>Also try <tt>od -xcv</tt> and/or <tt>cat -e</tt> on your file to check for non-printable characters.
|
|
|
|
<h1>Fields not selected</h1>
|
|
|
|
<p/>Check the field-separators of the data, e.g. with the command-line
|
|
<tt>head</tt> program. Example: for CSV, Miller’s default record
|
|
separator is comma; if your data is tab-delimited, e.g. <tt>aTABbTABc</tt>,
|
|
then Miller won’t find three fields named <tt>a</tt>, <tt>b</tt>, and
|
|
<tt>c</tt> but rather just one named <tt>aTABbTABc</tt>. Solution in this
|
|
case: <tt>mlr --fs tab {remaining arguments ...}</tt>.
|
|
|
|
<p/>Also try <tt>od -xcv</tt> and/or <tt>cat -e</tt> on your file to check for non-printable characters.
|
|
|
|
<h1>Diagnosing delimiter specifications</h1>
|
|
|
|
POKI_INCLUDE_ESCAPED(data/delimiter-examples.txt)HERE
|
|
|
|
<h1>Error-output in certain string cases</h1>
|
|
|
|
<p/> <tt>mlr put '$y = string($x)' then put '$z = $y . $y'</tt> gives
|
|
<tt>(error)</tt> on numeric data such as <tt>x=123</tt>, while <tt>mlr put
|
|
'$z=string($x).string($x)'</tt> and <tt>mlr put '$y = string($x); $z = $y .
|
|
$y'</tt> do not. This is because in the first case <tt>y</tt> is computed and
|
|
stored as a string, then re-parsed as an integer, for which
|
|
string-concatenation is an invalid operator. In the second case, casts are done
|
|
independently; in the third case, both assignments are within the same
|
|
<tt>put</tt> statement, where type information is maintained for the duration
|
|
of all assignments in the <tt>put</tt>.
|
|
|
|
<h1>How do I examine then-chaining?</h1>
|
|
|
|
<p/>Then-chaining found in Miller is intended to function the same as Unix
|
|
pipes. You can print your data one pipeline step at a time, to see what
|
|
intermediate
|
|
output at one step becomes the input to the next step.
|
|
|
|
<p/>First, review the input data:
|
|
|
|
POKI_RUN_COMMAND{{cat data/then-example.csv}}HERE
|
|
|
|
Next, run the first step of your command, omitting anything from the first <tt>then</tt> onward:
|
|
|
|
POKI_RUN_COMMAND{{mlr --icsv --rs lf --opprint count-distinct -f Status,Payment_Type data/then-example.csv}}HERE
|
|
|
|
After that, run it with the next <tt>then</tt> step included:
|
|
|
|
POKI_RUN_COMMAND{{mlr --icsv --rs lf --opprint count-distinct -f Status,Payment_Type then sort -nr count data/then-example.csv}}HERE
|
|
|
|
Now if you include another <tt>then</tt> step after this, the columns <tt>Status</tt>,
|
|
<tt>Payment_Type</tt>, and <tt>count</tt> will be its input.
|
|
|
|
<p/>Note, by the way, that you’ll get the same results using pipes:
|
|
POKI_RUN_COMMAND{{mlr --csv --rs lf count-distinct -f Status,Payment_Type data/then-example.csv | mlr --icsv --rs lf --opprint sort -nr count}}HERE
|
|
|
|
<h1>Why doesn’t mlr cut put fields in the order I want?</h1>
|
|
|
|
<p/>Example: columns <tt>x,i,a</tt> were requested but they appear here in the order <tt>a,i,x</tt>:
|
|
|
|
POKI_RUN_COMMAND{{cat data/small}}HERE
|
|
POKI_RUN_COMMAND{{mlr cut -f x,i,a data/small}}HERE
|
|
|
|
<p/>The issue is that Miller’s <tt>cut</tt>, by default, outputs cut fields in the order they
|
|
appear in the input data. This design decision was made intentionally to parallel the *nix system <tt>cut</tt>
|
|
command, which has the same semantics.
|
|
|
|
<p/>The solution is to use the <tt>-o</tt> option:
|
|
|
|
POKI_RUN_COMMAND{{mlr cut -o -f x,i,a data/small}}HERE
|
|
|
|
<h1>Why am I not seeing all possible joins occur?</h1>
|
|
|
|
<p/>For example, the right file here has nine records, and the left file should
|
|
add in the <tt>hostname</tt> column — so the join output should also have
|
|
9 records:
|
|
|
|
POKI_RUN_COMMAND{{mlr --icsvlite --opprint cat data/join-u-left.csv}}HERE
|
|
POKI_RUN_COMMAND{{mlr --icsvlite --opprint cat data/join-u-right.csv}}HERE
|
|
POKI_RUN_COMMAND{{mlr --icsvlite --opprint join -j ipaddr -f data/join-u-left.csv data/join-u-right.csv}}HERE
|
|
|
|
<p/>The issue is that Miller’s <tt>join</tt>, by default, takes input
|
|
sorted (lexically ascending) by the sort keys on both the left and right files.
|
|
This design decision was made intentionally to parallel the *nix system
|
|
<tt>join</tt> command, which has the same semantics. The benefit of this
|
|
default is that the joiner program can stream through the left and right files,
|
|
needing to load neither entirely into memory. The drawback, of course, is that
|
|
is requires sorted input.
|
|
|
|
<p/>The solution (besides pre-sorting the input files on the join keys) is to
|
|
simply use <b>mlr join -u</b>. This loads the left file entirely into memory
|
|
(while the right file is still streamed one line at a time) and does all
|
|
possible joins without requiring sorted input:
|
|
|
|
POKI_RUN_COMMAND{{mlr --icsvlite --opprint join -u -j ipaddr -f
|
|
data/join-u-left.csv data/join-u-right.csv}}HERE
|
|
|
|
<p/>General advice is to make sure the left-file is relatively small, e.g.
|
|
containing name-to-number mappings, while saving large amounts of data for the
|
|
right file.
|
|
|
|
<h1>What about XML or JSON file formats?</h1>
|
|
|
|
<p/>Miller handles <boldmaroon>tabular data</boldmaroon>, which is a list of
|
|
records each having fields which are key-value pairs. Miller also doesn’t
|
|
require that each record have the same field names (see also <a
|
|
href="record-heterogeneity.html">here</a>). Regardless, tabular data is a
|
|
<boldmaroon>non-recursive data structure</boldmaroon>.
|
|
|
|
<p/> XML, JSON, etc. are, by contrast, all <boldmaroon>recursive</boldmaroon>
|
|
or <boldmaroon>nested</boldmaroon> data structures. For example, in JSON
|
|
you can represent a hash map whose values are lists of lists.
|
|
|
|
<p/>Now, you can put tabular data into these formats — since list-of-key-value-pairs
|
|
is one of the things representable in XML or JSON. Example:
|
|
|
|
<p/>
|
|
<div class="pokipanel">
|
|
<pre>
|
|
# DKVP
|
|
x=1,y=2
|
|
z=3
|
|
|
|
# XML
|
|
<table>
|
|
<record>
|
|
<field>
|
|
<key> x </key> <value> 1 </value>
|
|
</field>
|
|
<field>
|
|
<key> y </key> <value> 2 </value>
|
|
</field>
|
|
</record>
|
|
<field>
|
|
<key> z </key> <value> 3 </value>
|
|
</field>
|
|
<record>
|
|
</record>
|
|
</table>
|
|
|
|
# JSON
|
|
[{"x":1,"y":2},{"z":3}]
|
|
</pre>
|
|
</div>
|
|
|
|
<p/>However, a tool like Miller which handles non-recursive data is never going
|
|
to be able to handle full XML/JSON semantics — only a small subset. If
|
|
tabular data represented in XML/JSON/etc are sufficiently well-structured, it
|
|
may be easy to grep/sed out the data into a simpler text form — but this
|
|
is a general text-processing problem.
|
|
|
|
<p/>My preference is to keep Miller doing what it does well, and to leave XML
|
|
to XML tools such as <tt>xmllint</tt> and JSON to JSON tools such as
|
|
<tt>jq</tt> or <tt>recs</tt>. Putting (necessarily) limited support for these
|
|
file formats into Miller seems like a slippery slope wherein inadequate
|
|
solutions would be delivered for an inherently unattainable goal.
|