473,473 Members | 2,151 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Yet Another Command Line Parser

Regards.
In the standard library there are two modules for command line
parsing: optparse and getopt.
In the Python Cookbook there is another simple method for parsing,
using a docstring.

However sometimes (actually, in all my small scripts) one has a simple
function whose arguments are choosen on the command line.

For this reason I have written a simple module, optlist, that parses
the command line as it was a function's argument list.

It is more simple to post an example:
import optlist
def main(a, b, *args, **kwargs):
print 'a =', a
print 'b =', b

print 'args:', args
print 'kwargs:', kwargs

optlist.call(main)
And on the shell:
shell: script.py 10, 20, 100, x=1

Since sometimes one needs to keep the options, I have provided an
alternate syntax, here is an example:
import optlist

optlist.setup('a, b, *args, **kwargs')

print 'a =', optlist.a
print 'b =', optlist.b

print 'args:', optlist.args
print 'kwargs:', optlist.kwargs

Finally, the module is so small that I post it here:

-------------------------- optlist.py --------------------------------

import sys

# add spaces to avoids errors like: 1 2, 3 4 -> (12, 34)
_options = ' '.join(sys.argv[1:])

def call(func):
"""
Call func, passing to it the arguments from the command line
"""
exec('func(' + _options + ')')

def setup(template):
"""
Template is a string containing the argument list.
The command line options are evaluated according to the template
and the values are stored in the module dictionary
"""
exec('def helper(' + template +
'):\n\tglobals().update(locals())')
exec('helper(' + _options + ')')

----------------------------------------------------------------------

I hope that this is not 'Yet Another Unuseful Module' and that the
code is correct.

The only problem is that error messages are ugly.

Regards Manlio Perillo
Jul 18 '05 #1
9 1817
Manlio Perillo wrote:
# add spaces to avoids errors like: 1 2, 3 4 -> (12, 34)
_options = ' '.join(sys.argv[1:])

def call(func):
"""
Call func, passing to it the arguments from the command line
"""
exec('func(' + _options + ')') The only problem is that error messages are ugly.


And it's a huge security hole. What if I did
script.py "x=6)\
import os
os.system('ls -l')"

Even if not a security hole, it's tricky to handle the
combined shell and Python escaping rules

script.py x="This is a string"

won't work, while

script.py 'x="This is a string"'

should. Embedding ! and \escaped characters should be
even more fun.

Andrew
da***@dalkescientific.com
Jul 18 '05 #2
On Tue, 26 Oct 2004 19:33:42 GMT, Andrew Dalke <ad****@mindspring.com>
wrote:
Manlio Perillo wrote:
# add spaces to avoids errors like: 1 2, 3 4 -> (12, 34)
_options = ' '.join(sys.argv[1:])

def call(func):
"""
Call func, passing to it the arguments from the command line
"""
exec('func(' + _options + ')')
The only problem is that error messages are ugly.


And it's a huge security hole.


I know that executing arbitrary code is a security hole.
However it is intended for 'personal' use.
In this way for my scripts I have only to write a single line of code
for options handling.
Later, for production code, one can use getopt.

What if I did
script.py "x=6)\
import os
os.system('ls -l')"

A solution is to use eval, but this does not handle keyword arguments.
Even if not a security hole, it's tricky to handle the
combined shell and Python escaping rules

script.py x="This is a string"

won't work, while

script.py 'x="This is a string"'

should. Embedding ! and \escaped characters should be
even more fun.


I'm not a shell expert, but the solution isn't simply to use ' or ''?

script.py x='\n'

Thanks and regards Manlio Perillo
Jul 18 '05 #3
Manlio Perillo wrote:
Regards.
In the standard library there are two modules for command line
parsing: optparse and getopt.
In the Python Cookbook there is another simple method for parsing,
using a docstring.

However sometimes (actually, in all my small scripts) one has a simple
function whose arguments are choosen on the command line.

For this reason I have written a simple module, optlist, that parses
the command line as it was a function's argument list.

It is more simple to post an example:
import optlist
def main(a, b, *args, **kwargs):
print 'a =', a
print 'b =', b

print 'args:', args
print 'kwargs:', kwargs

optlist.call(main)
And on the shell:
shell: script.py 10, 20, 100, x=1


I think it would be better if this was called like
script 10 20 100 --x=1

With something like:

def parse_args(args):
kw = {}
pos = []
for arg in args:
if arg.startswith('--') and '=' in arg:
name, value = arg.split('=', 1)
kw[name] = value
else:
pos.append(arg)
return pos, kw

def call(func, args=None):
if args is None:
args = sys.argv[1:]
pos, kw = parse_args(args)
func(*pos, **kw)
This isn't exactly what you want, since you want Python expressions
(e.g., 10 instead of '10'). But adding expressions (using eval) should
be easy. Or, you can be more restrictive, and thus safer:

def coerce(arg_value):
try:
return int(arg_value)
except TypeError:
pass
try:
return float(arg_value)
except TypeError:
pass
return arg_value

Or a little less restrictive, allowing for dictionaries and lists, but
still falling back on strings:

def coerce(arg_value):
# as above for int and float
if arg_value[0] in ('[', '{'):
return eval(arg_value)
return arg_value
--
Ian Bicking / ia**@colorstudy.com / http://blog.ianbicking.org
Jul 18 '05 #4
Andrew Dalke <ad****@mindspring.com> wrote:
...
exec('func(' + _options + ')')

The only problem is that error messages are ugly.


And it's a huge security hole. What if I did

script.py "x=6)\
import os
os.system('ls -l')"


Not to defend exec (ugly thing it is), but in this case I'm not sure
what the security hole would be. If I enter that tricky commandline at
a shell prompt, it will be just as if i had executed the 'ls -l' at the
same shell prompt; weird, but where is the huge security hole? It's not
as if there were setuid shell scripts (is there...? I sure hope not!-).

IOW, what's the difference between that and the commandline

script.py 'x=6' && ls -l

for example? The latter is no security hole, after all.

I understand and agree with the other criticisms you extend to the OP's
code, but this one leaves me perplexed. exec is a huge security hole of
you're doing it on untrusted data, data supplied by somebody else than
the uid running the script; but how are commandline arguments
'untrusted'...?
Alex
Jul 18 '05 #5
Alex:
Not to defend exec (ugly thing it is), but in this case I'm not sure
what the security hole would be.
In some sense we're both right, or wrong. Security depends on
the system. If someone saw that code, found it interesting, added
it to a script, which passed through a few people to someone
who uses it as part of a public service, then it's possible a
malicious user of that service may be able to execute arbitrary
code on the server.

If I enter that tricky commandline at
a shell prompt, it will be just as if i had executed the 'ls -l' at the
same shell prompt; weird, but where is the huge security hole? It's not
as if there were setuid shell scripts (is there...? I sure hope not!-).
In that environment there are fewer problems.
but how are commandline arguments 'untrusted'...?


I had to think about that for a bit. Much of the work I do
(for money or otherwise) ends up being called by some sort
of web interface or is the interface to such code. Much of
the data I use can come from untrusted sources. So I've
developed a programming habit of being distrustful of any
data I get, even if it's from me.

As a consequence that also means I don't need to think about
the multiple levels in the system.

Andrew
da***@dalkescientific.com
Jul 18 '05 #6
Andrew Dalke <ad****@mindspring.com> wrote:
...
Not to defend exec (ugly thing it is), but in this case I'm not sure
what the security hole would be.


In some sense we're both right, or wrong. Security depends on


Yeah, I see your POV.
but how are commandline arguments 'untrusted'...?


I had to think about that for a bit. Much of the work I do
(for money or otherwise) ends up being called by some sort
of web interface or is the interface to such code. Much of
the data I use can come from untrusted sources. So I've
developed a programming habit of being distrustful of any
data I get, even if it's from me.

As a consequence that also means I don't need to think about
the multiple levels in the system.


Yes: never trusting any data anywhere is a safer habit to acquire, and
if you do get into that mindset your code will have fewer risks of
vulnerabilities. An "Only the paranoids survive" kind of stance.

However, it's an interesting characteristic of security that it is _not_
free: each security measure, precaution and stance carries a cost in
terms of convenience and productivity. In any given situation, there
_are_ upper limits to the total amount of such costs that can and will
be born in the name of security. Thus, I believe it's _good_ for
security to be aware exactly of how much security you're buying, what
threat you are warding off and to what extent, with each security
measure you are taking -- a cost/benefit analysis.

Many practices that weaken security _also_ damage code quality in other
ways, for example by being prone to hard-to-reproduce,
hard-to-track-down bugs. The 'exec' statement that you criticized
surely falls into that category. For _those_ practices, I believe that
cost/benefit analysis may well be nearly superfluous: the old slogan
"quality is free" has some truth to it, in as much as the costs of
making good quality code today tend to be repaid with interest in
lowering maintenance costs in the future, enhancing reusability, etc.

So I think a "knee-jerk reaction" against some kinds of 'code smells' is
quite OK. More generally, I'm not sure "knee-jerk security" is a net
win, though. The classic example is forcing people to use
12-characters-long, randomly assigned passwords that they can't change:
inevitably they _will_ write those passwords down somewhere, creating
far worse security risks than if some cost-benefit analysis had been
done to find a reasonable compromise between security and practicality.

These are rather general considerations, musings if you will, about
security and development practices, and in no way meant to defend the
'exec' statement you were criticizing.
Alex
Jul 18 '05 #7
Alex:
However, it's an interesting characteristic of security that it is _not_
free: each security measure, precaution and stance carries a cost in
terms of convenience and productivity.


Almost completely agreed, though I think there are cases where
a solution with better security doesn't have that tradeoff.

Using Python is one .. haven't had to worry much about stack
overflows, etc. and I've been much more productive. :)

Andrew
da***@dalkescientific.com
Jul 18 '05 #8
Andrew Dalke <ad****@mindspring.com> wrote:
Alex:
However, it's an interesting characteristic of security that it is _not_
free: each security measure, precaution and stance carries a cost in
terms of convenience and productivity.


Almost completely agreed, though I think there are cases where
a solution with better security doesn't have that tradeoff.

Using Python is one .. haven't had to worry much about stack
overflows, etc. and I've been much more productive. :)


Right, of course: more generally, increasing code quality tends to
enhance security as a side effect (since many bugs might potentially be
subject to security exploits), as I indicated, yet it also tends to
lower lifetime costs (since maintenance costs are such a high part of
lifetime costs).

Using Python _is_ a case of "increasing code quality"!-)
Alex
Jul 18 '05 #9
On Tue, 26 Oct 2004 19:33:42 GMT, Andrew Dalke <ad****@mindspring.com>
wrote:
Manlio Perillo wrote:
# add spaces to avoids errors like: 1 2, 3 4 -> (12, 34)
_options = ' '.join(sys.argv[1:])

def call(func):
"""
Call func, passing to it the arguments from the command line
"""
exec('func(' + _options + ')')
The only problem is that error messages are ugly.


And it's a huge security hole. What if I did
script.py "x=6)\
import os
os.system('ls -l')"


I'm not sure (it does not works on Windows 'shell'), have you run this
code? It does not raises a SyntaxError?
Even if not a security hole, it's tricky to handle the
combined shell and Python escaping rules

script.py x="This is a string"

won't work, while

script.py 'x="This is a string"'

Actually on Windows the right syntax is
script.py x='"This is a string"'
should. Embedding ! and \escaped characters should be
even more fun.

Thanks and regards Manlio Perillo

Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Boogie El Aceitoso | last post by:
Hi, I need a command line parser that understands filename swith spaces. Since I'm absolutelly sure I'm not the first developer to need a command line parser, I was wondering is there's a...
6
by: Jon Hewer | last post by:
hi i am writing a little script and currently implementing command line arguments following the guide by mark pilgrim from dive into python; ...
4
by: Greg B | last post by:
Well since getopt() doesn't seem to be compatible with Windows, and the free implementation of it for Windows that I found still had some annoying restrictions, I thought I'd whip up a simple...
17
by: News | last post by:
Hi everyone, My goal is to pull command switches/options from a file and then assign the values to select variables which would eventually be included in a class object. The data file looks...
2
by: PyPK | last post by:
Is there a Command line parser in python that can: 1. resolve conflicts 2. specify something like requires 3. and smart for ex: python test.py --a --b --c --d Case 1: If 'a' is an option...
8
by: Andrew Robert | last post by:
Hi Everyone. I tried the following to get input into optionparser from either a file or command line. The code below detects the passed file argument and prints the file contents but the...
6
by: 31337one | last post by:
Hello all, I was wondering if there is a C/C++ command line parser that works for linux AND windows. . Anyways, the ideal parser im looking for should be able to support multiple arguments...
16
by: John Salerno | last post by:
Here's my new project: I want to write a little script that I can type at the terminal like this: $ scriptname package1 where scriptname is my module name and any subsequent arguments are the...
0
by: vincent90152900 | last post by:
I'm trying to get PowerShell script to run a program. Here is the command line I need to run: "\"C:\\Program Files\\PDF2allTest\\pdf2all\" -c pdf2jpg -s \"c:\\test\\test\\01.pdf\" -or 600" I...
4
by: cjt22 | last post by:
Hi there. I just wondered whether anyone could recommend the correct way I should be passing command line parameters into my program. I am currently using the following code: def main(argv =...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.