1

i need to use shell command to run python script

but the args is a list the python script:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import sys

def main(task_list):
    print('task_list:',task_list)

if __name__=='__main__':
main(sys.argv[1])

when i use the shell python

python scrpit.py [("store", "IDCODE", 18116485, 88779)]

the system show: "(' have a error"

how can i trans the list into script ?

the ("store", "IDCODE", 18116485, 88779) is a arg

3 Answers3

0

The shell passes your program an array of strings, that Python turns into a list of strings. The shell doesn't know Python syntax. You could call your program like

$ python scrpit.py '[("store", "IDCODE", 18116485, 88779)]'

then use ast.literal_eval to parse that into a list.

import sys
import ast

if len(sys.argv) == 2:
    data = ast.literal_eval(sys.argv[1])
    print(data)

output

[('store', 'IDCODE', 18116485, 88779)]

However, it would be more robust to receive the args as separate strings.

import sys

if len(sys.argv) == 5:
    name, code, num1, num2 = sys.argv[1:]
    num1, num2 = int(num1), int(num2)
    data = [name, code, num1, num2]
    print(data)

Call it like

$ python scrpit.py "store" "IDCODE" 18116485 88779

And the output is

['store', 'IDCODE', 18116485, 88779]
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
0

A cleaner way to do what you ask (mostly if you need other parameters) would be to identify your list from another param and enumerate allowed types (convert if necessary), which would look something like this:

import sys, getopt
sh_params, args = getopt.getopt(sys.argv[1:], "l:")

def convert_type(elem):
    for fn in (int, lambda e: e.strip('"')): # Lambda is the string conversion function and int is auto-cast fct
        try:
            return fn(elem)
        except ValueError:
            pass
    return elem

my_list = []
for param, val in sh_params:
    if param == "-l":
        my_list = [convert_type(elem) for elem in val.strip('[]').split(', ')]
print(my_list)

here is the command & result:

$ python3 scrpit.py -l '["store", "IDCODE", 18116485, 88779]'
$ ['store', 'IDCODE', 18116485, 88779]

Remember, the alternative of PM 2Ring is still better!

Axel Paccalin
  • 136
  • 1
  • 13
0

Here's an alternative you might like: send it as a single string and import it as encoded json. Just "import json" and change your main() call to look like this:

main(json.JSONDecoder().decode(sys.argv[1]))

and call the script with the parameters inside single quotes, but leave out the ()'s so it looks like a proper json encoding:

python scrpit.py '["store", "IDCODE", 18116485, 88779]'

which gives me an output that looks like:

('task_list:', [u'store', u'IDCODE', 18116485, 88779])

This will also allow you to send more complex structures like:

python try.py '{"p2": {"a": 1, "b": 2}, "p1": ["a", "B", "c"]}'
('task_list:', {u'p2': {u'a': 1, u'b': 2}, u'p1': [u'a', u'B', u'c']})

Without analyzing the internals of the json decoder, I cannot say if it directly opens any security holes, but I can say you have to be careful how you use the decoded values to ensure you don't add any of your own.

Hope this helps.