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.
Related
This question already has answers here:
How to get CRON to call in the correct PATHs
(15 answers)
Closed 6 months ago.
My BASH scrit has following line:
video_id=$(/usr/local/bin/yt-dlp --no-warnings --get-id "$ChannelPath")
it succeeds when runs from command line under certain user.
When it runs from cron, under the same user, it results in:
/usr/bin/env: python3: No such file or directory
What could be different in these two cases?
CentOS 7
Python 3.11.0a4
There are some discussions whether you should use #!/usr/bin/env python or #!/usr/bin/python. Proponents of the env variant say that it is better, because env uses the PATH to find the interpreter, and opponents say that the problem with the env variant is that it uses the PATH.
I dislike env, therefore I will give you a solution without it.
From the command line type
which python3
This will give you something like
/usr/bin/python3
In /usr/local/bin/yt-dlp, replace the first line with
#!/usr/bin/python3
(the output that you got from the which command.)
Or call /usr/local/bin/yt-dlp with explicitly the right interpreter:
video_id=$(/usr/bin/python3 /usr/local/bin/yt-dlp --no-warnings --get-id "$ChannelPath")
it succeeds when runs from command line under certain user.
When it runs from cron, under the same user, it results in:
/usr/bin/env: python3: No such file or directory
What could be different in these two cases?
The difference is the environment in which the script runs. In particular, the environment variables in it, and most particularly, the PATH.
When a user runs the script from the command line, it inherits the environment from which it was launched, which includes system-wide and possibly user-specific customizations that are engaged only for interactive shells. (For example, the contents of the user's ~/.bash_profile and / or ~/.bashrc files.) By default, when a shell is launched noninteractively (by cron, for example) it does not read or execute any environment configuration.
Evidently,
Your /usr/local/bin/yt-dlp is or attempts to launch a Python script that has a shebang line using /usr/bin/env to choose and launch the python3 binary. That is, the affected script starts with
#!/usr/bin/env python3
These days, that form is widely used and recommended in the Python world. The purpose is to use the PATH to locate the python3 binary to use, as opposed to hard-coding that into the script. However,
There is no system Python 3 installed on the machine. (That is, none installed in the default path.) The user who runs the script successfully is able to do so because they have an environment configured with some non-default directory in their PATH from which python3 can be launched.
One possible solution would be to install CentOS's Python 3:
sudo yum install python3
If you need a different version of Python 3 (CentOS 7's is version 3.6) then you can instead set an appropriate PATH in the relevant crontab file, maybe something like
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
0 * * * * /path/to/my_script
Alternatively, you could modify your shell script to set the path there:
PATH=/usr/local/bin:$PATH
video_id=$(/usr/local/bin/yt-dlp --no-warnings --get-id "$ChannelPath")
or you could modify /usr/local/bin/yt-dip by altering its shebang (supposing that this is the affected Python script).
I moved the python3 symlink from /usr/local/bin to /usr/bin and it works now.
/usr/local/bin was the suggested location in internet-manuals about how to compile and install Python 3.11 in CentOS7.
A better solution is to add
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
to the first line of crontab. Although it should be not /etc/crontab, but
crontab -l > crontab.txt
then edit crontab.txt
then
crontab crontab.txt
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.
Excuse the awkward question wording.
I've made a script. I would like for others to download it from github, and run it by typing programName argument1 argument2, similar to any other popular app used through the terminal such as Jupyter or even opening Atom/Sublime/etc. (ex:jupyter notebook, atom .). However, unlike Jupyter or sublime, my script isn't launching another app, it's a small app meant to be used in the shell.
Currently, to use my script, one must type into the command line python programName.py arg1 etc from within the file's directory.
How do I allow others to dl it and use it from anywhere (not having to be within the directory), without having to type out the whole python programName.py part, and only having to type programName arg1?
This blog post explains step by step how to create a distribution that you can install and it would turn into an executable.
You can refer to this github repo for a sample application.
The full documentation of setuptools is available here.
In general, you should configure your setup.py in order to use the command in the entry-point option:
setup(
name = "your_app_name",
packages = ["package_name"],
entry_points = {
"console_scripts": ['cmd_name = package_name.package_name:main']
},
....
)
This solution would work on every OS where you have installed python.
Your script may need to have an interpreter, "shebang", besides being "reachable" by the $PATH
#!interpreter [optional-arg]
For example, you could have something like
#!/usr/bin/env python
or to force a specific version
#!/usr/local/bin/python2.7
Next, your script needs to be available within the $PATH, check this answer that covers that part: https://unix.stackexchange.com/q/29608/53084
You can simply add your script to PATH variable in order to launch it from anywhere.
In Linux distros, you can simply do it by using a bash command PATH=$PATH:/path/to/your/script.
Make sure you don't have the space around the "=" operator.
Now, the second thing is you don't want your script to be named as pythonProgram.py.You can simply remove the extension .py from PythonProgram.py by adding a single line to the starting of your script.
Open up your script and at the very begining type #!/usr/bin/python.This should be the first line of your code.This line is called shebang and is used to tell the bash which interpreter to be used for compiling the script.
If everything went right, you will be able to run your script as pythonProgram arg1.
In addition to mabe02: Python is a scripting language and usually not compiled, which means you will need an interpreter to run your program.
Programms made in C f.e. can be run on its own because they were compiled into machine code by a compiler.
An interpreter is similar to a compiler as it reads your script and interprets it at runntime. That is why you need to write python before your programm, to tell your computer to interpret your script on runntime, using python. This doesn't mean that there are no possibilities to compile python as can be seen in the other answer and in this link Can a python program be run on a computer without Python? What about C/C++? (py2exe and py2app).
I'm having trouble executing a Ruby script with my Python code.
My server has a cron job that is supposed to execute a Python script and a Ruby script. However, the Ruby script has to be executed after the Python one, so I decided to add a line:
os.system("ruby /home/username/helloworld.rb")
at the end of the Python script.
It runs, but I'm getting this error in the log file:
/bin/sh 1: ruby not found
I'm not sure why this is happening; I've tried calling the exact same function in the Python console as well as running the Python script manually, and both work perfectly. In other words, this line of code doesn't work ONLY when the script is triggered by cron.
Is there something else I need to put in my crontab/Python script perhaps?
Cron passes only a very limited number of environment variables to your job. According to the CRONTAB(5) Man Page:
SHELL is set to /bin/sh
PATH is set to /usr/bin:/bin
LOGNAME and HOME are set from the /etc/passwd line of the crontab's
owner.
HOME, PATH and SHELL may be overridden by settings in the
crontab; LOGNAME may not.
So if your ruby executable is not located in either /usr/bin or /bin cron cannot find it by default.
You can a specify PATH within crontab to include your ruby executable though.
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
17 * * * * python my_ruby_calling_script.py
Yes, I know I can do
python2 cal.py
What I am asking for is a way to execute it on the command line such as:
calpy
and then the command afterwards. I put in in a path and when I write cal.py in the command line:
/usr/bin/cal.py: line 5: print: command not found
I don't want to issue cal.py to run my script, I want it to be issued with calpy
I'm running Arch Linux if that helps, thanks. Sorry for my English.
In order for bash to know to run your script via the Python interpreter, you need to put an appropriate shebang at the start. For example:
#!/usr/bin/python
tells bash to run /usr/bin/python with your script as the first argument. I personally prefer
#!/usr/bin/env python
which is compatible with virtualenv. You also need to ensure that the permissions on your script allow it to be executed:
~$ chmod +x path/to/cal.py
Finally, in order to call cal rather than path/to/cal.py, you need to remove the .py extension and make sure that the directory containing cal is in your command search path. I prefer to add ~/bin to the search path by modifying the $PATH environment variable in ~/.bashrc:
export PATH=$HOME/bin:$PATH
then put my own executables in ~/bin. You could also copy (or symlink) cal to one of the system-wide binary directories (/bin or /usr/bin), but I consider it bad practice to mess with system-wide directories unnecessarily.
Ok, you need a couple of things for achive what you want.
First you have to tell your script "How" is going to execute/interpret it. You can do this writting
#/usr/bin/env python
at the very beggining of the file.
The problem you have is the system is trying to execute the script using bash. And in bash there is no print command.
Second you need give execution privileges to your script. And of course if you want to call your script through the command "calcpy", the script has to be called like that.
Put this (exactly this) as the first line of your script:
#!/usr/bin/env python