I have a series of flags...
--one
--two
-a
-b
-c
-d
I would like to have -a and -b required whenever I start with --one and -c, -d whenever I start with --two.
How exactly do I accomplish this? I know I can make an option required, but that's not the same as requiring options based on already given options.
Related
I have a bash script that takes two parameters. Inside that script, I need to call ssh using a heredoc and call a method that expects the two arguments. For example:
ssh -o "IdentitiesOnly=yes" -t -i $key -l user localhost << 'ENDSSH'
/my_python_app.py -u -t tar -p $1 -f $2
ENDSSH
key is set by my script, I know that part is good.
However, my_python_app prints out args and it doesn't show any arguments for -p and -f
I would call my script like
my_script /tmp filename
I use argparse in my python app, but I am also printing out sys.argv and it gives me:
['my_python_app.py', '-u', '-t', 'tar', '-p', '-f']
Note there are no values received for -p and -f. (-u is a flag, and that is set correctly).
How do I pass $1 and $2 to my_python_app as the -p and -f values?
Remove the quotes around the here-document delimiter (i.e. use << ENDSSH instead of << 'ENDSSH'). The quotes tell the shell not to expand variable references (and some other things) in the here-document, so $1 and $2 are passed through to the remote shell... which doesn't have any parameters so it replaces them with nothing.
BTW, removing the single-quotes may not fully work, since if either argument contains whitespace or shell metacharacters, the remote end will parse those in a way you probably don't intend. As long as neither argument can contain a single-quote, you can use this:
ssh -o "IdentitiesOnly=yes" -t -i $key -l user localhost << ENDSSH
/my_python_app.py -u -t tar -p '$1' -f '$2'
ENDSSH
If either might contain single-quotes, it gets a little more complicated.
The more paranoid way to do this would be:
# store these in an array to reduce the incidental complexity below
ssh_args=( -o "IdentitiesOnly=yes" -t -i "$key" -l user )
posixQuote() {
python -c 'import sys, pipes; sys.stdout.write(pipes.quote(sys.argv[1])+"\n")' "$#"
}
ssh "${ssh_args[#]}" localhost "bash -s $(posixQuote "$1") $(posixQuote "$2")" << 'ENDSSH'
/path/to/my_python_app.py -u -t tar -p "$1" -f "$2"
ENDSSH
If you know with certainty that the destination account's shell matches the local one (bash if the local shell is bash, ksh if the local shell is ksh), consider the following instead:
printf -v remoteCmd '%q ' /path/to/my_python_app.py -u -t tar -p "$1" -f "$2"
ssh "${ssh_args[#]}" localhost "$remoteCmd"
Is it possible to get --help message for a selected argument in command prompt?
Example:
python my_program.py -h in cmd will provide the whole help message.
Say my_program.py takes 2 cmdline argument -a and -b. Can I get the --help message of -a alone?
Something like this, python my_program.py -h -a. Is that possible?
I have the following options:
python runscript.py -O start -a "-a "\"-o \\\"-f/dev/sda1 -b256k -Q8\\\" -l test -p maim\""
runscript takes -O and -a and then sends remaining to shell script 1
shell script 1 takes option -a and should consider remaining \"-o \\\"-f/dev/sda1 -b256k -Q8\\\" -l test -p maim\" as argument to shell script 2
shell script 2 takes argument -o, -l and -p.
Can anyone please help me with this kind of scenario. I am stuck where shell script 1 considers and starts parsing argument -o too.
Is there a simple way to do. The hierarchy of shell script 1 calling 2 should be maintained.
Regards
Sai
The command you gave is bit confusing. I am generalizing the scenario. Is this something you meant?
python runscript.py -p1 v1 -p2 v2 -p3 v3
runscript.py will take all given parameters.
and calls shellsript_1.sh with selected params say -p2 v2
and then calls shellscript_2.sh with remaining params say -p3 v3
We may need more accurate explanation of the problem.
The conventional way to do this in UNIX is to split the argument list about a pivot (usually --) such that the main script consumes all the arguments to the left of the pivot and leaves the remaining arguments for the other script(s). If you have flexibility in your calling function, I'd recommend doing it this way.
So, if runscript.py and both shell scripts all need to consume a separate argument list, your command line would look something like this:
python runscript.py <args for runscript> -- <args for 1st script> -- <args for 2nd script>
For example (I'm just guessing at your hierarchy):
python runscript.py -O start -- -l test -p maim -- -f/dev/sda1 -b256k -Q8
I have found some code that I think will allow me to communicate with my Helios Heat recovery unit. I am relatively new to Python (but not coding in general) and I really cannot work out how to use this code. It is obviously written for smarthome.py but I'd like to use it from the command line.
I can also see that the way this file is constructed is probably not the best way to construct an __init__.py but I'd like to try and use it first.
So, how do I run this code? https://github.com/mtiews/smarthomepy-helios
Cheers
After git clone https://github.com/mtiews/smarthomepy-helios.git: either
invoke python with the __init__.py script as argument:
python smarthomepy-helios/__init__.py
or
make the __init__.py executable and run it:
chmod u+x smarthomepy-helios/__init__.py
smarthomepy-helios/__init__.py
Running it either way gives me
2016-02-20 18:07:51,791 - root - ERROR - Helios: Could not open /dev/ttyUSB0.
Exception: Not connected
But passing --help I get some nice synopsis:
$> python smarthomepy-helios/__init__.py --help
usage: __init__.py [-h] [-t PORT] [-r READ_VAR] [-w WRITE_VAR] [-v VALUE] [-d]
Helios ventilation system commandline interface.
optional arguments:
-h, --help show this help message and exit
-t PORT, --tty PORT Serial device to use
-r READ_VAR, --read READ_VAR
Read variables from ventilation system
-w WRITE_VAR, --write WRITE_VAR
Write variable to ventilation system
-v VALUE, --value VALUE
Value to write (required with option -v)
-d, --debug Prints debug statements.
Without arguments all readable values using default tty will be retrieved.
I am using python2.7 and argparse for my script. I am executing script as below:
python2.7 script.py -a valuefora -b valueforb -c valueforc -d valueford
Now what I want is that,
if option -a is given, then only -b, -c, -d options should be asked.
In addition to above, I also want to make this group -a -b -c -d as a EITHER OR for -e i.e. ([-a -b -c -d] | -e )
Please correct me anywhere I am wrong.
Your best choice is to test for the presence of various combinations after parse_args and use parser.error to issue an argparse compatible error message. And write your own usage line. And make sure the defaults clearly indicate whether an option has been parsed or not.
If you can change the -a and -e options to command names like cmda or build, you could use subparsers. In this case you might define a command_a subparser that accepts -b, -c, and -d, and another command_e subparser that has none of these. This is closes argparse comes to 'required together' groups of arguments.
mutually exclusive groups can define something with a usage like [-a -b -c], but that just means -b cannot occur along with -a and -c. But there's nothing fancy about that mechanism. It just constructs a dictionary of such exclusions, and checks it each time it parses a new option. If there is a conflict it issues the error message and quits. It is not set up to handle fancy combinations, such as your (-e | agroup).
Custom actions can also check for the absence or presence of non-default values in the namespace, much as you would after parsing. But doing so during parsing isn't any simpler. And it raises questions about order. Do you want to handle -b -c -a the same way as -a -c -b? Should -a check for the presence of the others, or should -b check that -a has already been parsed? Who checks for the presence, or absence of -e.
The are a number of other stack questions about argparse groups, exclusive and inclusive, but I think these are the essential issues.