I have an issue with Rsyslog's 'omprog' module when trying to get it to interact with my python (2.7) code. Rsyslog is supposed to send desired messages to python's stdin, yet it does not receive anything. I wonder if anyone else has had better success with this output module?
Rsyslog.conf
module(load="omprog")
template(name="sshmsg" type="string" string="%msg%")
if ($programname == "myprogram") then {
action(type="omprog"
binary="/usr/sshtrack.py"
template="sshmsg")
}
If I replace the binary with a test shell script containing a line below, it works
test.sh
!#/bin/sh
cat /dev/stdin >> /var/log/ssh2.log
I also tried reading stdin in the shell script into a variable using
var="$(</dev/stdin)"
and
var="$(cat /dev/stdin)"
Neither of the above resulted var containing anything
Finally, when trying to read stdin from python script, I get nothing. Sometimes, it says resource unavailable (errno 11) error message.
sshtrack.py
#!/usr/bin/python
import sys
f = open("/var/log/ssh2.log", "a", 0)
while True:
f.write("Starting\n")
for line in sys.stdin:
f.flush()
msg = line.strip()
if not msg:
break
f.write(msg)
f.write("\n")
f.close()
The issue seems similar to can not read correctly from STDIN except adding a non-block flag did nothing.
I notice that your template sshmsg doesn't end with a newline. Try changing it to string="%msg%\n". Though it won't matter to rsyslog, Python will not be able to give you the data until it sees a newline.
Then it should work, but you probably not see any output from your python as it is buffered. Try adding an f.flush() after the last write in the loop, or opening the file unbuffered.
omprog will keep the pipe open, sending multiple lines until your program exits.
Note, not all shells might understand $() syntax.
In case of your shell script you can use read to read into a variable.
#!/bin/bash
# This will read until \n
read log
echo $log
The python source code (tested with python 3.8.2) can be adjusted to:
#!/usr/bin/env python3
import sys
# Changed from unbuffered to buffered as unbuffered is only possible in binary mode Ref (1):
f = open("/var/log/ssh2.log", "a", 1)
while True:
f.write("Starting\n")
for line in sys.stdin:
f.flush()
msg = line.strip()
if not msg:
break
f.write(msg)
f.write("\n")
f.close()
In case you want to have the output of you executed script (debugging) you can adjust the settings in Rsyslog.conf with the output option
module(load="omprog")
template(name="sshmsg" type="string" string="%msg%")
if ($programname == "myprogram") then {
action(type="omprog"
binary="/usr/sshtrack.py"
output="/var/log/sshtrack.log"
template="sshmsg")
}
Ref (1): https://stackoverflow.com/a/45263101/13108341
The else statement keeps flagging as invalid syntax, in the Visual Studio 2019 IDE and when running the .py file outside the IDE. I keep seeing invalid token for else: However looking through the python docs this appears to be correct. I am working on building out a system reboot script to push through a MDM solution. This is just the very basic start of the script.
import os
import time
import datetime
WorkStatus = input ("We are going to restart this computer now, did you save your work? Y or N")
if workStatus == n: print ('Save your work now restart will occur in 5 minutes')
# wait 5 minutes
print ("rebooting in 5 minutes")
time.sleep(300)
else:
os.system ("Shutdown /r /t 10")
import os
import time
import datetime
WorkStatus = input ("We are going to restart this computer now, did you save your work? Y or N")
if workStatus == n:
print ('Save your work now restart will occur in 5 minutes')
# wait 5 minutes
print ("rebooting in 5 minutes")
time.sleep(300)
else:
os.system ("Shutdown /r /t 10")
I am running a python script on my raspberry pi, at the end of which I want to call a second python script in the same directory. I call it using the os.system() command as shown in the code snippet below but get import errors. I understand this is because the system interprets the script name as a shell command and needs to be told to run it using python, using the shebang line at the beginning of my second script.
#!/usr/bin/env python
However doing so does not solve the errors
Here is the ending snippet from the first script:
# Time to Predict E
end3 = time.time()
prediction_time = end3-start3
print ("\nPrediction time: ", prediction_time, "seconds")
i = i+1
print (i)
script = '/home/pi/piNN/exampleScript.py'
os.system('"' + script + '"')
and here is the beginning of my second script:
'#!usr/bin/env python'
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
#from picamera import PiCamera
import argparse
import sys
import time
import numpy as np
import tensorflow as tf
import PIL.Image as Image
Any help is greatly appreciated :)
Since you have not posted the actual errors that you get when you run your code, this is my best guess. First, ensure that exampleScript.py is executable:
chmod +x /home/pi/piNN/exampleScript.py
Second, add a missing leading slash to the shebang in exampleScript.py, i.e. change
'#!usr/bin/env python'
to
'#!/usr/bin/env python'
The setup that you have here is not ideal.
Consider simply importing your other script (make sure they are in the same directory). Importing it will result in the execution of all executable python code inside the script that is not wrapped in if __name__ == "__main__":. While on the topic, should you need to safeguard some code from being executed, place it in there.
I have 2 python file a.py and b.py and I set execute permission for b.py with.
chmod a+x b.py
Below is my sample:
a.py
#!/usr/bin/python
print 'Script a'
import os
script = './b.py'
os.system('"' + script + '"')
b.py
#!/usr/bin/python
print 'Script b'
Execute "python a.py", the result is:
Script a
Script b
I'm trying to run a pygame program using pythonw to avoid having the console window show up. This causes a weird issue related to print statements.
Basically, the program will just exit after a few seconds with no error message. The more printing I do, the faster it happens.
If I run it in idle or at the command prompt (or in linux) the program works fine. This problem only happens when launched with pythonw (right-click, Open With, pythonw).
I'm using python 2.7.11 on Windows XP 32-bit. pygame 1.9.1release.
Is there a workaround for this? Why does the program simply terminate with no error?
import pygame
from pygame.locals import *
succeeded, failed = pygame.init()
display_surface = pygame.display.set_mode((320, 240))
clock = pygame.time.Clock()
terminate = False
while terminate is False:
for event in pygame.event.get():
if event.type == QUIT:
terminate = True
area = display_surface.fill((0,100,0))
pygame.display.flip()
elapsed = clock.tick(20)
print str(elapsed)*20
pygame.quit()
You don't need to remove print statements. Save them for later debugging. ;-)
Two steps to solve this problem:
Firstly, keep all the code in py file - don't change it to pyw now; Say it is actualCode.py
Then, create a new file runAs.pyw with the following lines in it
# In runAs.pyw file, we will first send stdout to StringIO so that it is not printed
import sys # access to stdout
import StringIO # StringIO implements a file like class without the need of disc
sys.stdout = StringIO.StringIO() # sends stdout to StringIO (not printed anymore)
import actualCode # or whatever the name of your file is, see further details below
Note that, just importing actualCode runs the file, so, in actualCode.py you should not enclose the code which is executed, in what I call is it main running file condition. For example,
# In actualCode.py file
....
....
....
if __name__ == '__main__': # Don't use this condition; it evaluates to false when imported
... # These lines won't be executed when this file is imported,
... # So, keep these lines outside
# Note: The file in your question, as it is, is fine
I know I'm quite late with all this, but I have a relatively simple command-line Python script, written for 2.7, which I'd like to make usable on both Python 2.7+ and Python 3+. Since it's a single script:
I do not want to use six - while six is just a single file, now I'd have to take care of two files (the six module and my script), instead of one
I do not want to use 2to3; because then again I'd have to take care of two files (the 2.7 version of my script and the 3.2 version of it), instead of one
So, I thought the best approach for me would be to write Python 2.x as much compatible with Python 3.x as possible; then I could code once, and not worry if I have to run the script on a USB-thumbdrive OS, which may only have Python 2.7 (or for that matter, only Python 3+), and which I may have trouble finding and/or installing the right version of Python for.
To demonstrate my problems, here is a sample script based on examples in Learning Python -- Sample chapter 9: Common Tasks in Python - and the preparation in bash on Ubuntu 11.04 (with a bit of Unicode, to spice it up):
cd /tmp
mkdir /tmp/ptest
echo 'Байхъусут, зæрæдтæ!.. Байхъусут, лæппутæ!..' > /tmp/ptest/test.txt
echo 'Байхъусут, зæрæдтæ!.. Байхъусут, лæппутæ!..
Байхъусут зарæгмæ, фыдæлты кадæгмæ,
Дзæбæхдæр бахъырнут уæ бæзджын хъæлæстæй!..' > /tmp/ptest/Байхъусут.txt
cat > tscript.py <<"EOF"
# -*- coding: utf-8 -*-
import fileinput, sys, string, os
if ( len(sys.argv) > 3 ) or ( len(sys.argv) < 2 ):
print "Usage: ", sys.argv[0], "searchterm [path]"
sys.exit()
# take the first argument out of sys.argv and assign it to searchterm
searchterm, sys.argv[1:] = sys.argv[1], sys.argv[2:]
if len(sys.argv) == 1: # if no dir is specified,
indir = os.curdir # use current dir
else: # otherwise, use dir specified
indir = sys.argv[1] # on the command line
filenames = [indir+"/"+f for f in os.listdir(indir) if os.path.isfile(indir+"/"+f)]
for line in fileinput.input(filenames):
num_matches = string.count(line, searchterm)
if num_matches: # a nonzero count means there was a match
print "found '%s' %d times in %s on line " % ( searchterm, num_matches, fileinput.filename() ), \
fileinput.filelineno()
EOF
Trying this:
$ python2.7 tscript.py Байхъусут /tmp/ptest
found 'Байхъусут' 2 times in /tmp/ptest/test.txt on line 1
found 'Байхъусут' 2 times in /tmp/ptest/Байхъусут.txt on line 1
found 'Байхъусут' 1 times in /tmp/ptest/Байхъусут.txt on line 2
$ python3.2 tscript.py Байхъусут /tmp/ptest
File "tscript.py", line 17
print "Usage: ", sys.argv[0], "searchterm [path]"
^
SyntaxError: invalid syntax
Ok, that must be the change of print - will just adding parenthesis do? I change like this:
print ("Usage: ", sys.argv[0], "searchterm [path]")
....
print ("found '%s' %d times in %s on line " % ( searchterm, num_matches, fileinput.filename() ), \
fileinput.filelineno() )
... will that do?:
$ python3.2 tscript.py Байхъусут /tmp/ptest
Traceback (most recent call last):
File "tscript.py", line 31, in <module>
num_matches = string.count(line, searchterm)
AttributeError: 'module' object has no attribute 'count'
Nope.. so I also change this line:
num_matches = line.count(searchterm) # string.count(line, searchterm)
... is that enough? Well - somewhat, it seems:
$ python3.2 tscript.py Байхъусут /tmp/ptest
found 'Байхъусут' 2 times in /tmp/ptest/test.txt on line 1
found 'Байхъусут' 2 times in /tmp/ptest/Байхъусут.txt on line 1
found 'Байхъусут' 1 times in /tmp/ptest/Байхъусут.txt on line 2
$ python2.7 tscript.py Байхъусут /tmp/ptest
("found '\xd0\x91\xd0\xb0\xd0\xb9\xd1\x85\xd1\x8a\xd1\x83\xd1\x81\xd1\x83\xd1\x82' 2 times in /tmp/ptest/test.txt on line ", 1)
("found '\xd0\x91\xd0\xb0\xd0\xb9\xd1\x85\xd1\x8a\xd1\x83\xd1\x81\xd1\x83\xd1\x82' 2 times in /tmp/ptest/\xd0\x91\xd0\xb0\xd0\xb9\xd1\x85\xd1\x8a\xd1\x83\xd1\x81\xd1\x83\xd1\x82.txt on line ", 1)
("found '\xd0\x91\xd0\xb0\xd0\xb9\xd1\x85\xd1\x8a\xd1\x83\xd1\x81\xd1\x83\xd1\x82' 1 times in /tmp/ptest/\xd0\x91\xd0\xb0\xd0\xb9\xd1\x85\xd1\x8a\xd1\x83\xd1\x81\xd1\x83\xd1\x82.txt on line ", 2)
Now at least it doesn't crash - but the python 2.7 print sees a tuple, and apparently it doesn't by default decode the string inside that tuple right ...
So, apparently, now I want to import print_function from __future__ for python 2.7 (Which python version needs from __future__ import with_statement?); so I try to put this at the top of the file (after the coding statement), thinking that I better try to use the import only for 2.x version:
import __future__, sys
if sys.version_info[0] < 3:
from __future__ import print_function
else:
pass
... but I get:
$ python2.7 tscript.py Байхъусут /tmp/ptest
File "tscript.py", line 6
from __future__ import print_function
SyntaxError: from __future__ imports must occur at the beginning of the file
The answer to this, in the question Python graceful future feature (__future__) import is to use a wrapper .py file - but then, I have the same problem again of having to think of two files, instead of one.
I thought I could cheat like this - even if it does create an extra file:
import __future__, sys
if sys.version_info[0] < 3:
str = """from __future__ import print_function"""
f = open('compat23.py','w')
f.write(str)
f.close()
import compat23
print("sys.version_info[0] < 3", end='(')
else:
print("sys.version_info[0] >= 3", end=')')
... but that doesn't matter really:
$ python2.7 tscript.py Байхъусут /tmp/ptest
File "tscript.py", line 11
print("sys.version_info[0] < 3", end='(')
^
SyntaxError: invalid syntax
... because the __future__ import was valid only for the scope of newly-created compat23 module, apparently.
So:
I am apparently making a mistake trying to limit __future__ import only to versions below 3, given that from __future__ ... is a compile-time statement; but then:
How does Python 3 react to this statement? Does it simply get ignored?
What happens then, when in Python 4 they decide to deprecate print again - wouldn't then from __future__ import print_function have a meaning again in Python 3, even if it may be ignored in Python 3 currently?
So, I guess, if I want to avoid thinking about this, and still use a single-file only script, I'm down to the advice in noconv.html: "... or you can use a separate print function that works under both Python 2 and Python 3 .. the trick is to use sys.stdout.write() and formatting ...."; also seen in Eli Bendersky's website » Making code compatible with Python 2 and 3.
And so I try with this at start of the file, instead of the __future__ import part - and change the corresponding print statements:
def printso(*inargs):
outstr = ""
for inarg in inargs:
outstr += str(inarg) + " "
outstr += "\n"
sys.stdout.write(outstr)
....
printso ("Usage: ", sys.argv[0], "searchterm [path]")
....
printso ("found '%s' %d times in %s on line " % ( searchterm, num_matches, fileinput.filename() ), \
fileinput.filelineno() )
... and this does, indeed, work fine in both python 2.7 and 3.2:
$ python2.7 tscript.py Байхъусут /tmp/ptest
found 'Байхъусут' 2 times in /tmp/ptest/test.txt on line 1
found 'Байхъусут' 2 times in /tmp/ptest/Байхъусут.txt on line 1
found 'Байхъусут' 1 times in /tmp/ptest/Байхъусут.txt on line 2
$ python3.2 tscript.py Байхъусут /tmp/ptest
found 'Байхъусут' 2 times in /tmp/ptest/test.txt on line 1
found 'Байхъусут' 2 times in /tmp/ptest/Байхъусут.txt on line 1
found 'Байхъусут' 1 times in /tmp/ptest/Байхъусут.txt on line 2
OK, but now it turns out that percent sign % for string formatting is deprecated as well; so instead I should write:
#printso ("found '%s' %d times in %s on line " % ( searchterm, num_matches, fileinput.filename() ), \
# fileinput.filelineno() )
printso ("found '{0}' {1} times in {2} on line ".format(searchterm, num_matches, fileinput.filename() ), \
fileinput.filelineno() )
Thankfully, this works for both 2.7 and 3.2, and in New Python 3.0 string formatting - really necessary? - comp.lang.python | Google Groups it is stated:
>> You can use the old 2.x syntax also in Python 3.x:
> Yeah, but it's deprecated, and - as I understand it - may be removed
> completely in future versions. Also, in the future, if you are working
> with code from another developer, it's likely that developer will use
> the new format. I suppose you can use both - but what an awful mess
> that would be.
It's not going to be removed for many years - if ever.
... however, who can be sure for how long this will stay true, given it's deprecated?
So, essentially - I would like to confirm:
How does from __future__ import behave in Python 3? What when Python 4 comes about, and the Python 3 at that time contains deprecated features, which will have to be imported from "future" Python 4?
for a script of this character, which I want to keep in single .py file, and compatible for both Python 2.7 and (hopefully) 3+: am I better off writing my own print function based on sys.stdout.write, and using that everywhere, instead of messing with __future__?
Am I also better off using the new string formatting syntax everywhere?
Python's __from__ future import feature statement is forwards compatible. That is, even if feature becomes standard in a future release, the import statement is still legal.
So rather than doing a bunch of work to get your own print function to work, just unconditionally put this at the top of your file (before any other code):
from __future__ import print_function
It will just work, forever.