I'm using a command shell on my script python to retrieve the Id of the last scenario created. (only 1 scenario)
I want to retrieve many scenarios by specifying an argument on my python in order to retrieve like 3 or 4 last scenario's ID.
This is my code:
import argparse
import os
import subprocess
import one_sdk
import time
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('num', help='Number of scenarios to select', default=1, type=int)
options = parser.parse_args()
process = "path/one-ctl so list kind:one.scenario.SharedScenario | tail -'{num}' | awk '{print $1}'"
retrieveId = subprocess.check_output(process, shell=True).rstrip()
print(retrieveId)
When I execute the script num is not known.
can anyone help me thanks to you all
try this:
process = "path/one-ctl so list kind:one.scenario.SharedScenario | tail -'%i' | awk '{print $1}'" % options.num
Related
I wrote a shell command inside Python to collect the IPv4 address in a server.
# cat ipv4.py
#!/usr/bin/env python3
import os
ipv4_regex = r'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
os_cmd = f"ip a s eth0 | egrep -o 'inet {ipv4_regex}' | cut -d' ' -f2"
os.system(os_cmd)
Output:
# ./ipv4.py
192.168.0.2
192.168.0.3
192.168.0.4
How do I append each IPv4 address from the above output to a list in Python?.
First of all, the return of the os.system() method you are invocating is not directly what you are expecting.
Instead, try using os.popen(), it is the same, essentialy, as the subprocess check_output() method:
import os
ipv4_regex = r'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
os_cmd = f"ip a s eth0 | egrep -o 'inet {ipv4_regex}' | cut -d' ' -f2"
x = os.popen(os_cmd).read()
Afterwards you can do some treatment in order get the return in the desired structure, creating a list from each line of x as example:
ips_list = x.split('\n')
You'll need the subprocess module to capture output from a process.
You'll probably have a better time finding your matches in Python rather than build a shell pipeline.
import re
import subprocess
import shlex
match_re = re.compile(
r"inet ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})"
)
def get_ips(interface_name):
ips = match_re.findall(
subprocess.check_output(
f"ip a s {shlex.quote(interface_name)}",
shell=True,
encoding="utf-8",
)
)
return ips
print(get_ips("eno1"))
This directly prints out (e.g.)
['192.168.1.20']
since findall() gets you the first capture group from the regexp.
This should do the trick:
import subprocess
x = subprocess.check_output(['os_cmd'])
I am trying to write data to a disk on a remote machine via ssh using a Python script. However it is giving an error of dd: /dev/xbd2d: Device not configured.
import argparse
import os
import time
parser = argparse.ArgumentParser(description='basis')
parser.add_argument("-g", default=1, help="")
args = parser.parse_args()
volume = args.g
instance_ip=10.1.12.3
cmd_ssh='ssh -tt -i basis.pem root#'+instance_ip+ ''' "date | dd of=/dev/xbd2d"'''
os.system(cmd_ssh)
What is quite unusual is that if use the command:
ssh -tt -i basis.pem root#10.1.12.3 "date | dd of=/dev/xbd2d"
in a terminal, it executes correctly without any problem and writes the data to the disk. I wrote the same script in C++ and it worked fine but for some reason Python gives me dd: /dev/xbd2d: Device not configured.
Checking the quotes around the variable and also using \" instead of the triple quotes solved my problem as recommended by Eran
import argparse
import os
import time
parser = argparse.ArgumentParser(description='basis')
parser.add_argument("-g", default=1, help="")
args = parser.parse_args()
volume = args.g
instance_ip=10.1.12.3
cmd_ssh="ssh -tt -i basis.pem root#"+str(instance_ip)+" \"date | dd of=/dev/xbd2d\""
os.system(cmd_ssh)
I want my script to take args like:
python myscript.py -i input.fastq -q 23 -l 30 -o outfile.fastq
not like
python myscript.py input.fastq 23 30 outfile.fastq
Is there any package available to do this in python?
You can use argparse for this:
For example python myscript.py -s customscriptvalue
import argparse
# Parse arguments
parser = argparse.ArgumentParser(description='Script options')
parser.add_argument('-s', '--script', help='Custom Script to execute', default=None)
result = parser.parse_args()
# Treat Arguments in your script
arguments = dict(result._get_kwargs())
if arguments['script'] is not None:
scriptMode = True
scriptPath = arguments['script']
See
https://docs.python.org/3/library/argparse.html
If I have the arguments '-a', '-b', '-c', '-d', with the add_mutually_exclusive_group() function my program will have to use just one of them. Is there a way to combine that, so that the program will accept only either '-a 999 -b 999' or '-c 999 -d 999'?
Edit: adding a simple program for more clarity:
>>> parser = argparse.ArgumentParser()
>>> group = parser.add_mutually_exclusive_group()
>>> group.add_argument('-a')
>>> group.add_argument('-b')
>>> group.add_argument('-c')
>>> group.add_argument('-d')
Then only ./app.py -a | ./app.py -b | ./app.py -c | ./app.py -d can be called. Is it possible to have argparse group the exclusion groups, so that only ./app.py -a .. -b .. | ./app.py -c .. -d .. be called?
EDIT: Never mind. Because argparse makes the horrible choice of having to create an option when invoking group.add_argument. That wouldn't be my design choice. If you're desperate for this feature, you can try doing it with ConflictsOptionParser:
# exclusivegroups.py
import conflictsparse
parser = conflictsparse.ConflictsOptionParser()
a_opt = parser.add_option('-a')
b_opt = parser.add_option('-b')
c_opt = parser.add_option('-c')
d_opt = parser.add_option('-d')
import itertools
compatible_opts1 = (a_opt, b_opt)
compatible_opts2 = (c_opt, d_opt)
exclusives = itertools.product(compatible_opts1, compatible_opts2)
for exclusive_grp in exclusives:
parser.register_conflict(exclusive_grp)
opts, args = parser.parse_args()
print "opts: ", opts
print "args: ", args
Thus when we invoke it, we can see we get the desired effect.
$ python exclusivegroups.py -a 1 -b 2
opts: {'a': '1', 'c': None, 'b': '2', 'd': None}
args: []
$ python exclusivegroups.py -c 3 -d 2
opts: {'a': None, 'c': '3', 'b': None, 'd': '2'}
args: []
$ python exclusivegroups.py -a 1 -b 2 -c 3
Usage: exclusivegroups.py [options]
exclusivegroups.py: error: -b, -c are incompatible options.
The warning message doesn't inform you that both '-a' and '-b' are incompatible with '-c', however a more appropriate error message could be crafted. Older, wrong answer below.
OLDER EDIT: [This edit is wrong, although wouldn't it be just a perfect world if argparse worked this way?] My previous answer actually was incorrect, you should be able to do this with argparse by specifying one group per mutually exclusive options. We can even use itertools to generalize the process. And make it so we don't have to type out all the combinations explicitly:
import itertools
compatible_opts1 = ('-a', '-b')
compatible_opts2 = ('-c', '-d')
exclusives = itertools.product(compatible_opts1, compatible_opts2)
for exclusive_grp in exclusives:
group = parser.add_mutually_exclusive_group()
group.add_argument(exclusive_grp[0])
group.add_argument(exclusive_grp[1])
Just stumbled on this problem myself. From my reading of the argparse docs, there doesn't seem to be a simple way to achieve that within argparse. I considered using parse_known_args, but that soon amounts to writing a special-purpose version of argparse ;-)
Perhaps a bug report is in order. In the meanwhile, if you're willing to make your user do a tiny bit extra typing, you can fake it with subgroups (like how git and svn's arguments work), e.g.
subparsers = parser.add_subparsers()
p_ab = subparsers.add_parser('ab')
p_ab.add_argument(...)
p_cd = subparsers.add_parser('cd')
p_cd.add_argument(...)
Not ideal, but at least it gives you the good from argparse without too much ugly hackery. I ended up doing away with the switches and just using the subparser operations with required subarguments.
The argparse enhancement request referenced in #hpaulj's comment is still open after more than nine years, so I figured other people might benefit from the workaround I just discovered. Based on this comment in the enhancement request, I found I was able to add an option to two different mutually-exclusive groups using this syntax:
#!/usr/bin/env python
import argparse
import os
import sys
def parse_args():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("-d", "--device", help="Path to UART device", default="./ttyS0")
mutex_group1 = parser.add_mutually_exclusive_group()
mutex_group2 = parser.add_mutually_exclusive_group()
mutex_group1.add_argument(
"-o",
"--output-file",
help="Name of output CSV file",
default="sensor_data_sent.csv",
)
input_file_action = mutex_group1.add_argument(
"-i", "--input-file", type=argparse.FileType("r"), help="Name of input CSV file"
)
# See: https://bugs.python.org/issue10984#msg219660
mutex_group2._group_actions.append(input_file_action)
mutex_group2.add_argument(
"-t",
"--time",
type=int,
help="How long to run, in seconds (-1 = loop forever)",
default=-1,
)
# Add missing ']' to usage message
usage = parser.format_usage()
usage = usage.replace('usage: ', '')
usage = usage.replace(']\n', ']]\n')
parser.usage = usage
return parser.parse_args()
if __name__ == "__main__":
args = parse_args()
print("Args parsed successfully...")
sys.exit(0)
This works well enough for my purposes:
$ ./fake_sensor.py -i input.csv -o output.csv
usage: fake_sensor.py [-h] [-d DEVICE] [-o OUTPUT_FILE | [-i INPUT_FILE | -t TIME]]
fake_sensor.py: error: argument -o/--output-file: not allowed with argument -i/--input-file
$ ./fake_sensor.py -i input.csv -t 30
usage: fake_sensor.py [-h] [-d DEVICE] [-o OUTPUT_FILE | [-i INPUT_FILE | -t TIME]]
fake_sensor.py: error: argument -t/--time: not allowed with argument -i/--input-file
$ ./fake_sensor.py -i input.csv
Args parsed successfully...
$ ./fake_sensor.py -o output.csv
Args parsed successfully...
$ ./fake_sensor.py -o output.csv -t 30
Args parsed successfully...
Accessing private members of argparse is, of course, rather brittle, so I probably wouldn't use this approach in production code. Also, an astute reader may notice that the usage message is misleading, since it implies that -o and -i can be used together when they cannot(!) However, I'm using this script for testing only, so I'm not overly concerned. (Fixing the usage message 'for real' would, I think, require much more time than I can spare for this task, but please comment if you know a clever hack for this.)
Subparsers?
Similar to unhammer's answer, but with more user control. Note: I have not actually tested this method, but it should work in theory and with the capabilities of python.
You can create two parsers, one for each of the two groups, and use conditionals to do the mutually exclusive part. Essentially using argparse for only part of the argument parsing. Using this method, you can go beyond the limitations of unhammer's answer as well.
# Python 3
import argparse
try:
parser = argparse.ArgumentParser()
parser.add_argument('-a')
parser.add_argument('-b')
args = parser.parse_args
except argparse.ArgumentError:
parser = argparse.ArgumentParser()
parser.add_argument('-c')
parser.add_argument('-d')
args = parser.parse_args
If I have the arguments '-a', '-b', '-c', '-d', with the add_mutually_exclusive_group() function my program will have to use just one of them. Is there a way to combine that, so that the program will accept only either '-a 999 -b 999' or '-c 999 -d 999'?
Edit: adding a simple program for more clarity:
>>> parser = argparse.ArgumentParser()
>>> group = parser.add_mutually_exclusive_group()
>>> group.add_argument('-a')
>>> group.add_argument('-b')
>>> group.add_argument('-c')
>>> group.add_argument('-d')
Then only ./app.py -a | ./app.py -b | ./app.py -c | ./app.py -d can be called. Is it possible to have argparse group the exclusion groups, so that only ./app.py -a .. -b .. | ./app.py -c .. -d .. be called?
EDIT: Never mind. Because argparse makes the horrible choice of having to create an option when invoking group.add_argument. That wouldn't be my design choice. If you're desperate for this feature, you can try doing it with ConflictsOptionParser:
# exclusivegroups.py
import conflictsparse
parser = conflictsparse.ConflictsOptionParser()
a_opt = parser.add_option('-a')
b_opt = parser.add_option('-b')
c_opt = parser.add_option('-c')
d_opt = parser.add_option('-d')
import itertools
compatible_opts1 = (a_opt, b_opt)
compatible_opts2 = (c_opt, d_opt)
exclusives = itertools.product(compatible_opts1, compatible_opts2)
for exclusive_grp in exclusives:
parser.register_conflict(exclusive_grp)
opts, args = parser.parse_args()
print "opts: ", opts
print "args: ", args
Thus when we invoke it, we can see we get the desired effect.
$ python exclusivegroups.py -a 1 -b 2
opts: {'a': '1', 'c': None, 'b': '2', 'd': None}
args: []
$ python exclusivegroups.py -c 3 -d 2
opts: {'a': None, 'c': '3', 'b': None, 'd': '2'}
args: []
$ python exclusivegroups.py -a 1 -b 2 -c 3
Usage: exclusivegroups.py [options]
exclusivegroups.py: error: -b, -c are incompatible options.
The warning message doesn't inform you that both '-a' and '-b' are incompatible with '-c', however a more appropriate error message could be crafted. Older, wrong answer below.
OLDER EDIT: [This edit is wrong, although wouldn't it be just a perfect world if argparse worked this way?] My previous answer actually was incorrect, you should be able to do this with argparse by specifying one group per mutually exclusive options. We can even use itertools to generalize the process. And make it so we don't have to type out all the combinations explicitly:
import itertools
compatible_opts1 = ('-a', '-b')
compatible_opts2 = ('-c', '-d')
exclusives = itertools.product(compatible_opts1, compatible_opts2)
for exclusive_grp in exclusives:
group = parser.add_mutually_exclusive_group()
group.add_argument(exclusive_grp[0])
group.add_argument(exclusive_grp[1])
Just stumbled on this problem myself. From my reading of the argparse docs, there doesn't seem to be a simple way to achieve that within argparse. I considered using parse_known_args, but that soon amounts to writing a special-purpose version of argparse ;-)
Perhaps a bug report is in order. In the meanwhile, if you're willing to make your user do a tiny bit extra typing, you can fake it with subgroups (like how git and svn's arguments work), e.g.
subparsers = parser.add_subparsers()
p_ab = subparsers.add_parser('ab')
p_ab.add_argument(...)
p_cd = subparsers.add_parser('cd')
p_cd.add_argument(...)
Not ideal, but at least it gives you the good from argparse without too much ugly hackery. I ended up doing away with the switches and just using the subparser operations with required subarguments.
The argparse enhancement request referenced in #hpaulj's comment is still open after more than nine years, so I figured other people might benefit from the workaround I just discovered. Based on this comment in the enhancement request, I found I was able to add an option to two different mutually-exclusive groups using this syntax:
#!/usr/bin/env python
import argparse
import os
import sys
def parse_args():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("-d", "--device", help="Path to UART device", default="./ttyS0")
mutex_group1 = parser.add_mutually_exclusive_group()
mutex_group2 = parser.add_mutually_exclusive_group()
mutex_group1.add_argument(
"-o",
"--output-file",
help="Name of output CSV file",
default="sensor_data_sent.csv",
)
input_file_action = mutex_group1.add_argument(
"-i", "--input-file", type=argparse.FileType("r"), help="Name of input CSV file"
)
# See: https://bugs.python.org/issue10984#msg219660
mutex_group2._group_actions.append(input_file_action)
mutex_group2.add_argument(
"-t",
"--time",
type=int,
help="How long to run, in seconds (-1 = loop forever)",
default=-1,
)
# Add missing ']' to usage message
usage = parser.format_usage()
usage = usage.replace('usage: ', '')
usage = usage.replace(']\n', ']]\n')
parser.usage = usage
return parser.parse_args()
if __name__ == "__main__":
args = parse_args()
print("Args parsed successfully...")
sys.exit(0)
This works well enough for my purposes:
$ ./fake_sensor.py -i input.csv -o output.csv
usage: fake_sensor.py [-h] [-d DEVICE] [-o OUTPUT_FILE | [-i INPUT_FILE | -t TIME]]
fake_sensor.py: error: argument -o/--output-file: not allowed with argument -i/--input-file
$ ./fake_sensor.py -i input.csv -t 30
usage: fake_sensor.py [-h] [-d DEVICE] [-o OUTPUT_FILE | [-i INPUT_FILE | -t TIME]]
fake_sensor.py: error: argument -t/--time: not allowed with argument -i/--input-file
$ ./fake_sensor.py -i input.csv
Args parsed successfully...
$ ./fake_sensor.py -o output.csv
Args parsed successfully...
$ ./fake_sensor.py -o output.csv -t 30
Args parsed successfully...
Accessing private members of argparse is, of course, rather brittle, so I probably wouldn't use this approach in production code. Also, an astute reader may notice that the usage message is misleading, since it implies that -o and -i can be used together when they cannot(!) However, I'm using this script for testing only, so I'm not overly concerned. (Fixing the usage message 'for real' would, I think, require much more time than I can spare for this task, but please comment if you know a clever hack for this.)
Subparsers?
Similar to unhammer's answer, but with more user control. Note: I have not actually tested this method, but it should work in theory and with the capabilities of python.
You can create two parsers, one for each of the two groups, and use conditionals to do the mutually exclusive part. Essentially using argparse for only part of the argument parsing. Using this method, you can go beyond the limitations of unhammer's answer as well.
# Python 3
import argparse
try:
parser = argparse.ArgumentParser()
parser.add_argument('-a')
parser.add_argument('-b')
args = parser.parse_args
except argparse.ArgumentError:
parser = argparse.ArgumentParser()
parser.add_argument('-c')
parser.add_argument('-d')
args = parser.parse_args