I can run a script locally, but cannot do "ssh HOSTNAME /path/to/script.sh"

I have a linux server, and a linux desktop.

I have written the following simple script to dump the database of a django web application:

#! /bin/bash
set -o errexit

cd $(dirname $0)

. virtualenv/bin/activate

cd mysite

export DJANGO_SETTINGS_MODULE="settings.my_hostname"
django-admin.py dumpdata --settings=$DJANGO_SETTINGS_MODULE > database.json

The programme django-admin.py requires the DJANGO_SETTINGS_MODULE environmental variable to work properly.

If I ssh into the machine, ssh HOSTNAME, and then run the script /var/www/example.com/dumper.sh from the bash terminal on the remote host, and everything works fine. I get no output (as expected), and the file database.json is there and has the right data.

However (on my linux desktop), I cannot run this command: "ssh HOSTNAME /var/www/example.com/dumper.sh`` and I get the following error:

Traceback (most recent call last):
  File "/var/www/example.com/virtualenv/bin/django-admin.py", line 5, in <module>
    management.execute_from_command_line()
  File "/var/www/example.com/virtualenv/lib/python2.6/site-packages/django/core/management/__init__.py", line 429, in execute_from_command_line
    utility.execute()
  File "/var/www/example.com/virtualenv/lib/python2.6/site-packages/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/var/www/example.com/virtualenv/lib/python2.6/site-packages/django/core/management/__init__.py", line 261, in fetch_command
    klass = load_command_class(app_name, subcommand)
  File "/var/www/example.com/virtualenv/lib/python2.6/site-packages/django/core/management/__init__.py", line 67, in load_command_class
    module = import_module('%s.management.commands.%s' % (app_name, name))
  File "/var/www/example.com/virtualenv/lib/python2.6/site-packages/django/utils/importlib.py", line 35, in import_module
    __import__(name)
  File "/var/www/example.com/virtualenv/lib/python2.6/site-packages/django/core/management/commands/dumpdata.py", line 4, in <module>
    from django.db import connections, router, DEFAULT_DB_ALIAS
  File "/var/www/example.com/virtualenv/lib/python2.6/site-packages/django/db/__init__.py", line 14, in <module>
    if not settings.DATABASES:
  File "/var/www/example.com/virtualenv/lib/python2.6/site-packages/django/utils/functional.py", line 276, in __getattr__
    self._setup()
  File "/var/www/example.com/virtualenv/lib/python2.6/site-packages/django/conf/__init__.py", line 42, in _setup
    self._wrapped = Settings(settings_module)
  File "/var/www/example.com/virtualenv/lib/python2.6/site-packages/django/conf/__init__.py", line 89, in __init__
    raise ImportError("Could not import settings '%s' (Is it on sys.path?): %s" % (self.SETTINGS_MODULE, e))
ImportError: Could not import settings 'settings.my_hostname' (Is it on sys.path?): No module named settings.my_hostname

It's as if the export command isn't being run, or isn't taking effect.

Why doesn't this work? (Or alternatively should it work? Am I mistaken in thinking that this should work?)

Update №1

On @faker's suggestion, I put echo $PATH in the script before the call to django-admin.py. The . virtualenv/bin/activate changes the shell path. I get a path of /var/www/example.com/virtualenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11:/usr/games when I run it via ssh HOSTNAME /path/to/script.sh, and after logging in I get /var/www/example.com/virtualenv/bin:/home/rory/bin/:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11:/usr/games. The only difference is the ~/bin part, but I did a which django-admin.py aswell, and in both instances it's using /var/www/example.com/virtualenv/bin/django-admin.py so in both instances it's using the same programme for the django-admin.py command.

Update №2

On @Andrew Schulman's advice of the same, but for $PYTHONPATH. PYTHONPATH was empty in both cases. However I added python -c 'import sys; print sys.path' instead of just echo $PYTHONPATH, and got different results.

When I ssh into HOSTNAME and run script manually (the one that works):

['', '/var/www/example.com/virtualenv/lib/python2.6/site-packages/distribute-0.6.10-py2.6.egg', '/var/www/example.com/virtualenv/lib/python2.6/site-packages/pip-1.0.2-py2.6.egg', '/var/www/example.com/mysite', '/home/rory/code/python/lib', '/var/www/example.com/virtualenv/lib/python2.6', '/var/www/example.com/virtualenv/lib/python2.6/plat-linux2', '/var/www/example.com/virtualenv/lib/python2.6/lib-tk', '/var/www/example.com/virtualenv/lib/python2.6/lib-old', '/var/www/example.com/virtualenv/lib/python2.6/lib-dynload', '/usr/lib/python2.6', '/usr/lib/python2.6/plat-linux2', '/usr/lib/python2.6/lib-tk', '/var/www/example.com/virtualenv/lib/python2.6/site-packages']

When I invoke the script over ssh (this doesn't work):

['', '/var/www/example.com/virtualenv/lib/python2.6/site-packages/distribute-0.6.10-py2.6.egg', '/var/www/example.com/virtualenv/lib/python2.6/site-packages/pip-1.0.2-py2.6.egg', '/var/www/example.com/virtualenv/lib/python2.6', '/var/www/example.com/virtualenv/lib/python2.6/plat-linux2', '/var/www/example.com/virtualenv/lib/python2.6/lib-tk', '/var/www/example.com/virtualenv/lib/python2.6/lib-old', '/var/www/example.com/virtualenv/lib/python2.6/lib-dynload', '/usr/lib/python2.6', '/usr/lib/python2.6/plat-linux2', '/usr/lib/python2.6/lib-tk', '/var/www/example.com/virtualenv/lib/python2.6/site-packages']

The working version has a /var/www/example.com/mysite. The settings file is located in /var/www/example.com/mysite/settings/my_hostname.py. This makes sense since the working invokcation can load the file.

Why isn't the 'remotely invoked' version getting that on it's python path?


Change your script and put -l after the shebang. so #!/bin/bash -l

Alternatively change your ssh command to ssh HOSTNAME bash -l /var/www/example.com/dumper.sh

Rationale: When you run ssh HOSTNAME command instead of just ssh HOSTNAME, the shell used to launch command is not a 'login' shell, and so different scripts get called (See the INVOCATION section of man bash) which results in your environment being setup differently.


I have discovered that you need to quote the bash line for it to recognize the -l properly, like this:

ssh HOSTNAME "bash -l /path/to/script.sh"