Python: -bash: syntax error near unexpected token - python

I have written a little script in Python that I use to append text to a work log. I have placed the script in a directory in my $PATH
#!/usr/bin/python
# import necessary modules
import sys
import os
import datetime
# main() function
def main():
now = datetime.datetime.now()
tmp = ' '.join(sys.argv[1:])
outfile = '/path/to/output/done.log'
outstr = now.strftime("%Y-%m-%d %H:%M:%S") + ' - ' + tmp + '\n'
f=open(outfile,'a')
f.write(outstr)
f.close()
# print sys.argv[0:1]
print 'Adding ' + outstr
# Call main()
if __name__ == '__main__':
main()
When I run the script as in example 1, I get an error.
Example 1:
host:scripts user$ done this is a test
-bash: syntax error near unexpected token `done'
If I run the script as in example 2, it behaves as expected.
Example 2:
host:scripts user$ python done this is a test
Adding 2012-11-15 09:57:44 - this is a test
How do I get this to work in the first example?

done is a bash keyword, so can't be used in certain places like "the place Bash expects a command name". You could use ./done (or /path/to/done, or python /path/to/done), or re-name the command.

Related

Command line argument with python

I am trying to execute below python script. But getting below issue after execution.
Code
#!/usr/bin/python
def Student(Student_Id):
msg = Student_Id + "." +
return msg
Error
C:\Users\Desktop>Test.py 2asd
After an investigation found that argument which I am passing through the command line is considered as Null.
You need to call like
Test.py -n 2asd

Python's sh module - is it at all possible for a script to request input?

Using Python's sh, I am running 3rd party shell script that requests my input (not that it matters much, but to be precise, I'm running an Ansible2 playbook with the --step option)
As an oversimplification of what is happening, I built a simple bash script that requests an input. I believe that if make this simple example work I can make the original case work too.
So please consider this bash script hello.sh:
#!/bin/bash
echo "Please input your name and press Enter:"
read name
echo "Hello $name"
I can run it from python using sh module, but it fails to receive my input...
import errno
import sh
cmd = sh.Command('./hello.sh')
for line in cmd(_iter=True, _iter_noblock=True):
if line == errno.EWOULDBLOCK:
pass
else:
print(line)
How could I make this work?
After following this tutorial, this works for my use case:
#!/usr/bin/env python3
import errno
import sh
import sys
def sh_interact(char, stdin):
global aggregated
sys.stdout.write(char)
sys.stdout.flush()
aggregated += char
if aggregated.endswith(":"):
val = input()
stdin.put(val + "\n")
cmd = sh.Command('./hello.sh')
aggregated = ""
cmd(_out=sh_interact, _out_bufsize=0)
For example, the output is:
$ ./testinput.py
Please input your name and press Enter:arod
Hello arod
There are two ways to solve this:
Using _in:
using _in, we can pass a list which can be taken as input in the python script
cmd = sh.Command('./read.sh')
stdin = ['hello']
for line in cmd(_iter=True, _iter_noblock=True, _in=stdin):
if line == errno.EWOULDBLOCK:
pass
else:
print(line)
Using command line args if you are willing to modify the script.

pass variable in to command in python

i'm writing a python script to execute shell command, and i'm taking arguments and i want to pass the value of that to the command
#!/usr/bin/env python
import commands
import subprocess
import sys
command = commands.getoutput('fs_cli -x "sofia profile external restart"')
this code works fine
when i try to take the argument and pass to command it fails
command = commands.getoutput('fs_cli -x "sofia profile" + sys.argv[1]
+ " restart"')
supp folks
You should write:
command = commands.getoutput('fs_cli -x "sofia profile ' + sys.argv[1] + ' restart"')
Take a look to argparse and subprocess.
One of the way to do this is to convert your command that you want to execute into string and then execute it as eval()
example :
eval(expression/command in string)

Passing a string as an argument to a python script

I want to pass a string of ZPL codes from one python script to another python script. The string becomes malformed when used in the second script. How can I pass a string literal as an argument to another python script without it being malformed?
Original String
^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
Malformed string
XAFO20,20BQ,2,3FDQA,001D4B02107A;1001000;49681207FSFO50,50ADN,36,20FDMAC:
Code where I call the second script
def printLabel():
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"
command = "zt320print.py "+label
print command
sys.stdout.flush()
exitCode = os.system(str(command))
Code that receives the argument
if __name__ == "__main__":
zplString = str(sys.argv[1])
print zplString
printZPL(zplString)
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
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 + '"'
You can put your string inside a double-quotes, or just import the other python script:
a.py
import sys, os
text = "a b c d"
# or '{} {} "{}"'.format("python", "b.py", text)
command = "python b.py \"" + text + "\""
os.system(str(command))
b.py
import sys
if __name__ == "__main__":
first_argument = str(sys.argv[1])
print(first_argument)
Output
a b c d

Bash doesn't think string is properly quoted?

I'm attempting to execute a command over SSH, but bash on the other end doesn't think it's escaped properly.
Here, self._client is a paramiko.SSHClient object; args is a list of arguments, the command to execute.
def run(self, args, stdin=None, capture_stdout=False):
"""Runs a command.
On success, returns the output, if requested, or None.
On failure, raises CommandError, with stderr and, if captured, stdout,
as well as the exit code.
"""
command = ' '.join(_shell_escape(arg) for arg in args)
print('About to run command:\n {}'.format(command))
print('About to run command:\n {!r}'.format(command))
channel = self._client.get_transport().open_session()
channel.exec_command(command)
_shell_escape:
_SHELL_SAFE = _re.compile(r'^[-A-Za-z0-9_./]+$')
def _shell_escape(s):
if _SHELL_SAFE.match(s):
return s
return '\'{}\''.format(s.replace('\'', '\'\\\'\''))
I'm attempt to run some Python through this. On stderr, I get back:
bash: -c: line 5: unexpected EOF while looking for matching `''
bash: -c: line 6: syntax error: unexpected end of file
The output from the two print statements:
About to run command:
python -c 'import os, sys
path = sys.argv[1]
if sys.version_info.major == 2:
path = path.decode('\''utf-8'\'')
entries = os.listdir(path)
out = b'\'''\''.join(e.encode('\''utf-8'\'') + b'\'''\'' for e in entries)
sys.stdout.write(out)
' .
About to run command:
"python -c 'import os, sys\npath = sys.argv[1]\nif sys.version_info.major == 2:\n path = path.decode('\\''utf-8'\\'')\nentries = os.listdir(path)\nout = b'\\'''\\''.join(e.encode('\\''utf-8'\\'') + b'\\''\x00'\\'' for e in entries)\nsys.stdout.write(out)\n' ."
If I copy and paste the output of command, and paste it into bash, it executes, so it really does appear to be properly escaped. My current understanding is that SSH, on the other end, will take command, and run [my_shell, '-c', command].
Why is bash erroring on that command?
The input contains an embedded nul character, which bash appears to treat as the end of the string. (I'm not sure there's any way it couldn't!). This is visible in my question, where I output command:
About to run command:
"python -c 'import os, sys [SNIP…] + b'\\''\x00'\\'' for [SNIP…]"
That's a repr output, but notice the single slash before the x in \x00: that's an actual \x00 that made it through. My original code has this Python embedded as a snippet, which I didn't include (I didn't believe it was relevant):
_LS_CODE = """\
import os, sys
path = sys.argv[1]
if sys.version_info.major == 2:
path = path.decode('utf-8')
entries = os.listdir(path)
out = b''.join(e.encode('utf-8') + b'\x00' for e in entries)
sys.stdout.write(out)
"""
Here, Python's """ is still processing \ as an escape character. I need to double up, or look into raw strings (r""")
You need to escape newlines as well. A better option is to put the program text in a here document.
Make the output of "About to run command:" to look like
python -c << EOF
import os, sys
path = sys.argv[1]
if sys.version_info.major == 2:
path = path.decode('\''utf-8'\'')
entries = os.listdir(path)
out = b'\'''\''.join(e.encode('\''utf-8'\'') + b'\'''\'' for e in entries)
sys.stdout.write(out)
.
EOF
Maybe you wouldn't need to escape anything at all.

Categories