Crontab wont run scripts - python

I have a light show on my raspberry pi. I also have crontab running to automate it. When I run the script in terminal it acts normally and works flawless. When cron runs it wont work correctly. I have it set to turn the lights off 15 sec before the show, run the show, 15 seconds later turn them back on. Now when the job runs it only plays the show and the relays never trigger to keep the lights on or off. I have 3 scripts. One is the show and 2 are turning the lights on and off. I'm really confused here.
Run the show
/home/pi/lightshowpi/./lightsoff.sh
sleep 15
$SYNCHRONIZED_LIGHTS_HOME/bin/start_playlist_once $SYNCHRONIZED_LIGHTS_HOME/mus$
sleep 15
/home/pi/lightshowpi/./lightson.sh
Lights on
#!/bin/bash
export SYNCHRONIZED_LIGHTS_HOME=/home/pi/lightshowpi
python py/hardware_controller.py --config=overmech.cfg --state=on
Lights off
#!/bin/bash
export SYNCHRONIZED_LIGHTS_HOME=/home/pi/lightshowpi
python py/hardware_controller.py --config=overmech.cfg --state=off
All these are .sh files with chmod +x. Thanks

I don't know what PATH cronjobs run with, but it may be that it's not finding the python executable. Try putting in the full path:
#!/bin/bash
export SYNCHRONIZED_LIGHTS_HOME=/home/pi/lightshowpi
/usr/bin/python py/hardware_controller.py --config=overmech.cfg --state=on
Assuming python is in /usr/bin, of course.
I'd also put in an absolute path to py/hardware_controller.py but I don't know where you put it :)

There's a couple of things you should fix regardless of it being the culprit, by changing these your crontab should work.
First and foremost, like everybody else mentioned make sure your shell scripts have this or it's equivalent in your system. You can also redirect sdout and stderrr in your crontab by using something similar to this in your crontab:
*/15 * * * * /bin/bash /home/pi/lightshowpi/lightson.sh 2&>1 >> lights_on_log.txt
By using 2&>1 you'll be appending stdout and stderr to that file in the home directory for the user running the cron job, that way you can review the output and errors and figure out exactly what the problem is.
The most likely cause of the problem is that you're not using the full path to the python binary i.e.
/usr/bin/python
Instead of just
python
One other thing you should probably look into is the fact that your command line arguments for both scripts use relative paths, and depending on what user the cron job is running as this may pose a problem. Either change into whatever directory the py directory and overmech.cfg file are in or make sure to also use fully qualified paths for those.
The last bit I'd point out (I saved it for last because it doesn't really mean much) is that one of your examples shows
/home/pi/lightshowpi/./lightsoff.sh
The . is redundant and not needed. Dot-slash is used as a means to abbreviate the fully qualified path to a file within the current directory since . expands to the current working directory and / helps construct the last bit of the path. In the above example you'll do just fine without the . and just using the complete path like this:
/home/pi/lightshowpi/lightsoff.sh

Related

Python scripts couldn't work with crontab

I'm new to stackoverflow and really hope to get answers to my question about crontab.
I'm using MacbookAir in BigSur(don't know if it affects)And my crontab just couldn't run python scripts below.
f = open("test_crontab.txt",'w+')
f.write("Success")
f.close()
But I could run this script with Spyder.
I could edit crontab with crontab -e, and my code in vi crontab was
13 01 * * * /bin/zsh /Users/myusername/Documents/Lynn\'s\ Python\ work/shopee/test.py >>/Users/myusername/Desktop/out.log 2>>/Users/tzulingkuo/Desktop/err.log
But it failed to generate txt file.
The messages in err.log were like below:
/Users/*myusername*/Documents/Lynn's Python work/shopee/test.py:5: missing end of string
/Users/*myusername*/Documents/Lynn's Python work/shopee/test.py:6: unknown username ''
I've searched stackoverflow for two nights and couldn't find the solution. I major in finance and I have no friends studying computer science.
Could anyone help me 🥺
Any help is reaaaaally appreciated!
Since that's a python script, you need to run it in python, not /bin/zsh. zsh is trying to interpret it as a shell script, but the syntax is all wrong, so you get errors.
The simplest way to fix this to replace /bin/zsh in your crontab entry with /usr/bin/python (assuming you're using the built-in Python version 2; if you have installed Python version 3 and want to use that, run which python at the command line to find its path).
But it's generally better to add a shebang line to your python script, and let that control how it's run. Add this as the very first line of the script:
#!/usr/bin/python
(Again, if you want to use Python 3, replace the path part with the path for the Python 3 interpreter.) Then make the script executable with chmod +x /Users/myusername/Documents/Lynn\'s\ Python\ work/shopee/test.py, and just remove the /bin/zsh part from the crontab entry.
BTW, you're probably going to have trouble with paths. By default, cron jobs run with their working directory set to your home directory, so when the script opens test_crontab.txt, that's going to be interpreted as /Users/myusername/test_crontab.txt. If you want it down in the Documents/Lynn's Python work/shopee directory, you'll have to specify that explicitly.
You may also run into trouble with missing environment variables. If you're setting any environment variables in your shell initialization scripts that configure Python, add libraries, etc, those won't be set up in the cron job's environment.

Why using crontab I get "-bash: Applications: command not found"?

I'm trying to schedule a simple python script on MacOS using crontab. I have seen lot of guides and answers to other questions here in SO but still can't get my task to work. Actually I'm not so familiar with terminal and this kind of stuff but it didn't seem so difficult so I'm hoping to solve it.
I followed two different approaches.
First approach:
I use the command crontab -e on the terminal
In VIM I press I for Insert and paste the following:
* * * * * /usr/bin/python mypath/ap.py
Press "esc" and ":qw" to close VIM window.
crontab -l shows my cron entry as expected, BUT nothing happens from the script (it is supposed to create a txt file).
Second approach:
I paste this line in the terminal:
* * * * * /usr/bin/python mypath/ap.py >> mypath/MyCronLog.txt 2>&1
In this way I can see a txt file where I can read the log and eventual errors. MyCronLog.txt shows: -bash: Applications: command not found or -bash: ap.py: command not found.
My python script is located in a folder on my dekstop (I don't know if it matters).
Moreover I run my python script from terminal and it works perfectly.
Any suggestion is appreciated!
EDIT 1:
The path of my python script is the following:
/Users/myname/Desktop/ap/ap.py
EDIT 2:
"/opt/anaconda3/bin/python" in place of "/usr/bin/python" but nothing has changed.
The problem seems to be in your python script. I guess the txt-file is created but in the wrong folder. When cron calls a python script, the working directory is NOT the directory of that script (see here). Look here for a workaround.
EDIT:
The behavior of your script might depend on the directory from which you call it (not an ideal way to write scripts). When you are in /Users/myname/Desktop/ap and call python ap.py, this might lead to something different than calling python ap/ap.py from /Users/myname/Desktop
You can verify this by calling this short script:
import os
print(os.getcwd())
I can imagine that your script crashes when called by cron while it works if you call it from the containing directory.

Cronjob on Ubuntu Mate for Raspberry stops right after execution

I use a RaspberryPi 3 with UbuntuMate 16.04. On it, I want to start a little Python (3.5) program every midnight. For that I call a little shell script, so that I can change into the wanted directory comfortably.
crontab:
5 0 * * * /path/to/script/start.sh
start.sh (yes, it's executable):
#!/bin/bash
cd /path/to/wanted/workingDir/
python3.5 ControllerQueue.py
#also tried: python3.5 ControllerQueue.py &
Now if I execute the programm or script from the terminal, everything runs fine. But if I use the crontab it starts the script and stops right after. I also tried running the programm directly but get the same outcome. The paths are correct as I copied the workingDir path from the crontab-file and started it via the terminal.
Is there something I overlook?
As stofvl suggested, I saved the error output of my shell script. It turns out that I needed to add a display. My programm is divided into two scripts. One which provides a GUI and the other main application. The script only starts the main application, without the GUI, but it seems that this didn't matter.
This discussion helped me solve the problem.

Change caller's current working directory in Python

I'm writing a simple script which ideally will help me conveniently change directories around my system.
The details of the implementation don't matter, but let's say ideally I will place this script in /usr/bin and call it with an argument denoting where I want to go to on the system: goto project1
I would expect that when the script exits, my terminal's current working would have changed to that of Project 1.
In order to accomplish this, I tried:
os.chdir('/')
subprocess.call('cd /', shell=True)
Neither of which work. The first changes the working directory in Python and the second spawns a shell at /.
Then I realized how naive I was being. When a program is run, the terminal is just forking a process, while reading from stdout, which my program is writing to. Whatever it does, it wouldn't affect the state of terminal.
But then I thought "I've been using cd for years, surely someone wrote code for that", thinking there might be something to go off of (system call or something?).
But cd is not even coreutils. Instead, the source of cd is this:
builtin `echo ${0##*/} | tr \[:upper:] \[:lower:]` ${1+"$#"}
So, a couple of questions come to mind:
What's actually going on behind the scenes when a user calls cd? (Meaning, how is the terminal and the system actually interacting?)
Is it possible to have something like a Python script alter the terminal location?
Thanks so much for your help!
You could do it as a pair of scripts:
directory.py
#!/usr/bin/python
import sys
directory = sys.argv[1]
# do something interesting to manipulate directory...
print directory + "tmp"
directory.csh
#!/bin/csh -f
cd `python directory.py $1`
Result:
> pwd
/Users/cdl
> source directory.csh "/"
> pwd
/tmp
>
Substitute your favorite shell and variant of Python as desired. Turn on execute for the Python script to simplify further.
Clearly the shell is changing the directory but Python can do all the clever logic you want to figure out where to send the shell.

Default Folder for Terminal in OSX, When Running Python Interactive Shell

This is a follow up question as I'm trying to move forward with Zelle's Python:Programming.
It appears that IDLE 2.7.2 has hang issues when opening graphics windows in interactive mode. But, I can simply run Python interactively in Terminal and don't have any of those issues. So that's a big help. Zelle provides a simplified graphics file called graphics.py, to get up to speed with objects and graphics, before dealing directly with Tkinter.
My question is this. Where should I put graphics.py, so Terminal will see it (when it's called), without including the full path every time? Thanks,
Henry
According to PEP 0370, a good place to put your user packages is in ~/.local/lib/python2.7/site-packages.
Modules in here should be importable.
You can modify your ~/.bashrc to include a PYTHONPATH definition that includes the location of the file.
export PYTHONPATH="/path/to/directory_containing_graphics.py"
Just be careful if it's in your home director to use /Users/[username]/etc/directory_containing_graphics.py, I vaguely recall being bitten by ~ not expanding like I expected one time on OS X.
I went deep down the rabbit hole to get to bottom of this issue. It turns out that bash on OSX has a few quirks, not unexpected with the various flavors of UNIX around. It turns out that when firing up a bash shell, bash looks in .bash_profile for config statements. If you enter bash into bash, you fire up a sub shell, and that's when and only when .bashrc is executed.
To make sure you only have to manage one config file, put:
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
in your .bash_profile. This just tells bash to look into the .bashrc file if it exists. You can then leave that file alone and only modify your .bashrc file and all instances of bash will be modified the same. Once I figured this out, I still had to solve my problem. Here's the best I could do. When Python installed it installed this into my .bash_profile:
PATH="/Library/Frameworks/Python.framework/Versions/2.7/bin:${PATH}"
export PATH
This tells bash where to look for the libraries needed to run Python. So I moved this statement to my .bashrc file after putting the "if" statement into my .bash_profile. I then tried adding a : to the PATH statement with the path to my Python modules, but that didn't work. So, I have settled for a statement like this in .bashrc:
PYTHONPATH=$PYTHONPATH:/Users/ftpbub/Documents/workspace/Python\ Programming\ Modules/src/
export PYTHONPATH
Now I enter python at the command prompt, and when I get to python, I can enter import modulename without the path and it works. If I start a new project in a new directory, I should be able to add it to my PYTHONPATH and be good. I would have liked to be able to enter python modulename right into bash and have the module execute, but I haven't figured out how to do that. Other than that, I think this the best I can do. Ideas for how to go straight to the module from the bash prompt, without entering the path?

Categories