mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-18 00:45:47 +00:00
276 lines
13 KiB
HTML
276 lines
13 KiB
HTML
POKI_PUT_TOC_HERE
|
|
|
|
<p/>
|
|
<button style="font-weight:bold;color:maroon;border:0" onclick="expand_all();" href="javascript:;">Expand all sections</button>
|
|
<button style="font-weight:bold;color:maroon;border:0" onclick="collapse_all();" href="javascript:;">Collapse all sections</button>
|
|
|
|
<h1>No output at all</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_no_output_at_all');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_no_output_at_all" style="display: block">
|
|
|
|
<p/>Try <tt>od -xcv</tt> and/or <tt>cat -e</tt> on your file to check for non-printable characters.
|
|
|
|
<p/>If you’re using Miller version less than 5.0.0 (try
|
|
<tt>mlr --version</tt> on your system to find out), when the
|
|
line-ending-autodetect feature was introduced, please see
|
|
<a href="http://johnkerl.org/miller-releases/miller-4.5.0/doc/index.html">here</a>.
|
|
|
|
</div>
|
|
<h1>Fields not selected</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_fields_not_selected');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_fields_not_selected" style="display: block">
|
|
|
|
<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.
|
|
|
|
</div>
|
|
<h1>Diagnosing delimiter specifications</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_diagnosing_delimiter_specifications');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_diagnosing_delimiter_specifications" style="display: block">
|
|
|
|
POKI_INCLUDE_ESCAPED(data/delimiter-examples.txt)HERE
|
|
|
|
</div>
|
|
<h1>How do I examine then-chaining?</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_examine_then_chaining');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_examine_then_chaining" style="display: block">
|
|
|
|
<p/>Then-chaining found in Miller is intended to function the same as Unix
|
|
pipes, but with less keystroking. 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, look at 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 --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 --opprint count-distinct -f Status,Payment_Type then sort -nr count data/then-example.csv}}HERE
|
|
|
|
Now if you use <tt>then</tt> to include another verb after that, the columns
|
|
<tt>Status</tt>, <tt>Payment_Type</tt>, and <tt>count</tt> will be the input to
|
|
that verb.
|
|
|
|
<p/>Note, by the way, that you’ll get the same results using pipes:
|
|
POKI_RUN_COMMAND{{mlr --csv count-distinct -f Status,Payment_Type data/then-example.csv | mlr --icsv --opprint sort -nr count}}HERE
|
|
|
|
</div>
|
|
<h1>I assigned $9 and it’s not 9th</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_9_not_9th');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_9_not_9th" style="display: block">
|
|
|
|
<p/> Miller records are ordered lists of key-value pairs. For NIDX format, DKVP
|
|
format when keys are missing, or CSV/CSV-lite format with
|
|
<tt>--implicit-csv-header</tt>, Miller will sequentially assign keys of the
|
|
form <tt>1</tt>, <tt>2</tt>, etc. But these are not integer array indices:
|
|
they’re just field names taken from the initial field ordering in the
|
|
input data.
|
|
|
|
POKI_RUN_COMMAND{{echo x,y,z | mlr --dkvp cat}}HERE
|
|
POKI_RUN_COMMAND{{echo x,y,z | mlr --dkvp put '$6="a";$4="b";$55="cde"'}}HERE
|
|
POKI_RUN_COMMAND{{echo x,y,z | mlr --nidx cat}}HERE
|
|
POKI_RUN_COMMAND{{echo x,y,z | mlr --csv --implicit-csv-header cat}}HERE
|
|
POKI_RUN_COMMAND{{echo x,y,z | mlr --dkvp rename 2,999}}HERE
|
|
POKI_RUN_COMMAND{{echo x,y,z | mlr --dkvp rename 2,newname}}HERE
|
|
POKI_RUN_COMMAND{{echo x,y,z | mlr --csv --implicit-csv-header reorder -f 3,1,2}}HERE
|
|
|
|
</div>
|
|
<h1>How can I handle field names with special symbols in them?</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_field_names_with_special_symbols');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_field_names_with_special_symbols" style="display: block">
|
|
|
|
<p/>Simply surround the field names with curly braces:
|
|
|
|
POKI_RUN_COMMAND{{echo 'x.a=3,y:b=4,z/c=5' | mlr put '${product.all} = ${x.a} * ${y:b} * ${z/c}'}}HERE
|
|
|
|
</div>
|
|
<h1>How can I put single-quotes into strings?</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_single_quotes_in_strings');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_single_quotes_in_strings" style="display: block">
|
|
|
|
<p/> This is a little tricky due to the shell’s handling of quotes. For simplicity, let’s first put
|
|
an update script into a file:
|
|
|
|
POKI_INCLUDE_ESCAPED(data/single-quote-example.mlr)HERE
|
|
|
|
POKI_RUN_COMMAND{{echo a=bcd | mlr put -f data/single-quote-example.mlr}}HERE
|
|
|
|
<p/>So, it’s simple: Miller’s DSL uses double quotes for strings,
|
|
and you can put single quotes (or backslash-escaped double-quotes) inside
|
|
strings, no problem.
|
|
|
|
<p/> Without putting the update expression in a file, it’s messier:
|
|
|
|
POKI_RUN_COMMAND{{echo a=bcd | mlr put '$a="It'\''s OK, I said, '\''for now'\''."'}}HERE
|
|
|
|
<p/> The idea is that the outermost single-quotes are to protect the
|
|
<tt>put</tt> expression from the shell, and the double quotes within them are
|
|
for Miller. To get a single quote in the middle there, you need to actually put it <i>outside</i> the single-quoting
|
|
for the shell. The pieces are
|
|
|
|
<ul>
|
|
<li/> <tt>$a="It</tt>
|
|
<li/> <tt>\'</tt>
|
|
<li/> <tt>s OK, I said,</tt>
|
|
<li/> <tt>\'</tt>
|
|
<li/> <tt>for now</tt>
|
|
<li/> <tt>\'</tt>
|
|
<li/> <tt>.</tt>
|
|
</ul>
|
|
|
|
all concatenated together.
|
|
|
|
</div>
|
|
<h1>Why doesn’t mlr cut put fields in the order I want?</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_cut_out_of_order');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_cut_out_of_order" style="display: block">
|
|
|
|
<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
|
|
|
|
</div>
|
|
<h1>NR is not consecutive after then-chaining</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_NR_not_consecutive_after_then');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_NR_not_consecutive_after_then" style="display: block">
|
|
|
|
<p/> Given this input data:
|
|
POKI_RUN_COMMAND{{cat data/small}}HERE
|
|
|
|
why don’t I see <tt>NR=1</tt> and <tt>NR=2</tt> here??
|
|
|
|
POKI_RUN_COMMAND{{mlr filter '$x > 0.5' then put '$NR = NR' data/small}}HERE
|
|
|
|
<p/>The reason is that <tt>NR</tt> is computed for the original input records and isn’t dynamically
|
|
updated. By contrast, <tt>NF</tt> is dynamically updated: it’s the number of fields in the
|
|
current record, and if you add/remove a field, the value of <tt>NF</tt> will change:
|
|
|
|
POKI_RUN_COMMAND{{echo x=1,y=2,z=3 | mlr put '$nf1 = NF; $u = 4; $nf2 = NF; unset $x,$y,$z; $nf3 = NF'}}HERE
|
|
|
|
<p/><tt>NR</tt>, by contrast (and <tt>FNR</tt> as well), retains the value from the original input stream,
|
|
and records may be dropped by a <tt>filter</tt> within a <tt>then</tt>-chain. To recover consecutive record
|
|
numbers, you can use out-of-stream variables as follows:
|
|
|
|
POKI_INCLUDE_AND_RUN_ESCAPED(data/dynamic-nr.sh)HERE
|
|
|
|
<p/>Or, simply use <tt>mlr cat -n</tt>:
|
|
|
|
POKI_RUN_COMMAND{{mlr filter '$x > 0.5' then cat -n data/small}}HERE
|
|
|
|
</div>
|
|
<h1>Why am I not seeing all possible joins occur?</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_not_all_possible_joins');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_not_all_possible_joins" style="display: block">
|
|
|
|
<p/><b>This section describes behavior before Miller 5.1.0. As of 5.1.0, <tt>-u</tt> is the default.</b>
|
|
|
|
<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 -s -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 (before 5.1.0),
|
|
took 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> (which is now the default). 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.
|
|
|
|
</div>
|
|
<h1>What about XML or JSON file formats?</h1>
|
|
<button style="font-weight:bold;color:maroon;border:0" padding=0 onclick="toggle_by_name('section_toggle_xml_or_json');" href="javascript:;">Toggle section visibility</button>
|
|
<div id="section_toggle_xml_or_json" style="display: block">
|
|
|
|
<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 — this is a
|
|
general text-processing problem.
|
|
|
|
<p/>Miller does support tabular data represented in JSON: please see
|
|
POKI_PUT_LINK_FOR_PAGE(file-formats.html)HERE. See also <a
|
|
href="http://stedolan.github.io/jq/">jq</a> for a truly powerful, JSON-specific
|
|
tool.
|
|
|
|
<p/>For XML, my suggestion is to use a tool like
|
|
<a href="http://ff-extractor.sourceforge.net/">ff-extractor</a> to do format
|
|
conversion.
|
|
|
|
</div>
|