2

I'm setting up a cron job to run an executable bash script which contains a pypdfocr command. Whenever I manually execute the script everything works as expected, if instead I use cron with this schedule:

* 6 * * * cd /path/to/ && ./executable

I get this error:

pypdfocr: command not found

Given this, in the bash script I've tried to give the full path to pypdfocr, i.e.:

/anaconda/bin/pypdfocr

But now I have:

/bin/sh: pdfimages: command not found
/bin/sh: gs: command not found

Any idea on how I can fix this?

  • 2
    add the full path to pdfimages and gs in your script. – fd0 Sep 17 '17 at 21:22
  • I don't call pdfimages and gs directly in my script, they're both used by pypdfocr, hence I cannot add the full path in my script. – SergeGardien Sep 18 '17 at 6:04
4

When cron runs an event, it uses the default shell environment of the running UID. However, no "profile" customization is applied, i.e. your .bash_profile is not sourced and thus any PATH settings are not picked up. As well, I don't believe that the common profiles are picked up either. As such, you probably have no PATH or LD_LIBRARY_PATH environment settings available to the process you're trying to launch and this is why pdfimages and gs isn't being picked up by default.

In the past, I've solved this one of two ways:

  1. Directly reference the full path of the file I need.
  2. Create a wrapper shell script for the job.

I typically prefer the 2nd one since it not only allows me to set up an environment for the job to run in, but it also makes it relatively easy to add debug situations easily. For example, if the job isn't working right I can just edit the shell script and put in STDOUT redirection to a debug file.

So in short, I would have a cron entry of

* 6 * * * cd /path/to/ && ./executable.sh

.. which would change to the path, but the executable.sh would do all the export PATH, export LD_LIBRARY_PATH, etc. to get my job set up.

Your sample executable.sh could be as simple as this:

#!/bin/bash

# if you want to just pick up your profile, you can '.' source it
. ~/.bash_profile

export PATH=/where/i/find/gs
export LD_LIBRARY_PATH=/if/i/need/libs

(./executable 2&>1) >executable.out

The executable.out file redirection isn't necessary since without it all STDOUT goes to cron.out, but it does make it a bit cleaner to do it this way. Also the 2>&1 nonsense with the parenthesis makes sure that both STDERR and STDOUT make it into the output file; this helps with debugging why a job didn't run.

  • cron creates its own environment. In particular, SHELL is set to /bin/sh and PATH is set to /usr/bin:/bin. The environment can customized in a user's crontab. Read more in man 5 crontab. – fd0 Sep 18 '17 at 19:50
  • @fd0: setting of environment variables in the crontab is not universal across all implementations; I'm not sure if darwin/osx/macos does it? Regardless, those settings would be applied to all cron entries which may or may not be desirable. As such I'd probably still suggest having cron run a script anyway since you at least have individual job control. – bjb Sep 20 '17 at 17:03
0

In the end I've followed the solution provided at How to use macports Python in a cron job?.

I've checked my environment PATH by running env from Terminal, then I've exported it to my executable.

executable:

#!/bin/bash
export PATH=/Library/Frameworks/Mono.framework/Versions/Current/bin/:/opt/local/bin:/opt/local/sbin://anaconda/bin:/Library/Frameworks/Python.framework/Versions/2.7/bin:/opt/local/bin:/opt/local/sbin:/Library/Frameworks/Python.framework/Versions/2.6/bin:/sw/bin:/sw/sbin:/usr/bin:/bin:/usr/local/bin:/opt/X11/bin:/Users/USER/Library/Android/sdk/platform-tools/:/Users/USER/Library/Android/sdk/tools/:/usr/sbin/:/Users/USER/Tools/cpdf/OSX-Intel/
# ...
# REST OF SCRIPT
# ...

After this I've modified my cronfile with the following:

* * * * * /path/to/executable

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .