From 0a09a38aac25ce2aa682770f8e88862ce7476c14 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 22 Aug 2026 23:34:34 +0700 Subject: [PATCH] long-lines: helper for finding long lines --- .bin/long-lines | 134 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100755 .bin/long-lines diff --git a/.bin/long-lines b/.bin/long-lines new file mode 100755 index 0000000..d52abe2 --- /dev/null +++ b/.bin/long-lines @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +# Written by Mike Frysinger . 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:])) -- 2.47.3