I want to use .sh script for deployment of my app. That script is on my home server (Ubuntu 15.10 Server), marked as executable. Access to this script is done through ssh, using this tutorial, I have set up ssh login, that runs that script. So basically I just call ssh someArguments and it runs my script with someArguments as parameters. The user deployer has uid=0, so its basically root (this will be changed in the future, I have set it only to eliminate permissions problems until it works fine).
And here is where the things get tricky. The script reports /usr/bin/env: php: No such file or directory at command /bin/composer install (using Composer). Things are more weird the more I look on that script. Before this line, there is also called /bin/composer self-update and /bin/composer -V, which both runs correctly and displays correct output.
I have checked following things:
/usr/bin/env php -vdisplays correct PHP version (same as/usr/bin/php -v)whereis phpdisplaysphp: /usr/bin/php /usr/local/bin/php /usr/share/man/man1/php.1.gzphp5-clipackage is installed and newest version$PATHcontains/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/gameswhich envdisplays/usr/bin/env
I have also tried following things:
- running the script directly as
bash deploy.shunder root (since it is same as that user) - works perfectly without errors - running failing commands directly - also perfectly without errors
So this seems to me as very specific case, why this command does not work. I spent 12 hours of debugging it and I am out of ideas here.
P.S.: Similar error (/usr/bin/env: node: No such file or directory) occurs when there is bower install (using Bower), but not when running npm install (using NPM).
6 Answers
Make sure that line endings and/or invisible spaces aren't causing the problem.
Remove the spaces in the first line of the script and insert new ones, making sure not to hold CTRL while pressing space.
Also, make sure you don't have DOS line endings (CR+LF). See for details.
1The env command will look through a user's $PATH to find the first executable of the given name. So, /usr/bin/env php will look for an executable file called php in any of the directories in the $PATH of the user running it.
In your case, that's almost certainly because when running a command over ssh, you don't start a full shell and don't actually read your shell's initialization files. You can check this by running this command (note the single quotes):
ssh 'echo $PATH'And comparing the output to what you get if you ssh and then run echo $PATH. On my system. for example:
$ echo $PATH
/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:
$ ssh localhost 'echo $PATH'
/usr/bin:/bin:/usr/sbin:/sbinTherefore, the $PATH that your script has access to when run with ssh is not the same as when you log in to test it.
In any case, the simple solution is to use the full path to the interpreter instead of env. Both env and full paths have their benefits and drawbacks but, in this case, the path is safer:
#!/usr/bin/php 5 Easiest way.... change the user's shell as the script.
/etc/passwd
Before:
deploy:x:0:0:,,,:/root:/bin/bash
After:
deploy:x:0:0:,,,:/root:/scripts/deploy.shExample script (make sure execute bit is set chmod +x)
/scripts/deploy.sh
#!/bin/bash
PATH=$PATH:/moo etc...
moo.shWorks everytime! You should even be able to use the script to troubleshoot/debug any env variables which you may feel are unset etc ... also the handling arguments being passed into ssh will work as well..
Note: Its Best Practice to always FULLY QUALIFY the paths for any scripts, executables, etc.. Above is just an example which allows the default path to be set to call moo.sh within the moo folder ;)
That was easy.. Thanks for posting..
Reference: /etc/passwd format
4Is it possible that bash needs a reset to its hash table?
If so, you might try adding hash -r somewhere in your script, which forces the shell to look through $PATH again rather than relying on (possibly outdated) info from the hash table.
When needed, hash can also enable the shell to remember paths to executables installed in non-standard locations using the -p option, or forget paths with the -d option.
Sources:
Looks like maybe you need to add php to your path. Try:
vim ~/.bashrc
PATH=$PATH:/usr/local/bin/php
export PATHYou might also want to check where your php lives to be sure that the path there is correct. Try:
which php 1 It is clear that you have a path problem since your deploy script can't find things that are definitely on the path when you do a normal ssh login.
First thing to do to confirm you have a PATH issue is to update your deploy script to log the output of env or at least echo $PATH. I am guessing that the way your deploy script is called, $PATH is not set as you would expect. This debug output will confirm/deny my theory.
I looked at the tutorial you followed. You should probably make sure at update the command= to be command="/bin/sh /path/to/your/script..." if you haven't already to make sure your script is run by the right shell.
If you do have a PATH problem, a quick/dirty fix is just to explicitly set PATH at the beginning of your deploy script.
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"Detailed explanation and further options...
On linux when commands are run they inherit the environment of their parent process.
When you login as a normal user via SSH there are things that happen (like running /etc/bashrc /etc/profile ~/.bash_profile ~/.bashrc etc). At that point you have may have updated your process's environment by doing things like export PATH="$PATH:~/mybin" in those scripts. Now any future processes that you run will inherit your current environment.
Running a command instead of getting a login shell means that command is run by the ssh daemon and will inherit the environment of the ssh daemon process...which is likely different than your environment as a logged in user.
The man page for authorized keys covers what happens after authentication. Regarding environment:
- Reads the file ~/.ssh/environment, if it exists, and users are allowed to change their environment. See the PermitUserEnvironment option in sshd_config(5).
So the appropriate place to configure environment for the process is in ~/.ssh/environment where ~ is the home directory for the user that is authenticated to run the command. You also need to check your sshd_config to make sure PermitUserEnvironment is allowed.
~/.ssh/environment format is also specified in the man page of course.
This file is read into the environment at login (if it exists). It can only contain empty lines, comment lines (that start with '#'), and assignment lines of the form name=value. The file should be writable only by the user; it need not be readable by directory becomes accessible. This file should be writable only by the user, and need not be readable by anyone else.
An alternative way to specify the environment without using the above mentioned method is to use the environment="NAME=value" option in the authorized_keys file. See the man page I linked above for details.