Parsing command-line arguments similar to archlinux pacman

I'm creating a python script with usage in the same style as pacman in Arch Linux, summarized by:

prog <operation> [options] [targets]
  • operations are of the form -X (hyphen, uppercase letter), and one is required when calling the script.
  • options are of the form -x (hyphen, lowercase letter), and can mean different things for different operations.

For example:

  • pacman -Syu means perform the sync operation with refresh and sysupgrade options, upgrading the entire system with fresh packages.
  • pacman -Qu means perform the query operation with the upgrades option, listing all outdated packages.
  • pacman -Ss <arg> means perform the sync operation with the search option, which expects another argument as the pattern to search for in the sync packages.

The punchline:

I've been looking into the argparse library for python, trying to figure out how to implement this. I've run into some problems/design issues so far:

  • argparse only accepts hyphen-prefixed arguments as optional arguments. All my "operations" would show up as optional arguments, when one is definitely required.
  • I could make my script have one "positional"/required argument, which would be the operation (I would have to switch operations to words, like upgrade or add), followed by optional arguments. This, however, still wouldn't solve the same-option-symbol-working-differently issue, and also wouldn't let me easily list all the supported operations in the --help text.

What's the smoothest way to handle this argument parsing? I'm not against changing my command's usage, but as I said above, it doesn't seem to help my situation as far as I can tell.


Asked by: Aida142 | Posted: 30-11-2021

Answer 1

One option would be to make -S and -Q part of a mutually exclusive option group with the required keyword argument set to True. This wouldn't enforce the requirement to make those the first arguments given, nor would it restrict which other options could be used with each. You'd have to enforce the latter after calling parse_args.

Another option I thought of was to make -S and -Q subcommands. Calling add_parser with a first argument starting with '-' seems to be legal, but the errors you get when you actually try to call your script makes me think that either the support is buggy/unintended, or that the error reporting is buggy.

Answered by: Lenny484 | Posted: 01-01-2022

Answer 2

Yet another option would be to use getopt:

Answered by: Brianna503 | Posted: 01-01-2022

Answer 3

So I found this support for sub-commands buried in the argparse help. It's exactly what I need, with the only caveat being I am not using -X as the format for operations; I am just using words like add and search instead.

For completeness here's an example of using sub-parsers from the link above:

>>> # create the top-level parser
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo', action='store_true', help='foo help')
>>> subparsers = parser.add_subparsers(help='sub-command help')
>>> # create the parser for the "a" command
>>> parser_a = subparsers.add_parser('a', help='a help')
>>> parser_a.add_argument('bar', type=int, help='bar help')
>>> # create the parser for the "b" command
>>> parser_b = subparsers.add_parser('b', help='b help')
>>> parser_b.add_argument('--baz', choices='XYZ', help='baz help')
>>> # parse some argument lists
>>> parser.parse_args(['a', '12'])
Namespace(bar=12, foo=False)
>>> parser.parse_args(['--foo', 'b', '--baz', 'Z'])
Namespace(baz='Z', foo=True)

Answered by: Ada587 | Posted: 01-01-2022

Similar questions

python - How to prompt for user input and read command-line arguments

Closed. This question needs to be more focused. It ...

python - command-line options and arguments using getopt

I'm trying to write a piece of code in python to get command-line options and arguments using getopt module. Here is my code: import getopt import sys def usage (): print('Usage') def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'xy:') except getopt.GetoptError as err: print(err) usage() sys.exit() for o,a in opts: if o in ("-x", "--xxx"):...

ruby on rails - UTF-8 minus sign rejected in python command-line arguments

I am running python 2.6 on Ubuntu Lucent and having trouble getting the minus sign in negative command-line arguments to be interpreted properly, especially when the call to the script is initiated through the OS via Rails (using backquotes). In particular, the minus sign seems to be coming in as UTF-8. When command-line arguments are interpreted manually, as in: lng = float(sys.argv[4])

python - Passing Command-line Arguments in C++

I've been trying to learn how to extend Python 3 with C++, and I was recommended using Boost. I believe I've followed the procedure of setting up Boost::Python correctly so far, and I have the following code from here (saved as example.cpp) which builds successfully: #incl...

python - How can I get the command-line arguments in an embedded Pig script?

I'm writing an embedded pig script in python, and I'd like to pass arguments like this: $ pig arg1 arg2 I'd expect sys.argv to be ['', 'arg1', 'arg2'], but it's empty. Any idea how I can pass command-line arguments to an embedded pig script?

How to access command-line arguments from a Python script?

I am writing code in Python that I should run with the command line and when I call the script i should give some arguments that I would use in the code. What can I use to achieve that? To run the script it would be something like this: python s1 s2 s4 where s1, s2 and s4 would be the arguments that I would use in my code.

Passing Strings as Python command-line arguments

I’m able to pass ints and chars as Python command-line args, but can’t pass Strings successfully to the following: if __name__ == '__main__' : try : print(len(sys.argv)) arg1 = ast.literal_eval(sys.argv[1]) arg2 = ast.literal_eval(sys.argv[2]) print(arg1) print(arg2) except Exception : print('error') The following works:

Parsing command-line arguments in Python: array of variable length?

is it possible to create an array in Python with an variable length? I'm getting different kind of length from sys.argv when I start the program and I need as much array field as long as the string from sys.argv is. EDIT for better understanding: I wrote a python script which can controle the GPIO Ports of a Raspberry Pi Until now, the script is just able to control one port at the same time...

Can I pass command-line arguments to Abaqus python?

I have an abaqus python script I've been using for a parametric study. It is exhausting to go into the code and edit it every time I want to run different options. I'd like to be able to pass the script arguments so that I can run different options without needing to change the code. I'd like to do something like this... abaqus cae script=' --verbose --data=someData.dat' I...

python - Provide command-line arguments for function in file

This question already has answers here:

linux - How to make a python, command-line program autocomplete arbitrary things NOT interpreter

I am aware of how to setup autocompletion of python objects in the python interpreter (on unix). Google shows many hits for explanations on how to do this. Unfortunately, there are so many references to that it is difficult to find what I need to do, which is slightly different. I need to know how to enable, tab/auto completion of arbitrary items in a command-line program written in ...

java - OCSP command-line test tool?

Closed. This question does not meet Stack Overflow guid...

python - How to prompt for user input and read command-line arguments

Closed. This question needs to be more focused. It ...

eclipse - Integrating command-line generated python .coverage files with PyDev

My build environment is configured to compile, run and create coverage file at the command line (using Ned Batchelder tool). I'm using Eclipse with PyDev as my editor, but for practical reasons, it's not possible/convenient for me to convert my whole build environment to Eclipse (and thus generate the coverage data directly from the IDE, as it's designed to do) PyDev seems to be using the same ...

c++ - How do I compile a Visual Studio project from the command-line?

I'm scripting the checkout, build, distribution, test, and commit cycle for a large C++ solution that is using Monotone, CMake, Visual Studio Express 2008, and custom tests. All of the other parts seem pretty straight-forward, but I don't see how to compile the Visu...

How to make a simple command-line chat in Python?

I study network programming and would like to write a simple command-line chat in Python. I'm wondering how make receving constant along with inputing available for sending at any time. As you see, this client can do only one job at a time: from socket import * HOST = 'localhost' PORT = 21567 BUFSIZE = 1024 ADDR = (HOST, PORT) tcpCliSock = socket(AF_INET, SOCK_STREAM) tcpCliSock.connect(A...

interpreter - Persistent Python Command-Line History

I'd like to be able to "up-arrow" to commands that I input in a previous Python interpreter. I have found the readline module which offers functions like: read_history_file, write_history_file, and set_startup_hook. I'm not quite savvy enough to put this into practice though, so could someone please help? My thoughts on the solution are: (1) Modify .login PYTHO...

data structures - Processing command-line arguments in prefix notation in Python

I'm trying to parse a command-line in Python which looks like the following: $ ./command -o option1 arg1 -o option2 arg2 arg3 In other words, the command takes an unlimited number of arguments, and each argument may optionally be preceded with an -o option, which relates specifically to that argument. I think this is called a "prefix notation". In the Bourne shell I wo...

Display constantly updating information in-place in command-line window using python?

I am essentially building a timer. I have a python script that monitors for an event and then prints out the seconds that have elapsed since that event. Instead of an ugly stream of numbers printed to the command line, I would like to display only the current elapsed time "in-place"-- so that only one number is visible at any given time. Is there a simple way to do this? If possible I'd like to u...

python - How to write script output to file and command-line?

I have a long-running Python script that I run from the command-line. The script writes progress messages and results to the standard output. I want to capture everything the script write to the standard output in a file, but also see it on the command line. Alternatively, I want the output to go to the file immediately, so I can use tail to view the progress. I have tried this: python MyLongRu...

Still can't find your answer? Check out these communities...

PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python