If your code needs to be written just as it is (including the rather odd way of stringing together the ZPL code, and calling a separate script via a shell intermediary, and the avoidance of subprocess, for that matter), you can resolve your issue with a few small adjustments:
First, wrap your code string in double-quotes.
label= '"^XA'+"^FO20,20^BQ,2,3^FDQA,"+"001D4B02107A;1001000;49681207"+"^FS"+"^FO50,50"+"^ADN,36,20"+"^FD"+"MAC: "+"001D4B02107A"+"^FS"+"^FO50,150"+"^ADN,36,20"+"^FD"+"SN: "+"1001000"+"^FS"+"^FO50,250"+"^ADN,36,20"+"^FD" + "Code: "+"49681207"+"^FS"+'^XZ"'
Second, make sure you're actually calling python from the shell:
command = "python script2.py "+label
Finally, if you're concerned about special characters not being read in correctly from the command line, use unicode_escape from codecs.decode to ensure correct transmission.
See this answer for more on unicode_escape.
# contents of second script
if __name__ == "__main__":
from codecs import decode
import sys
zplString = decode(sys.argv[1], 'unicode_escape')
print(zplString)
Now the call from your first script will transmit the code correctly:
import sys
import os
sys.stdout.flush()
exitCode = os.system(str(command))
Output:
^XA^FO20,20^BQ,2,3^FDQA,001D4B02107A;1001000;49681207^FS^FO50,50^ADN,36,20^FDMAC: 001D4B02107A^FS^FO50,150^ADN,36,20^FDSN: 1001000^FS^FO50,250^ADN,36,20^FDCode: 49681207^FS^XZ
Answer from andrew_reece on Stack OverflowIf your code needs to be written just as it is (including the rather odd way of stringing together the ZPL code, and calling a separate script via a shell intermediary, and the avoidance of subprocess, for that matter), you can resolve your issue with a few small adjustments:
First, wrap your code string in double-quotes.
label= '"^XA'+"^FO20,20^BQ,2,3^FDQA,"+"001D4B02107A;1001000;49681207"+"^FS"+"^FO50,50"+"^ADN,36,20"+"^FD"+"MAC: "+"001D4B02107A"+"^FS"+"^FO50,150"+"^ADN,36,20"+"^FD"+"SN: "+"1001000"+"^FS"+"^FO50,250"+"^ADN,36,20"+"^FD" + "Code: "+"49681207"+"^FS"+'^XZ"'
Second, make sure you're actually calling python from the shell:
command = "python script2.py "+label
Finally, if you're concerned about special characters not being read in correctly from the command line, use unicode_escape from codecs.decode to ensure correct transmission.
See this answer for more on unicode_escape.
# contents of second script
if __name__ == "__main__":
from codecs import decode
import sys
zplString = decode(sys.argv[1], 'unicode_escape')
print(zplString)
Now the call from your first script will transmit the code correctly:
import sys
import os
sys.stdout.flush()
exitCode = os.system(str(command))
Output:
^XA^FO20,20^BQ,2,3^FDQA,001D4B02107A;1001000;49681207^FS^FO50,50^ADN,36,20^FDMAC: 001D4B02107A^FS^FO50,150^ADN,36,20^FDSN: 1001000^FS^FO50,250^ADN,36,20^FDCode: 49681207^FS^XZ
Some demo code:
import sys
if __name__ == "__main__":
for i, arg in enumerate(sys.argv):
print("{}: '{}'".format(i, arg))
when called like
python test.py ^this^is^a^test
it gives
0: 'test.py'
1: 'thisisatest'
when called like
python test.py "^this^is^a^test"
it gives
0: 'test.py'
1: '^this^is^a^test'
Solution: enclose your parameter string in double-quotes, ie
label = '"' + label + '"'
This worked for me:
import sys
firstarg=sys.argv[1]
secondarg=sys.argv[2]
thirdarg=sys.argv[3]
You can use the argv from sys
from sys import argv
arg1, arg2, arg3, ... = argv
You can actually put an abitrary number of arguments in the command line. argv will be a list with the arguments. Thus it can also be called as arg1 = sys.argv[0] arg2 = sys.argv[1] . . .
Keep also in mind that sys.argv[0] is simply the name of your python program. Additionally, the "eval" and "exec" functions are nice when you use command line input. Usually, everything in the command line is interpreted as a string. So, if you want to give a formula in the command line you use eval().
>>> x = 1
>>> print eval('x+1')
2
ssh - How to pass string from bash to python function - Unix & Linux Stack Exchange
python - Pass in string as argument without it being treated as raw - Stack Overflow
Bash pass string argument to python script - Stack Overflow
Pass an argument to a Python script
Make it a shell function instead. Paste this into your terminal, or add to your shell's configuration files (e.g. ~/.bashrc for bash)
pipeline_test(){
python -c 'from sys import argv; from pipeline_runs.z_full_pipeline import test; test(argv[1])' "$@"
}
And then run as
pipeline_test "$a"
Just try:
export a="test"
python -c "from pipeline_runs.z_full_pipeline import test; test('$a')"
In this case, the command will be expanded to from pipeline_runs.z_full_pipeline import test; test('test')
And you will have 'test' instead of test. The former is a string and the later is an undefined variable.
But a safe way to proceed is to use the os.environ dictionary. Then you put a script in a example.py file. And start with:
import os
a = os.environ['a']
test(a)
This way is better scalable and you don't have to expand a string.
Note, in shell, a="test" and a=test are synonymous.
The string you receive in sys.argv[1] is exactly what you typed on the command line. Its backslash sequences are left intact, not interpreted.
To interpret them, follow this answer: basically use .decode('string_escape').
myscript.py contains:
import sys
print(sys.argv[1].decode('string-escape'))
result abcd abcd
Your bash needs to look like this:
if [ -n "${my_param}" ]
then
my_param_str="--my_param \"${my_param}\""
fi
echo ${my_param_str}|xargs python -u my_script.py
Otherwise, the quotes around the parameter string will not be preserved, and "Some", "--" and "thing" will be passed as three separate arguments.
For the limited example you can basically get the same behavior just using
arg = os.environ.get('my_param', '')
where the first argument to get is the variable name and the second is the default value used should the var not be in the environment.
How do I pass an argument to a Python script? In this case, a string, which is a filename. How do I call it at the command prompt, and how do I reference the passed argument within the script?
argv will be a list of all the arguments that the shell parses.
So if I make
#script.py
from sys import argv
print argv
$python script.py hello, how are you
['script.py','hello','how','are','you]
the name of the script is always the first element in the list. If we don't use quotes, each word will also become an element of the list.
print argv[1]
print argv[2]
$python script.py hello how are you
hello
how
But if we use quotes,
$python script.py "hello, how are you"
['script.py','hello, how are you']
The all words are now one item in the list. So do something like this
print "The script is called:", argv[0] #slicing our list for the first item
print "Your first variable is:", argv[1]
Or if you don't want to use quotes for some reason:
print "The script is called:", argv[0] #slicing our list for the first item
print "Your first variable is:", " ".join(argv[1:]) #slicing the remaining part of our list and joining it as a string.
$python script.py hello, how are you
$The script is called: script.py
$Your first variable is: hello, how are you
Multi word command line arguments, that is single value arguments that contain multiple ASCII sequences separated by the space character %20 have to be enclosed with quotes on the command line.
$ python test.py "f i r s t a r g u m e n t"
The script is called:test.py
Your first variable is:f i r s t a r g u m e n t
This is actually not related to Python at all, but to the way your shell parses the command line arguments.
First (and probably most preferable) solution is to put the second and third argument in quotes as Susmit Agrawal suggested. Then the shell itself will split the command line into arguments appropriately.
python mytest.py [email protected] "value of file 1" "value of file 2"
In case you really need to pass arguments without quotes though, you will have to accept that the shell will be splitting your second and third argument at spaces, so you will need to reconstruct them from sys.argv yourself.
Lastly, you may want to explore argparse library to help you with parsing the command line arguments. In this case you may want to use optional arguments with nargs set to '+' or some certain number based on your command line API. For example, if you define and parse your arguments the following way,
parser = argparse.ArgumentParser()
parser.add_argument('--value-1', nargs=4)
parser.add_argument('--value-2', nargs=4)
parser.add_argument('email', nargs='+')
args = parser.parse_args()
print(args)
then you can call your Python program as
python mytest.py [email protected] --value-1 value of file 1 --value-2 value of file 2
And get the following result,
Namespace(email=['[email protected]'], value_1=['value', 'of', 'file', '1'], value_2=['value', 'of', 'file', '2'])
which you can then conveniently access as
print(args.value_1)
print(args.value_2)
print(args.email)
you can use argparse to pass your argument:
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-stv1', type=str)
parser.add_argument('-stv2', type=str)
parser.add_argument('-email', nargs='+')
args = parser.parse_args()
print(args)
nargs='+' indicate that at least you should pass one argument as email or more.
Executing the script give the following :
python3 script.py -email [email protected] [email protected] -stv1 "value of file 1" -stv2 "value of file 2"
Namespace(email=['[email protected]', '[email protected]'], stv1='value of file 1', stv2='value of file 2')
Your shell will eat those quotes before python ever sees them. Try like this:
python test.py '"one"' '"two"'
As an aside, command-line args are passed as strings anyway. It is odd to literal_eval them like this; a better pattern is to convert the strings to numbers when you need the numbers, and to just leave them as strings otherwise. This will also save you from having to quote-pad the strings twice on the command line.
The argparse module can handle that stuff for you automatically.
optparse.OptionParser may be helpful for you.
You can use it like this:
from optparse import OptionParser
if __name__ == "__main__":
parser = OptionParser(version="%prog 1.0.0")
parser.add_option("-c", "--config", action="store", dest="config_file",
default="test", type="string",
help="let prog load a specified configure file")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
default=False, help="let prog run in verbose model")
options, args = parser.parse_args()
if options.verbose:
print "run in verbose model"
print "configure file is %s"%(options.config_file)
There are a few modules specialized in parsing command line arguments: getopt, optparse and argparse. optparse is deprecated, and getopt is less powerful than argparse, so I advise you to use the latter, it'll be more helpful in the long run.
Here's a short example:
import argparse
# Define the parser
parser = argparse.ArgumentParser(description='Short sample app')
# Declare an argument (`--algo`), saying that the
# corresponding value should be stored in the `algo`
# field, and using a default value if the argument
# isn't given
parser.add_argument('--algo', action="store", dest='algo', default=0)
# Now, parse the command line arguments and store the
# values in the `args` variable
args = parser.parse_args()
# Individual arguments can be accessed as attributes...
print args.algo
That should get you started. At worst, there's plenty of documentation available on line (say, this one for example)...
It might not answer your question, but some people might find it usefull (I was looking for this here):
How to send 2 args (arg1 + arg2) from cmd to python 3:
----- Send the args in test.cmd:
python "C:\Users\test.pyw" "arg1" "arg2"
----- Retrieve the args in test.py:
import sys, getopt
print ("This is the name of the script= ", sys.argv[0])
print("Number of arguments= ", len(sys.argv))
print("all args= ", str(sys.argv))
print("arg1= ", sys.argv[1])
print("arg2= ", sys.argv[2])
You can use the sys module like this to pass command line arguments to your Python script.
import sys
name_of_script = sys.argv[0]
position = sys.argv[1]
sample = sys.argv[2]
and then your command line would be:
./myscript.py 10 100
Use argparse module:
The argparse module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and argparse will figure out how to parse those out of sys.argv. The argparse module also automatically generates help and usage messages and issues errors when users give the program invalid arguments.
It's pretty powerful: you can specify help messages, make validations, provide defaults..whatever you can imagine about working with command-line arguments.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-p", "--position", type=int)
parser.add_argument("-s", "--sample", type=int)
args = parser.parse_args()
col = args.position
sample = args.sample
print col
print sample
Here's what on the command-line:
$ python test.py --help
usage: test.py [-h] [-p POSITION] [-s SAMPLE]
optional arguments:
-h, --help show this help message and exit
-p POSITION, --position POSITION
-s SAMPLE, --sample SAMPLE
$ python test.py -p 10 -s 100
10
100
$ python test.py --position 10 --sample 100
10
100
Speaking about the code you've provided:
- unused
import randomstatement - move
from random import shuffleto the top of the script - no need to call
f.close()(especially with;) -withhandles closing the file automagically
Here's how the code would look like after the fixes:
#!/usr/bin/python
import argparse
import csv
from random import shuffle
parser = argparse.ArgumentParser()
parser.add_argument("-p", "--position", type=int)
parser.add_argument("-s", "--sample", type=int)
args = parser.parse_args()
with open('<filename>', 'r') as f:
reader = csv.reader(f)
data = [row[args.position] for row in reader]
shuffle(data)
print '\n'.join(data[:args.sample])