Parsing a string with spaces from command line in Python

16,394

Solution 1

If you really want to use argparse add nargs='+' or nargs='*' to add_argument:

import argparse
parser = argparse.ArgumentParser(description='Parse input string')
parser.add_argument('string', help='Input String', nargs='+')
args = parser.parse_args()
arg_str = ' '.join(args.string)
print(arg_str)

python test.py abc xyz will produce abc xyz. * means that empty list is ok and + requires at least one word.

Alternatively you may just user sys.arg if you don't need anything fancy:

import sys
arg_str = ' '.join(sys.argv[1:])  # skip name of file
print(arg_str)

And if I may, I really like docopt so I would recommend it:

"""Usage:
  test.py <input>...
"""

import docopt
arguments = docopt.docopt(__doc__)
input_argument = ' '.join(arguments['<input>'])
print(input_argument)

Docopt generates parser based on help message, it's so great.

Solution 2

The "correct" approach is as already mentioned. But OP specifically asked:

I want it to parse without declaring the string as 'String I want to parse' but as String I want to parse

It is possible to do this with a custom action. The advantage of this approach over simply joining sys.argv[1:] is to address the following:

Is there anyway to tell the script to account for spaces and take the input as one string until either the end of the input is reached or another parse argument such as -s is reached?

We can add other options without them being mopped up into the 'string' argument:

import argparse

class MyAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, ' '.join(values))

parser = argparse.ArgumentParser(description='Parse input string')
parser.add_argument('string', help='Input String', nargs='+', action=MyAction)
parser.add_argument('--extra', '-s', help='Another Option!')

args = parser.parse_args()
print args

Demo:

$ python example.py abc def ghi
Namespace(extra=None, string='abc def ghi')
$ python example.py abc def ghi -s hello
Namespace(extra='hello', string='abc def ghi')
$ python example.py -s hello abc def ghi 
Namespace(extra='hello', string='abc def ghi')

Solution 3

The problem is you give five arguments instead of one. Put your string with space between double quote and it will work.

~ ❯❯❯ python test.py asd asd
usage: test.py [-h] string
test.py: error: unrecognized arguments: asd
~ ❯❯❯ python test.py "asd asd"
asd asd
~ ❯❯❯
Share:
16,394
wprins
Author by

wprins

Studied biology and biomedical engineering. Said wait, I like computers too. So here we are today. If you think I'm doing this for the badge, you're not right. But you're not wrong.

Updated on June 09, 2022

Comments

  • wprins
    wprins almost 2 years

    Is there a way to call my program in python and pass it a string I want it to parse without declaring the string as 'String I want to parse' but as String I want to parse

    import argparse
    
    #Parse command line for input
    parser = argparse.ArgumentParser(description='Parse input string')
    #position input argument
    parser.add_argument('string', help='Input String')
    
    args = parser.parse_args()
    arg_str = args.string
    
    print(arg_str)
    

    when I run $ python test.py String I want to parse I get the error: test.py: error: unrecognized arguments: I want to parse

    Is there anyway to tell the script to account for spaces and take the input as one string until either the end of the input is reached or another parse argument such as -s is reached?

  • wprins
    wprins over 8 years
    Thanks for the input @Just but I want my input to be typed without quotes
  • wprins
    wprins over 8 years
    Thank you this is great. Can you explain to me what: arg_str = ' '.join(args.string) is doing?
  • Piotrek Wilczyński
    Piotrek Wilczyński over 8 years
    When you use nargs then args.string is a list of strings, not single string (so the name of variable is unfortunate). ' '.join(['a', 'b', 'c'] results in 'a b c'.
  • wim
    wim over 8 years
    This approach may get hairy once "either the end of the input is reached or another parse argument such as -s is reached" , as mentioned in the question. If there are other options to parse, there will be some interesting coding required
  • Piotrek Wilczyński
    Piotrek Wilczyński over 8 years
    why? in my (not so extensive) experience it works and documentation of nargs doesn't mention any restrictions, it even gives example like this >>> parser.add_argument('--bar', nargs='*') >>> parser.add_argument('baz', nargs='*')
  • wim
    wim over 8 years
    Sorry, I was talking about the option to use ' '.join(sys.argv[1:]). Ideally I think this joining should be done by the ArgumentParser instance, rather than by manual post-processing on the args
  • Piotrek Wilczyński
    Piotrek Wilczyński over 8 years
    I wrote about it just as simpler alternative to using argparse, kinda ignoring comment by OP. It's probably unnecessary. I agree with the second part, that's why I upvoted your answer :).