{
"schema_version": "1.0",
"command": "uniq",
"variant": "bsd",
"match": {
"platform": ["macos", "freebsd"],
"probe": { "args": ["--version"], "expect": "failure" },
"binary_globs": ["/usr/bin/uniq", "/bin/uniq"]
},
"mode": "authoritative",
"confidence": "verified",
"provenance": {
"platform": "macos",
"tool_version": "macOS 26.3",
"source": "man-page",
"checked_on": "2026-07-27",
"command": "man -P cat uniq | col -b",
"environment": "macOS 26.3 (Darwin arm64), system /usr/bin/uniq",
"notes": "Flags transcribed from the block after 'The following options are available:'. COMPATIBILITY and STANDARDS were read for flags documented outside that block: STANDARDS adds none, COMPATIBILITY records that 'the historic +number and -number options have been deprecated but are still supported in this implementation'. Both were confirmed against the binary ('uniq -1' and 'uniq +1' exit 0); they are a family of numeric operands rather than named options, so the overlay format cannot carry them, and they are deprecated aliases for -f number and -s chars. The named option set is closed: the binary's getopt(3) option string is '+D::cdif:s:u', so mode is authoritative. All seven long forms were run against the binary and exited 0; -D takes an optional argument, so only the attached forms '-Dprepend' and '--all-repeated=prepend' pass a septype, while '-D separate' reads 'separate' as an input file. An unknown septype is rejected ('uniq -Dbogus' fails). conflicts_with: -d and -D come from '-d ... Ignored if -D is also specified'; the binary accepts the pairing rather than diagnosing it, which is the same shape as GNU cp's '-f ... is ignored when the -n option is also used', already recorded as a conflict in cp@gnu.json. -u against -d and -D is not diagnosed and is not described as exclusive anywhere in this page, but neither is it last-one-wins: -d wins in BOTH orders ('uniq -d -u' and 'uniq -u -d' each print the -d output, while -u alone prints a different set), and -D wins in both orders likewise. One side is silently discarded either way, so both pairs are recorded as conflicts. GNU uniq differs: there '-d -u' yields the empty set and '-D -u' the -d output, the same whichever order they are given, so neither is declared on that side. The man page describes -s as taking effect 'in conjunction with the -f, --unique option'; --unique is -u, not -f, so the description below names --skip-fields, which is what -f actually is. BSD uniq rejects --version (exit 1, 'unrecognized option `--version''), which is why the probe matches on failure. annotations: readonly is false because uniq writes its second operand -- 'uniq input_file output_file' truncates and rewrites output_file, verified against a pre-existing file. conflicts_with was extended in a later pass, after the field's definition widened to cover override groups as well as diagnosed errors: apexe's input is a JSON object, which carries no ordering, so for a last-one-wins group which flag actually wins is decided by the order the caller happened to write the keys in. Every pair added then was run in BOTH orders against the reference build recorded above, and only pairs whose outcome depends on that order, or where one side is silently discarded, were added. value_optional was added on 2026-08-24 and established behaviourally on the build recorded above, since a BSD man page has no notation for an optional option argument: each candidate was run in BOTH spellings and marked only when the separated form demonstrably lost the value. `uniq --all-repeated prepend s.txt` is \"uniq: prepend: No such file or directory\" (exit 1) while `uniq --all-repeated=prepend s.txt` succeeds. The short form -D is optional-valued too, but apexe emits the long literal, which is the spelling the attached form needs. --skip-fields and --skip-chars were tested and NOT marked; both accept the separated form."
},
"description": "The uniq utility reads the specified input_file comparing adjacent lines, and writes a copy of each unique input line to the output_file. If input_file is a single dash (-) or absent, the standard input is read. If output_file is absent, standard output is used for output. The second and succeeding copies of identical adjacent input lines are not written. Repeated lines in the input will not be detected if they are not adjacent, so it may be necessary to sort the files first.",
"flags": [
{ "short": "-c", "long": "--count", "type": "boolean", "description": "Precede each output line with the count of the number of times the line occurred in the input, followed by a single space." },
{ "short": "-d", "long": "--repeated", "type": "boolean", "conflicts_with": ["-D", "-u"], "description": "Output a single copy of each line that is repeated in the input. Ignored if -D is also specified." },
{ "short": "-D", "long": "--all-repeated", "type": "enum", "value_name": "septype", "value_optional": true, "enum_values": ["none", "prepend", "separate"], "conflicts_with": ["-d", "-u"], "description": "Output all lines that are repeated (like -d, but each copy of the repeated line is written). The optional septype argument controls how to separate groups of repeated lines in the output: none does not separate groups of lines (this is the default), prepend outputs an empty line before each group of lines, separate outputs an empty line after each group of lines. The septype must be attached, as in -Dprepend or --all-repeated=prepend." },
{ "short": "-f", "long": "--skip-fields", "type": "integer", "value_name": "num", "description": "Ignore the first num fields in each input line when doing comparisons. A field is a string of non-blank characters separated from adjacent fields by blanks. Field numbers are one based, i.e., the first field is field one." },
{ "short": "-i", "long": "--ignore-case", "type": "boolean", "description": "Case insensitive comparison of lines." },
{ "short": "-s", "long": "--skip-chars", "type": "integer", "value_name": "chars", "description": "Ignore the first chars characters in each input line when doing comparisons. If specified in conjunction with the -f, --skip-fields option, the first chars characters after the first num fields will be ignored. Character numbers are one based, i.e., the first character is character one." },
{ "short": "-u", "long": "--unique", "type": "boolean", "conflicts_with": ["-d", "-D"], "description": "Only output lines that are not repeated in the input." }
],
"positional_args": [
{ "name": "input_file", "type": "path", "required": false, "description": "File to read. A single dash (-) or no operand reads the standard input." },
{ "name": "output_file", "type": "path", "required": false, "description": "File to write. It is truncated and rewritten. With no operand the standard output is used." }
],
"annotations": {
"readonly": false,
"destructive": true,
"idempotent": true,
"requires_approval": true
}
}