3

GNU grep has an argument to print a certain number of extra lines around a matching line. From the man page:

-C NUM, -NUM, --context=NUM Print NUM lines of output context. Places a line containing a group separator (--) between contiguous groups of matches. With the -o or --only-matching option, this has no effect and a warning is given.

So I can do something like

grep -5 pattern file.txt

would be the equivalent of

grep -C 5 pattern file.txt

How can I emulate the -NUMBER behavior using argparse to where a user can pass in -NUM and I can get that number easily from argparse.

A silly way of doing this is to do something like this:

parser = argparse.ArgumentParser()
for i in range(1, 10000):
    parser.add_argument(f'-{i}', action='store_true', dest=f'border_lines_{i}', help=argparse.SUPPRESS)

args = parser.parse_args()

border_line_count = 0
for i in range(1, 10000):
    if getattr(args, f'border_lines_{i}'):
        border_line_count = i
        break

Basically, I add a bunch of hidden arguments for different -NUMs. Then find the one that is set. Is there a better way?

2
  • You have to define each '-1', '-3'. There's no generic or pattern flag definition. Commented Apr 1, 2021 at 4:27
  • grep probably dates from before the development of unix/POSIX getopt standards. It does its own parsing from scratch. Commented Apr 1, 2021 at 4:32

1 Answer 1

1

This is a way to do this, but I don't like it personally.

parser.add_argument('-', dest='border_lines')

will give you the basic behaviour you want. Note that this is a required argument and if you want this to be an optional argument, you could:

parser.add_argument('-', dest='border_lines', default=0)

A (weird) problem with this now is that it accepts only single digits. To fix that, you'll need to define and override the parse action.

 class ConcatAction(argparse.Action):
     def __call__(self, parser, namespace, values, option_string):
         value = int(''.join(values))
         setattr(namespace, 'border_lines', value)

Now you can use this as:

parser = argparse.ArgumentParser()
parser.add_argument('-', dest='border_lines', default=0, nargs='*', action=ConcatAction)
parser.parse_args('-555')  # Gives Namespace(border_lines=555)

I strongly feel that this will mess up with other arguments, I have not tested that. I repeat, I don't like this way and following python zen, we should be explicit (with arg name) and as clear as possible.

Sign up to request clarification or add additional context in comments.

2 Comments

I agree that it is a weird thing, was just trying to match some grep syntax with a quick python script to use my muscle memory.
@csm10495 right, I like to practice weird stuff often myself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.