]> git.wh0rd.org - home.git/commitdiff
long-lines: helper for finding long lines
authorMike Frysinger <vapier@gmail.com>
Sat, 22 Aug 2026 16:34:34 +0000 (23:34 +0700)
committerMike Frysinger <vapier@gmail.com>
Sat, 22 Aug 2026 16:34:34 +0000 (23:34 +0700)
.bin/long-lines [new file with mode: 0755]

diff --git a/.bin/long-lines b/.bin/long-lines
new file mode 100755 (executable)
index 0000000..d52abe2
--- /dev/null
@@ -0,0 +1,134 @@
+#!/usr/bin/env python3
+# Written by Mike Frysinger <vapier@gmail.com>.  Released into the public domain.
+
+"""Find long lines in text files."""
+
+import argparse
+from pathlib import Path
+import sys
+
+
+THIS_SCRIPT = Path(__file__).resolve()
+
+
+def get_parser() -> argparse.ArgumentParser:
+    """Get CLI parser."""
+    parser = argparse.ArgumentParser(description=__doc__)
+
+    # parser.add_argument("-c", "--count", action="store_true", help="Count how many lines match.")
+
+    parser.add_argument(
+        "--length", "--limit", default=80, type=int, help="Show lines longer than this."
+    )
+
+    parser.add_argument(
+        "-l",
+        "--list",
+        "--files-with-matches",
+        default=None,
+        action="store_true",
+        help="Print files that match.",
+    )
+    parser.add_argument(
+        "-L",
+        "--files-without-matches",
+        dest="list",
+        action="store_false",
+        help="Print files that do not match.",
+    )
+
+    parser.add_argument(
+        "-s",
+        "--with-size",
+        "--size",
+        default=False,
+        action="store_true",
+        help="Include line length.",
+    )
+    parser.add_argument(
+        "-S",
+        "--without-size",
+        dest="with_size",
+        action="store_false",
+        help="Do not include line length.",
+    )
+
+    parser.add_argument(
+        "-n",
+        "--line-number",
+        "--with-line-number",
+        dest="with_line_number",
+        default=True,
+        action="store_true",
+        help="Include line number.",
+    )
+    parser.add_argument(
+        "-N",
+        "--without-line-number",
+        dest="with_line_number",
+        action="store_false",
+        help="Do not include line number.",
+    )
+
+    parser.add_argument(
+        "--with-filename",
+        default=None,
+        action="store_true",
+        help="Prefix matches with the filename.",
+    )
+    parser.add_argument(
+        "-H",
+        "--without-filename",
+        dest="with_filename",
+        action="store_false",
+        help="Do not prefix matches with the filename.",
+    )
+
+    parser.add_argument("files", metavar="file", nargs="+", type=Path)
+    return parser
+
+
+def main(argv: list[str]) -> int | None:
+    """The main entry point for scripts."""
+    parser = get_parser()
+    opts = parser.parse_args(argv)
+    if opts.length < 0:
+        parser.error(f"--length={opts.length} may not be negative")
+
+    with_filename = opts.with_filename
+    if with_filename is None:
+        with_filename = len(opts.files) > 1
+
+    ret = 0
+    for file in opts.files:
+        pfx = f"{file}:" if with_filename else ""
+        try:
+
+          with file.open(encoding="utf-8") as fp:
+            for i, line in enumerate(fp, start=1):
+                line = line.rstrip("\n")
+                if len(line) > opts.length:
+                    if opts.list is not None:
+                        if opts.list:
+                            print(file)
+                        break
+
+                    print(pfx, end="")
+                    if opts.with_line_number:
+                        print(f"{i}:", end="")
+                    if opts.with_size:
+                        print(f"{len(line)}:", end="")
+                    print(line)
+            else:
+                if opts.list is False:
+                    print(file)
+
+        except IOError as e:
+            print(f"{THIS_SCRIPT.name}: error: {file}: {e}", file=sys.stderr)
+            ret = 1
+
+    return ret
+
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv[1:]))