diff --git a/docs/src/keystroke-savers.md b/docs/src/keystroke-savers.md index ec15e9308..e8fbc9073 100644 --- a/docs/src/keystroke-savers.md +++ b/docs/src/keystroke-savers.md @@ -57,6 +57,208 @@ red square true 2 15 79.2778 0.0130 You can get the full list [here](file-formats.md#data-conversion-keystroke-savers). +## Omitting the verb for format conversions + +The verb defaults to [`cat`](reference-verbs.md#cat), so for pure format conversions you can leave the verb off entirely: + +
+mlr --c2j cat example.csv
+
+
+[
+{
+  "color": "yellow",
+  "shape": "triangle",
+  "flag": "true",
+  "k": 1,
+  "index": 11,
+  "quantity": 43.6498,
+  "rate": 9.8870
+},
+{
+  "color": "red",
+  "shape": "square",
+  "flag": "true",
+  "k": 2,
+  "index": 15,
+  "quantity": 79.2778,
+  "rate": 0.0130
+},
+{
+  "color": "red",
+  "shape": "circle",
+  "flag": "true",
+  "k": 3,
+  "index": 16,
+  "quantity": 13.8103,
+  "rate": 2.9010
+},
+{
+  "color": "red",
+  "shape": "square",
+  "flag": "false",
+  "k": 4,
+  "index": 48,
+  "quantity": 77.5542,
+  "rate": 7.4670
+},
+{
+  "color": "purple",
+  "shape": "triangle",
+  "flag": "false",
+  "k": 5,
+  "index": 51,
+  "quantity": 81.2290,
+  "rate": 8.5910
+},
+{
+  "color": "red",
+  "shape": "square",
+  "flag": "false",
+  "k": 6,
+  "index": 64,
+  "quantity": 77.1991,
+  "rate": 9.5310
+},
+{
+  "color": "purple",
+  "shape": "triangle",
+  "flag": "false",
+  "k": 7,
+  "index": 65,
+  "quantity": 80.1405,
+  "rate": 5.8240
+},
+{
+  "color": "yellow",
+  "shape": "circle",
+  "flag": "true",
+  "k": 8,
+  "index": 73,
+  "quantity": 63.9785,
+  "rate": 4.2370
+},
+{
+  "color": "yellow",
+  "shape": "circle",
+  "flag": "true",
+  "k": 9,
+  "index": 87,
+  "quantity": 63.5058,
+  "rate": 8.3350
+},
+{
+  "color": "purple",
+  "shape": "square",
+  "flag": "false",
+  "k": 10,
+  "index": 91,
+  "quantity": 72.3735,
+  "rate": 8.2430
+}
+]
+
+ +
+mlr --c2j --from example.csv
+
+
+[
+{
+  "color": "yellow",
+  "shape": "triangle",
+  "flag": "true",
+  "k": 1,
+  "index": 11,
+  "quantity": 43.6498,
+  "rate": 9.8870
+},
+{
+  "color": "red",
+  "shape": "square",
+  "flag": "true",
+  "k": 2,
+  "index": 15,
+  "quantity": 79.2778,
+  "rate": 0.0130
+},
+{
+  "color": "red",
+  "shape": "circle",
+  "flag": "true",
+  "k": 3,
+  "index": 16,
+  "quantity": 13.8103,
+  "rate": 2.9010
+},
+{
+  "color": "red",
+  "shape": "square",
+  "flag": "false",
+  "k": 4,
+  "index": 48,
+  "quantity": 77.5542,
+  "rate": 7.4670
+},
+{
+  "color": "purple",
+  "shape": "triangle",
+  "flag": "false",
+  "k": 5,
+  "index": 51,
+  "quantity": 81.2290,
+  "rate": 8.5910
+},
+{
+  "color": "red",
+  "shape": "square",
+  "flag": "false",
+  "k": 6,
+  "index": 64,
+  "quantity": 77.1991,
+  "rate": 9.5310
+},
+{
+  "color": "purple",
+  "shape": "triangle",
+  "flag": "false",
+  "k": 7,
+  "index": 65,
+  "quantity": 80.1405,
+  "rate": 5.8240
+},
+{
+  "color": "yellow",
+  "shape": "circle",
+  "flag": "true",
+  "k": 8,
+  "index": 73,
+  "quantity": 63.9785,
+  "rate": 4.2370
+},
+{
+  "color": "yellow",
+  "shape": "circle",
+  "flag": "true",
+  "k": 9,
+  "index": 87,
+  "quantity": 63.5058,
+  "rate": 8.3350
+},
+{
+  "color": "purple",
+  "shape": "square",
+  "flag": "false",
+  "k": 10,
+  "index": 91,
+  "quantity": 72.3735,
+  "rate": 8.2430
+}
+]
+
+ +The second form is equivalent to `mlr --c2j cat example.csv`. Piped stdin works the same way: `cat example.csv | mlr --c2j`. + ## File names up front, including --from Already, we saw that you can put the filename first using `--from`. When you're interacting with your data at the command line, this makes it easier to up-arrow and append to the previous command: diff --git a/docs/src/keystroke-savers.md.in b/docs/src/keystroke-savers.md.in index 648c63fc7..b39a6affc 100644 --- a/docs/src/keystroke-savers.md.in +++ b/docs/src/keystroke-savers.md.in @@ -14,6 +14,20 @@ GENMD-EOF You can get the full list [here](file-formats.md#data-conversion-keystroke-savers). +## Omitting the verb for format conversions + +The verb defaults to [`cat`](reference-verbs.md#cat), so for pure format conversions you can leave the verb off entirely: + +GENMD-RUN-COMMAND +mlr --c2j cat example.csv +GENMD-EOF + +GENMD-RUN-COMMAND +mlr --c2j --from example.csv +GENMD-EOF + +The second form is equivalent to `mlr --c2j cat example.csv`. Piped stdin works the same way: `cat example.csv | mlr --c2j`. + ## File names up front, including --from Already, we saw that you can put the filename first using `--from`. When you're interacting with your data at the command line, this makes it easier to up-arrow and append to the previous command: diff --git a/docs/src/manpage.md b/docs/src/manpage.md index 8a4de9a56..71f87da1b 100644 --- a/docs/src/manpage.md +++ b/docs/src/manpage.md @@ -26,9 +26,13 @@ This is simply a copy of what you should see on running `man mlr` at a command p as CSV and tabular JSON. 1mSYNOPSIS0m - Usage: mlr [flags] {verb} [verb-dependent options ...] {zero or more + Usage: mlr [flags] [verb] [verb-dependent options ...] {zero or more file names} + If no verb is given, "cat" is used, which is handy for format + conversions, e.g. + mlr --c2j < example.csv + If zero file names are provided, standard input is read, e.g. mlr --csv sort -f shape example.csv @@ -3846,5 +3850,5 @@ This is simply a copy of what you should see on running `man mlr` at a command p MIME Type for Comma-Separated Values (CSV) Files, the Miller docsite https://miller.readthedocs.io - 2026-05-16 4mMILLER24m(1) + 2026-05-17 4mMILLER24m(1) diff --git a/docs/src/manpage.txt b/docs/src/manpage.txt index c505c8ee4..e55be814b 100644 --- a/docs/src/manpage.txt +++ b/docs/src/manpage.txt @@ -5,9 +5,13 @@ as CSV and tabular JSON. 1mSYNOPSIS0m - Usage: mlr [flags] {verb} [verb-dependent options ...] {zero or more + Usage: mlr [flags] [verb] [verb-dependent options ...] {zero or more file names} + If no verb is given, "cat" is used, which is handy for format + conversions, e.g. + mlr --c2j < example.csv + If zero file names are provided, standard input is read, e.g. mlr --csv sort -f shape example.csv @@ -3825,4 +3829,4 @@ MIME Type for Comma-Separated Values (CSV) Files, the Miller docsite https://miller.readthedocs.io - 2026-05-16 4mMILLER24m(1) + 2026-05-17 4mMILLER24m(1) diff --git a/docs/src/online-help.md b/docs/src/online-help.md index f112b1e18..9571696d5 100644 --- a/docs/src/online-help.md +++ b/docs/src/online-help.md @@ -26,7 +26,10 @@ The front door is `mlr --help` or its synonym `mlr -h`. This leads you to `mlr h mlr --help
-Usage: mlr [flags] {verb} [verb-dependent options ...] {zero or more file names}
+Usage: mlr [flags] [verb] [verb-dependent options ...] {zero or more file names}
+
+If no verb is given, "cat" is used, which is handy for format conversions, e.g.
+  mlr --c2j < example.csv
 
 If zero file names are provided, standard input is read, e.g.
   mlr --csv sort -f shape example.csv
diff --git a/docs/src/reference-main-overview.md b/docs/src/reference-main-overview.md
index b7e1a97c4..de241cf5f 100644
--- a/docs/src/reference-main-overview.md
+++ b/docs/src/reference-main-overview.md
@@ -66,6 +66,8 @@ See also the [Glossary](glossary.md) for more about terms such as
 
 When you type `mlr {something} myfile.dat`, the `{something}` part is called a **verb**. It specifies how you want to transform your data. Most of the verbs are counterparts of built-in system tools like `cut` and `sort` -- but with file-format awareness, and giving you the ability to refer to fields by name.
 
+The verb is optional: if you omit it, Miller behaves as if you had written [`cat`](reference-verbs.md#cat), which is handy for pure format conversions such as `mlr --c2j < input.csv`.
+
 The verbs `put` and `filter` are special in that they have a rich expression language (domain-specific language, or "DSL"). More information about them can be found on the [Intro to Miller's Programming Language page](miller-programming-language.md); see also the [DSL Reference](reference-dsl.md) for more details.
 
 Here's a comparison of verbs and `put`/`filter` DSL expressions:
diff --git a/docs/src/reference-main-overview.md.in b/docs/src/reference-main-overview.md.in
index 42c3b8f0c..cd36e3583 100644
--- a/docs/src/reference-main-overview.md.in
+++ b/docs/src/reference-main-overview.md.in
@@ -35,6 +35,8 @@ See also the [Glossary](glossary.md) for more about terms such as
 
 When you type `mlr {something} myfile.dat`, the `{something}` part is called a **verb**. It specifies how you want to transform your data. Most of the verbs are counterparts of built-in system tools like `cut` and `sort` -- but with file-format awareness, and giving you the ability to refer to fields by name.
 
+The verb is optional: if you omit it, Miller behaves as if you had written [`cat`](reference-verbs.md#cat), which is handy for pure format conversions such as `mlr --c2j < input.csv`.
+
 The verbs `put` and `filter` are special in that they have a rich expression language (domain-specific language, or "DSL"). More information about them can be found on the [Intro to Miller's Programming Language page](miller-programming-language.md); see also the [DSL Reference](reference-dsl.md) for more details.
 
 Here's a comparison of verbs and `put`/`filter` DSL expressions:
diff --git a/docs/src/reference-verbs.md b/docs/src/reference-verbs.md
index 724f5bcd9..342c9d292 100644
--- a/docs/src/reference-verbs.md
+++ b/docs/src/reference-verbs.md
@@ -274,7 +274,27 @@ Options:
 
 ## cat
 
-Most useful for format conversions (see [File Formats](file-formats.md)) and concatenating multiple same-schema CSV files to have the same header:
+Most useful for format conversions (see [File Formats](file-formats.md)) and concatenating multiple same-schema CSV files to have the same header.
+
+`cat` is also the default verb: if you omit the verb entirely, Miller behaves as if you had written `cat`. This makes pure format conversions more concise:
+
+
+mlr --c2j < data/a.csv
+
+
+[
+{
+  "a": 1,
+  "b": 2,
+  "c": 3
+},
+{
+  "a": 4,
+  "b": 5,
+  "c": 6
+}
+]
+
 mlr cat -h
@@ -1828,7 +1848,7 @@ Same, but showing only unpaired records:
   data/join-right-example.csv
 
-status  idcode
+status  id
 missing 600
 
 id  name
diff --git a/docs/src/reference-verbs.md.in b/docs/src/reference-verbs.md.in
index 5f6f31097..adedd4829 100644
--- a/docs/src/reference-verbs.md.in
+++ b/docs/src/reference-verbs.md.in
@@ -155,7 +155,13 @@ GENMD-EOF
 
 ## cat
 
-Most useful for format conversions (see [File Formats](file-formats.md)) and concatenating multiple same-schema CSV files to have the same header:
+Most useful for format conversions (see [File Formats](file-formats.md)) and concatenating multiple same-schema CSV files to have the same header.
+
+`cat` is also the default verb: if you omit the verb entirely, Miller behaves as if you had written `cat`. This makes pure format conversions more concise:
+
+GENMD-RUN-COMMAND
+mlr --c2j < data/a.csv
+GENMD-EOF
 
 GENMD-RUN-COMMAND
 mlr cat -h
diff --git a/man/manpage.txt b/man/manpage.txt
index c505c8ee4..e55be814b 100644
--- a/man/manpage.txt
+++ b/man/manpage.txt
@@ -5,9 +5,13 @@
        as CSV and tabular JSON.
 
 1mSYNOPSIS0m
-       Usage: mlr [flags] {verb} [verb-dependent options ...] {zero or more
+       Usage: mlr [flags] [verb] [verb-dependent options ...] {zero or more
        file names}
 
+       If no verb is given, "cat" is used, which is handy for format
+       conversions, e.g.
+         mlr --c2j < example.csv
+
        If zero file names are provided, standard input is read, e.g.
          mlr --csv sort -f shape example.csv
 
@@ -3825,4 +3829,4 @@
        MIME Type for Comma-Separated Values (CSV) Files, the Miller docsite
        https://miller.readthedocs.io
 
-                                  2026-05-16                         4mMILLER24m(1)
+                                  2026-05-17                         4mMILLER24m(1)
diff --git a/man/mlr.1 b/man/mlr.1
index 7108bfde8..f1eca6002 100644
--- a/man/mlr.1
+++ b/man/mlr.1
@@ -2,12 +2,12 @@
 .\"     Title: mlr
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: ./mkman.rb
-.\"      Date: 2026-05-16
+.\"      Date: 2026-05-17
 .\"    Manual: \ \&
 .\"    Source: \ \&
 .\"  Language: English
 .\"
-.TH "MILLER" "1" "2026-05-16" "\ \&" "\ \&"
+.TH "MILLER" "1" "2026-05-17" "\ \&" "\ \&"
 .\" -----------------------------------------------------------------
 .\" * Portability definitions
 .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -29,7 +29,10 @@
 Miller \-\- like awk, sed, cut, join, and sort for name-indexed data such as CSV and tabular JSON.
 .SH "SYNOPSIS"
 .sp
-Usage: mlr [flags] {verb} [verb-dependent options ...] {zero or more file names}
+Usage: mlr [flags] [verb] [verb-dependent options ...] {zero or more file names}
+
+If no verb is given, "cat" is used, which is handy for format conversions, e.g.
+  mlr --c2j < example.csv
 
 If zero file names are provided, standard input is read, e.g.
   mlr --csv sort -f shape example.csv
diff --git a/pkg/climain/mlrcli_parse.go b/pkg/climain/mlrcli_parse.go
index 5963fc985..78837b557 100644
--- a/pkg/climain/mlrcli_parse.go
+++ b/pkg/climain/mlrcli_parse.go
@@ -245,9 +245,14 @@ func parseCommandLinePassOne(
 		}
 
 		if len(verbSequences) == 0 {
-			fmt.Fprintf(os.Stderr, "%s: no verb supplied.\n", "mlr")
-			help.MainUsage(os.Stderr)
-			os.Exit(1)
+			// Bare 'mlr' with no flags, no verb, and no files: keep the
+			// friendly usage banner. Anything else (e.g. 'mlr --c2j' on a
+			// piped stdin) defaults to 'cat'.
+			if argc == 1 {
+				help.MainUsage(os.Stderr)
+				os.Exit(1)
+			}
+			verbSequences = append(verbSequences, []string{"cat"})
 		}
 	}
 
diff --git a/pkg/terminals/help/entry.go b/pkg/terminals/help/entry.go
index 31d752e5f..6a9ed0563 100644
--- a/pkg/terminals/help/entry.go
+++ b/pkg/terminals/help/entry.go
@@ -244,7 +244,10 @@ func HelpMain(args []string) int {
 
 func MainUsage(o *os.File) {
 	fmt.Fprintf(o,
-		`Usage: mlr [flags] {verb} [verb-dependent options ...] {zero or more file names}
+		`Usage: mlr [flags] [verb] [verb-dependent options ...] {zero or more file names}
+
+If no verb is given, "cat" is used, which is handy for format conversions, e.g.
+  mlr --c2j < example.csv
 
 If zero file names are provided, standard input is read, e.g.
   mlr --csv sort -f shape example.csv
diff --git a/test/cases/cli-default-verb-cat/0001/cmd b/test/cases/cli-default-verb-cat/0001/cmd
new file mode 100644
index 000000000..728315268
--- /dev/null
+++ b/test/cases/cli-default-verb-cat/0001/cmd
@@ -0,0 +1 @@
+mlr --j2y < ./${CASEDIR}/input
diff --git a/test/cases/cli-default-verb-cat/0001/experr b/test/cases/cli-default-verb-cat/0001/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/cli-default-verb-cat/0001/expout b/test/cases/cli-default-verb-cat/0001/expout
new file mode 100644
index 000000000..7249bd885
--- /dev/null
+++ b/test/cases/cli-default-verb-cat/0001/expout
@@ -0,0 +1,3 @@
+- b: 22
+  c: 33
+  a: 11
diff --git a/test/cases/cli-default-verb-cat/0001/input b/test/cases/cli-default-verb-cat/0001/input
new file mode 100644
index 000000000..5fa6201b6
--- /dev/null
+++ b/test/cases/cli-default-verb-cat/0001/input
@@ -0,0 +1 @@
+{"b":22,"c":33,"a":11}
diff --git a/test/cases/cli-default-verb-cat/0002/cmd b/test/cases/cli-default-verb-cat/0002/cmd
new file mode 100644
index 000000000..8eef97542
--- /dev/null
+++ b/test/cases/cli-default-verb-cat/0002/cmd
@@ -0,0 +1 @@
+mlr --c2p < ./${CASEDIR}/input
diff --git a/test/cases/cli-default-verb-cat/0002/experr b/test/cases/cli-default-verb-cat/0002/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/cli-default-verb-cat/0002/expout b/test/cases/cli-default-verb-cat/0002/expout
new file mode 100644
index 000000000..d0c04ad13
--- /dev/null
+++ b/test/cases/cli-default-verb-cat/0002/expout
@@ -0,0 +1,3 @@
+a b c
+1 2 3
+4 5 6
diff --git a/test/cases/cli-default-verb-cat/0002/input b/test/cases/cli-default-verb-cat/0002/input
new file mode 100644
index 000000000..88700c714
--- /dev/null
+++ b/test/cases/cli-default-verb-cat/0002/input
@@ -0,0 +1,3 @@
+a,b,c
+1,2,3
+4,5,6
diff --git a/test/cases/cli-default-verb-cat/0003/cmd b/test/cases/cli-default-verb-cat/0003/cmd
new file mode 100644
index 000000000..beaf65901
--- /dev/null
+++ b/test/cases/cli-default-verb-cat/0003/cmd
@@ -0,0 +1 @@
+mlr --icsv --ojson --from test/input/example.csv
diff --git a/test/cases/cli-default-verb-cat/0003/experr b/test/cases/cli-default-verb-cat/0003/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/cli-default-verb-cat/0003/expout b/test/cases/cli-default-verb-cat/0003/expout
new file mode 100644
index 000000000..4277e2c14
--- /dev/null
+++ b/test/cases/cli-default-verb-cat/0003/expout
@@ -0,0 +1,92 @@
+[
+{
+  "color": "yellow",
+  "shape": "triangle",
+  "flag": "true",
+  "k": 1,
+  "index": 11,
+  "quantity": 43.64980000,
+  "rate": 9.88700000
+},
+{
+  "color": "red",
+  "shape": "square",
+  "flag": "true",
+  "k": 2,
+  "index": 15,
+  "quantity": 79.27780000,
+  "rate": 0.01300000
+},
+{
+  "color": "red",
+  "shape": "circle",
+  "flag": "true",
+  "k": 3,
+  "index": 16,
+  "quantity": 13.81030000,
+  "rate": 2.90100000
+},
+{
+  "color": "red",
+  "shape": "square",
+  "flag": "false",
+  "k": 4,
+  "index": 48,
+  "quantity": 77.55420000,
+  "rate": 7.46700000
+},
+{
+  "color": "purple",
+  "shape": "triangle",
+  "flag": "false",
+  "k": 5,
+  "index": 51,
+  "quantity": 81.22900000,
+  "rate": 8.59100000
+},
+{
+  "color": "red",
+  "shape": "square",
+  "flag": "false",
+  "k": 6,
+  "index": 64,
+  "quantity": 77.19910000,
+  "rate": 9.53100000
+},
+{
+  "color": "purple",
+  "shape": "triangle",
+  "flag": "false",
+  "k": 7,
+  "index": 65,
+  "quantity": 80.14050000,
+  "rate": 5.82400000
+},
+{
+  "color": "yellow",
+  "shape": "circle",
+  "flag": "true",
+  "k": 8,
+  "index": 73,
+  "quantity": 63.97850000,
+  "rate": 4.23700000
+},
+{
+  "color": "yellow",
+  "shape": "circle",
+  "flag": "true",
+  "k": 9,
+  "index": 87,
+  "quantity": 63.50580000,
+  "rate": 8.33500000
+},
+{
+  "color": "purple",
+  "shape": "square",
+  "flag": "false",
+  "k": 10,
+  "index": 91,
+  "quantity": 72.37350000,
+  "rate": 8.24300000
+}
+]
diff --git a/test/cases/cli-default-verb-cat/0004/cmd b/test/cases/cli-default-verb-cat/0004/cmd
new file mode 100644
index 000000000..4fe92612e
--- /dev/null
+++ b/test/cases/cli-default-verb-cat/0004/cmd
@@ -0,0 +1 @@
+${MLR}
diff --git a/test/cases/cli-default-verb-cat/0004/experr b/test/cases/cli-default-verb-cat/0004/experr
new file mode 100644
index 000000000..a0e8d6ffc
--- /dev/null
+++ b/test/cases/cli-default-verb-cat/0004/experr
@@ -0,0 +1,13 @@
+Usage: mlr [flags] [verb] [verb-dependent options ...] {zero or more file names}
+
+If no verb is given, "cat" is used, which is handy for format conversions, e.g.
+  mlr --c2j < example.csv
+
+If zero file names are provided, standard input is read, e.g.
+  mlr --csv sort -f shape example.csv
+
+Output of one verb may be chained as input to another using "then", e.g.
+  mlr --csv stats1 -a min,mean,max -f quantity then sort -f color example.csv
+
+Please see 'mlr help topics' for more information.
+Please also see https://miller.readthedocs.io
diff --git a/test/cases/cli-default-verb-cat/0004/expout b/test/cases/cli-default-verb-cat/0004/expout
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/cli-default-verb-cat/0004/should-fail b/test/cases/cli-default-verb-cat/0004/should-fail
new file mode 100644
index 000000000..e69de29bb