user33plus1
user33plus1

Reputation: 75

How do I pass arbitrary arguments in Python

In the assignment I have to do, I'm supposed to create an alternative to the 'rm' command. I have to pass variable number of arguments like ,

$ rm.py /path/to/some/file ./somefile someotherfile
$ rm.py /path/to/some/file ./somefile someotherfile -r
$ rm.py -r /path/to/some/file ./somefile someotherfile
$ rm.py *.java

the -r argument can be passed as any argument, at any place. the meaning of the -r is the same as in when using the regular 'rm' command. it recursively removes a directory and its contents within it.

it runs the script, and whichever path is given like

rm.py /path/to/some/file

it then moves that to the output directory '~/rm_trash' if there are duplicates, i worry about that as well.

But to start, I'm having some trouble understanding how to approach it. Should I go about it in a for loop, and if one of the arguments equals to the '-r' go from there?

Should i import and use argparse?

I have some more questions, but I'd like to first handle what I'm asking above.

Having to post again, still don't understand how I can get the specific argument for any number of argument besides the 'r'

Upvotes: 3

Views: 744

Answers (4)

lenik
lenik

Reputation: 23556

Why not use:

os.system( 'rm ' + ' '.join( sys.argv[1:] )

and get it done.

Upvotes: 0

hpaulj
hpaulj

Reputation: 231665

Define a parsing function, which looks for the '-r' string:

def parse(alist, astr='-r'):
    try:
        idx = alist.index(astr)
        r = alist.pop(idx)
        return True, alist
    except ValueError:
        return False, alist

If we do

import sys
r, rest = parse(sys.argv[1:])

should give a True/False value for r, and a list of file names. Use those in the rest of your code.

Testing:

In [326]: list1 = 'rm.py /path/to/some/file ./somefile someotherfile'.split()   
In [329]: r, rest = parse(list1[1:])                                            
In [330]: r, rest                                                               
Out[330]: (False, ['/path/to/some/file', './somefile', 'someotherfile'])

In [331]: list2 = 'rm.py /path/to/some/file ./somefile someotherfile -r'.split()                                                                     
In [332]: r, rest = parse(list2[1:])                                            
In [333]: r, rest                                                               
Out[333]: (True, ['/path/to/some/file', './somefile', 'someotherfile'])

To illustrate what happens when '-r' is present:

In [335]: list2.index('-r')                                                     
Out[335]: 4
In [336]: list2.pop(4)                                                          
Out[336]: '-r'
In [337]: list2                                                                 
Out[337]: ['rm.py', '/path/to/some/file', './somefile', 'someotherfile']

if it isn't present we get a ValueError:

In [338]: list1.index('-r')                                                     
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-338-807fbe60be44> in <module>
----> 1 list1.index('-r')

ValueError: '-r' is not in list

======

The equivalent functionality using argparse:

In [339]: import argparse                                                       
In [340]: parser = argparse.ArgumentParser()                                    
In [341]: parser.add_argument('-r', action='store_true', help='recursive flag');                                                                       
In [342]: parser.add_argument('rest', nargs='*', help='file names');            
In [343]: args = parser.parse_args(list1[1:])                                   

Use args = parser.parse_args() to read the sys.argv.

The result is a namespace object that has the needed attributes:

In [344]: args                                                                  
Out[344]: Namespace(r=False, rest=['/path/to/some/file', './somefile', 'someotherfile'])
In [345]: args.r                                                                
Out[345]: False
In [346]: args.rest                                                             
Out[346]: ['/path/to/some/file', './somefile', 'someotherfile']

Use args.r and args.rest in the same way as r and rest above.

The '-r' can be before or after the list of file names. argparse becomes more useful when you want to define more options like '-r'. It also takes care of displaying a help message, and meaningful errors.

In [347]: parser.parse_args(['--help'])                                         
usage: ipython3 [-h] [-r] [rest [rest ...]]

positional arguments:
  rest        file names

optional arguments:
  -h, --help  show this help message and exit
  -r          recursive flag

Upvotes: 1

NicholasM
NicholasM

Reputation: 4673

If you don't want to use argparse, or cannot for purposes of an assignment, you could look inside sys.argv:

is_recursive = any(arg == '-r' for arg in sys.argv)  

# `paths` will be a list of all other arguments
paths = [arg for arg in sys.argv if arg != '-r']   

Upvotes: 1

oppressionslayer
oppressionslayer

Reputation: 7224

I would use argparse, as you can specify out of order actions:

https://docs.python.org/3/library/argparse.html

Upvotes: 2

Related Questions