views:

569

answers:

4

Hi guys, I'm writing a small program that's supposed to execute a command on a remote server (let's say a reasonably dumb wrapper around ssh [hostname] [command]).

I want to execute it as such:

./floep [command] 

However, I need to pass certain command lines from time to time:

./floep -v [command]

so I decided to use optparse.OptionParser for this. Problem is, I sometimes the command also has argument, which works fine if I do:

./floep -v "uname -a"

But I also want it to work when I use:

./floep -v uname -a

The idea is, as soon as I come across the first non-option argument, everything after that should be part of my command.

This, however, gives me:

Usage: floep [options]

floep: error: no such option: -a

Does OptionParser support this syntax? If so: how? If not: what's the best way to fix this?

A: 

You can use a bash script like this:

#!/bin/bash
while [ "-" == "${1:0:1}" ] ; do
  if [ "-v" == "${1}" ] ; then
    # do something
    echo "-v"
  elif [ "-s" == "${1}" ] ; then
    # do something
    echo "-s"
  fi
  shift
done
${@}

The ${@} gives you the rest of the command line that was not consumed by the shift calls. To use ssh you simply change the line from ${@} to ssh ${user}@${host} ${@}

test.sh echo bla
bla

test.sh -v echo bla
-v
bla

test.sh -v -s echo bla
-v
-s
bla

lothar
Even though your answer might be correct, for me this is an exercise in python
Evert
+1  A: 

OptionParser instances can actually be manipulated during the parsing operation for complex cases. In this case, however, I believe the scenario you describe is supported out-of-the-box (which would be good news if true! how often does that happen??). See this section in the docs: Querying and manipulating your option parser.

To quote the link above:

disable_interspersed_args()

Set parsing to stop on the first non-option. Use this if you have a command processor which runs another command which has options of its own and you want to make sure these options don’t get confused. For example, each command might have a different set of options.

Jarret Hardie
+6  A: 

Try using disable_interspersed_args()

#!/usr/bin/env python
from optparse import OptionParser

parser = OptionParser()
parser.disable_interspersed_args()
parser.add_option("-v", action="store_true", dest="verbose")
(options, args) = parser.parse_args()

print "Options: %s args: %s" % (options, args)

When run:

$ ./options.py foo -v bar
Options: {'verbose': None} args: ['foo', '-v', 'bar']
$ ./options.py -v foo  bar
Options: {'verbose': True} args: ['foo', 'bar']
$ ./options.py foo -a bar
Options: {'verbose': None} args: ['foo', '-a', 'bar']
Brian Campbell
Thank, you.. That's a very thorough answer and worked perfectly
Evert
+1  A: 
from optparse import OptionParser
import subprocess
import os
import sys

parser = OptionParser()
parser.add_option("-q", "--quiet",
                  action="store_true", dest="quiet", default=False,
                  help="don't print output")
parser.add_option("-s", "--signal",
                  action="store_true", dest="signal", default=False,
                  help="signal end of program and return code")

parser.disable_interspersed_args()
(options, command) = parser.parse_args()

if not command:
    parser.print_help()
    sys.exit(1)

if options.quiet:
    ret = subprocess.call(command, stdout=open(os.devnull, 'w'), 
                             stderr=subprocess.STDOUT)
else:
    ret = subprocess.call(command)

if options.signal:
    print "END OF PROGRAM!!! Code: %d" % ret
nosklo